source: sage/categories/action.pyx @ 6663:8e7c1ba08cd1

Revision 6663:8e7c1ba08cd1, 7.9 KB checked in by Robert Bradshaw <robertwb@…>, 6 years ago (diff)

Matrix actions

Line 
1"""
2Group, ring, etc. actions on objects.
3
4The terminology and notation used is suggestive of groups
5acting on sets, but this framework can be used for modules,
6algebras, etc.
7
8A group action $G \times S \rightarrow S$ is a functor from $G$ to Sets.
9
10AUTHORS:
11    -- Robert Bradshaw: initial version
12"""
13
14#*****************************************************************************
15#  Copyright (C) 2007 Robert Bradshaw <robertwb@math.washington.edu>
16#
17#  Distributed under the terms of the GNU General Public License (GPL)
18#
19#    This code is distributed in the hope that it will be useful,
20#    but WITHOUT ANY WARRANTY; without even the implied warranty
21#    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22#
23#  See the GNU General Public License for more details; the full text
24#  is available at:
25#
26#                  http://www.gnu.org/licenses/
27#*****************************************************************************
28
29from functor cimport Functor
30from morphism cimport Morphism
31
32import homset
33import sage.structure.element
34
35include "../ext/stdsage.pxi"
36
37#def LeftAction(G, S, op=None):
38#    return Action(G, S, 1, op)
39#   
40#def RightAction(G, S, op=None):
41#    return Action(G, S, 0, op)
42
43cdef class Action(Functor):
44   
45    def __init__(self, G, S, bint is_left = 1, op=None):
46        from category_types import Groupoid
47        Functor.__init__(self, Groupoid(G), S.category())
48        self.G = G
49        self.S = S
50        self._is_left = is_left
51       
52    def _apply_functor(self, x):
53        return self(x)
54       
55    def __call__(self, *args):
56        if len(args) == 1:
57            g = args[0]
58            if g in self.G:
59                return ActionEndomorphism(self, self.G(g))
60            elif g == self.G:
61                return self.S
62            else:
63                raise TypeError, "%s not an element of %s"%(g, self.G)
64        elif len(args) == 2:
65            if self._is_left:
66                return self._call_c(self.G(args[0]), self.S(args[1]))
67            else:
68                return self._call_c(self.S(args[0]), self.G(args[1]))
69           
70    def _call_(self, a, b):
71        return self._call_c_impl(a, b)
72           
73    cdef Element _call_c(self, a, b):
74        if HAS_DICTIONARY(self):
75            return self._call_(a, b)
76        else:
77            return self._call_c_impl(a, b)
78           
79    cdef Element _call_c_impl(self, Element a, Element b):
80        raise NotImplementedError, "Action not implemented."
81       
82    def act(self, g, a):
83        """
84        This is a consistant interface for acting on a by g,
85        irregardless of whether its a left or right action.
86        """
87        if self._is_left:
88            return self._call_c(g, a)
89        else:
90            return self._call_c(a, g)
91           
92    def __invert__(self):
93        return InverseAction(self)
94           
95    def is_left(self):
96        return self._is_left
97       
98    def __repr__(self):
99        side = "Left" if self._is_left else "Right"
100        return "%s %s by %r on %r"%(side, self._repr_name_(), self.G, self.S)
101       
102    def _repr_name_(self):
103        return "action"
104       
105    def actor(self):
106        return self.G
107   
108    def codomain(self):
109        return self.S
110       
111    def domain(self):
112        return self.codomain()
113       
114    def left_domain(self):
115        if self._is_left:
116            return self.G
117        else:
118            return self.domain()
119       
120    def right_domain(self):
121        if self._is_left:
122            return self.domain()
123        else:
124            return self.G
125       
126       
127cdef class InverseAction(Action):
128    """
129    An action whose acts as the inverse of the given action.
130    """
131    def __init__(self, Action action):
132        G = action.G
133        try:
134            from sage.groups.group import Group
135            if (PY_TYPE_CHECK(G, Group) and G.is_multiplicative()) or G.is_field():
136                Action.__init__(self, G, action.S, action._is_left)
137                self._action = action
138                return
139            elif G.is_ring() and action.S.base_ring() is not action.S:
140                G = G.fraction_field()
141                S = action.S.base_extend(G)
142                Action.__init__(self, G, S, action._is_left)
143                self._action = action
144                if S is not action.S:
145                    self.S_precomposition = S.coerce_map_from(action.S)
146                return
147        except (AttributeError, NotImplementedError):
148            pass
149        raise TypeError, "No inverse defined for %r." % action
150       
151    cdef Element _call_c(self, a, b):
152        if self._action._is_left:
153            if self.S_precomposition is not None:
154                b = self.S_precomposition(b)
155            return self._action._call_c(~a, b)
156        else:
157            if self.S_precomposition is not None:
158                a = self.S_precomposition(a)
159            return self._action._call_c(a, ~b)
160           
161    def __invert__(self):
162        return self._action
163
164
165cdef class PrecomposedAction(Action):
166   
167    def __init__(self, Action action, Morphism left_precomposition, Morphism right_precomposition):
168        left = action.left_domain()
169        right = action.right_domain()
170        if left_precomposition is not None:
171            if left_precomposition._codomain is not left:
172                left_precomposition = homset.Hom(left_precomposition._codomain, left).natural_map() * left_precomposition
173            left = left_precomposition._domain
174        if right_precomposition is not None:
175            if right_precomposition._codomain is not right:
176              right_precomposition = homset.Hom(right_precomposition._codomain, right).natural_map() * right_precomposition
177            right = right_precomposition._domain
178        if action._is_left:
179            Action.__init__(left, action.S, 1)
180        else:
181            Action.__init__(right, action.S, 0)
182        self._action = action
183        self.left_precomposition = left_precomposition
184        self.right_precomposition = right_precomposition
185       
186    cdef Element _call_c(self, a, b):
187        if self.left_precomposition is not None:
188            a = self.left_precomposition._call_c(a)
189        if self.right_precomposition is not None:
190            b = self.right_precomposition._call_c(b)
191        return self._action._call_c(a, b)
192       
193    def domain(self):
194        if self._is_left and self.right_precomposition is not None:
195            return self.right_precomposition.domain()
196        elif not self._is_left and self.left_precomposition is not None:
197            return self.left_precomposition.domain()
198        else:
199            return self.codomain()
200
201
202cdef class ActionEndomorphism(Morphism):
203   
204    def __init__(self, Action action, g):
205        Morphism.__init__(self, homset.Hom(action.S, action.S))
206        self._action = action
207        self._g = g
208       
209    cdef Element _call_c(self, x):
210        if self._action._is_left:
211            return self._action._call_c(self._g, x)
212        else:
213            return self._action._call_c(x, self._g)
214               
215    def _repr_(self):
216        return "Action of %s on %s under %s."%(self._g, self._action.S, self._action)
217       
218    def __mul__(left, right):
219        cdef ActionEndomorphism left_c, right_c
220        if PY_TYPE_CHECK(left, ActionEndomorphism) and PY_TYPE_CHECK(right, ActionEndomorphism):
221            left_c = left
222            right_c = right
223            if left_c._action is right_c._action:
224                if left_c._action._is_left:
225                    return ActionEndomorphism(left_c._action, left_c._g * right_c._g)
226                else:
227                    return ActionEndomorphism(left_c._action, right_c._g * left_c._g)
228        return Morphism.__mul__(left, right)
229       
230    def __invert__(self):
231            inv_g = ~self._g
232            if sage.structure.element.parent(inv_g) is sage.structure.element.parent(self._g):
233                return ActionEndomorphism(self._action, inv_g)
234            else:
235                return (~self._action)(self._g)
236                   
237
Note: See TracBrowser for help on using the repository browser.