Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/groups/matrix_gps/orthogonal.py
8815 views
1
r"""
2
Orthogonal Linear Groups
3
4
The general orthogonal group `GO(n,R)` consists of all `n\times n`
5
matrices over the ring `R` preserving an `n`-ary positive definite
6
quadratic form. In cases where there are muliple non-isomorphic
7
quadratic forms, additional data needs to be specified to
8
disambiguate. The special orthogonal group is the normal subgroup of
9
matrices of determinant one.
10
11
In characteristics different from 2, a quadratic form is equivalent to
12
a bilinear symmetric form. Furthermore, over the real numbers a
13
positive definite quadratic form is equivalent to the diagonal
14
quadratic form, equivalent to the bilinear symmetric form defined by
15
the identity matrix. Hence, the orthogonal group `GO(n,\RR)` is the
16
group of orthogonal matrices in the usual sense.
17
18
In the case of a finite field and if the degree `n` is even, then
19
there are two inequivalent quadratic forms and a third parameter ``e``
20
must be specified to disambiguate these two possibilities. The index
21
of `SO(e,d,q)` in `GO(e,d,q)` is `2` if `q` is odd, but `SO(e,d,q) =
22
GO(e,d,q)` if `q` is even.)
23
24
.. warning::
25
26
GAP and Sage use different notations:
27
28
* GAP notation: The optional ``e`` comes first, that is, ``GO([e,]
29
d, q)``, ``SO([e,] d, q)``.
30
31
* Sage notation: The optional ``e`` comes last, the standard Python
32
convention: ``GO(d, GF(q), e=0)``, ``SO( d, GF(q), e=0)``.
33
34
EXAMPLES::
35
36
sage: GO(3,7)
37
General Orthogonal Group of degree 3 over Finite Field of size 7
38
39
sage: G = SO( 4, GF(7), 1); G
40
Special Orthogonal Group of degree 4 and form parameter 1 over Finite Field of size 7
41
sage: G.random_element() # random
42
[4 3 5 2]
43
[6 6 4 0]
44
[0 4 6 0]
45
[4 4 5 1]
46
47
TESTS::
48
49
sage: G = GO(3, GF(5))
50
sage: latex(G)
51
\text{GO}_{3}(\Bold{F}_{5})
52
sage: G = SO(3, GF(5))
53
sage: latex(G)
54
\text{SO}_{3}(\Bold{F}_{5})
55
sage: G = SO(4, GF(5), 1)
56
sage: latex(G)
57
\text{SO}_{4}(\Bold{F}_{5}, +)
58
59
AUTHORS:
60
61
- David Joyner (2006-03): initial version
62
63
- David Joyner (2006-05): added examples, _latex_, __str__, gens,
64
as_matrix_group
65
66
- William Stein (2006-12-09): rewrite
67
68
- Volker Braun (2013-1) port to new Parent, libGAP, extreme refactoring.
69
"""
70
71
#*****************************************************************************
72
# Copyright (C) 2006 David Joyner and William Stein
73
# Copyright (C) 2013 Volker Braun <[email protected]>
74
#
75
# Distributed under the terms of the GNU General Public License (GPL)
76
# http://www.gnu.org/licenses/
77
#*****************************************************************************
78
79
from sage.rings.all import ZZ, is_FiniteField
80
from sage.misc.latex import latex
81
from sage.misc.cachefunc import cached_method
82
from sage.groups.matrix_gps.named_group import (
83
normalize_args_vectorspace, NamedMatrixGroup_generic, NamedMatrixGroup_gap )
84
85
86
87
def normalize_args_e(degree, ring, e):
88
"""
89
Normalize the arguments that relate the choice of quadratic form
90
for special orthogonal groups over finite fields.
91
92
INPUT:
93
94
- ``degree`` -- integer. The degree of the affine group, that is,
95
the dimension of the affine space the group is acting on.
96
97
- ``ring`` -- a ring. The base ring of the affine space.
98
99
- ``e`` -- integer, one of `+1`, `0`, `-1`. Only relevant for
100
finite fields and if the degree is even. A parameter that
101
distinguishes inequivalent invariant forms.
102
103
OUTPUT:
104
105
The integer ``e`` with values required by GAP.
106
107
TESTS::
108
109
sage: from sage.groups.matrix_gps.orthogonal import normalize_args_e
110
sage: normalize_args_e(2, GF(3), +1)
111
1
112
sage: normalize_args_e(3, GF(3), 0)
113
0
114
sage: normalize_args_e(3, GF(3), +1)
115
0
116
sage: normalize_args_e(2, GF(3), 0)
117
Traceback (most recent call last):
118
...
119
ValueError: must have e=-1 or e=1 for even degree
120
"""
121
if is_FiniteField(ring) and degree%2 == 0:
122
if e not in (-1, +1):
123
raise ValueError('must have e=-1 or e=1 for even degree')
124
else:
125
e = 0
126
return ZZ(e)
127
128
129
130
131
132
########################################################################
133
# General Orthogonal Group
134
########################################################################
135
136
def GO(n, R, e=0, var='a'):
137
"""
138
Return the general orthogonal group.
139
140
The general orthogonal group `GO(n,R)` consists of all `n\times n`
141
matrices over the ring `R` preserving an `n`-ary positive definite
142
quadratic form. In cases where there are muliple non-isomorphic
143
quadratic forms, additional data needs to be specified to
144
disambiguate.
145
146
In the case of a finite field and if the degree `n` is even, then
147
there are two inequivalent quadratic forms and a third parameter
148
``e`` must be specified to disambiguate these two possibilities.
149
150
.. note::
151
152
This group is also available via ``groups.matrix.GO()``.
153
154
INPUT:
155
156
- ``n`` -- integer. The degree.
157
158
- ``R`` -- ring or an integer. If an integer is specified, the
159
corresponding finite field is used.
160
161
- ``e`` -- ``+1`` or ``-1``, and ignored by default. Only relevant
162
for finite fields and if the degree is even. A parameter that
163
distinguishes inequivalent invariant forms.
164
165
OUTPUT:
166
167
The general orthogonal group of given degree, base ring, and
168
choice of invariant form.
169
170
EXAMPLES:
171
172
sage: GO( 3, GF(7))
173
General Orthogonal Group of degree 3 over Finite Field of size 7
174
sage: GO( 3, GF(7)).order()
175
672
176
sage: GO( 3, GF(7)).gens()
177
(
178
[3 0 0] [0 1 0]
179
[0 5 0] [1 6 6]
180
[0 0 1], [0 2 1]
181
)
182
183
TESTS::
184
185
sage: groups.matrix.GO(2, 3, e=-1)
186
General Orthogonal Group of degree 2 and form parameter -1 over Finite Field of size 3
187
"""
188
degree, ring = normalize_args_vectorspace(n, R, var=var)
189
e = normalize_args_e(degree, ring, e)
190
if e == 0:
191
name = 'General Orthogonal Group of degree {0} over {1}'.format(degree, ring)
192
ltx = r'\text{{GO}}_{{{0}}}({1})'.format(degree, latex(ring))
193
else:
194
name = 'General Orthogonal Group of degree' + \
195
' {0} and form parameter {1} over {2}'.format(degree, e, ring)
196
ltx = r'\text{{GO}}_{{{0}}}({1}, {2})'.format(degree, latex(ring), '+' if e == 1 else '-')
197
if is_FiniteField(ring):
198
cmd = 'GO({0}, {1}, {2})'.format(e, degree, ring.characteristic())
199
return OrthogonalMatrixGroup_gap(degree, ring, False, name, ltx, cmd)
200
else:
201
return OrthogonalMatrixGroup_generic(degree, ring, False, name, ltx)
202
203
204
205
########################################################################
206
# Special Orthogonal Group
207
########################################################################
208
209
def SO(n, R, e=None, var='a'):
210
"""
211
Return the special orthogonal group.
212
213
The special orthogonal group `GO(n,R)` consists of all `n\times n`
214
matrices with determint one over the ring `R` preserving an
215
`n`-ary positive definite quadratic form. In cases where there are
216
muliple non-isomorphic quadratic forms, additional data needs to
217
be specified to disambiguate.
218
219
.. note::
220
221
This group is also available via ``groups.matrix.SO()``.
222
223
INPUT:
224
225
- ``n`` -- integer. The degree.
226
227
- ``R`` -- ring or an integer. If an integer is specified, the
228
corresponding finite field is used.
229
230
- ``e`` -- ``+1`` or ``-1``, and ignored by default. Only relevant
231
for finite fields and if the degree is even. A parameter that
232
distinguishes inequivalent invariant forms.
233
234
OUTPUT:
235
236
The special orthogonal group of given degree, base ring, and choice of
237
invariant form.
238
239
EXAMPLES::
240
241
sage: G = SO(3,GF(5))
242
sage: G
243
Special Orthogonal Group of degree 3 over Finite Field of size 5
244
245
sage: G = SO(3,GF(5))
246
sage: G.gens()
247
(
248
[2 0 0] [3 2 3] [1 4 4]
249
[0 3 0] [0 2 0] [4 0 0]
250
[0 0 1], [0 3 1], [2 0 4]
251
)
252
sage: G = SO(3,GF(5))
253
sage: G.as_matrix_group()
254
Matrix group over Finite Field of size 5 with 3 generators (
255
[2 0 0] [3 2 3] [1 4 4]
256
[0 3 0] [0 2 0] [4 0 0]
257
[0 0 1], [0 3 1], [2 0 4]
258
)
259
260
TESTS::
261
262
sage: groups.matrix.SO(2, 3, e=1)
263
Special Orthogonal Group of degree 2 and form parameter 1 over Finite Field of size 3
264
"""
265
degree, ring = normalize_args_vectorspace(n, R, var=var)
266
e = normalize_args_e(degree, ring, e)
267
if e == 0:
268
name = 'Special Orthogonal Group of degree {0} over {1}'.format(degree, ring)
269
ltx = r'\text{{SO}}_{{{0}}}({1})'.format(degree, latex(ring))
270
else:
271
name = 'Special Orthogonal Group of degree' + \
272
' {0} and form parameter {1} over {2}'.format(degree, e, ring)
273
ltx = r'\text{{SO}}_{{{0}}}({1}, {2})'.format(degree, latex(ring), '+' if e == 1 else '-')
274
if is_FiniteField(ring):
275
cmd = 'SO({0}, {1}, {2})'.format(e, degree, ring.characteristic())
276
return OrthogonalMatrixGroup_gap(degree, ring, True, name, ltx, cmd)
277
else:
278
return OrthogonalMatrixGroup_generic(degree, ring, True, name, ltx)
279
280
281
282
########################################################################
283
# Orthogonal Group class
284
########################################################################
285
286
class OrthogonalMatrixGroup_generic(NamedMatrixGroup_generic):
287
288
@cached_method
289
def invariant_bilinear_form(self):
290
"""
291
Return the symmetric bilinear form preserved by the orthogonal
292
group.
293
294
OUTPUT:
295
296
A matrix.
297
298
EXAMPLES::
299
300
sage: GO(2,3,+1).invariant_bilinear_form()
301
[0 1]
302
[1 0]
303
sage: GO(2,3,-1).invariant_bilinear_form()
304
[2 1]
305
[1 1]
306
"""
307
from sage.matrix.constructor import identity_matrix
308
m = identity_matrix(self.base_ring(), self.degree())
309
m.set_immutable()
310
return m
311
312
@cached_method
313
def invariant_quadratic_form(self):
314
"""
315
Return the quadratic form preserved by the orthogonal group.
316
317
OUTPUT:
318
319
A matrix.
320
321
EXAMPLES::
322
323
sage: GO(2,3,+1).invariant_quadratic_form()
324
[0 1]
325
[0 0]
326
sage: GO(2,3,-1).invariant_quadratic_form()
327
[1 1]
328
[0 2]
329
"""
330
from sage.matrix.constructor import identity_matrix
331
m = identity_matrix(self.base_ring(), self.degree())
332
m.set_immutable()
333
return m
334
335
def _check_matrix(self, x, *args):
336
"""a
337
Check whether the matrix ``x`` is symplectic.
338
339
See :meth:`~sage.groups.matrix_gps.matrix_group._check_matrix`
340
for details.
341
342
EXAMPLES::
343
344
sage: G = GO(4, GF(5), +1)
345
sage: G._check_matrix(G.an_element().matrix())
346
"""
347
if self._special and x.determinant() != 1:
348
raise TypeError('matrix must have determinant one')
349
F = self.invariant_bilinear_form()
350
if x * F * x.transpose() != F:
351
raise TypeError('matrix must be orthogonal with respect to the invariant form')
352
# TODO: check that quadratic form is preserved in characteristic two
353
354
355
class OrthogonalMatrixGroup_gap(OrthogonalMatrixGroup_generic, NamedMatrixGroup_gap):
356
357
@cached_method
358
def invariant_bilinear_form(self):
359
"""
360
Return the symmetric bilinear form preserved by the orthogonal
361
group.
362
363
OUTPUT:
364
365
A matrix `M` such that, for every group element g, the
366
identity `g m g^T = m` holds. In characteristic different from
367
two, this uniquely determines the orthogonal group.
368
369
EXAMPLES::
370
371
sage: G = GO(4, GF(7), -1)
372
sage: G.invariant_bilinear_form()
373
[0 1 0 0]
374
[1 0 0 0]
375
[0 0 2 0]
376
[0 0 0 2]
377
378
sage: G = GO(4, GF(7), +1)
379
sage: G.invariant_bilinear_form()
380
[0 1 0 0]
381
[1 0 0 0]
382
[0 0 6 0]
383
[0 0 0 2]
384
385
sage: G = GO(4, QQ)
386
sage: G.invariant_bilinear_form()
387
[1 0 0 0]
388
[0 1 0 0]
389
[0 0 1 0]
390
[0 0 0 1]
391
392
sage: G = SO(4, GF(7), -1)
393
sage: G.invariant_bilinear_form()
394
[0 1 0 0]
395
[1 0 0 0]
396
[0 0 2 0]
397
[0 0 0 2]
398
"""
399
m = self.gap().InvariantBilinearForm()['matrix'].matrix()
400
m.set_immutable()
401
return m
402
403
@cached_method
404
def invariant_quadratic_form(self):
405
"""
406
Return the quadratic form preserved by the orthogonal group.
407
408
OUTPUT:
409
410
The matrix `Q` defining "orthogonal" as follows. The matrix
411
determines a quadratic form `q` on the natural vector space
412
`V`, on which `G` acts, by `q(v) = v Q v^t`. A matrix `M' is
413
an element of the orthogonal group if `q(v) = q(v M)` for all
414
`v \in V`.
415
416
EXAMPLES::
417
418
sage: G = GO(4, GF(7), -1)
419
sage: G.invariant_quadratic_form()
420
[0 1 0 0]
421
[0 0 0 0]
422
[0 0 1 0]
423
[0 0 0 1]
424
425
sage: G = GO(4, GF(7), +1)
426
sage: G.invariant_quadratic_form()
427
[0 1 0 0]
428
[0 0 0 0]
429
[0 0 3 0]
430
[0 0 0 1]
431
432
sage: G = GO(4, QQ)
433
sage: G.invariant_quadratic_form()
434
[1 0 0 0]
435
[0 1 0 0]
436
[0 0 1 0]
437
[0 0 0 1]
438
439
sage: G = SO(4, GF(7), -1)
440
sage: G.invariant_quadratic_form()
441
[0 1 0 0]
442
[0 0 0 0]
443
[0 0 1 0]
444
[0 0 0 1]
445
"""
446
m = self.gap().InvariantQuadraticForm()['matrix'].matrix()
447
m.set_immutable()
448
return m
449
450
451
452
453