Coverage for local/lib/python2.7/site-packages/sage/categories/action.pyx : 64%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
|
r""" Group, ring, etc. actions on objects.
The terminology and notation used is suggestive of groups acting on sets, but this framework can be used for modules, algebras, etc.
A group action $G \times S \rightarrow S$ is a functor from $G$ to Sets.
.. WARNING::
An :class:`Action` object only keeps a weak reference to the underlying set which is acted upon. This decision was made in :trac:`715` in order to allow garbage collection within the coercion framework (this is where actions are mainly used) and avoid memory leaks.
::
sage: from sage.categories.action import Action sage: class P: pass sage: A = Action(P(),P()) sage: import gc sage: _ = gc.collect() sage: A <repr(<sage.categories.action.Action at 0x...>) failed: RuntimeError: This action acted on a set that became garbage collected>
To avoid garbage collection of the underlying set, it is sufficient to create a strong reference to it before the action is created.
::
sage: _ = gc.collect() sage: from sage.categories.action import Action sage: class P: pass sage: q = P() sage: A = Action(P(),q) sage: gc.collect() 0 sage: A Left action by <__main__.P instance at ...> on <__main__.P instance at ...>
AUTHOR:
- Robert Bradshaw: initial version """
#***************************************************************************** # Copyright (C) 2007 Robert Bradshaw <robertwb@math.washington.edu> # # Distributed under the terms of the GNU General Public License (GPL) # # This code is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # See the GNU General Public License for more details; the full text # is available at: # # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import absolute_import
from .functor cimport Functor from .morphism cimport Morphism from .map cimport Map from sage.structure.parent cimport Parent
from . import homset import sage.structure.element from weakref import ref from sage.misc.constant_function import ConstantFunction
cdef inline category(x):
cdef class Action(Functor):
def __init__(self, G, S, bint is_left = 1, op=None):
def _apply_functor(self, x): return self(x)
def __call__(self, *args): elif g == self.G: return self.underlying_set() else: raise TypeError("%s not an element of %s" % (g, self.G)) else:
cpdef _call_(self, a, b):
def act(self, g, a): """ This is a consistent interface for acting on a by g, regardless of whether it's a left or right action. """ else:
def __invert__(self):
def is_left(self):
def _repr_(self):
def _repr_name_(self):
def actor(self):
cdef underlying_set(self): """ The set on which the actor acts (it is not necessarily the codomain of the action).
.. NOTE::
Since this is a cdef'ed method, we can only provide an indirect doctest.
EXAMPLES::
sage: P = QQ['x'] sage: R = (ZZ['x'])['y'] sage: A = R.get_action(P,operator.mul,True) sage: A # indirect doctest Right scalar multiplication by Univariate Polynomial Ring in x over Rational Field on Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Integer Ring
In this example, the underlying set is the ring ``R``. This is the same as the left domain, which is different from the codomain of the action::
sage: A.codomain() Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field sage: A.codomain() == R False sage: A.left_domain() is R True
By :trac:`715`, there is only a weak reference to the underlying set. Hence, the underlying set may be garbage collected, even when the action is still alive. This may result in a runtime error, as follows::
sage: from sage.categories.action import Action sage: class P: pass sage: p = P() sage: q = P() sage: A = Action(p,q) sage: A Left action by <__main__.P instance at ...> on <__main__.P instance at ...> sage: del q sage: import gc sage: _ = gc.collect() sage: A <repr(<sage.categories.action.Action at 0x...>) failed: RuntimeError: This action acted on a set that became garbage collected> """
def codomain(self):
def domain(self):
def left_domain(self): else:
def right_domain(self): else:
def operation(self):
cdef class InverseAction(Action): """ An action that acts as the inverse of the given action.
EXAMPLES::
sage: V = QQ^3 sage: v = V((1, 2, 3)) sage: cm = get_coercion_model()
sage: a = cm.get_action(V, QQ, operator.mul) sage: a Right scalar multiplication by Rational Field on Vector space of dimension 3 over Rational Field sage: ~a Right inverse action by Rational Field on Vector space of dimension 3 over Rational Field sage: (~a)(v, 1/3) (3, 6, 9)
sage: b = cm.get_action(QQ, V, operator.mul) sage: b Left scalar multiplication by Rational Field on Vector space of dimension 3 over Rational Field sage: ~b Left inverse action by Rational Field on Vector space of dimension 3 over Rational Field sage: (~b)(1/3, v) (3, 6, 9)
sage: c = cm.get_action(ZZ, list, operator.mul) sage: c Left action by Integer Ring on <... 'list'> sage: ~c Traceback (most recent call last): ... TypeError: no inverse defined for Left action by Integer Ring on <... 'list'>
TESTS:
sage: x = polygen(QQ,'x') sage: a = 2*x^2+2; a 2*x^2 + 2 sage: a / 2 x^2 + 1 sage: a /= 2 sage: a x^2 + 1 """ def __init__(self, Action action): # We must be in the case that parent(~a) == parent(a) # so we can invert in _call_ code below. except (AttributeError, NotImplementedError): pass
cpdef _call_(self, a, b): b = self.S_precomposition(b) else: a = self.S_precomposition(a)
def codomain(self):
def __invert__(self): return self._action
def _repr_name_(self):
cdef class PrecomposedAction(Action): """ A precomposed action first applies given maps, and then applying an action to the return values of the maps.
EXAMPLES:
We demonstrate that an example discussed on :trac:`14711` did not become a problem::
sage: E = ModularSymbols(11).2 sage: s = E.modular_symbol_rep() sage: del E,s sage: import gc sage: _ = gc.collect() sage: E = ModularSymbols(11).2 sage: v = E.manin_symbol_rep() sage: c,x = v[0] sage: y = x.modular_symbol_rep() sage: A = y.parent().get_action(QQ, self_on_left=False, op=operator.mul) sage: A Left scalar multiplication by Rational Field on Abelian Group of all Formal Finite Sums over Rational Field with precomposition on right by Coercion map: From: Abelian Group of all Formal Finite Sums over Integer Ring To: Abelian Group of all Formal Finite Sums over Rational Field """ def __init__(self, Action action, Map left_precomposition, Map right_precomposition): cdef Parent lco, rco left_precomposition = homset.Hom(lco, left).natural_map() * left_precomposition right_precomposition = homset.Hom(rco, right).natural_map() * right_precomposition else:
cpdef _call_(self, a, b):
def domain(self): else:
def codomain(self):
def __invert__(self):
def _repr_(self):
cdef class ActionEndomorphism(Morphism): """ The endomorphism defined by the action of one element.
EXAMPLES::
sage: A = ZZ['x'].get_action(QQ, self_on_left=False, op=operator.mul) sage: A Left scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring sage: A(1/2) Action of 1/2 on Univariate Polynomial Ring in x over Integer Ring under Left scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring. """ def __init__(self, Action action, g):
cdef dict _extra_slots(self): """ Helper for pickling and copying.
TESTS::
sage: P.<x> = ZZ[] sage: A = P.get_action(QQ, self_on_left=False, op=operator.mul) sage: phi = A(1/2) sage: psi = copy(phi) # indirect doctest sage: psi Action of 1/2 on Univariate Polynomial Ring in x over Integer Ring under Left scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring. sage: psi(x) == phi(x) True """
cdef _update_slots(self, dict _slots): """ Helper for pickling and copying.
TESTS::
sage: P.<x> = ZZ[] sage: A = P.get_action(QQ, self_on_left=False, op=operator.mul) sage: phi = A(1/2) sage: psi = copy(phi) # indirect doctest sage: psi Action of 1/2 on Univariate Polynomial Ring in x over Integer Ring under Left scalar multiplication by Rational Field on Univariate Polynomial Ring in x over Integer Ring. sage: psi(x) == phi(x) True """
cpdef Element _call_(self, x): else: return self._action._call_(x, self._g)
def _repr_(self):
def __mul__(left, right): cdef ActionEndomorphism left_c, right_c if isinstance(left, ActionEndomorphism) and isinstance(right, ActionEndomorphism): left_c = left right_c = right if left_c._action is right_c._action: if left_c._action._is_left: return ActionEndomorphism(left_c._action, left_c._g * right_c._g) else: return ActionEndomorphism(left_c._action, right_c._g * left_c._g) return Morphism.__mul__(left, right)
def __invert__(self): inv_g = ~self._g if sage.structure.element.parent(inv_g) is sage.structure.element.parent(self._g): return ActionEndomorphism(self._action, inv_g) else: return (~self._action)(self._g)
|