Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/groups/affine_gps/group_element.py
8815 views
1
"""
2
Elements of Affine Groups
3
4
The class in this module is used to represent the elements of
5
:func:`~sage.groups.affine_gps.affine_group.AffineGroup` and its
6
subgroups.
7
8
EXAMPLES::
9
10
sage: F = AffineGroup(3, QQ)
11
sage: F([1,2,3,4,5,6,7,8,0], [10,11,12])
12
[1 2 3] [10]
13
x |-> [4 5 6] x + [11]
14
[7 8 0] [12]
15
16
sage: G = AffineGroup(2, ZZ)
17
sage: g = G([[1,1],[0,1]], [1,0])
18
sage: h = G([[1,2],[0,1]], [0,1])
19
sage: g*h
20
[1 3] [2]
21
x |-> [0 1] x + [1]
22
sage: h*g
23
[1 3] [1]
24
x |-> [0 1] x + [1]
25
sage: g*h != h*g
26
True
27
28
AUTHORS:
29
30
- Volker Braun
31
"""
32
33
#*****************************************************************************
34
# Copyright (C) 2006 David Joyner and William Stein <[email protected]>
35
#
36
# Distributed under the terms of the GNU General Public License (GPL)
37
#
38
# http://www.gnu.org/licenses/
39
#*****************************************************************************
40
41
from sage.matrix.matrix import is_Matrix
42
from sage.misc.cachefunc import cached_method
43
from sage.groups.matrix_gps.group_element import MatrixGroupElement_base
44
45
class AffineGroupElement(MatrixGroupElement_base):
46
"""
47
An affine group element.
48
49
INPUT:
50
51
- ``A`` -- an invertible matrix, or something defining a
52
matrix if ``convert==True``.
53
54
- ``b``-- a vector, or something defining a vector if
55
``convert==True`` (default: ``0``, defining the zero
56
vector).
57
58
- ``parent`` -- the parent affine group.
59
60
- ``convert`` - bool (default: ``True``). Whether to convert
61
``A`` into the correct matrix space and ``b`` into the
62
correct vector space.
63
64
- ``check`` - bool (default: ``True``). Whether to do some
65
checks or just accept the input as valid.
66
67
As a special case, ``A`` can be a matrix obtained from
68
:meth:`matrix`, that is, one row and one column larger. In
69
that case, the group element defining that matrix is
70
reconstructed.
71
72
OUTPUT:
73
74
The affine group element `x \mapsto Ax + b`
75
76
EXAMPLES::
77
78
sage: G = AffineGroup(2, GF(3))
79
sage: g = G.random_element()
80
sage: type(g)
81
<class 'sage.groups.affine_gps.group_element.AffineGroup_with_category.element_class'>
82
sage: G(g.matrix()) == g
83
True
84
sage: G(2)
85
[2 0] [0]
86
x |-> [0 2] x + [0]
87
"""
88
def __init__(self, parent, A, b=0, convert=True, check=True):
89
r"""
90
Create element of an affine group.
91
92
TESTS::
93
94
sage: G = AffineGroup(4, GF(5))
95
sage: g = G.random_element()
96
sage: TestSuite(g).run()
97
"""
98
if is_Matrix(A) and A.nrows() == A.ncols() == parent.degree()+1:
99
g = A
100
A = g.submatrix(0,0,2,2)
101
d = parent.degree()
102
b = [ g[i,d] for i in range(d) ]
103
convert = True
104
if convert:
105
A = parent.matrix_space()(A)
106
b = parent.vector_space()(b)
107
if check:
108
# Note: the coercion framework expects that we raise TypeError for invalid input
109
if not is_Matrix(A):
110
raise TypeError('A must be a matrix')
111
if not (A.parent() is parent.matrix_space()):
112
raise TypeError('A must be an element of '+str(parent.matrix_space()))
113
if not (b.parent() is parent.vector_space()):
114
raise TypeError('b must be an element of '+str(parent.vector_space()))
115
parent._element_constructor_check(A, b)
116
super(AffineGroupElement, self).__init__(parent)
117
self._A = A
118
self._b = b
119
120
def A(self):
121
"""
122
Return the general linear part of an affine group element.
123
124
OUTPUT:
125
126
The matrix `A` of the affine group element `Ax + b`.
127
128
EXAMPLES::
129
130
sage: G = AffineGroup(3, QQ)
131
sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12])
132
sage: g.A()
133
[1 2 3]
134
[4 5 6]
135
[7 8 0]
136
"""
137
return self._A
138
139
def b(self):
140
"""
141
Return the translation part of an affine group element.
142
143
OUTPUT:
144
145
The vector `b` of the affine group element `Ax + b`.
146
147
EXAMPLES::
148
149
sage: G = AffineGroup(3, QQ)
150
sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12])
151
sage: g.b()
152
(10, 11, 12)
153
"""
154
return self._b
155
156
@cached_method
157
def matrix(self):
158
"""
159
Return the standard matrix representation of ``self``.
160
161
.. SEEALSO::
162
163
- :meth:`AffineGroup.linear_space()`
164
165
EXAMPLES::
166
167
sage: G = AffineGroup(3, GF(7))
168
sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12])
169
sage: g
170
[1 2 3] [3]
171
x |-> [4 5 6] x + [4]
172
[0 1 0] [5]
173
sage: g.matrix()
174
[1 2 3|3]
175
[4 5 6|4]
176
[0 1 0|5]
177
[-----+-]
178
[0 0 0|1]
179
sage: parent(g.matrix())
180
Full MatrixSpace of 4 by 4 dense matrices over Finite Field of size 7
181
sage: g.matrix() == matrix(g)
182
True
183
184
Composition of affine group elements equals multiplication of
185
the matrices::
186
187
sage: g1 = G.random_element()
188
sage: g2 = G.random_element()
189
sage: g1.matrix() * g2.matrix() == (g1*g2).matrix()
190
True
191
"""
192
A = self._A
193
b = self._b
194
parent = self.parent()
195
d = parent.degree()
196
from sage.matrix.constructor import matrix, zero_matrix, block_matrix
197
zero = zero_matrix(parent.base_ring(), 1, d)
198
one = matrix(parent.base_ring(), [[1]])
199
m = block_matrix(2,2, [A, b.column(), zero, one])
200
m.set_immutable()
201
return m
202
203
_matrix_ = matrix
204
205
def _repr_(self):
206
"""
207
Return a string representation of ``self``.
208
209
EXAMPLES::
210
211
sage: G = AffineGroup(2, QQ)
212
sage: g = G([[1, 1], [0, 1]], [3,4])
213
sage: g
214
[1 1] [3]
215
x |-> [0 1] x + [4]
216
"""
217
A = str(self._A)
218
b = str(self._b.column())
219
deg = self.parent().degree()
220
indices = range(deg)
221
s = []
222
for Ai, bi, i in zip(A.splitlines(), b.splitlines(), indices):
223
if i == deg//2:
224
s.append('x |-> '+Ai+' x + '+bi)
225
else:
226
s.append(' '+Ai+' '+bi)
227
return '\n'.join(s)
228
229
def _latex_(self):
230
r"""
231
Return a LaTeX representation of ``self``.
232
233
EXAMPLES::
234
235
sage: G = AffineGroup(2, QQ)
236
sage: g = G([[1, 1], [0, 1]], [3,4])
237
sage: latex(g)
238
\vec{x}\mapsto \left(\begin{array}{rr}
239
1 & 1 \\
240
0 & 1
241
\end{array}\right)\vec{x} + \left(\begin{array}{r}
242
3 \\
243
4
244
\end{array}\right)
245
sage: g._latex_()
246
'\\vec{x}\\mapsto \\left(\\begin{array}{rr}\n1 & 1 \\\\\n0 &
247
1\n\\end{array}\\right)\\vec{x} + \\left(\\begin{array}{r}\n3
248
\\\\\n4\n\\end{array}\\right)'
249
"""
250
return r'\vec{x}\mapsto '+self.A()._latex_()+r'\vec{x} + '+self.b().column()._latex_()
251
252
def _mul_(self, other):
253
"""
254
Return the composition of ``self`` and ``other``.
255
256
INPUT:
257
258
- ``other`` -- another element of the same affine group.
259
260
OUTPUT:
261
262
The product of the affine group elements ``self`` and
263
``other`` defined by the composition of the two affine
264
transformations.
265
266
EXAMPLES::
267
268
sage: G = AffineGroup(2, GF(3))
269
sage: g = G([1,1, 0,1], [0,1])
270
sage: h = G([1,1, 0,1], [1,2])
271
sage: g*h
272
[1 2] [0]
273
x |-> [0 1] x + [0]
274
sage: g.matrix() * h.matrix() == (g*h).matrix()
275
True
276
"""
277
parent = self.parent()
278
A = self._A * other._A
279
b = self._b + self._A * other._b
280
return parent.element_class(parent, A, b, check=False)
281
282
def __call__(self, v):
283
"""
284
Apply the affine transformation to ``v``.
285
286
INPUT:
287
288
- ``v`` -- a multivariate polynomial, a vector, or anything
289
that can be converted into a vector.
290
291
OUTPUT:
292
293
The image of ``v`` under the affine group element.
294
295
EXAMPLES::
296
297
sage: G = AffineGroup(2, QQ)
298
sage: g = G([0,1,-1,0],[2,3]); g
299
[ 0 1] [2]
300
x |-> [-1 0] x + [3]
301
sage: v = vector([4,5])
302
sage: g(v)
303
(7, -1)
304
305
sage: R.<x,y> = QQ[]
306
sage: g(x), g(y)
307
(y + 2, -x + 3)
308
sage: p = x^2 + 2*x*y + y + 1
309
sage: g(p)
310
-2*x*y + y^2 - 5*x + 10*y + 20
311
312
The action on polynomials is such that it intertwines with
313
evaluation. That is::
314
315
sage: p(*g(v)) == g(p)(*v)
316
True
317
318
Test that the univariate polynomial ring is covered::
319
320
sage: H = AffineGroup(1, QQ)
321
sage: h = H([2],[3]); h
322
x |-> [2] x + [3]
323
sage: R.<z> = QQ[]
324
sage: h(z+1)
325
3*z + 2
326
"""
327
from sage.rings.polynomial.polynomial_element import is_Polynomial
328
from sage.rings.polynomial.multi_polynomial import is_MPolynomial
329
parent = self.parent()
330
if is_Polynomial(v) and parent.degree() == 1:
331
ring = v.parent()
332
return ring([self._A[0,0], self._b[0]])
333
if is_MPolynomial(v) and parent.degree() == v.parent().ngens():
334
ring = v.parent()
335
from sage.modules.all import vector
336
image_coords = self._A * vector(ring, ring.gens()) + self._b
337
return v(*image_coords)
338
v = parent.vector_space()(v)
339
return self._A*v + self._b
340
341
def _act_on_(self, x, self_on_left):
342
"""
343
Define the multiplicative action of the affine group elements.
344
345
EXAMPLES::
346
347
sage: G = AffineGroup(2, GF(3))
348
sage: g = G([1,2,3,4], [5,6])
349
sage: g
350
[1 2] [2]
351
x |-> [0 1] x + [0]
352
sage: v = vector(GF(3), [1,-1]); v
353
(1, 2)
354
sage: g*v
355
(1, 2)
356
sage: g*v == g.A() * v + g.b()
357
True
358
"""
359
if self_on_left:
360
return self.__call__(x)
361
362
def inverse(self):
363
"""
364
Return the inverse group element.
365
366
OUTPUT:
367
368
Another affine group element.
369
370
EXAMPLES::
371
372
sage: G = AffineGroup(2, GF(3))
373
sage: g = G([1,2,3,4], [5,6])
374
sage: g
375
[1 2] [2]
376
x |-> [0 1] x + [0]
377
sage: ~g
378
[1 1] [1]
379
x |-> [0 1] x + [0]
380
sage: g * g.inverse()
381
[1 0] [0]
382
x |-> [0 1] x + [0]
383
sage: g * g.inverse() == g.inverse() * g == G(1)
384
True
385
"""
386
parent = self.parent()
387
A = parent.matrix_space()(self._A.inverse())
388
b = -A*self.b()
389
return parent.element_class(parent, A, b, check=False)
390
391
__invert__ = inverse
392
393
def __cmp__(self, other):
394
"""
395
Compare ``self`` with ``other``.
396
397
OUTPUT:
398
399
-1, 0, or +1.
400
401
EXAMPLES::
402
403
sage: F = AffineGroup(3, QQ)
404
sage: g = F([1,2,3,4,5,6,7,8,0], [10,11,12])
405
sage: h = F([1,2,3,4,5,6,7,8,0], [10,11,0])
406
sage: g == h
407
False
408
sage: g == g
409
True
410
sage: abs(cmp(g, 'anything'))
411
1
412
"""
413
assert self.parent() is other.parent()
414
c = cmp(self._A, other._A)
415
if (c != 0):
416
return c
417
return cmp(self._b, other._b)
418
419
420