Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/categories/action.pyx
4058 views
1
r"""
2
Group, ring, etc. actions on objects.
3
4
The terminology and notation used is suggestive of groups
5
acting on sets, but this framework can be used for modules,
6
algebras, etc.
7
8
A group action $G \times S \rightarrow S$ is a functor from $G$ to Sets.
9
10
AUTHORS:
11
-- Robert Bradshaw: initial version
12
"""
13
14
#*****************************************************************************
15
# Copyright (C) 2007 Robert Bradshaw <[email protected]>
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
29
from functor cimport Functor
30
from morphism cimport Morphism
31
from map cimport Map
32
33
import homset
34
import sage.structure.element
35
36
include "../ext/stdsage.pxi"
37
38
cdef inline category(x):
39
try:
40
return x.category()
41
except AttributeError:
42
import sage.categories.all
43
return sage.categories.all.Objects()
44
45
cdef class Action(Functor):
46
47
def __init__(self, G, S, bint is_left = 1, op=None):
48
from groupoid import Groupoid
49
Functor.__init__(self, Groupoid(G), category(S))
50
self.G = G
51
self.S = S
52
self._is_left = is_left
53
self.op = op
54
55
def _apply_functor(self, x):
56
return self(x)
57
58
def __call__(self, *args):
59
if len(args) == 1:
60
g = args[0]
61
if g in self.G:
62
return ActionEndomorphism(self, self.G(g))
63
elif g == self.G:
64
return self.S
65
else:
66
raise TypeError, "%s not an element of %s"%(g, self.G)
67
elif len(args) == 2:
68
if self._is_left:
69
return self._call_(self.G(args[0]), self.S(args[1]))
70
else:
71
return self._call_(self.S(args[0]), self.G(args[1]))
72
73
cpdef _call_(self, a, b):
74
raise NotImplementedError, "Action not implemented."
75
76
def act(self, g, a):
77
"""
78
This is a consistent interface for acting on a by g,
79
regardless of whether it's a left or right action.
80
"""
81
if self._is_left:
82
return self._call_(g, a)
83
else:
84
return self._call_(a, g)
85
86
def __invert__(self):
87
return InverseAction(self)
88
89
def is_left(self):
90
return self._is_left
91
92
def __repr__(self):
93
side = "Left" if self._is_left else "Right"
94
return "%s %s by %r on %r"%(side, self._repr_name_(), self.G, self.S)
95
96
def _repr_name_(self):
97
return "action"
98
99
def actor(self):
100
return self.G
101
102
def codomain(self):
103
return self.S
104
105
def domain(self):
106
return self.S
107
108
def left_domain(self):
109
if self._is_left:
110
return self.G
111
else:
112
return self.domain()
113
114
def right_domain(self):
115
if self._is_left:
116
return self.domain()
117
else:
118
return self.G
119
120
def operation(self):
121
return self.op
122
123
124
cdef class InverseAction(Action):
125
"""
126
An action that acts as the inverse of the given action.
127
128
TESTS:
129
This illustrates a shortcoming in the current coercion model.
130
See the comments in _call_ below.
131
132
sage: x = polygen(QQ,'x')
133
sage: a = 2*x^2+2; a
134
2*x^2 + 2
135
sage: a / 2
136
x^2 + 1
137
sage: a /= 2
138
sage: a
139
x^2 + 1
140
"""
141
def __init__(self, Action action):
142
G = action.G
143
try:
144
from sage.groups.group import Group
145
# We must be in the case that parent(~a) == parent(a)
146
# so we can invert in call_c code below.
147
if (PY_TYPE_CHECK(G, Group) and G.is_multiplicative()) or G.is_field():
148
Action.__init__(self, G, action.S, action._is_left)
149
self._action = action
150
return
151
else:
152
K = G._pseudo_fraction_field()
153
Action.__init__(self, K, action.S, action._is_left)
154
self._action = action
155
return
156
except (AttributeError, NotImplementedError):
157
pass
158
raise TypeError, "No inverse defined for %r." % action
159
160
cpdef _call_(self, a, b):
161
if self._action._is_left:
162
if self.S_precomposition is not None:
163
b = self.S_precomposition(b)
164
return self._action._call_(~a, b)
165
else:
166
if self.S_precomposition is not None:
167
a = self.S_precomposition(a)
168
return self._action._call_(a, ~b)
169
170
def codomain(self):
171
return self._action.codomain()
172
173
def __invert__(self):
174
return self._action
175
176
def _repr_name_(self):
177
return "inverse action"
178
179
cdef class PrecomposedAction(Action):
180
181
def __init__(self, Action action, Map left_precomposition, Map right_precomposition):
182
left = action.left_domain()
183
right = action.right_domain()
184
if left_precomposition is not None:
185
if left_precomposition._codomain is not left:
186
left_precomposition = homset.Hom(left_precomposition._codomain, left).natural_map() * left_precomposition
187
left = left_precomposition._domain
188
if right_precomposition is not None:
189
if right_precomposition._codomain is not right:
190
right_precomposition = homset.Hom(right_precomposition._codomain, right).natural_map() * right_precomposition
191
right = right_precomposition._domain
192
if action._is_left:
193
Action.__init__(self, left, action.S, 1)
194
else:
195
Action.__init__(self, right, action.S, 0)
196
self._action = action
197
self.left_precomposition = left_precomposition
198
self.right_precomposition = right_precomposition
199
200
cpdef _call_(self, a, b):
201
if self.left_precomposition is not None:
202
a = self.left_precomposition._call_(a)
203
if self.right_precomposition is not None:
204
b = self.right_precomposition._call_(b)
205
return self._action._call_(a, b)
206
207
def domain(self):
208
if self._is_left and self.right_precomposition is not None:
209
return self.right_precomposition.domain()
210
elif not self._is_left and self.left_precomposition is not None:
211
return self.left_precomposition.domain()
212
else:
213
return self._action.domain()
214
215
def codomain(self):
216
return self._action.codomain()
217
218
def __invert__(self):
219
return PrecomposedAction(~self._action, self.left_precomposition, self.right_precomposition)
220
221
def __repr__(self):
222
s = repr(self._action)
223
if self.left_precomposition is not None:
224
s += "\nwith precomposition on left by %r" % self.left_precomposition
225
if self.right_precomposition is not None:
226
s += "\nwith precomposition on right by %r" % self.right_precomposition
227
return s
228
229
230
cdef class ActionEndomorphism(Morphism):
231
232
def __init__(self, Action action, g):
233
Morphism.__init__(self, homset.Hom(action.S, action.S))
234
self._action = action
235
self._g = g
236
237
cpdef Element _call_(self, x):
238
if self._action._is_left:
239
return self._action._call_(self._g, x)
240
else:
241
return self._action._call_(x, self._g)
242
243
def _repr_(self):
244
return "Action of %s on %s under %s."%(self._g, self._action.S, self._action)
245
246
def __mul__(left, right):
247
cdef ActionEndomorphism left_c, right_c
248
if PY_TYPE_CHECK(left, ActionEndomorphism) and PY_TYPE_CHECK(right, ActionEndomorphism):
249
left_c = left
250
right_c = right
251
if left_c._action is right_c._action:
252
if left_c._action._is_left:
253
return ActionEndomorphism(left_c._action, left_c._g * right_c._g)
254
else:
255
return ActionEndomorphism(left_c._action, right_c._g * left_c._g)
256
return Morphism.__mul__(left, right)
257
258
def __invert__(self):
259
inv_g = ~self._g
260
if sage.structure.element.parent(inv_g) is sage.structure.element.parent(self._g):
261
return ActionEndomorphism(self._action, inv_g)
262
else:
263
return (~self._action)(self._g)
264
265
266
267