# HG changeset patch
# User Jean-Pierre Flori <jean-pierre.flori@ssi.gouv.fr>
# Date 1328879416 -3600
# Node ID 5bc48828f8b11afe38a78e97494f616330290466
# Parent cd70dd22ca28927add3ba28eca28379bb89f4fe8
#715: Make use of weakrefs for action optional: off by default, on for coercion
diff --git a/sage/categories/action.pxd b/sage/categories/action.pxd
a
|
b
|
|
8 | 8 | cdef S |
9 | 9 | cdef bint _is_left |
10 | 10 | cdef op |
| 11 | cdef bint _use_weakrefs |
11 | 12 | cdef underlying_set(self) |
12 | 13 | cpdef _call_(self, a, b) |
13 | 14 | |
diff --git a/sage/categories/action.pyx b/sage/categories/action.pyx
a
|
b
|
|
45 | 45 | |
46 | 46 | cdef class Action(Functor): |
47 | 47 | |
48 | | def __init__(self, G, S, bint is_left = 1, op=None): |
| 48 | def __init__(self, G, S, bint is_left = 1, op=None, |
| 49 | bint use_weakrefs = False): |
49 | 50 | from groupoid import Groupoid |
50 | 51 | Functor.__init__(self, Groupoid(G), category(S)) |
| 52 | self._use_weakrefs = use_weakrefs |
51 | 53 | self.G = G |
52 | | self.S = ref(S) |
| 54 | if self._use_weakrefs: |
| 55 | self.S = ref(S) |
| 56 | else: |
| 57 | self.S = S |
53 | 58 | self._is_left = is_left |
54 | 59 | self.op = op |
55 | 60 | |
… |
… |
|
150 | 155 | RuntimeError: This action acted on a set that became garbage collected |
151 | 156 | |
152 | 157 | """ |
153 | | S = self.S() |
154 | | if S is None: |
155 | | raise RuntimeError, "This action acted on a set that became garbage collected" |
156 | | return S |
| 158 | if self._use_weakrefs: |
| 159 | return self.S() |
| 160 | return self.S |
157 | 161 | |
158 | 162 | def codomain(self): |
159 | | return self.underlying_set() |
| 163 | return self.underlying_set() |
160 | 164 | |
161 | 165 | def domain(self): |
162 | 166 | return self.underlying_set() |
… |
… |
|
201 | 205 | # We must be in the case that parent(~a) == parent(a) |
202 | 206 | # so we can invert in call_c code below. |
203 | 207 | if (PY_TYPE_CHECK(G, Group) and G.is_multiplicative()) or G.is_field(): |
204 | | Action.__init__(self, G, action.underlying_set(), action._is_left) |
| 208 | Action.__init__(self, G, action.underlying_set(), action._is_left, use_weakrefs=action._use_weakrefs) |
205 | 209 | self._action = action |
206 | 210 | return |
207 | 211 | else: |
208 | 212 | K = G._pseudo_fraction_field() |
209 | | Action.__init__(self, K, action.underlying_set(), action._is_left) |
| 213 | Action.__init__(self, K, action.underlying_set(), action._is_left, use_weakrefs=action._use_weakrefs) |
210 | 214 | self._action = action |
211 | 215 | return |
212 | 216 | except (AttributeError, NotImplementedError): |
… |
… |
|
246 | 250 | right_precomposition = homset.Hom(right_precomposition._codomain, right).natural_map() * right_precomposition |
247 | 251 | right = right_precomposition._domain |
248 | 252 | if action._is_left: |
249 | | Action.__init__(self, left, action.underlying_set(), 1) |
| 253 | Action.__init__(self, left, action.underlying_set(), 1, use_weakrefs=action._use_weakrefs) |
250 | 254 | else: |
251 | | Action.__init__(self, right, action.underlying_set(), 0) |
| 255 | Action.__init__(self, right, action.underlying_set(), 0, use_weakrefs=action._use_weakrefs) |
252 | 256 | self._action = action |
253 | 257 | self.left_precomposition = left_precomposition |
254 | 258 | self.right_precomposition = right_precomposition |
diff --git a/sage/structure/coerce.pyx b/sage/structure/coerce.pyx
a
|
b
|
|
1362 | 1362 | if is_inverse: a = ~a |
1363 | 1363 | if a is not None and PY_TYPE_CHECK(a, RightModuleAction): |
1364 | 1364 | # We want a new instance so that we don't alter the (potentially cached) original |
1365 | | a = RightModuleAction(S, R) |
| 1365 | a = RightModuleAction(S, R, use_weakrefs=True) |
1366 | 1366 | a.is_inplace = 1 |
1367 | 1367 | if is_inverse: a = ~a |
1368 | 1368 | return a |
diff --git a/sage/structure/coerce_actions.pyx b/sage/structure/coerce_actions.pyx
a
|
b
|
|
39 | 39 | |
40 | 40 | cdef class LAction(Action): |
41 | 41 | """Action calls _l_action of the actor.""" |
42 | | def __init__(self, G, S): |
43 | | Action.__init__(self, G, S, True, operator.mul) |
| 42 | def __init__(self, G, S, bint use_weakrefs = False): |
| 43 | Action.__init__(self, G, S, True, operator.mul, use_weakrefs) |
44 | 44 | cpdef _call_(self, g, a): |
45 | 45 | return g._l_action(a) # a * g |
46 | 46 | |
47 | 47 | |
48 | 48 | cdef class RAction(Action): |
49 | 49 | """Action calls _r_action of the actor.""" |
50 | | def __init__(self, G, S): |
51 | | Action.__init__(self, G, S, False, operator.mul) |
| 50 | def __init__(self, G, S, bint use_weakrefs = False): |
| 51 | Action.__init__(self, G, S, False, operator.mul, use_weakrefs) |
52 | 52 | cpdef _call_(self, a, g): |
53 | 53 | return g._r_action(a) # g * a |
54 | 54 | |
… |
… |
|
59 | 59 | |
60 | 60 | cdef _codomain |
61 | 61 | |
62 | | def __init__(self, Parent G, S, is_left, bint check=True): |
| 62 | def __init__(self, Parent G, S, is_left, bint check=True, |
| 63 | bint use_weakrefs = False): |
63 | 64 | """ |
64 | 65 | TESTS:: |
65 | 66 | |
… |
… |
|
77 | 78 | Left action by Rational Field on Ring of integers modulo 6 |
78 | 79 | |
79 | 80 | """ |
80 | | Action.__init__(self, G, S, is_left, operator.mul) |
| 81 | Action.__init__(self, G, S, is_left, operator.mul, use_weakrefs) |
81 | 82 | if check: |
82 | 83 | res = self.act(G.an_element(), S.an_element()) |
83 | 84 | if res is None: |
… |
… |
|
201 | 202 | try: |
202 | 203 | # Elements defining _act_on_ |
203 | 204 | if x._act_on_(y, X_on_left) is not None: |
204 | | return ActOnAction(X, Y, X_on_left, False) |
| 205 | return ActOnAction(X, Y, X_on_left, False, use_weakrefs=True) |
205 | 206 | except CoercionException: |
206 | 207 | _record_exception() |
207 | 208 | if isinstance(Y, Parent): |
208 | 209 | try: |
209 | 210 | # Elements defining _acted_upon_ |
210 | 211 | if x._acted_upon_(y, X_on_left) is not None: |
211 | | return ActedUponAction(Y, X, not X_on_left, False) |
| 212 | return ActedUponAction(Y, X, not X_on_left, False, use_weakrefs=True) |
212 | 213 | except CoercionException: |
213 | 214 | _record_exception() |
214 | 215 | |
215 | 216 | |
216 | 217 | cdef class ModuleAction(Action): |
217 | 218 | |
218 | | def __init__(self, G, S): |
| 219 | def __init__(self, G, S, use_weakrefs = False): |
219 | 220 | """ |
220 | 221 | This creates an action of an element of a module by an element of its |
221 | 222 | base ring. The simplest example to keep in mind is R acting on the |
… |
… |
|
253 | 254 | 1/x |
254 | 255 | |
255 | 256 | """ |
256 | | Action.__init__(self, G, S, not PY_TYPE_CHECK(self, RightModuleAction), operator.mul) |
| 257 | Action.__init__(self, G, S, not PY_TYPE_CHECK(self, RightModuleAction), operator.mul, use_weakrefs) |
257 | 258 | if not isinstance(G, Parent): |
258 | 259 | # only let Parents act |
259 | 260 | raise TypeError, "Actor must be a parent." |
… |
… |
|
425 | 426 | |
426 | 427 | cdef class IntegerMulAction(Action): |
427 | 428 | |
428 | | def __init__(self, ZZ, M, is_left=True): |
| 429 | def __init__(self, ZZ, M, is_left=True, bint use_weakrefs = False): |
429 | 430 | r""" |
430 | 431 | This class implements the action `n \cdot a = a + a + \cdots + a` via |
431 | 432 | repeated doubling. |
… |
… |
|
448 | 449 | from sage.structure.parent import Set_PythonType |
449 | 450 | ZZ = Set_PythonType(ZZ) |
450 | 451 | test = M.an_element() + (-M.an_element()) # make sure addition and negation is allowed |
451 | | Action.__init__(self, ZZ, M, is_left, operator.mul) |
| 452 | Action.__init__(self, ZZ, M, is_left, operator.mul, use_weakrefs) |
452 | 453 | |
453 | 454 | cpdef _call_(self, nn, a): |
454 | 455 | """ |
diff --git a/sage/structure/parent.pyx b/sage/structure/parent.pyx
a
|
b
|
|
1630 | 1630 | |
1631 | 1631 | sage: class SymmetricGroupAction(sage.categories.action.Action): |
1632 | 1632 | ... "Act on a multivariate polynomial ring by permuting the generators." |
1633 | | ... def __init__(self, G, M, is_left=True): |
1634 | | ... sage.categories.action.Action.__init__(self, G, M, is_left, operator.mul) |
| 1633 | ... def __init__(self, G, M, is_left=True, use_weak_references=True): |
| 1634 | ... sage.categories.action.Action.__init__(self, G, M, is_left, operator.mul, use_weak_references) |
1635 | 1635 | ... |
1636 | 1636 | ... def _call_(self, g, a): |
1637 | 1637 | ... if not self.is_left(): |
… |
… |
|
2255 | 2255 | R = action |
2256 | 2256 | _register_pair(self, R, "action") # to kill circular recursion |
2257 | 2257 | if self_on_left: |
2258 | | action = LeftModuleAction(R, self) # self is acted on from right |
| 2258 | action = LeftModuleAction(R, self, use_weakrefs=True) # self is acted on from right |
2259 | 2259 | else: |
2260 | | action = RightModuleAction(R, self) # self is acted on from left |
| 2260 | action = RightModuleAction(R, self, use_weakrefs=True) # self is acted on from left |
2261 | 2261 | ## The following two lines are disabled to prevent the following from working: |
2262 | 2262 | ## sage: x, y = var('x,y') |
2263 | 2263 | ## sage: parent(ZZ[x][y](1)*vector(QQ[y],[1,2])) |
… |
… |
|
2304 | 2304 | from sage.rings.integer_ring import ZZ |
2305 | 2305 | if S is ZZ and not self.has_coerce_map_from(ZZ): |
2306 | 2306 | from sage.structure.coerce_actions import IntegerMulAction |
2307 | | action = IntegerMulAction(S, self, not self_on_left) |
| 2307 | action = IntegerMulAction(S, self, not self_on_left, use_weakrefs=True) |
2308 | 2308 | return action |
2309 | 2309 | except (CoercionException, TypeError): |
2310 | 2310 | _record_exception() |