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)
|