Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/groups/affine_gps/affine_group.py
8815 views
1
r"""
2
Affine Groups
3
4
AUTHORS:
5
6
- Volker Braun: initial version
7
"""
8
9
##############################################################################
10
# Copyright (C) 2013 Volker Braun <[email protected]>
11
#
12
# Distributed under the terms of the GNU General Public License (GPL)
13
#
14
# The full text of the GPL is available at:
15
#
16
# http://www.gnu.org/licenses/
17
##############################################################################
18
19
20
from sage.categories.groups import Groups
21
from sage.groups.group import Group
22
from sage.matrix.all import MatrixSpace
23
from sage.modules.all import FreeModule
24
from sage.structure.unique_representation import UniqueRepresentation
25
from sage.misc.cachefunc import cached_method
26
27
from sage.groups.affine_gps.group_element import AffineGroupElement
28
29
30
#################################################################
31
32
class AffineGroup(UniqueRepresentation, Group):
33
r"""
34
An affine group.
35
36
The affine group `\mathrm{Aff}(A)` (or general affine group) of an affine
37
space `A` is the group of all invertible affine transformations from the
38
space into itself.
39
40
If we let `A_V` be the affine space of a vector space `V`
41
(essentially, forgetting what is the origin) then the affine group
42
`\mathrm{Aff}(A_V)` is the group generated by the general linear group
43
`GL(V)` together with the translations. Recall that the group of
44
translations acting on `A_V` is just `V` itself. The general linear and
45
translation subgroups do not quite commute, and in fact generate the
46
semidirect product
47
48
.. MATH::
49
50
\mathrm{Aff}(A_V) = GL(V) \ltimes V.
51
52
As such, the group elements can be represented by pairs `(A, b)` of a
53
matrix and a vector. This pair then represents the transformation
54
55
.. MATH::
56
57
x \mapsto A x + b.
58
59
We can also represent affine transformations as linear transformations by
60
considering `\dim(V) + 1` dimensonal space. We take the affine
61
transformation `(A, b)` to
62
63
.. MATH::
64
65
\begin{pmatrix}
66
A & b \\
67
0 & 1
68
\end{pmatrix}
69
70
and lifting `x = (x_1, \ldots, x_n)` to `(x_1, \ldots, x_n, 1)`. Here
71
the `(n + 1)`-th component is always 1, so the linear representations
72
acts on the affine hyperplane `x_{n+1} = 1` as affine transformations
73
which can be seen directly from the matrix multiplication.
74
75
INPUT:
76
77
Something that defines an affine space. For example
78
79
- An affine space itself:
80
81
* ``A`` -- affine space
82
83
- A vector space:
84
85
* ``V`` -- a vector space
86
87
- Degree and base ring:
88
89
* ``degree`` -- An integer. The degree of the affine group, that
90
is, the dimension of the affine space the group is acting on.
91
92
* ``ring`` -- A ring or an integer. The base ring of the affine
93
space. If an integer is given, it must be a prime power and
94
the corresponding finite field is constructed.
95
96
* ``var`` -- (Defalut: ``'a'``) Keyword argument to specify the finite
97
field generator name in the case where ``ring`` is a prime power.
98
99
EXAMPLES::
100
101
sage: F = AffineGroup(3, QQ); F
102
Affine Group of degree 3 over Rational Field
103
sage: F(matrix(QQ,[[1,2,3],[4,5,6],[7,8,0]]), vector(QQ,[10,11,12]))
104
[1 2 3] [10]
105
x |-> [4 5 6] x + [11]
106
[7 8 0] [12]
107
sage: F([[1,2,3],[4,5,6],[7,8,0]], [10,11,12])
108
[1 2 3] [10]
109
x |-> [4 5 6] x + [11]
110
[7 8 0] [12]
111
sage: F([1,2,3,4,5,6,7,8,0], [10,11,12])
112
[1 2 3] [10]
113
x |-> [4 5 6] x + [11]
114
[7 8 0] [12]
115
116
Instead of specifying the complete matrix/vector information, you can
117
also create special group elements::
118
119
sage: F.linear([1,2,3,4,5,6,7,8,0])
120
[1 2 3] [0]
121
x |-> [4 5 6] x + [0]
122
[7 8 0] [0]
123
sage: F.translation([1,2,3])
124
[1 0 0] [1]
125
x |-> [0 1 0] x + [2]
126
[0 0 1] [3]
127
128
Some additional ways to create affine groups::
129
130
sage: A = AffineSpace(2, GF(4,'a')); A
131
Affine Space of dimension 2 over Finite Field in a of size 2^2
132
sage: G = AffineGroup(A); G
133
Affine Group of degree 2 over Finite Field in a of size 2^2
134
sage: G is AffineGroup(2,4) # shorthand
135
True
136
137
sage: V = ZZ^3; V
138
Ambient free module of rank 3 over the principal ideal domain Integer Ring
139
sage: AffineGroup(V)
140
Affine Group of degree 3 over Integer Ring
141
142
REFERENCES:
143
144
- :wikipedia:`Affine_group`
145
"""
146
@staticmethod
147
def __classcall__(cls, *args, **kwds):
148
"""
149
Normalize input to ensure a unique representation.
150
151
EXAMPLES::
152
153
sage: A = AffineSpace(2, GF(4,'a'))
154
sage: AffineGroup(A) is AffineGroup(2,4)
155
True
156
sage: AffineGroup(A) is AffineGroup(2, GF(4,'a'))
157
True
158
sage: A = AffineGroup(2, QQ)
159
sage: V = QQ^2
160
sage: A is AffineGroup(V)
161
True
162
"""
163
if len(args) == 1:
164
V = args[0]
165
if isinstance(V, AffineGroup):
166
return V
167
try:
168
degree = V.dimension_relative()
169
except AttributeError:
170
degree = V.dimension()
171
ring = V.base_ring()
172
if len(args) == 2:
173
degree, ring = args
174
from sage.rings.integer import is_Integer
175
if is_Integer(ring):
176
from sage.rings.finite_rings.constructor import FiniteField
177
var = kwds.get('var', 'a')
178
ring = FiniteField(ring, var)
179
return super(AffineGroup, cls).__classcall__(cls, degree, ring)
180
181
def __init__(self, degree, ring):
182
"""
183
Initialize ``self``.
184
185
INPUT:
186
187
- ``degree`` -- integer. The degree of the affine group, that
188
is, the dimension of the affine space the group is acting on
189
naturally.
190
191
- ``ring`` -- a ring. The base ring of the affine space.
192
193
EXAMPLES::
194
195
sage: Aff6 = AffineGroup(6, QQ)
196
sage: Aff6 == Aff6
197
True
198
sage: Aff6 != Aff6
199
False
200
201
TESTS::
202
203
sage: G = AffineGroup(2, GF(5)); G
204
Affine Group of degree 2 over Finite Field of size 5
205
sage: TestSuite(G).run()
206
"""
207
self._degree = degree
208
Group.__init__(self, base=ring)
209
210
Element = AffineGroupElement
211
212
def _element_constructor_check(self, A, b):
213
"""
214
Verify that ``A``, ``b`` define an affine group element and raises a
215
``TypeError`` if the input does not define a valid group element.
216
217
This is called from the group element constructor and can be
218
overridden for subgroups of the affine group. It is guaranteed
219
that ``A``, ``b`` are in the correct matrix/vetor space.
220
221
INPUT:
222
223
- ``A`` -- an element of :meth:`matrix_space`
224
225
- ``b`` -- an element of :meth:`vector_space`
226
227
TESTS::
228
229
sage: Aff3 = AffineGroup(3, QQ)
230
sage: A = Aff3.matrix_space()([1,2,3,4,5,6,7,8,0])
231
sage: det(A)
232
27
233
sage: b = Aff3.vector_space().an_element()
234
sage: Aff3._element_constructor_check(A, b)
235
236
sage: A = Aff3.matrix_space()([1,2,3,4,5,6,7,8,9])
237
sage: det(A)
238
0
239
sage: Aff3._element_constructor_check(A, b)
240
Traceback (most recent call last):
241
...
242
TypeError: A must be invertible
243
"""
244
if not A.is_invertible():
245
raise TypeError('A must be invertible')
246
247
def _latex_(self):
248
r"""
249
Return a LaTeX representation of ``self``.
250
251
EXAMPLES::
252
253
sage: G = AffineGroup(6, GF(5))
254
sage: latex(G)
255
\mathrm{Aff}_{6}(\Bold{F}_{5})
256
"""
257
return "\\mathrm{Aff}_{%s}(%s)"%(self.degree(), self.base_ring()._latex_())
258
259
def _repr_(self):
260
"""
261
Return a string representation of ``self``.
262
263
EXAMPLES::
264
265
sage: AffineGroup(6, GF(5))
266
Affine Group of degree 6 over Finite Field of size 5
267
"""
268
return "Affine Group of degree %s over %s"%(self.degree(), self.base_ring())
269
270
def degree(self):
271
"""
272
Return the dimension of the affine space.
273
274
OUTPUT:
275
276
An integer.
277
278
EXAMPLES::
279
280
sage: G = AffineGroup(6, GF(5))
281
sage: g = G.an_element()
282
sage: G.degree()
283
6
284
sage: G.degree() == g.A().nrows() == g.A().ncols() == g.b().degree()
285
True
286
"""
287
return self._degree
288
289
@cached_method
290
def matrix_space(self):
291
"""
292
Return the space of matrices representing the general linear
293
transformations.
294
295
OUTPUT:
296
297
The parent of the matrices `A` defining the affine group
298
element `Ax+b`.
299
300
EXAMPLES::
301
302
sage: G = AffineGroup(3, GF(5))
303
sage: G.matrix_space()
304
Full MatrixSpace of 3 by 3 dense matrices over Finite Field of size 5
305
"""
306
d = self.degree()
307
return MatrixSpace(self.base_ring(), d, d)
308
309
@cached_method
310
def vector_space(self):
311
"""
312
Return the vector space of the underlying affine space.
313
314
EXAMPLES::
315
316
sage: G = AffineGroup(3, GF(5))
317
sage: G.vector_space()
318
Vector space of dimension 3 over Finite Field of size 5
319
"""
320
return FreeModule(self.base_ring(), self.degree())
321
322
@cached_method
323
def linear_space(self):
324
r"""
325
Return the space of the affine transformations represented as linear
326
transformations.
327
328
We can represent affine transformations `Ax + b` as linear
329
transformations by
330
331
.. MATH::
332
333
\begin{pmatrix}
334
A & b \\
335
0 & 1
336
\end{pmatrix}
337
338
and lifting `x = (x_1, \ldots, x_n)` to `(x_1, \ldots, x_n, 1)`.
339
340
.. SEEALSO::
341
342
- :meth:`sage.groups.affine_gps.group_element.AffineGroupElement.matrix()`
343
344
EXAMPLES::
345
346
sage: G = AffineGroup(3, GF(5))
347
sage: G.linear_space()
348
Full MatrixSpace of 4 by 4 dense matrices over Finite Field of size 5
349
"""
350
dp = self.degree() + 1
351
return MatrixSpace(self.base_ring(), dp, dp)
352
353
def linear(self, A):
354
"""
355
Construct the general linear transformation by ``A``.
356
357
INPUT:
358
359
- ``A`` -- anything that determines a matrix
360
361
OUTPUT:
362
363
The affine group element `x \mapsto A x`.
364
365
EXAMPLES::
366
367
sage: G = AffineGroup(3, GF(5))
368
sage: G.linear([1,2,3,4,5,6,7,8,0])
369
[1 2 3] [0]
370
x |-> [4 0 1] x + [0]
371
[2 3 0] [0]
372
"""
373
A = self.matrix_space()(A)
374
return self.element_class(self, A, self.vector_space().zero(), check=True, convert=False)
375
376
def translation(self, b):
377
"""
378
Construct the translation by ``b``.
379
380
INPUT:
381
382
- ``b`` -- anything that determines a vector
383
384
OUTPUT:
385
386
The affine group element `x \mapsto x + b`.
387
388
EXAMPLES::
389
390
sage: G = AffineGroup(3, GF(5))
391
sage: G.translation([1,4,8])
392
[1 0 0] [1]
393
x |-> [0 1 0] x + [4]
394
[0 0 1] [3]
395
"""
396
b = self.vector_space()(b)
397
return self.element_class(self, self.matrix_space().one(), b, check=False, convert=False)
398
399
def reflection(self, v):
400
"""
401
Construct the Householder reflection.
402
403
A Householder reflection (transformation) is the affine transformation
404
corresponding to an elementary reflection at the hyperplane
405
perpendicular to `v`.
406
407
INPUT:
408
409
- ``v`` -- a vector, or something that determines a vector.
410
411
OUTPUT:
412
413
The affine group element that is just the Householder
414
transformation (a.k.a. Householder reflection, elementary
415
reflection) at the hyperplane perpendicular to `v`.
416
417
EXAMPLES::
418
419
sage: G = AffineGroup(3, QQ)
420
sage: G.reflection([1,0,0])
421
[-1 0 0] [0]
422
x |-> [ 0 1 0] x + [0]
423
[ 0 0 1] [0]
424
sage: G.reflection([3,4,-5])
425
[ 16/25 -12/25 3/5] [0]
426
x |-> [-12/25 9/25 4/5] x + [0]
427
[ 3/5 4/5 0] [0]
428
"""
429
v = self.vector_space()(v)
430
try:
431
two_norm2inv = self.base_ring()(2) / sum([ vi**2 for vi in v ])
432
except ZeroDivisionError:
433
raise ValueError('v has norm zero')
434
from sage.matrix.constructor import identity_matrix
435
A = self.matrix_space().one() - v.column() * (v.row() * two_norm2inv)
436
return self.element_class(self, A, self.vector_space().zero(), check=True, convert=False)
437
438
def random_element(self):
439
"""
440
Return a random element of this group.
441
442
EXAMPLES::
443
444
sage: G = AffineGroup(4, GF(3))
445
sage: G.random_element() # random
446
[2 0 1 2] [1]
447
[2 1 1 2] [2]
448
x |-> [1 0 2 2] x + [2]
449
[1 1 1 1] [2]
450
sage: G.random_element() in G
451
True
452
"""
453
A = self.matrix_space().random_element()
454
while not A.is_invertible(): # a generic matrix is invertible
455
A.randomize()
456
b = self.vector_space().random_element()
457
return self.element_class(self, A, b, check=False, convert=False)
458
459
@cached_method
460
def _an_element_(self):
461
"""
462
Return an element.
463
464
TESTS::
465
466
sage: G = AffineGroup(4,5)
467
sage: G.an_element() in G
468
True
469
"""
470
A = self.matrix_space().an_element()
471
while not A.is_invertible(): # a generic matrix is not always invertible
472
A.randomize()
473
b = self.vector_space().an_element()
474
return self.element_class(self, A, b, check=False, convert=False)
475
476
477