Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/coding/codecan/autgroup_can_label.pyx
8815 views
1
r"""
2
Canonical forms and automorphisms for linear codes over finite fields.
3
4
We implemented the algorithm described in [Feu2009]_ which computes, a unique
5
code (canonical form) in the equivalence class of a given
6
linear code `C \leq \GF{q}^n`. Furthermore, this algorithm will return the
7
automorphism group of `C`, too. You will find more details about the algorithm
8
in the documentation of the class
9
:class:`~sage.coding.codecan.autgroup_can_label.LinearCodeAutGroupCanLabel`.
10
11
The equivalence of codes is modeled as a group action by the group
12
`G = {\GF{q}^*}^n \rtimes (Aut(\GF{q}) \times S_n)` on the set
13
of subspaces of `\GF{q}^n` . The group `G` will be called the
14
semimonomial group of degree `n`.
15
16
The algorithm is started by initializing the class
17
:class:`~sage.coding.codecan.autgroup_can_label.LinearCodeAutGroupCanLabel`.
18
When the object gets available, all computations are already finished and
19
you can access the relevant data using the member functions:
20
21
* :meth:`~sage.coding.codecan.autgroup_can_label.LinearCodeAutGroupCanLabel.get_canonical_form`
22
23
* :meth:`~sage.coding.codecan.autgroup_can_label.LinearCodeAutGroupCanLabel.get_transporter`
24
25
* :meth:`~sage.coding.codecan.autgroup_can_label.LinearCodeAutGroupCanLabel.get_autom_gens`
26
27
People do also use some weaker notions of equivalence, namely
28
**permutational** equivalence and monomial equivalence (**linear** isometries).
29
These can be seen as the subgroups `S_n` and `{\GF{q}^*}^n \rtimes S_n` of `G`.
30
If you are interested in one of these notions, you can just pass
31
the optional parameter ``algorithm_type``.
32
33
A second optional parameter ``P`` allows you to restrict the
34
group of permutations `S_n` to a subgroup which respects the coloring given
35
by ``P``.
36
37
AUTHORS:
38
39
- Thomas Feulner (2012-11-15): initial version
40
41
REFERENCES:
42
43
.. [Feu2009] T. Feulner. The Automorphism Groups of Linear Codes and
44
Canonical Representatives of Their Semilinear Isometry Classes.
45
Advances in Mathematics of Communications 3 (4), pp. 363-383, Nov 2009
46
47
EXAMPLES::
48
49
sage: from sage.coding.codecan.autgroup_can_label import LinearCodeAutGroupCanLabel
50
sage: C = codes.HammingCode(3, GF(3)).dual_code()
51
sage: P = LinearCodeAutGroupCanLabel(C)
52
sage: P.get_canonical_form().gen_mat()
53
[1 0 0 0 0 1 1 1 1 1 1 1 1]
54
[0 1 0 1 1 0 0 1 1 2 2 1 2]
55
[0 0 1 1 2 1 2 1 2 1 2 0 0]
56
sage: LinearCode(P.get_transporter()*C.gen_mat()) == P.get_canonical_form()
57
True
58
sage: A = P.get_autom_gens()
59
sage: all( [ LinearCode(a*C.gen_mat()) == C for a in A])
60
True
61
sage: P.get_autom_order() == GL(3, GF(3)).order()
62
True
63
64
If the dimension of the dual code is smaller, we will work on this code::
65
66
sage: C2 = codes.HammingCode(3, GF(3))
67
sage: P2 = LinearCodeAutGroupCanLabel(C2)
68
sage: P2.get_canonical_form().check_mat() == P.get_canonical_form().gen_mat()
69
True
70
71
There is a specialization of this algorithm to pass a coloring on the
72
coordinates. This is just a list of lists, telling the algorithm which
73
columns do share the same coloring::
74
75
sage: C = codes.HammingCode(3, GF(4, 'a')).dual_code()
76
sage: P = LinearCodeAutGroupCanLabel(C, P=[ [0], [1], range(2, C.length()) ])
77
sage: P.get_autom_order()
78
864
79
sage: A = [a.get_perm() for a in P.get_autom_gens()]
80
sage: H = SymmetricGroup(21).subgroup(A)
81
sage: H.orbits()
82
[[1], [2], [3, 5, 4], [6, 10, 13, 20, 17, 9, 8, 11, 18, 15, 14, 16, 12, 19, 21, 7]]
83
84
We can also restrict the group action to linear isometries::
85
86
sage: P = LinearCodeAutGroupCanLabel(C, algorithm_type="linear")
87
sage: P.get_autom_order() == GL(3, GF(4, 'a')).order()
88
True
89
90
and to the action of the symmetric group only::
91
92
sage: P = LinearCodeAutGroupCanLabel(C, algorithm_type="permutational")
93
sage: P.get_autom_order() == C.permutation_automorphism_group().order()
94
True
95
"""
96
#*****************************************************************************
97
# Copyright (C) 2012 Thomas Feulner <[email protected]>
98
#
99
# Distributed under the terms of the GNU General Public License (GPL)
100
# as published by the Free Software Foundation; either version 2 of
101
# the License, or (at your option) any later version.
102
# http://www.gnu.org/licenses/
103
#*****************************************************************************
104
105
from sage.coding.codecan.codecan import PartitionRefinementLinearCode
106
from sage.combinat.permutation import Permutation
107
from sage.functions.other import factorial
108
109
def _cyclic_shift(n, p):
110
r"""
111
If ``p`` is a list of pairwise distinct coordinates in ``range(n)``,
112
then this function returns the cyclic shift of
113
the coordinates contained in ``p``, when acting on a vector of length `n`.
114
115
Note that the domain of a ``Permutation`` is ``range(1, n+1)``.
116
117
EXAMPLE::
118
119
sage: from sage.coding.codecan.autgroup_can_label import _cyclic_shift
120
sage: p = _cyclic_shift(10, [2,7,4,1]); p
121
[1, 3, 8, 4, 2, 6, 7, 5, 9, 10]
122
123
We prove that the action is as expected::
124
125
sage: t = range(10)
126
sage: p.action(t)
127
[0, 2, 7, 3, 1, 5, 6, 4, 8, 9]
128
"""
129
x = range(1, n + 1)
130
for i in range(1, len(p)):
131
x[p[i - 1]] = p[i] + 1
132
x[p[len(p) - 1]] = p[0] + 1
133
return Permutation(x)
134
135
class LinearCodeAutGroupCanLabel:
136
r"""
137
Canonical representatives and automorphism group computation for linear
138
codes over finite fields.
139
140
There are several notions of equivalence for linear codes:
141
Let `C`, `D` be linear codes of length `n` and dimension `k`.
142
`C` and `D` are said to be
143
144
- permutational equivalent, if there is some permutation `\pi \in S_n`
145
such that `(c_{\pi(0)}, \ldots, c_{\pi(n-1)}) \in D` for all `c \in C`.
146
147
- linear equivalent, if there is some permutation `\pi \in S_n` and a
148
vector `\phi \in {\GF{q}^*}^n` of units of length `n` such that
149
`(c_{\pi(0)} \phi_0^{-1}, \ldots, c_{\pi(n-1)} \phi_{n-1}^{-1}) \in D`
150
for all `c \in C`.
151
152
- semilinear equivalent, if there is some permutation `\pi \in S_n`, a
153
vector `\phi` of units of length `n` and a field automorphism `\alpha`
154
such that
155
`(\alpha(c_{\pi(0)}) \phi_0^{-1}, \ldots, \alpha( c_{\pi(n-1)}) \phi_{n-1}^{-1} ) \in D`
156
for all `c \in C`.
157
158
These are group actions. This class provides an algorithm that will compute
159
a unique representative `D` in the orbit of the given linear code `C`.
160
Furthermore, the group element `g` with `g * C = D` and the automorphism
161
group of `C` will be computed as well.
162
163
There is also the possibility to restrict the permutational part of this
164
action to a Young subgroup of `S_n`. This could be achieved by passing a
165
partition `P` (as a list of lists) of the set `\{0, \ldots, n-1\}`. This is
166
an option which is also available in the computation of a canonical form of
167
a graph, see :meth:`sage.graphs.generic_graph.GenericGraph.canonical_label`.
168
169
EXAMPLES::
170
171
sage: from sage.coding.codecan.autgroup_can_label import LinearCodeAutGroupCanLabel
172
sage: C = codes.HammingCode(3, GF(3)).dual_code()
173
sage: P = LinearCodeAutGroupCanLabel(C)
174
sage: P.get_canonical_form().gen_mat()
175
[1 0 0 0 0 1 1 1 1 1 1 1 1]
176
[0 1 0 1 1 0 0 1 1 2 2 1 2]
177
[0 0 1 1 2 1 2 1 2 1 2 0 0]
178
sage: LinearCode(P.get_transporter()*C.gen_mat()) == P.get_canonical_form()
179
True
180
sage: a = P.get_autom_gens()[0]
181
sage: (a*C.gen_mat()).echelon_form() == C.gen_mat().echelon_form()
182
True
183
sage: P.get_autom_order() == GL(3, GF(3)).order()
184
True
185
"""
186
187
def __init__(self, C, P=None, algorithm_type="semilinear"):
188
"""
189
see :class:`LinearCodeAutGroupCanLabel`
190
191
INPUT:
192
193
- ``C`` -- a linear code
194
195
- ``P`` (optional) -- a coloring of the coordinates i.e. a partition
196
(list of disjoint lists) of [0 , ..., C.length()-1 ]
197
198
- ``algorithm_type`` (optional) -- which defines the acting group, either
199
200
* ``permutational``
201
202
* ``linear``
203
204
* ``semilinear``
205
206
EXAMPLES::
207
208
sage: from sage.coding.codecan.autgroup_can_label import LinearCodeAutGroupCanLabel
209
sage: C = codes.HammingCode(3, GF(2)).dual_code()
210
sage: P = LinearCodeAutGroupCanLabel(C)
211
sage: P.get_canonical_form().gen_mat()
212
[1 0 0 0 1 1 1]
213
[0 1 0 1 0 1 1]
214
[0 0 1 1 1 1 0]
215
sage: P2 = LinearCodeAutGroupCanLabel(C, P=[[0,3,5],[1,2,4,6]],
216
....: algorithm_type="permutational")
217
sage: P2.get_canonical_form().gen_mat()
218
[1 1 1 0 0 0 1]
219
[0 1 0 1 1 0 1]
220
[0 0 1 0 1 1 1]
221
"""
222
from sage.groups.semimonomial_transformations.semimonomial_transformation_group import SemimonomialTransformationGroup
223
from sage.coding.linear_code import LinearCode
224
225
if not isinstance(C, LinearCode):
226
raise TypeError("%s is not a linear code"%C)
227
228
self.C = C
229
mat = C.gen_mat()
230
F = mat.base_ring()
231
S = SemimonomialTransformationGroup(F, mat.ncols())
232
233
if P is None:
234
P = [range(mat.ncols())]
235
236
pos2P = [-1] * mat.ncols()
237
for i in range(len(P)):
238
P[i].sort(reverse=True)
239
for x in P[i]:
240
pos2P[x] = i
241
242
col_list = mat.columns()
243
nz = [i for i in range(mat.ncols()) if not col_list[i].is_zero()]
244
z = [(pos2P[i], i) for i in range(mat.ncols()) if col_list[i].is_zero()]
245
z.sort()
246
z = [i for (p, i) in z]
247
248
normalization_factors = [ F.one() ] * mat.ncols()
249
if algorithm_type == "permutational":
250
for c in col_list:
251
c.set_immutable()
252
else:
253
for x in nz:
254
normalization_factors[x] = col_list[x][(col_list[x].support())[0]]
255
col_list[x] = normalization_factors[x] ** (-1) * col_list[x]
256
col_list[x].set_immutable()
257
258
normalization = S(v=normalization_factors)
259
normalization_inverse = normalization ** (-1)
260
col_set = list({col_list[y] for y in nz })
261
col2pos = []
262
col2P = []
263
for c in col_set:
264
X = [(pos2P[y], y) for y in range(mat.ncols()) if col_list[y] == c ]
265
X.sort()
266
col2pos.append([b for (a, b) in X ])
267
col2P.append([a for (a, b) in X ])
268
269
zipped = zip(col2P, col_set, col2pos)
270
zipped.sort()
271
272
col2P = [qty for (qty, c, pos) in zipped]
273
col_set = [c for (qty, c, pos) in zipped]
274
col2pos = [pos for (qty, c, pos) in zipped]
275
P_refined = []
276
p = [0]
277
act_qty = col2P[0]
278
for i in range(1, len(col_set)):
279
if act_qty == col2P[i]:
280
p.append(i)
281
else:
282
P_refined.append(p)
283
p = [i]
284
act_qty = col2P[i]
285
P_refined.append(p)
286
# now we can start the main algorithm:
287
from sage.matrix.constructor import matrix
288
289
if len(col_set) >= 2 * mat.nrows():
290
# the dimension of the code is smaller or equal than
291
# the dimension of the dual code
292
# in this case we work with the code itself.
293
pr = PartitionRefinementLinearCode(len(col_set),
294
matrix(col_set).transpose(), P=P_refined, algorithm_type=algorithm_type)
295
296
# this command allows you some advanced debuging
297
# it prints the backtrack tree -> must be activated when installing
298
# pr._latex_view(title="MyTitle") #this will provide you some visual representation of what is going on
299
300
can_transp = pr.get_transporter()
301
can_col_set = pr.get_canonical_form().columns()
302
self._PGammaL_autom_gens = self._compute_PGammaL_automs(pr.get_autom_gens(),
303
normalization, normalization_inverse, col2pos)
304
self._PGammaL_autom_size = pr.get_autom_order_permutation()
305
self._PGammaL_autom_size *= pr.get_autom_order_inner_stabilizer()
306
self._full_autom_order = self._PGammaL_autom_size
307
self._PGammaL_autom_size /= (len(self.C.base_ring()) - 1)
308
elif mat.nrows() == len(col_set):
309
# it could happen (because of the recursive call, see `else`) that
310
# the canonical form is the identity matrix
311
n = len(col_set)
312
from sage.modules.free_module import VectorSpace
313
can_col_set = VectorSpace(F, n).gens()
314
A = []
315
self._full_autom_order = 1
316
S_short = SemimonomialTransformationGroup(F, n)
317
can_transp = S_short.one()
318
if algorithm_type != "permutational":
319
# linear or semilinear
320
if algorithm_type == "semilinear":
321
A.append(S_short(autom=F.hom([F.gen() ** F.characteristic()])))
322
self._full_autom_order *= F.degree()
323
for p in P_refined:
324
m = [F.one()] * n
325
m[p[0]] = F.gen()
326
A.append(S_short(v=m))
327
self._full_autom_order *= (len(F) - 1) ** n
328
for p in P_refined:
329
if len(p) > 1:
330
A.append(S_short(perm=_cyclic_shift(n, p[:2])))
331
if len(p) > 2:
332
# cyclic shift of all elements
333
A.append(S_short(perm=_cyclic_shift(n, p)))
334
self._full_autom_order *= factorial(len(p))
335
self._PGammaL_autom_size = self._full_autom_order / (len(F) - 1)
336
self._PGammaL_autom_gens = self._compute_PGammaL_automs(A,
337
normalization, normalization_inverse, col2pos)
338
else:
339
# use the dual code for the computations
340
# this might have zero columns or multiple columns, hence
341
# we call this algorithm again.
342
short_dual_code = LinearCode(matrix(col_set).transpose()).dual_code()
343
agcl = LinearCodeAutGroupCanLabel(short_dual_code,
344
P=P_refined, algorithm_type=algorithm_type)
345
can_transp = agcl.get_transporter()
346
can_transp.invert_v()
347
can_col_set = agcl.get_canonical_form().check_mat().columns()
348
A = agcl.get_autom_gens()
349
for a in A:
350
a.invert_v()
351
self._PGammaL_autom_gens = self._compute_PGammaL_automs(A,
352
normalization, normalization_inverse, col2pos)
353
self._PGammaL_autom_size = agcl.get_PGammaL_order()
354
self._full_autom_order = agcl.get_autom_order()
355
356
count = 0
357
block_ptr = []
358
canonical_form = matrix(F, mat.ncols(), mat.nrows())
359
360
perm = [-1] * mat.ncols()
361
mult = [F.one()] * mat.ncols()
362
363
for i in range(len(can_col_set)):
364
img = can_transp.get_perm()(i + 1)
365
for j in col2pos[img - 1]:
366
pos = P[ pos2P[j] ].pop()
367
canonical_form[ pos ] = can_col_set[i]
368
mult[pos] = can_transp.get_v()[i]
369
perm[pos] = j + 1
370
371
it = iter(z)
372
for p in P:
373
while len(p) > 0:
374
pos = p.pop()
375
perm[pos] = it.next() + 1
376
377
self._canonical_form = LinearCode(canonical_form.transpose())
378
self._transporter = S(perm=Permutation(perm), v=mult, autom=can_transp.get_autom()) * normalization
379
self._trivial_autom_gens, a = self._compute_trivial_automs(normalization,
380
normalization_inverse, z, [pos2P[x] for x in z], zero_column_case=True)
381
self._full_autom_order *= a
382
383
384
for i in range(len(col2P)):
385
if len(col2P[i]) > 1:
386
A, a = self._compute_trivial_automs(normalization,
387
normalization_inverse, col2pos[i], col2P[i])
388
self._full_autom_order *= a
389
self._trivial_autom_gens += A
390
391
@staticmethod
392
def _compute_trivial_automs(normalization, normalization_inverse, col2pos, col2P, zero_column_case=False):
393
"""
394
In order to call the algorithm described in
395
:class:`PartitionRefinementLinearCode` we remove
396
zero columns and multiple occurrences of the same column (up to
397
normalization).
398
399
This function computes a set of generators for the allowed permutations
400
of such a block of equal columns (depending on the partition).
401
If ``zero_column_case==True`` we also add a generator for the
402
multiplication by units. Furthermore, we return the order of this group.
403
404
INPUT:
405
406
- ``normalization`` -- an element in the semimonomial transformation group `S`
407
408
- ``normalization_inverse`` -- the inverse of ``normalization``
409
410
- ``col2pos`` -- a list of disjoint indices in ``range(n)``
411
412
- ``col2P`` -- an increasing list of integers, with
413
``len(col2P) == len(col2pos)`` with ``col2P[i] == col2P[j]`` if and
414
only if the indices ``col2pos[i]`` and ``col2pos[j]`` are in the
415
same partition
416
417
- ``zero_column_case`` (boolean) -- set to ``True`` iff we are dealing
418
with the zero column
419
420
OUTPUT:
421
422
- a list of generators in `S`
423
424
- the order of this group
425
426
EXAMPLES::
427
428
sage: from sage.coding.codecan.autgroup_can_label import LinearCodeAutGroupCanLabel
429
sage: S = SemimonomialTransformationGroup(GF(3), 10)
430
sage: s = S.one()
431
sage: col2pos = [1,4,2,3,5]
432
sage: col2P = [1,1,3,3,3]
433
sage: LinearCodeAutGroupCanLabel._compute_trivial_automs(s, s, col2pos, col2P, True)
434
([((1, 2, 1, 1, 1, 1, 1, 1, 1, 1); (), Ring endomorphism of Finite Field of size 3
435
Defn: 1 |--> 1), ((1, 1, 1, 1, 1, 1, 1, 1, 1, 1); (2,5), Ring endomorphism of Finite Field of size 3
436
Defn: 1 |--> 1), ((1, 1, 2, 1, 1, 1, 1, 1, 1, 1); (), Ring endomorphism of Finite Field of size 3
437
Defn: 1 |--> 1), ((1, 1, 1, 1, 1, 1, 1, 1, 1, 1); (3,4), Ring endomorphism of Finite Field of size 3
438
Defn: 1 |--> 1), ((1, 1, 1, 1, 1, 1, 1, 1, 1, 1); (3,4,6), Ring endomorphism of Finite Field of size 3
439
Defn: 1 |--> 1)], 384)
440
"""
441
S = normalization.parent()
442
F = S.base_ring()
443
n = S.degree()
444
445
beg = 0
446
if zero_column_case:
447
aut_order = (len(F) - 1) ** len(col2P)
448
else:
449
aut_order = 1
450
A = []
451
while beg < len(col2P):
452
if zero_column_case:
453
mult = [F.one()] * n
454
mult[col2pos[beg]] = F.primitive_element()
455
A.append(S(v=mult))
456
P_indx = col2P[beg]
457
j = beg + 1
458
while j < len(col2P) and col2P[j] == P_indx:
459
j += 1
460
461
if j - beg > 1:
462
aut_order *= factorial(j - beg)
463
# we append a transposition of the first two elements
464
A.append(normalization_inverse *
465
S(perm=_cyclic_shift(n, col2pos[beg:beg + 2])) * normalization)
466
if j - beg > 2:
467
# we append a cycle on all elements
468
A.append(normalization_inverse *
469
S(perm=_cyclic_shift(n, col2pos[beg:j])) * normalization)
470
beg = j
471
return A, aut_order
472
473
@staticmethod
474
def _compute_PGammaL_automs(gens, normalization, normalization_inverse, col2pos):
475
"""
476
In order to call the algorithm described in
477
:class:`sage.coding.codecan.codecan.PartitionRefinementLinearCode` we removed
478
zero columns and multiple occurrences of the same column (up to normalization).
479
This function lifts the generators ``gens`` which were returned to their full length.
480
481
INPUT:
482
483
- ``gens`` -- a list of semimonomial transformation group elements of length `m`
484
485
- ``normalization`` -- a semimonomial transformation of length `n`
486
487
- ``normalization_inverse`` -- the inverse of ``normalization``
488
489
- ``col2pos`` -- a partition of ``range(n)`` into `m` disjoint sets,
490
given as a list of lists. The elements `g` in ``gens`` are only
491
allowed to permute entries of ``col2pos`` of equal length.
492
493
OUTPUT:
494
495
- a list of semimonomial transformations containing
496
``normalization`` which are the lifts of the elements in ``gens``
497
498
EXAMPLES::
499
500
sage: from sage.coding.codecan.autgroup_can_label import LinearCodeAutGroupCanLabel
501
sage: S = SemimonomialTransformationGroup(GF(3), 10)
502
sage: T = SemimonomialTransformationGroup(GF(3), 5)
503
sage: s = S.one()
504
sage: col2pos = [[1,4,2,3,5], [0],[6],[8],[7,9]]
505
sage: gens = [T(perm=Permutation([1,3,4,2,5]), v=[2,1,1,1,1])]
506
sage: LinearCodeAutGroupCanLabel._compute_PGammaL_automs(gens, s, s, col2pos)
507
[((1, 2, 2, 2, 2, 2, 1, 1, 1, 1); (1,7,9), Ring endomorphism of Finite Field of size 3
508
Defn: 1 |--> 1)]
509
"""
510
S = normalization.parent()
511
n = S.degree()
512
A = []
513
for g in gens:
514
perm = range(1, n + 1)
515
mult = [S.base_ring().one()] * n
516
short_perm = g.get_perm()
517
short_mult = g.get_v()
518
for i in range(len(col2pos)):
519
c = col2pos[i]
520
img_iter = iter(col2pos[short_perm(i + 1) - 1])
521
for x in c:
522
perm[x] = img_iter.next() + 1
523
mult[x] = short_mult[i]
524
A.append(normalization_inverse * S(perm=perm, v=mult, autom=g.get_autom()) * normalization)
525
return A
526
527
def get_canonical_form(self):
528
"""
529
Return the canonical orbit representative we computed.
530
531
EXAMPLES::
532
533
sage: from sage.coding.codecan.autgroup_can_label import LinearCodeAutGroupCanLabel
534
sage: C = codes.HammingCode(3, GF(3)).dual_code()
535
sage: CF1 = LinearCodeAutGroupCanLabel(C).get_canonical_form()
536
sage: s = SemimonomialTransformationGroup(GF(3), C.length()).an_element()
537
sage: C2 = LinearCode(s*C.gen_mat())
538
sage: CF2 = LinearCodeAutGroupCanLabel(C2).get_canonical_form()
539
sage: CF1 == CF2
540
True
541
"""
542
return self._canonical_form
543
544
def get_transporter(self):
545
"""
546
Return the element which maps the code to its canonical form.
547
548
EXAMPLES::
549
550
sage: from sage.coding.codecan.autgroup_can_label import LinearCodeAutGroupCanLabel
551
sage: C = codes.HammingCode(3, GF(2)).dual_code()
552
sage: P = LinearCodeAutGroupCanLabel(C)
553
sage: g = P.get_transporter()
554
sage: D = P.get_canonical_form()
555
sage: (g*C.gen_mat()).echelon_form() == D.gen_mat().echelon_form()
556
True
557
"""
558
return self._transporter
559
560
def get_autom_gens(self):
561
"""
562
Return a generating set for the automorphism group of the code.
563
564
EXAMPLES::
565
566
sage: from sage.coding.codecan.autgroup_can_label import LinearCodeAutGroupCanLabel
567
sage: C = codes.HammingCode(3, GF(2)).dual_code()
568
sage: A = LinearCodeAutGroupCanLabel(C).get_autom_gens()
569
sage: Gamma = C.gen_mat().echelon_form()
570
sage: all([(g*Gamma).echelon_form() == Gamma for g in A])
571
True
572
"""
573
return self._PGammaL_autom_gens + self._trivial_autom_gens
574
575
def get_autom_order(self):
576
"""
577
Return the size of the automorphism group of the code.
578
579
EXAMPLES::
580
581
sage: from sage.coding.codecan.autgroup_can_label import LinearCodeAutGroupCanLabel
582
sage: C = codes.HammingCode(3, GF(2)).dual_code()
583
sage: LinearCodeAutGroupCanLabel(C).get_autom_order()
584
168
585
"""
586
return self._full_autom_order
587
588
589
def get_PGammaL_gens(self):
590
r"""
591
Return the set of generators translated to the group `P\Gamma L(k,q)`.
592
593
There is a geometric point of view of code equivalence. A linear
594
code is identified with the multiset of points in the finite projective
595
geometry `PG(k-1, q)`. The equivalence of codes translates to the
596
natural action of `P\Gamma L(k,q)`. Therefore, we may interpret the
597
group as a subgroup of `P\Gamma L(k,q)` as well.
598
599
EXAMPLES::
600
601
sage: from sage.coding.codecan.autgroup_can_label import LinearCodeAutGroupCanLabel
602
sage: C = codes.HammingCode(3, GF(4, 'a')).dual_code()
603
sage: A = LinearCodeAutGroupCanLabel(C).get_PGammaL_gens()
604
sage: Gamma = C.gen_mat()
605
sage: N = [ x.monic() for x in Gamma.columns() ]
606
sage: all([ (g[0]*n.apply_map(g[1])).monic() in N for n in N for g in A])
607
True
608
"""
609
Gamma = self.C.gen_mat()
610
res = []
611
for a in self._PGammaL_autom_gens:
612
B = Gamma.solve_left(a * Gamma, check=True)
613
res.append([B, a.get_autom()])
614
615
return res
616
617
def get_PGammaL_order(self):
618
r"""
619
Return the size of the automorphism group as a subgroup of
620
`P\Gamma L(k,q)`.
621
622
There is a geometric point of view of code equivalence. A linear
623
code is identified with the multiset of points in the finite projective
624
geometry `PG(k-1, q)`. The equivalence of codes translates to the
625
natural action of `P\Gamma L(k,q)`. Therefore, we may interpret the
626
group as a subgroup of `P\Gamma L(k,q)` as well.
627
628
EXAMPLES::
629
630
sage: from sage.coding.codecan.autgroup_can_label import LinearCodeAutGroupCanLabel
631
sage: C = codes.HammingCode(3, GF(4, 'a')).dual_code()
632
sage: LinearCodeAutGroupCanLabel(C).get_PGammaL_order() == GL(3, GF(4, 'a')).order()*2/3
633
True
634
"""
635
return self._PGammaL_autom_size
636
637