Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/coding/linear_code.py
8815 views
1
# -*- coding: utf-8 -*-
2
r"""
3
Linear Codes
4
5
VERSION: 1.2
6
7
Let `F` be a finite field. Here, we will denote the finite field with `q`
8
elements by `\GF{q}`. A subspace of `F^n` (with the standard basis) is
9
called a linear code of length `n`. If its dimension is denoted `k` then we
10
typically store a basis of `C` as a `k \times n` matrix, with rows the basis
11
vectors. It is called the generator matrix of `C`. The rows of the parity
12
check matrix of `C` are a basis for the code,
13
14
.. math::
15
16
C^* = \{ v \in GF(q)^n\ |\ v\cdot c = 0,\ for \ all\ c \in C \},
17
18
called the dual space of `C`.
19
20
If `F=\GF{2}` then `C` is called a binary code. If `F = \GF{q}` then `C` is
21
called a `q`-ary code. The elements of a code `C` are called codewords.
22
23
Let `C`, `D` be linear codes of length `n` and dimension `k`. There are
24
several notions of equivalence for linear codes:
25
26
`C` and `D` are
27
28
- permutational equivalent, if there is some permutation `\pi \in S_n`
29
such that `(c_{\pi(0)}, \ldots, c_{\pi(n-1)}) \in D` for all `c \in C`.
30
31
- linear equivalent, if there is some permutation `\pi \in S_n` and a
32
vector `\phi` of units of length `n` such that
33
`(c_{\pi(0)} \phi_0^{-1}, \ldots, c_{\pi(n-1)} \phi_{n-1}^{-1}) \in D`
34
for all `c \in C`.
35
36
- semilinear equivalent, if there is some permutation `\pi \in S_n`, a
37
vector `\phi` of units of length `n` and a field automorphism `\alpha`
38
such that
39
`(\alpha(c_{\pi(0)}) \phi_0^{-1}, \ldots, \alpha( c_{\pi(n-1)}) \phi_{n-1}^{-1} ) \in D`
40
for all `c \in C`.
41
42
These are group actions. If one of these group elements sends
43
the linear code `C` to itself, then we will call it an automorphism.
44
Depending on the group action we will call those groups:
45
46
- permuation automorphism group
47
48
- monomial automorphism group (every linear Hamming isometry is a monomial
49
transformation of the ambient space, for `n\geq 3`)
50
51
- automorphism group (every semilinear Hamming isometry is a semimonomial
52
transformation of the ambient space, for `n\geq 3`)
53
54
This file contains
55
56
#. LinearCode class definition; LinearCodeFromVectorspace conversion function,
57
58
#. The spectrum (weight distribution), covering_radius, minimum distance
59
programs (calling Steve Linton's or CJ Tjhal's C programs),
60
characteristic_function, and several implementations of the Duursma zeta
61
function (sd_zeta_polynomial, zeta_polynomial, zeta_function,
62
chinen_polynomial, for example),
63
64
#. interface with best_known_linear_code_www (interface with codetables.de
65
since A. Brouwer's online tables have been disabled),
66
bounds_minimum_distance which call tables in GUAVA (updated May 2006)
67
created by Cen Tjhai instead of the online internet tables,
68
69
#. gen_mat, gen_mat_systematic, information_set, list, check_mat, decode,
70
dual_code, extended_code, shortened, punctured, genus, binomial_moment,
71
and divisor methods for LinearCode,
72
73
#. Boolean-valued functions such as "==", is_self_dual, is_self_orthogonal,
74
is_subcode, is_permutation_automorphism, is_permutation_equivalent (which
75
interfaces with Robert Miller's partition refinement code),
76
77
#. permutation methods: is_permutation_automorphism,
78
permutation_automorphism_group, permuted_code, standard_form,
79
module_composition_factors,
80
81
#. design-theoretic methods: assmus_mattson_designs (implementing
82
Assmus-Mattson Theorem),
83
84
#. code constructions, such as HammingCode and ToricCode, are in a separate
85
``code_constructions.py`` module; in the separate ``guava.py`` module, you
86
will find constructions, such as RandomLinearCodeGuava and
87
BinaryReedMullerCode, wrapped from the corresponding GUAVA codes.
88
89
EXAMPLES::
90
91
sage: MS = MatrixSpace(GF(2),4,7)
92
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
93
sage: C = LinearCode(G)
94
sage: C.basis()
95
[(1, 1, 1, 0, 0, 0, 0),
96
(1, 0, 0, 1, 1, 0, 0),
97
(0, 1, 0, 1, 0, 1, 0),
98
(1, 1, 0, 1, 0, 0, 1)]
99
sage: c = C.basis()[1]
100
sage: c in C
101
True
102
sage: c.nonzero_positions()
103
[0, 3, 4]
104
sage: c.support()
105
[0, 3, 4]
106
sage: c.parent()
107
Vector space of dimension 7 over Finite Field of size 2
108
109
To be added:
110
111
#. More wrappers
112
113
#. GRS codes and special decoders.
114
115
#. `P^1` Goppa codes and group actions on `P^1` RR space codes.
116
117
REFERENCES:
118
119
- [HP] W. C. Huffman and V. Pless, Fundamentals of error-correcting codes,
120
Cambridge Univ. Press, 2003.
121
122
- [Gu] GUAVA manual, http://www.gap-system.org/Packages/guava.html
123
124
AUTHORS:
125
126
- David Joyner (2005-11-22, 2006-12-03): initial version
127
128
- William Stein (2006-01-23): Inclusion in Sage
129
130
- David Joyner (2006-01-30, 2006-04): small fixes
131
132
- David Joyner (2006-07): added documentation, group-theoretical methods,
133
ToricCode
134
135
- David Joyner (2006-08): hopeful latex fixes to documentation, added list and
136
__iter__ methods to LinearCode and examples, added hamming_weight function,
137
fixed random method to return a vector, TrivialCode, fixed subtle bug in
138
dual_code, added galois_closure method, fixed mysterious bug in
139
permutation_automorphism_group (GAP was over-using "G" somehow?)
140
141
- David Joyner (2006-08): hopeful latex fixes to documentation, added
142
CyclicCode, best_known_linear_code, bounds_minimum_distance,
143
assmus_mattson_designs (implementing Assmus-Mattson Theorem).
144
145
- David Joyner (2006-09): modified decode syntax, fixed bug in
146
is_galois_closed, added LinearCode_from_vectorspace, extended_code,
147
zeta_function
148
149
- Nick Alexander (2006-12-10): factor GUAVA code to guava.py
150
151
- David Joyner (2007-05): added methods punctured, shortened, divisor,
152
characteristic_polynomial, binomial_moment, support for
153
LinearCode. Completely rewritten zeta_function (old version is now
154
zeta_function2) and a new function, LinearCodeFromVectorSpace.
155
156
- David Joyner (2007-11): added zeta_polynomial, weight_enumerator,
157
chinen_polynomial; improved best_known_code; made some pythonic revisions;
158
added is_equivalent (for binary codes)
159
160
- David Joyner (2008-01): fixed bug in decode reported by Harald Schilly,
161
(with Mike Hansen) added some doctests.
162
163
- David Joyner (2008-02): translated standard_form, dual_code to Python.
164
165
- David Joyner (2008-03): translated punctured, shortened, extended_code,
166
random (and renamed random to random_element), deleted zeta_function2,
167
zeta_function3, added wrapper automorphism_group_binary_code to Robert
168
Miller's code), added direct_sum_code, is_subcode, is_self_dual,
169
is_self_orthogonal, redundancy_matrix, did some alphabetical reorganizing
170
to make the file more readable. Fixed a bug in permutation_automorphism_group
171
which caused it to crash.
172
173
- David Joyner (2008-03): fixed bugs in spectrum and zeta_polynomial, which
174
misbehaved over non-prime base rings.
175
176
- David Joyner (2008-10): use CJ Tjhal's MinimumWeight if char = 2 or 3 for
177
min_dist; add is_permutation_equivalent and improve
178
permutation_automorphism_group using an interface with Robert Miller's code;
179
added interface with Leon's code for the spectrum method.
180
181
- David Joyner (2009-02): added native decoding methods (see module_decoder.py)
182
183
- David Joyner (2009-05): removed dependence on Guava, allowing it to be an
184
option. Fixed errors in some docstrings.
185
186
- Kwankyu Lee (2010-01): added methods gen_mat_systematic, information_set, and
187
magma interface for linear codes.
188
189
- Niles Johnson (2010-08): :trac:`#3893`: ``random_element()`` should pass on ``*args`` and ``**kwds``.
190
191
- Thomas Feulner (2012-11): :trac:`13723`: deprecation of ``hamming_weight()``
192
193
- Thomas Feulner (2013-10): added methods to compute a canonical representative
194
and the automorphism group
195
196
TESTS::
197
198
sage: MS = MatrixSpace(GF(2),4,7)
199
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
200
sage: C = LinearCode(G)
201
sage: C == loads(dumps(C))
202
True
203
"""
204
205
#******************************************************************************
206
# Copyright (C) 2005 David Joyner <[email protected]>
207
# 2006 William Stein <[email protected]>
208
#
209
# Distributed under the terms of the GNU General Public License (GPL),
210
# version 2 or later (at your preference).
211
#
212
# http://www.gnu.org/licenses/
213
#******************************************************************************
214
215
import urllib
216
import sage.modules.free_module as fm
217
import sage.modules.module as module
218
from sage.interfaces.all import gap
219
from sage.rings.finite_rings.constructor import FiniteField as GF
220
from sage.groups.perm_gps.permgroup import PermutationGroup
221
from sage.matrix.matrix_space import MatrixSpace
222
from sage.matrix.constructor import Matrix
223
from sage.modules.free_module_element import vector
224
from sage.rings.arith import GCD, rising_factorial, binomial
225
from sage.groups.all import SymmetricGroup
226
from sage.misc.misc import prod
227
from sage.misc.functional import log, is_even
228
from sage.rings.rational_field import QQ
229
from sage.structure.parent_gens import ParentWithGens
230
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
231
from sage.rings.fraction_field import FractionField
232
from sage.rings.integer_ring import IntegerRing
233
from sage.rings.integer import Integer
234
from sage.combinat.set_partition import SetPartitions
235
from sage.misc.randstate import current_randstate
236
from sage.misc.decorators import rename_keyword
237
from sage.misc.cachefunc import cached_method
238
239
ZZ = IntegerRing()
240
VectorSpace = fm.VectorSpace
241
242
####################### coding theory functions ###############################
243
244
def hamming_weight(v):
245
r"""
246
Returns the Hamming weight of the vector ``v``, which is the number of
247
non-zero entries.
248
249
INPUT:
250
251
- ``v`` - Vector
252
253
OUTPUT:
254
255
- Integer, the Hamming weight of ``v``
256
257
EXAMPLES::
258
259
sage: hamming_weight(vector(GF(2),[0,0,1]))
260
doctest:1: DeprecationWarning: The global function hamming_weight(v) is
261
deprecated, instead use v.hamming_weight().
262
See http://trac.sagemath.org/13723 for details.
263
1
264
sage: hamming_weight(vector(GF(2),[0,0,0]))
265
0
266
"""
267
from sage.misc.superseded import deprecation
268
deprecation(13723, "The global function hamming_weight(v) is deprecated, " +
269
"instead use v.hamming_weight().")
270
271
return len(v.nonzero_positions())
272
273
def code2leon(C):
274
r"""
275
Writes a file in Sage's temp directory representing the code C, returning
276
the absolute path to the file. This is the Sage translation of the
277
GuavaToLeon command in Guava's codefun.gi file.
278
279
INPUT:
280
281
- ``C`` - a linear code (over GF(p), p < 11)
282
283
OUTPUT:
284
285
- Absolute path to the file written
286
287
EXAMPLES::
288
289
sage: C = codes.HammingCode(3,GF(2)); C
290
Linear code of length 7, dimension 4 over Finite Field of size 2
291
sage: file_loc = sage.coding.linear_code.code2leon(C)
292
sage: f = open(file_loc); print f.read()
293
LIBRARY code;
294
code=seq(2,4,7,seq(
295
1,0,0,0,0,1,1,
296
0,1,0,0,1,0,1,
297
0,0,1,0,1,1,0,
298
0,0,0,1,1,1,1
299
));
300
FINISH;
301
sage: f.close()
302
303
"""
304
from sage.misc.misc import tmp_filename
305
F = C.base_ring()
306
p = F.order() # must be prime and <11
307
s = "LIBRARY code;\n"+"code=seq(%s,%s,%s,seq(\n"%(p,C.dimension(),C.length())
308
Gr = [str(r)[1:-1].replace(" ","") for r in C.gen_mat().rows()]
309
s += ",\n".join(Gr) + "\n));\nFINISH;"
310
file_loc = tmp_filename()
311
f = open(file_loc,"w")
312
f.write(s)
313
f.close()
314
return file_loc
315
316
def wtdist_gap(Gmat, n, F):
317
r"""
318
INPUT:
319
320
- ``Gmat`` - String representing a GAP generator matrix G of a linear code
321
322
- ``n`` - Integer greater than 1, representing the number of columns of G
323
(i.e., the length of the linear code)
324
325
- ``F`` - Finite field (in Sage), base field the code
326
327
OUTPUT:
328
329
- Spectrum of the associated code
330
331
EXAMPLES::
332
333
sage: Gstr = 'Z(2)*[[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]'
334
sage: F = GF(2)
335
sage: sage.coding.linear_code.wtdist_gap(Gstr, 7, F)
336
[1, 0, 0, 7, 7, 0, 0, 1]
337
338
Here ``Gstr`` is a generator matrix of the Hamming [7,4,3] binary code.
339
340
ALGORITHM:
341
342
Uses C programs written by Steve Linton in the kernel of GAP, so is fairly
343
fast.
344
345
AUTHORS:
346
347
- David Joyner (2005-11)
348
"""
349
G = gap(Gmat)
350
q = F.order()
351
k = gap(F)
352
#C = G.GeneratorMatCode(k)
353
#n = int(C.WordLength())
354
z = 'Z(%s)*%s'%(q, [0]*n) # GAP zero vector as a string
355
_ = gap.eval("w:=DistancesDistributionMatFFEVecFFE("+Gmat+", GF("+str(q)+"),"+z+")")
356
# for some reason, this commented code doesn't work:
357
#dist0 = gap("DistancesDistributionMatFFEVecFFE("+Gmat+", GF("+str(q)+"),"+z+")")
358
#v0 = dist0._matrix_(F)
359
#print dist0,v0
360
#d = G.DistancesDistributionMatFFEVecFFE(k, z)
361
v = [eval(gap.eval("w["+str(i)+"]")) for i in range(1,n+2)] # because GAP returns vectors in compressed form
362
return v
363
364
@rename_keyword(deprecation=11033, method="algorithm")
365
def min_wt_vec_gap(Gmat, n, k, F, algorithm=None):
366
r"""
367
Returns a minimum weight vector of the code generated by ``Gmat``.
368
369
Uses C programs written by Steve Linton in the kernel of GAP, so is fairly
370
fast. The option ``algorithm="guava"`` requires Guava. The default algorithm
371
requires GAP but not Guava.
372
373
INPUT:
374
375
- ``Gmat`` - String representing a GAP generator matrix G of a linear code
376
- n - Length of the code generated by G
377
- k - Dimension of the code generated by G
378
- F - Base field
379
380
OUTPUT:
381
382
- Minimum weight vector of the code generated by ``Gmat``
383
384
REMARKS:
385
386
- The code in the default case allows one (for free) to also compute the
387
message vector `m` such that `m\*G = v`, and the (minimum) distance, as
388
a triple. however, this output is not implemented.
389
- The binary case can presumably be done much faster using Robert Miller's
390
code (see the docstring for the spectrum method). This is also not (yet)
391
implemented.
392
393
EXAMPLES::
394
395
sage: Gstr = "Z(2)*[[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]"
396
sage: sage.coding.linear_code.min_wt_vec_gap(Gstr,7,4,GF(2))
397
(0, 1, 0, 1, 0, 1, 0)
398
399
This output is different but still a minimum weight vector::
400
401
sage: sage.coding.linear_code.min_wt_vec_gap(Gstr,7,4,GF(2),algorithm="guava") # optional - gap_packages (Guava package)
402
(0, 0, 1, 0, 1, 1, 0)
403
404
Here ``Gstr`` is a generator matrix of the Hamming [7,4,3] binary code.
405
406
AUTHORS:
407
408
- David Joyner (11-2005)
409
"""
410
current_randstate().set_seed_gap()
411
if algorithm=="guava":
412
gap.LoadPackage('"guava"')
413
from sage.interfaces.gap import gfq_gap_to_sage
414
gap.eval("G:="+Gmat)
415
C = gap(Gmat).GeneratorMatCode(F)
416
#n = int(C.length())
417
cg = C.MinimumDistanceCodeword()
418
c = [gfq_gap_to_sage(cg[j],F) for j in range(1,n+1)]
419
V = VectorSpace(F,n)
420
return V(c)
421
qstr = str(F.order())
422
zerovec = [0 for i in range(n)]
423
zerovecstr = "Z("+qstr+")*"+str(zerovec)
424
all = []
425
gap.eval('Gmat:='+Gmat)
426
for i in range(1,k+1):
427
gap.eval("P:=AClosestVectorCombinationsMatFFEVecFFECoords(Gmat, GF("+qstr+"),"+zerovecstr+","+str(i)+",0); d:=WeightVecFFE(P[1])")
428
v = gap("[P[1]]")
429
m = gap("[P[2]]")
430
dist = gap("d")
431
#print v,m,dist
432
#print [gap.eval("v["+str(i+1)+"]") for i in range(n)]
433
all.append([v._matrix_(F), m._matrix_(F), int(dist)])
434
ans = all[0]
435
for x in all:
436
if x[2]<ans[2] and x[2]>0:
437
ans = x
438
#print ans[0], ans[0].parent()
439
return vector(F,[x for x in ans[0].rows()[0]]) # ugly 1xn matrix->vector coercion!
440
441
def best_known_linear_code(n, k, F):
442
r"""
443
Returns the best known (as of 11 May 2006) linear code of length ``n``,
444
dimension ``k`` over field ``F``. The function uses the tables described
445
in ``bounds_minimum_distance`` to construct this code.
446
447
This does not require an internet connection.
448
449
EXAMPLES::
450
451
sage: best_known_linear_code(10,5,GF(2)) # long time; optional - gap_packages (Guava package)
452
Linear code of length 10, dimension 5 over Finite Field of size 2
453
sage: gap.eval("C:=BestKnownLinearCode(10,5,GF(2))") # long time; optional - gap_packages (Guava package)
454
'a linear [10,5,4]2..4 shortened code'
455
456
This means that best possible binary linear code of length 10 and
457
dimension 5 is a code with minimum distance 4 and covering radius
458
somewhere between 2 and 4. Use ``minimum_distance_why(10,5,GF(2))`` or
459
``print bounds_minimum_distance(10,5,GF(2))`` for further details.
460
"""
461
q = F.order()
462
C = gap("BestKnownLinearCode(%s,%s,GF(%s))"%(n,k,q))
463
G = C.GeneratorMat()
464
k = G.Length()
465
n = G[1].Length()
466
Gs = G._matrix_(F)
467
MS = MatrixSpace(F,k,n)
468
return LinearCode(MS(Gs))
469
#return gap.eval("BestKnownLinearCode(%s,%s,GF(%s))"%(n,k,q))
470
471
def best_known_linear_code_www(n, k, F, verbose=False):
472
r"""
473
Explains the construction of the best known linear code over GF(q) with
474
length n and dimension k, courtesy of the www page
475
http://www.codetables.de/.
476
477
INPUT:
478
479
- ``n`` - Integer, the length of the code
480
481
- ``k`` - Integer, the dimension of the code
482
483
- ``F`` - Finite field, of order 2, 3, 4, 5, 7, 8, or 9
484
485
- ``verbose`` - Bool (default: ``False``)
486
487
OUTPUT:
488
489
490
- Text about why the bounds are as given
491
492
EXAMPLES::
493
494
sage: L = best_known_linear_code_www(72, 36, GF(2)) # optional - internet
495
sage: print L # optional - internet
496
Construction of a linear code
497
[72,36,15] over GF(2):
498
[1]: [73, 36, 16] Cyclic Linear Code over GF(2)
499
CyclicCode of length 73 with generating polynomial x^37 + x^36 + x^34 +
500
x^33 + x^32 + x^27 + x^25 + x^24 + x^22 + x^21 + x^19 + x^18 + x^15 + x^11 +
501
x^10 + x^8 + x^7 + x^5 + x^3 + 1
502
[2]: [72, 36, 15] Linear Code over GF(2)
503
Puncturing of [1] at 1
504
last modified: 2002-03-20
505
506
This function raises an ``IOError`` if an error occurs downloading data or
507
parsing it. It raises a ``ValueError`` if the ``q`` input is invalid.
508
509
AUTHORS:
510
511
- Steven Sivek (2005-11-14)
512
- David Joyner (2008-03)
513
"""
514
q = F.order()
515
if not q in [2, 3, 4, 5, 7, 8, 9]:
516
raise ValueError, "q (=%s) must be in [2,3,4,5,7,8,9]"%q
517
n = int(n)
518
k = int(k)
519
520
param = ("?q=%s&n=%s&k=%s"%(q,n,k)).replace('L','')
521
522
url = "http://iaks-www.ira.uka.de/home/grassl/codetables/BKLC/BKLC.php"+param
523
#url = "http://homepages.cwi.nl/htbin/aeb/lincodbd/"+param
524
if verbose:
525
print "Looking up the bounds at %s"%url
526
f = urllib.urlopen(url)
527
s = f.read()
528
f.close()
529
#print s
530
531
i = s.find("<PRE>")
532
j = s.find("</PRE>")
533
if i == -1 or j == -1:
534
raise IOError, "Error parsing data (missing pre tags)."
535
text = s[i+5:j].strip()
536
return text
537
538
def bounds_minimum_distance(n, k, F):
539
r"""
540
Calculates a lower and upper bound for the minimum distance of an optimal
541
linear code with word length ``n`` and dimension ``k`` over the field
542
``F``.
543
544
The function returns a record with the two bounds and an explanation for
545
each bound. The function Display can be used to show the explanations.
546
547
The values for the lower and upper bound are obtained from a table
548
constructed by Cen Tjhai for GUAVA, derived from the table of
549
Brouwer. (See http://www.win.tue.nl/ aeb/voorlincod.html or use the
550
Sage function ``minimum_distance_why`` for the most recent data.)
551
These tables contain lower and upper bounds for `q=2` (when ``n <= 257``),
552
`q=3` (when ``n <= 243``), `q=4` (``n <= 256``). (Current as of
553
11 May 2006.) For codes over other fields and for larger word lengths,
554
trivial bounds are used.
555
556
This does not require an internet connection. The format of the output is
557
a little non-intuitive. Try ``bounds_minimum_distance(10,5,GF(2))`` for
558
an example.
559
560
This function requires optional GAP package (Guava).
561
562
EXAMPLES::
563
564
sage: print bounds_minimum_distance(10,5,GF(2)) # optional - gap_packages (Guava package)
565
rec(
566
construction :=
567
[ <Operation "ShortenedCode">,
568
[
569
[ <Operation "UUVCode">,
570
[
571
[ <Operation "DualCode">,
572
[ [ <Operation "RepetitionCode">, [ 8, 2 ] ] ] ],
573
[ <Operation "UUVCode">,
574
[
575
[ <Operation "DualCode">,
576
[ [ <Operation "RepetitionCode">, [ 4, 2 ] ] ] ]
577
, [ <Operation "RepetitionCode">, [ 4, 2 ] ] ] ]
578
] ], [ 1, 2, 3, 4, 5, 6 ] ] ],
579
k := 5,
580
lowerBound := 4,
581
lowerBoundExplanation := ...
582
n := 10,
583
q := 2,
584
references := rec(
585
),
586
upperBound := 4,
587
upperBoundExplanation := ... )
588
"""
589
q = F.order()
590
gap.eval("data := BoundsMinimumDistance(%s,%s,GF(%s))"%(n,k,q))
591
Ldata = gap.eval("Display(data)")
592
return Ldata
593
594
def self_orthogonal_binary_codes(n, k, b=2, parent=None, BC=None, equal=False,
595
in_test=None):
596
"""
597
Returns a Python iterator which generates a complete set of
598
representatives of all permutation equivalence classes of
599
self-orthogonal binary linear codes of length in ``[1..n]`` and
600
dimension in ``[1..k]``.
601
602
INPUT:
603
604
- ``n`` - Integer, maximal length
605
606
- ``k`` - Integer, maximal dimension
607
608
- ``b`` - Integer, requires that the generators all have weight divisible
609
by ``b`` (if ``b=2``, all self-orthogonal codes are generated, and if
610
``b=4``, all doubly even codes are generated). Must be an even positive
611
integer.
612
613
- ``parent`` - Used in recursion (default: ``None``)
614
615
- ``BC`` - Used in recursion (default: ``None``)
616
617
- ``equal`` - If ``True`` generates only [n, k] codes (default: ``False``)
618
619
- ``in_test`` - Used in recursion (default: ``None``)
620
621
EXAMPLES:
622
623
Generate all self-orthogonal codes of length up to 7 and dimension up
624
to 3::
625
626
sage: for B in self_orthogonal_binary_codes(7,3):
627
... print B
628
...
629
Linear code of length 2, dimension 1 over Finite Field of size 2
630
Linear code of length 4, dimension 2 over Finite Field of size 2
631
Linear code of length 6, dimension 3 over Finite Field of size 2
632
Linear code of length 4, dimension 1 over Finite Field of size 2
633
Linear code of length 6, dimension 2 over Finite Field of size 2
634
Linear code of length 6, dimension 2 over Finite Field of size 2
635
Linear code of length 7, dimension 3 over Finite Field of size 2
636
Linear code of length 6, dimension 1 over Finite Field of size 2
637
638
Generate all doubly-even codes of length up to 7 and dimension up
639
to 3::
640
641
sage: for B in self_orthogonal_binary_codes(7,3,4):
642
... print B; print B.gen_mat()
643
...
644
Linear code of length 4, dimension 1 over Finite Field of size 2
645
[1 1 1 1]
646
Linear code of length 6, dimension 2 over Finite Field of size 2
647
[1 1 1 1 0 0]
648
[0 1 0 1 1 1]
649
Linear code of length 7, dimension 3 over Finite Field of size 2
650
[1 0 1 1 0 1 0]
651
[0 1 0 1 1 1 0]
652
[0 0 1 0 1 1 1]
653
654
Generate all doubly-even codes of length up to 7 and dimension up
655
to 2::
656
657
sage: for B in self_orthogonal_binary_codes(7,2,4):
658
... print B; print B.gen_mat()
659
Linear code of length 4, dimension 1 over Finite Field of size 2
660
[1 1 1 1]
661
Linear code of length 6, dimension 2 over Finite Field of size 2
662
[1 1 1 1 0 0]
663
[0 1 0 1 1 1]
664
665
Generate all self-orthogonal codes of length equal to 8 and
666
dimension equal to 4::
667
668
sage: for B in self_orthogonal_binary_codes(8, 4, equal=True):
669
... print B; print B.gen_mat()
670
Linear code of length 8, dimension 4 over Finite Field of size 2
671
[1 0 0 1 0 0 0 0]
672
[0 1 0 0 1 0 0 0]
673
[0 0 1 0 0 1 0 0]
674
[0 0 0 0 0 0 1 1]
675
Linear code of length 8, dimension 4 over Finite Field of size 2
676
[1 0 0 1 1 0 1 0]
677
[0 1 0 1 1 1 0 0]
678
[0 0 1 0 1 1 1 0]
679
[0 0 0 1 0 1 1 1]
680
681
Since all the codes will be self-orthogonal, b must be divisible by
682
2::
683
684
sage: list(self_orthogonal_binary_codes(8, 4, 1, equal=True))
685
Traceback (most recent call last):
686
...
687
ValueError: b (1) must be a positive even integer.
688
"""
689
d=int(b)
690
if d!=b or d%2==1 or d <= 0:
691
raise ValueError("b (%s) must be a positive even integer."%b)
692
from binary_code import BinaryCode, BinaryCodeClassifier
693
if k < 1 or n < 2:
694
return
695
if equal:
696
in_test = lambda M : (M.ncols() - M.nrows()) <= (n-k)
697
out_test = lambda C : (C.dimension() == k) and (C.length() == n)
698
else:
699
in_test = lambda M : True
700
out_test = lambda C : True
701
if BC is None:
702
BC = BinaryCodeClassifier()
703
if parent is None:
704
for j in xrange(d, n+1, d):
705
M = Matrix(GF(2), [[1]*j])
706
if in_test(M):
707
for N in self_orthogonal_binary_codes(n, k, d, M, BC, in_test=in_test):
708
if out_test(N): yield N
709
else:
710
C = LinearCode(parent)
711
if out_test(C): yield C
712
if k == parent.nrows():
713
return
714
for nn in xrange(parent.ncols()+1, n+1):
715
if in_test(parent):
716
for child in BC.generate_children(BinaryCode(parent), nn, d):
717
for N in self_orthogonal_binary_codes(n, k, d, child, BC, in_test=in_test):
718
if out_test(N): yield N
719
720
############################ linear codes python class ########################
721
722
class LinearCode(module.Module_old):
723
r"""
724
A class for linear codes over a finite field or finite ring. Each instance
725
is a linear code determined by a generator matrix `G` (i.e., a
726
`k \times n` matrix of (full) rank `k`, `k \leq n` over a finite field `F`.
727
728
INPUT:
729
730
- ``G`` - a generator matrix over `F`. (``G`` can be defined over a
731
finite ring but the matrices over that ring must have certain
732
attributes, such as ``rank``.)
733
734
- ``d`` - (Optional, default: ``None``) the minimum distance of the
735
code. This is an optional parameter.
736
737
.. note::
738
The veracity of the minimum distance ``d``, if provided, is not
739
checked.
740
741
OUTPUT:
742
743
The linear code of length `n` over `F` having `G` as a generator matrix.
744
745
EXAMPLES::
746
747
sage: MS = MatrixSpace(GF(2),4,7)
748
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
749
sage: C = LinearCode(G)
750
sage: C
751
Linear code of length 7, dimension 4 over Finite Field of size 2
752
sage: C.base_ring()
753
Finite Field of size 2
754
sage: C.dimension()
755
4
756
sage: C.length()
757
7
758
sage: C.minimum_distance()
759
3
760
sage: C.spectrum()
761
[1, 0, 0, 7, 7, 0, 0, 1]
762
sage: C.weight_distribution()
763
[1, 0, 0, 7, 7, 0, 0, 1]
764
765
The minimum distance of the code, if known, can be provided as an
766
optional parameter.::
767
768
sage: C = LinearCode(G, d=3)
769
sage: C.minimum_distance()
770
3
771
772
Another example.::
773
774
sage: MS = MatrixSpace(GF(5),4,7)
775
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
776
sage: C = LinearCode(G)
777
sage: C
778
Linear code of length 7, dimension 4 over Finite Field of size 5
779
780
AUTHORS:
781
782
- David Joyner (11-2005)
783
"""
784
# sage: C.minimum_distance_upper_bound() # optional (net connection)
785
# 3
786
# sage: C.minimum_distance_why() # optional (net connection)
787
# Ub(7,4) = 3 follows by the Griesmer bound.
788
def __init__(self, gen_mat, d=None):
789
r"""
790
See the docstring for :meth:`LinearCode`.
791
792
EXAMPLES::
793
794
sage: MS = MatrixSpace(GF(2),4,7)
795
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
796
sage: C = LinearCode(G) # indirect doctest
797
sage: C
798
Linear code of length 7, dimension 4 over Finite Field of size 2
799
800
The minimum distance of the code, if known, can be provided as an
801
optional parameter.::
802
803
sage: C = LinearCode(G, d=3)
804
sage: C.minimum_distance()
805
3
806
"""
807
base_ring = gen_mat[0,0].parent()
808
ParentWithGens.__init__(self, base_ring)
809
self.__gens = gen_mat.rows()
810
self.__gen_mat = gen_mat
811
self.__length = len(gen_mat.row(0))
812
self.__dim = gen_mat.rank()
813
self.__distance = d
814
815
def _repr_(self):
816
r"""
817
See the docstring for :meth:`LinearCode`.
818
819
EXAMPLES::
820
821
sage: MS = MatrixSpace(GF(2),4,7)
822
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
823
sage: C = LinearCode(G)
824
sage: C # indirect doctest
825
Linear code of length 7, dimension 4 over Finite Field of size 2
826
"""
827
return "Linear code of length %s, dimension %s over %s"%(self.length(), self.dimension(), self.base_ring())
828
829
def automorphism_group_gens(self, equivalence="semilinear"):
830
r"""
831
Return generators of the automorphism group of ``self``.
832
833
INPUT:
834
835
- ``equivalence`` (optional) -- which defines the acting group, either
836
837
* ``permutational``
838
839
* ``linear``
840
841
* ``semilinear``
842
843
OUTPUT:
844
845
- generators of the automorphism group of ``self``
846
- the order of the automorphism group of ``self``
847
848
EXAMPLES::
849
850
sage: C = codes.HammingCode(3,GF(4,"z"));
851
sage: C.automorphism_group_gens()
852
([((1, 1, 1, z, z + 1, z + 1, z + 1, z, z, 1, 1, 1, z, z, z + 1, z, z, z + 1, z + 1, z + 1, 1); (1,6,12,17)(2,16,4,5,11,8,14,13)(3,21,19,10,20,18,15,9), Ring endomorphism of Finite Field in z of size 2^2
853
Defn: z |--> z + 1), ((1, 1, 1, z, z + 1, 1, 1, z, z, z + 1, z, z, z + 1, z + 1, z + 1, 1, z + 1, z, z, 1, 1); (1,6,9,13,15,18)(2,21)(3,16,7)(4,5,11,10,12,14)(17,19), Ring endomorphism of Finite Field in z of size 2^2
854
Defn: z |--> z), ((z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z); (), Ring endomorphism of Finite Field in z of size 2^2
855
Defn: z |--> z)], 362880)
856
sage: C.automorphism_group_gens(equivalence="linear")
857
([((z, z, 1, 1, z + 1, z, z + 1, z, z, z + 1, 1, 1, 1, z + 1, z, z, z + 1, z + 1, 1, 1, z); (1,5,10,9,4,14,11,16,18,20,6,19,12,15,3,8,2,17,7,13,21), Ring endomorphism of Finite Field in z of size 2^2
858
Defn: z |--> z), ((z + 1, 1, z, 1, 1, z + 1, z + 1, z, 1, z, z + 1, z, z + 1, z + 1, z, 1, 1, z + 1, z + 1, z + 1, z); (1,17,10)(2,15,13)(4,11,21)(5,18,12)(6,14,19)(7,8,16), Ring endomorphism of Finite Field in z of size 2^2
859
Defn: z |--> z), ((z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1, z + 1); (), Ring endomorphism of Finite Field in z of size 2^2
860
Defn: z |--> z)], 181440)
861
sage: C.automorphism_group_gens(equivalence="permutational")
862
([((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); (1,11)(3,10)(4,9)(5,7)(12,21)(14,20)(15,19)(16,17), Ring endomorphism of Finite Field in z of size 2^2
863
Defn: z |--> z), ((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); (2,18)(3,19)(4,10)(5,16)(8,13)(9,14)(11,21)(15,20), Ring endomorphism of Finite Field in z of size 2^2
864
Defn: z |--> z), ((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); (1,19)(3,17)(4,21)(5,20)(7,14)(9,12)(10,16)(11,15), Ring endomorphism of Finite Field in z of size 2^2
865
Defn: z |--> z), ((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); (2,13)(3,14)(4,20)(5,11)(8,18)(9,19)(10,15)(16,21), Ring endomorphism of Finite Field in z of size 2^2
866
Defn: z |--> z)], 64)
867
"""
868
aut_group_can_label = self._canonize(equivalence)
869
return aut_group_can_label.get_autom_gens(), \
870
aut_group_can_label.get_autom_order()
871
872
873
def automorphism_group_binary_code(self):
874
r"""
875
This function is deprecated. Use permutation_automorphism_group instead.
876
877
This only applies to linear binary codes and returns its (permutation)
878
automorphism group. In other words, if the code `C` has length `n`
879
then it returns the subgroup of the symmetric group `S_n`:
880
881
.. math::
882
883
\{ g \in S_n\ |\ g(c) \in C, \forall c\in C\},
884
885
where `S_n` acts on `GF(2)^n` by permuting coordinates.
886
887
EXAMPLES::
888
889
sage: C = codes.HammingCode(3,GF(2))
890
sage: G = C.automorphism_group_binary_code(); G
891
doctest:...: DeprecationWarning: This function is deprecated...
892
Permutation Group with generators [(4,5)(6,7), (4,6)(5,7), (2,3)(6,7), (2,4)(3,5), (1,2)(5,6)]
893
sage: G.order()
894
168
895
"""
896
from sage.misc.superseded import deprecation
897
deprecation(11033, "This function is deprecated. Call the method"
898
+" permutation_automorphism_group instead.")
899
#deprecated 4.7
900
C = self
901
F = C.base_ring()
902
if F!=GF(2):
903
raise NotImplementedError, "Only implemented for binary codes."
904
return self.permutation_automorphism_group()
905
906
def __iter__(self):
907
"""
908
Return an iterator over the elements of this linear code.
909
910
EXAMPLES::
911
912
sage: C = codes.HammingCode(3,GF(2))
913
sage: [list(c) for c in C if c.hamming_weight() < 4]
914
[[0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 1, 1],
915
[0, 1, 0, 0, 1, 0, 1], [0, 0, 1, 0, 1, 1, 0],
916
[1, 1, 1, 0, 0, 0, 0], [1, 0, 0, 1, 1, 0, 0],
917
[0, 1, 0, 1, 0, 1, 0], [0, 0, 1, 1, 0, 0, 1]]
918
"""
919
from sage.modules.finite_submodule_iter import \
920
FiniteFieldsubspace_iterator
921
return FiniteFieldsubspace_iterator(self.gen_mat())
922
923
def ambient_space(self):
924
r"""
925
Returns the ambient vector space of `self`.
926
927
EXAMPLES::
928
929
sage: C = codes.HammingCode(3,GF(2))
930
sage: C.ambient_space()
931
Vector space of dimension 7 over Finite Field of size 2
932
"""
933
return VectorSpace(self.base_ring(),self.__length)
934
935
def assmus_mattson_designs(self, t, mode=None):
936
r"""
937
Assmus and Mattson Theorem (section 8.4, page 303 of [HP]): Let
938
`A_0, A_1, ..., A_n` be the weights of the codewords in a binary
939
linear `[n , k, d]` code `C`, and let `A_0^*, A_1^*, ..., A_n^*` be
940
the weights of the codewords in its dual `[n, n-k, d^*]` code `C^*`.
941
Fix a `t`, `0<t<d`, and let
942
943
.. math::
944
945
s = |\{ i\ |\ A_i^* \not= 0, 0< i \leq n-t\}|.
946
947
Assume `s\leq d-t`.
948
949
1. If `A_i\not= 0` and `d\leq i\leq n`
950
then `C_i = \{ c \in C\ |\ wt(c) = i\}` holds a simple t-design.
951
952
2. If `A_i^*\not= 0` and `d*\leq i\leq n-t` then
953
`C_i^* = \{ c \in C^*\ |\ wt(c) = i\}` holds a simple t-design.
954
955
A block design is a pair `(X,B)`, where `X` is a non-empty finite set
956
of `v>0` elements called points, and `B` is a non-empty finite
957
multiset of size b whose elements are called blocks, such that each
958
block is a non-empty finite multiset of `k` points. `A` design without
959
repeated blocks is called a simple block design. If every subset of
960
points of size `t` is contained in exactly `\lambda` blocks the block
961
design is called a `t-(v,k,\lambda)` design (or simply a `t`-design
962
when the parameters are not specified). When `\lambda=1` then the
963
block design is called a `S(t,k,v)` Steiner system.
964
965
In the Assmus and Mattson Theorem (1), `X` is the set `\{1,2,...,n\}`
966
of coordinate locations and `B = \{supp(c)\ |\ c \in C_i\}` is the set
967
of supports of the codewords of `C` of weight `i`. Therefore, the
968
parameters of the `t`-design for `C_i` are
969
970
::
971
972
t = given
973
v = n
974
k = i (k not to be confused with dim(C))
975
b = Ai
976
lambda = b*binomial(k,t)/binomial(v,t) (by Theorem 8.1.6,
977
p 294, in [HP])
978
979
Setting the ``mode="verbose"`` option prints out the values of the
980
parameters.
981
982
The first example below means that the binary [24,12,8]-code C has
983
the property that the (support of the) codewords of weight 8 (resp.,
984
12, 16) form a 5-design. Similarly for its dual code `C^*` (of course
985
`C=C^*` in this case, so this info is extraneous). The test fails to
986
produce 6-designs (ie, the hypotheses of the theorem fail to hold,
987
not that the 6-designs definitely don't exist). The command
988
assmus_mattson_designs(C,5,mode="verbose") returns the same value
989
but prints out more detailed information.
990
991
The second example below illustrates the blocks of the 5-(24, 8, 1)
992
design (i.e., the S(5,8,24) Steiner system).
993
994
EXAMPLES::
995
996
sage: C = codes.ExtendedBinaryGolayCode() # example 1
997
sage: C.assmus_mattson_designs(5)
998
['weights from C: ',
999
[8, 12, 16, 24],
1000
'designs from C: ',
1001
[[5, (24, 8, 1)], [5, (24, 12, 48)], [5, (24, 16, 78)], [5, (24, 24, 1)]],
1002
'weights from C*: ',
1003
[8, 12, 16],
1004
'designs from C*: ',
1005
[[5, (24, 8, 1)], [5, (24, 12, 48)], [5, (24, 16, 78)]]]
1006
sage: C.assmus_mattson_designs(6)
1007
0
1008
sage: X = range(24) # example 2
1009
sage: blocks = [c.support() for c in C if c.hamming_weight()==8]; len(blocks) # long time computation
1010
759
1011
1012
REFERENCE:
1013
1014
- [HP] W. C. Huffman and V. Pless, Fundamentals of ECC,
1015
Cambridge Univ. Press, 2003.
1016
"""
1017
C = self
1018
ans = []
1019
G = C.gen_mat()
1020
n = len(G.columns())
1021
Cp = C.dual_code()
1022
wts = C.spectrum()
1023
d = min([i for i in range(1,len(wts)) if wts[i]!=0])
1024
if t>=d:
1025
return 0
1026
nonzerowts = [i for i in range(len(wts)) if wts[i]!=0 and i<=n and i>=d]
1027
#print d,t,len(nonzerowts)
1028
if mode=="verbose":
1029
#print "\n"
1030
for w in nonzerowts:
1031
print "The weight ",w," codewords of C form a t-(v,k,lambda) design, where"
1032
print " t = ",t," , v = ",n," , k = ",w," , lambda = ",wts[w]*binomial(w,t)/binomial(n,t)#,"\n"
1033
print " There are ",wts[w]," blocks of this design."
1034
wtsp = Cp.spectrum()
1035
dp = min([i for i in range(1,len(wtsp)) if wtsp[i]!=0])
1036
nonzerowtsp = [i for i in range(len(wtsp)) if wtsp[i]!=0 and i<=n-t and i>=dp]
1037
s = len([i for i in range(1,n) if wtsp[i]!=0 and i<=n-t and i>0])
1038
if mode=="verbose":
1039
#print "\n"
1040
for w in nonzerowtsp:
1041
print "The weight ",w," codewords of C* form a t-(v,k,lambda) design, where"
1042
print " t = ",t," , v = ",n," , k = ",w," , lambda = ",wtsp[w]*binomial(w,t)/binomial(n,t)#,"\n"
1043
print " There are ",wts[w]," blocks of this design."
1044
if s<=d-t:
1045
des = [[t,(n,w,wts[w]*binomial(w,t)/binomial(n,t))] for w in nonzerowts]
1046
ans = ans + ["weights from C: ",nonzerowts,"designs from C: ",des]
1047
desp = [[t,(n,w,wtsp[w]*binomial(w,t)/binomial(n,t))] for w in nonzerowtsp]
1048
ans = ans + ["weights from C*: ",nonzerowtsp,"designs from C*: ",desp]
1049
return ans
1050
return 0
1051
1052
def basis(self):
1053
r"""
1054
Returns a basis of `self`.
1055
1056
EXAMPLES::
1057
1058
sage: C = codes.HammingCode(3, GF(2))
1059
sage: C.basis()
1060
[(1, 0, 0, 0, 0, 1, 1), (0, 1, 0, 0, 1, 0, 1), (0, 0, 1, 0, 1, 1, 0), (0, 0, 0, 1, 1, 1, 1)]
1061
"""
1062
return self.__gens
1063
1064
# S. Pancratz, 19 Jan 2010: In the doctests below, I removed the example
1065
# ``C.binomial_moment(3)``, which was also marked as ``#long``. This way,
1066
# we shorten the doctests time while still maintaining a zero and a
1067
# non-zero example.
1068
def binomial_moment(self, i):
1069
r"""
1070
Returns the i-th binomial moment of the `[n,k,d]_q`-code `C`:
1071
1072
.. math::
1073
1074
B_i(C) = \sum_{S, |S|=i} \frac{q^{k_S}-1}{q-1}
1075
1076
where `k_S` is the dimension of the shortened code `C_{J-S}`,
1077
`J=[1,2,...,n]`. (The normalized binomial moment is
1078
`b_i(C) = \binom(n,d+i)^{-1}B_{d+i}(C)`.) In other words, `C_{J-S}`
1079
is isomorphic to the subcode of C of codewords supported on S.
1080
1081
EXAMPLES::
1082
1083
sage: C = codes.HammingCode(3,GF(2))
1084
sage: C.binomial_moment(2)
1085
0
1086
sage: C.binomial_moment(4) # long time
1087
35
1088
1089
.. warning::
1090
1091
This is slow.
1092
1093
REFERENCE:
1094
1095
- I. Duursma, "Combinatorics of the two-variable zeta function",
1096
Finite fields and applications, 109-136, Lecture Notes in
1097
Comput. Sci., 2948, Springer, Berlin, 2004.
1098
"""
1099
n = self.length()
1100
k = self.dimension()
1101
d = self.minimum_distance()
1102
F = self.base_ring()
1103
q = F.order()
1104
J = range(1,n+1)
1105
Cp = self.dual_code()
1106
dp = Cp.minimum_distance()
1107
if i<d:
1108
return 0
1109
if i>n-dp and i<=n:
1110
return binomial(n,i)*(q**(i+k-n) -1)/(q-1)
1111
P = SetPartitions(J,2).list()
1112
b = QQ(0)
1113
for p in P:
1114
p = list(p)
1115
S = p[0]
1116
if len(S)==n-i:
1117
C_S = self.shortened(S)
1118
k_S = C_S.dimension()
1119
b = b + (q**(k_S) -1)/(q-1)
1120
return b
1121
1122
@cached_method
1123
def _canonize(self, equivalence):
1124
r"""
1125
Compute a canonical representative and the automorphism group
1126
under the action of the semimonomial transformation group.
1127
1128
INPUT:
1129
1130
- ``equivalence`` -- which defines the acting group, either
1131
1132
* ``permutational``
1133
1134
* ``linear``
1135
1136
* ``semilinear``
1137
1138
EXAMPLES::
1139
1140
sage: C = codes.HammingCode(3,GF(4,"z"));
1141
sage: aut_group_can_label = C._canonize("semilinear")
1142
sage: C_iso = LinearCode(aut_group_can_label.get_transporter()*C.gen_mat())
1143
sage: C_iso == aut_group_can_label.get_canonical_form()
1144
True
1145
sage: aut_group_can_label.get_autom_gens()
1146
[((z, z + 1, 1, z + 1, z, z, z, z + 1, 1, z + 1, z + 1, z, z + 1, 1, z + 1, 1, z, z + 1, 1, z + 1, z + 1); (1,12,21,18,15,20)(2,19,16)(3,4,11,6,13,7)(5,8)(10,14,17), Ring endomorphism of Finite Field in z of size 2^2
1147
Defn: z |--> z + 1), ((z + 1, 1, z, 1, 1, z, 1, z + 1, z, z + 1, z, z + 1, z, 1, z, z + 1, z, z, z + 1, z + 1, 1); (1,20,2,9,13,21,11,17,10,16,3,5,18,8)(4,12,6,15,14,19,7), Ring endomorphism of Finite Field in z of size 2^2
1148
Defn: z |--> z + 1), ((z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z); (), Ring endomorphism of Finite Field in z of size 2^2
1149
Defn: z |--> z)]
1150
"""
1151
from sage.coding.codecan.autgroup_can_label import LinearCodeAutGroupCanLabel
1152
return LinearCodeAutGroupCanLabel(self, algorithm_type=equivalence)
1153
1154
def canonical_representative(self, equivalence="semilinear"):
1155
r"""
1156
Compute a canonical orbit representative under the action of the
1157
semimonomial transformation group.
1158
1159
See :mod:`sage.coding.codecan.autgroup_can_label`
1160
for more details, for example if you would like to compute
1161
a canonical form under some more restrictive notion of equivalence,
1162
i.e. if you would like to restrict the permutation group
1163
to a Young subgroup.
1164
1165
INPUT:
1166
1167
- ``equivalence`` (optional) -- which defines the acting group, either
1168
1169
* ``permutational``
1170
1171
* ``linear``
1172
1173
* ``semilinear``
1174
1175
OUTPUT:
1176
1177
- a canonical representative of ``self``
1178
- a semimonomial transformation mapping ``self`` onto its representative
1179
1180
EXAMPLES::
1181
1182
sage: F.<z> = GF(4)
1183
sage: C = codes.HammingCode(3,F)
1184
sage: CanRep, transp = C.canonical_representative()
1185
1186
Check that the transporter element is correct::
1187
1188
sage: LinearCode(transp*C.gen_mat()) == CanRep
1189
True
1190
1191
Check if an equivalent code has the same canonical representative::
1192
1193
sage: f = F.hom([z**2])
1194
sage: C_iso = LinearCode(C.gen_mat().apply_map(f))
1195
sage: CanRep_iso, _ = C_iso.canonical_representative()
1196
sage: CanRep_iso == CanRep
1197
True
1198
1199
Since applying the Frobenius automorphism could be extended to an
1200
automorphism of `C`, the following must also yield ``True``::
1201
1202
sage: CanRep1, _ = C.canonical_representative("linear")
1203
sage: CanRep2, _ = C_iso.canonical_representative("linear")
1204
sage: CanRep2 == CanRep1
1205
True
1206
"""
1207
aut_group_can_label = self._canonize(equivalence)
1208
return aut_group_can_label.get_canonical_form(), \
1209
aut_group_can_label.get_transporter()
1210
1211
def __contains__(self,v):
1212
r"""
1213
Returns True if `v` can be coerced into `self`. Otherwise, returns False.
1214
1215
EXAMPLES::
1216
1217
sage: C = codes.HammingCode(3,GF(2))
1218
sage: vector((1, 0, 0, 0, 0, 1, 1)) in C # indirect doctest
1219
True
1220
sage: vector((1, 0, 0, 0, 2, 1, 1)) in C # indirect doctest
1221
True
1222
sage: vector((1, 0, 0, 0, 0, 1/2, 1)) in C # indirect doctest
1223
False
1224
"""
1225
A = self.ambient_space()
1226
C = A.subspace(self.gens())
1227
return C.__contains__(v)
1228
1229
def characteristic(self):
1230
r"""
1231
Returns the characteristic of the base ring of `self`.
1232
1233
EXAMPLES::
1234
1235
sage: C = codes.HammingCode(3,GF(2))
1236
sage: C.characteristic()
1237
2
1238
"""
1239
return (self.base_ring()).characteristic()
1240
1241
def characteristic_polynomial(self):
1242
r"""
1243
Returns the characteristic polynomial of a linear code, as defined in
1244
van Lint's text [vL].
1245
1246
EXAMPLES::
1247
1248
sage: C = codes.ExtendedBinaryGolayCode()
1249
sage: C.characteristic_polynomial()
1250
-4/3*x^3 + 64*x^2 - 2816/3*x + 4096
1251
1252
REFERENCES:
1253
1254
- van Lint, Introduction to coding theory, 3rd ed., Springer-Verlag
1255
GTM, 86, 1999.
1256
"""
1257
R = PolynomialRing(QQ,"x")
1258
x = R.gen()
1259
C = self
1260
Cd = C.dual_code()
1261
Sd = Cd.support()
1262
k = C.dimension()
1263
n = C.length()
1264
q = (C.base_ring()).order()
1265
return q**(n-k)*prod([1-x/j for j in Sd if j>0])
1266
1267
def chinen_polynomial(self):
1268
"""
1269
Returns the Chinen zeta polynomial of the code.
1270
1271
EXAMPLES::
1272
1273
sage: C = codes.HammingCode(3,GF(2))
1274
sage: C.chinen_polynomial() # long time
1275
1/5*(2*sqrt(2)*t^3 + 2*sqrt(2)*t^2 + 2*t^2 + sqrt(2)*t + 2*t + 1)/(sqrt(2) + 1)
1276
sage: C = codes.TernaryGolayCode()
1277
sage: C.chinen_polynomial() # long time
1278
1/7*(3*sqrt(3)*t^3 + 3*sqrt(3)*t^2 + 3*t^2 + sqrt(3)*t + 3*t + 1)/(sqrt(3) + 1)
1279
1280
This last output agrees with the corresponding example given in
1281
Chinen's paper below.
1282
1283
REFERENCES:
1284
1285
- Chinen, K. "An abundance of invariant polynomials satisfying the
1286
Riemann hypothesis", April 2007 preprint.
1287
"""
1288
from sage.functions.all import sqrt
1289
C = self
1290
n = C.length()
1291
RT = PolynomialRing(QQ,2,"Ts")
1292
T,s = FractionField(RT).gens()
1293
t = PolynomialRing(QQ,"t").gen()
1294
Cd = C.dual_code()
1295
k = C.dimension()
1296
q = (C.base_ring()).characteristic()
1297
d = C.minimum_distance()
1298
dperp = Cd.minimum_distance()
1299
if dperp > d:
1300
P = RT(C.zeta_polynomial())
1301
# Sage does not find dealing with sqrt(int) *as an algebraic object*
1302
# an easy thing to do. Some tricky gymnastics are used to
1303
# make Sage deal with objects over QQ(sqrt(q)) nicely.
1304
if is_even(n):
1305
Pd = q**(k-n/2)*RT(Cd.zeta_polynomial())*T**(dperp - d)
1306
if not(is_even(n)):
1307
Pd = s*q**(k-(n+1)/2)*RT(Cd.zeta_polynomial())*T**(dperp - d)
1308
CP = P+Pd
1309
f = CP/CP(1,s)
1310
return f(t,sqrt(q))
1311
if dperp < d:
1312
P = RT(C.zeta_polynomial())*T**(d - dperp)
1313
if is_even(n):
1314
Pd = q**(k-n/2)*RT(Cd.zeta_polynomial())
1315
if not(is_even(n)):
1316
Pd = s*q**(k-(n+1)/2)*RT(Cd.zeta_polynomial())
1317
CP = P+Pd
1318
f = CP/CP(1,s)
1319
return f(t,sqrt(q))
1320
if dperp == d:
1321
P = RT(C.zeta_polynomial())
1322
if is_even(n):
1323
Pd = q**(k-n/2)*RT(Cd.zeta_polynomial())
1324
if not(is_even(n)):
1325
Pd = s*q**(k-(n+1)/2)*RT(Cd.zeta_polynomial())
1326
CP = P+Pd
1327
f = CP/CP(1,s)
1328
return f(t,sqrt(q))
1329
1330
def __cmp__(self, right):
1331
r"""
1332
Returns True if the generator matrices of `self` and `right` are
1333
equal.
1334
1335
EXAMPLES::
1336
1337
sage: C = codes.HammingCode(3,GF(2))
1338
sage: MS = MatrixSpace(GF(2),4,7)
1339
sage: G = MS([1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1])
1340
sage: G
1341
[1 0 0 0 0 1 1]
1342
[0 1 0 0 1 0 1]
1343
[0 0 1 0 1 1 0]
1344
[0 0 0 1 1 1 1]
1345
sage: D = LinearCode(G)
1346
sage: C == D
1347
True
1348
1349
sage: Cperp = C.dual_code()
1350
sage: Cperpperp = Cperp.dual_code()
1351
sage: C == Cperpperp
1352
True
1353
"""
1354
if not isinstance(right, LinearCode):
1355
return cmp(type(self), type(right))
1356
return cmp(self.__gen_mat, right.__gen_mat)
1357
1358
def check_mat(self):
1359
r"""
1360
Returns the check matrix of ``self``.
1361
1362
EXAMPLES::
1363
1364
sage: C = codes.HammingCode(3,GF(2))
1365
sage: Cperp = C.dual_code()
1366
sage: C; Cperp
1367
Linear code of length 7, dimension 4 over Finite Field of size 2
1368
Linear code of length 7, dimension 3 over Finite Field of size 2
1369
sage: C.gen_mat()
1370
[1 0 0 0 0 1 1]
1371
[0 1 0 0 1 0 1]
1372
[0 0 1 0 1 1 0]
1373
[0 0 0 1 1 1 1]
1374
sage: C.check_mat()
1375
[1 0 1 0 1 0 1]
1376
[0 1 1 0 0 1 1]
1377
[0 0 0 1 1 1 1]
1378
sage: Cperp.check_mat()
1379
[1 0 0 0 0 1 1]
1380
[0 1 0 0 1 0 1]
1381
[0 0 1 0 1 1 0]
1382
[0 0 0 1 1 1 1]
1383
sage: Cperp.gen_mat()
1384
[1 0 1 0 1 0 1]
1385
[0 1 1 0 0 1 1]
1386
[0 0 0 1 1 1 1]
1387
"""
1388
Cperp = self.dual_code()
1389
return Cperp.gen_mat()
1390
1391
def covering_radius(self):
1392
r"""
1393
Wraps Guava's ``CoveringRadius`` command.
1394
1395
The covering radius of a linear code `C` is the smallest number `r`
1396
with the property that each element `v` of the ambient vector space
1397
of `C` has at most a distance `r` to the code `C`. So for each
1398
vector `v` there must be an element `c` of `C` with `d(v,c) \leq r`.
1399
A binary linear code with reasonable small covering radius is often
1400
referred to as a covering code.
1401
1402
For example, if `C` is a perfect code, the covering radius is equal
1403
to `t`, the number of errors the code can correct, where `d = 2t+1`,
1404
with `d` the minimum distance of `C`.
1405
1406
EXAMPLES::
1407
1408
sage: C = codes.HammingCode(5,GF(2))
1409
sage: C.covering_radius() # optional - gap_packages (Guava package)
1410
1
1411
"""
1412
F = self.base_ring()
1413
G = self.gen_mat()
1414
gapG = gap(G)
1415
C = gapG.GeneratorMatCode(gap(F))
1416
r = C.CoveringRadius()
1417
try:
1418
return ZZ(r)
1419
except TypeError:
1420
raise RuntimeError("the covering radius of this code cannot be computed by Guava")
1421
1422
@rename_keyword(deprecation=11033, method="algorithm")
1423
def decode(self, right, algorithm="syndrome"):
1424
r"""
1425
Decodes the received vector ``right`` to an element `c` in this code.
1426
1427
Optional algorithms are "guava", "nearest neighbor" or "syndrome". The
1428
``algorithm="guava"`` wraps GUAVA's ``Decodeword``. Hamming codes have
1429
a special decoding algorithm; otherwise, ``"syndrome"`` decoding is
1430
used.
1431
1432
INPUT:
1433
1434
- ``right`` - Vector of length the length of this code
1435
- ``algorithm`` - Algorithm to use, one of ``"syndrome"``, ``"nearest
1436
neighbor"``, and ``"guava"`` (default: ``"syndrome"``)
1437
1438
OUTPUT:
1439
1440
- The codeword in this code closest to ``right``.
1441
1442
EXAMPLES::
1443
1444
sage: C = codes.HammingCode(3,GF(2))
1445
sage: MS = MatrixSpace(GF(2),1,7)
1446
sage: F = GF(2); a = F.gen()
1447
sage: v1 = [a,a,F(0),a,a,F(0),a]
1448
sage: C.decode(v1)
1449
(1, 1, 0, 1, 0, 0, 1)
1450
sage: C.decode(v1,algorithm="nearest neighbor")
1451
(1, 1, 0, 1, 0, 0, 1)
1452
sage: C.decode(v1,algorithm="guava") # optional - gap_packages (Guava package)
1453
(1, 1, 0, 1, 0, 0, 1)
1454
sage: v2 = matrix([[a,a,F(0),a,a,F(0),a]])
1455
sage: C.decode(v2)
1456
(1, 1, 0, 1, 0, 0, 1)
1457
sage: v3 = vector([a,a,F(0),a,a,F(0),a])
1458
sage: c = C.decode(v3); c
1459
(1, 1, 0, 1, 0, 0, 1)
1460
sage: c in C
1461
True
1462
sage: C = codes.HammingCode(2,GF(5))
1463
sage: v = vector(GF(5),[1,0,0,2,1,0])
1464
sage: C.decode(v)
1465
(1, 0, 0, 2, 2, 0)
1466
sage: F.<a> = GF(4)
1467
sage: C = codes.HammingCode(2,F)
1468
sage: v = vector(F, [1,0,0,a,1])
1469
sage: C.decode(v)
1470
(a + 1, 0, 0, a, 1)
1471
sage: C.decode(v, algorithm="nearest neighbor")
1472
(a + 1, 0, 0, a, 1)
1473
sage: C.decode(v, algorithm="guava") # optional - gap_packages (Guava package)
1474
(a + 1, 0, 0, a, 1)
1475
1476
Does not work for very long codes since the syndrome table grows too
1477
large.
1478
"""
1479
from decoder import decode
1480
if algorithm == 'syndrome' or algorithm == 'nearest neighbor':
1481
return decode(self,right)
1482
elif algorithm == 'guava':
1483
gap.LoadPackage('"guava"')
1484
code = gap.GeneratorMatCode(self.gen_mat(), self.base_ring())
1485
right = gap(list(right))
1486
right_word = gap.Codeword(right)
1487
result = gap.Decodeword(code, right_word)
1488
result = gap.VectorCodeword(result)
1489
from sage.interfaces.gap import gfq_gap_to_sage
1490
result = [gfq_gap_to_sage(v, self.base_ring()) for v in result]
1491
return self.ambient_space()(result)
1492
else:
1493
raise NotImplementedError, "Only 'syndrome','nearest neighbor','guava' are implemented."
1494
1495
def divisor(self):
1496
r"""
1497
Returns the divisor of a code, which is the smallest integer `d_0 > 0`
1498
such that each `A_i > 0` iff `i` is divisible by `d_0`.
1499
1500
EXAMPLES::
1501
1502
sage: C = codes.ExtendedBinaryGolayCode()
1503
sage: C.divisor() # Type II self-dual
1504
4
1505
sage: C = codes.QuadraticResidueCodeEvenPair(17,GF(2))[0]
1506
sage: C.divisor()
1507
2
1508
"""
1509
C = self
1510
A = C.spectrum()
1511
n = C.length()
1512
V = VectorSpace(QQ,n+1)
1513
S = V(A).nonzero_positions()
1514
S0 = [S[i] for i in range(1,len(S))]
1515
#print S0
1516
if len(S)>1: return GCD(S0)
1517
return 1
1518
1519
def dual_code(self):
1520
r"""
1521
This computes the dual code `Cd` of the code `C`,
1522
1523
.. math::
1524
1525
Cd = \{ v \in V\ |\ v\cdot c = 0,\ \forall c \in C \}.
1526
1527
Does not call GAP.
1528
1529
EXAMPLES::
1530
1531
sage: C = codes.HammingCode(3,GF(2))
1532
sage: C.dual_code()
1533
Linear code of length 7, dimension 3 over Finite Field of size 2
1534
sage: C = codes.HammingCode(3,GF(4,'a'))
1535
sage: C.dual_code()
1536
Linear code of length 21, dimension 3 over Finite Field in a of size 2^2
1537
"""
1538
G = self.gen_mat()
1539
H = G.transpose().kernel()
1540
V = H.ambient_vector_space()
1541
Cd = LinearCodeFromVectorSpace(V.span(H))
1542
return Cd
1543
#another way:
1544
#Gsf, p = standard_form(G)
1545
#k = len(G.rows())
1546
#n = len(G.columns())
1547
#MS = G.parent()
1548
#sG = G.matrix_from_columns(range(k,n))
1549
#Inmk = MatrixSpace(F,n-k,n-k).identity_matrix()
1550
#H = Inmk.augment(sG.transpose())
1551
#return LinearCode(H)
1552
1553
def dimension(self):
1554
r"""
1555
Returns the dimension of this code.
1556
1557
EXAMPLES::
1558
1559
sage: G = matrix(GF(2),[[1,0,0],[1,1,0]])
1560
sage: C = LinearCode(G)
1561
sage: C.dimension()
1562
2
1563
"""
1564
return self.__dim
1565
1566
def direct_sum(self, other):
1567
"""
1568
Returns the code given by the direct sum of the codes ``self`` and
1569
``other``, which must be linear codes defined over the same base ring.
1570
1571
EXAMPLES::
1572
1573
sage: C1 = codes.HammingCode(3,GF(2))
1574
sage: C2 = C1.direct_sum(C1); C2
1575
Linear code of length 14, dimension 8 over Finite Field of size 2
1576
sage: C3 = C1.direct_sum(C2); C3
1577
Linear code of length 21, dimension 12 over Finite Field of size 2
1578
"""
1579
C1 = self; C2 = other
1580
G1 = C1.gen_mat()
1581
G2 = C2.gen_mat()
1582
F = C1.base_ring()
1583
n1 = len(G1.columns())
1584
k1 = len(G1.rows())
1585
n2 = len(G2.columns())
1586
k2 = len(G2.rows())
1587
MS1 = MatrixSpace(F,k2,n1)
1588
MS2 = MatrixSpace(F,k1,n2)
1589
Z1 = MS1(0)
1590
Z2 = MS2(0)
1591
top = G1.augment(Z2)
1592
bottom = Z1.augment(G2)
1593
G = top.stack(bottom)
1594
return LinearCode(G)
1595
1596
def __eq__(self, right):
1597
"""
1598
Checks if ``self`` is equal to ``right``.
1599
1600
EXAMPLES::
1601
1602
sage: C1 = codes.HammingCode(3,GF(2))
1603
sage: C2 = codes.HammingCode(3,GF(2))
1604
sage: C1 == C2
1605
True
1606
sage: C2 = C1.extended_code()
1607
sage: C3 = C2.punctured([7])
1608
sage: C1 == C3
1609
True
1610
"""
1611
slength = self.length()
1612
rlength = right.length()
1613
sdim = self.dimension()
1614
rdim = right.dimension()
1615
sF = self.base_ring()
1616
rF = right.base_ring()
1617
if slength != rlength:
1618
return False
1619
if sdim != rdim:
1620
return False
1621
if sF != rF:
1622
return False
1623
sbasis = self.gens()
1624
rbasis = right.gens()
1625
scheck = self.check_mat()
1626
rcheck = right.check_mat()
1627
for c in sbasis:
1628
if rcheck*c:
1629
return False
1630
for c in rbasis:
1631
if scheck*c:
1632
return False
1633
return True
1634
1635
def extended_code(self):
1636
r"""
1637
If ``self`` is a linear code of length `n` defined over `F` then this
1638
returns the code of length `n+1` where the last digit `c_n` satisfies
1639
the check condition `c_0+...+c_n=0`. If ``self`` is an `[n,k,d]`
1640
binary code then the extended code `C^{\vee}` is an `[n+1,k,d^{\vee}]`
1641
code, where `d^=d` (if d is even) and `d^{\vee}=d+1` (if `d` is odd).
1642
1643
EXAMPLES::
1644
1645
sage: C = codes.HammingCode(3,GF(4,'a'))
1646
sage: C
1647
Linear code of length 21, dimension 18 over Finite Field in a of size 2^2
1648
sage: Cx = C.extended_code()
1649
sage: Cx
1650
Linear code of length 22, dimension 18 over Finite Field in a of size 2^2
1651
"""
1652
G = self.gen_mat()
1653
F = self.base_ring()
1654
k = len(G.rows())
1655
MS1 = MatrixSpace(F,k,1)
1656
ck_sums = [-sum(G.rows()[i]) for i in range(k)]
1657
last_col = MS1(ck_sums)
1658
Gx = G.augment(last_col)
1659
return LinearCode(Gx)
1660
1661
def galois_closure(self, F0):
1662
r"""
1663
If ``self`` is a linear code defined over `F` and `F_0` is a subfield
1664
with Galois group `G = Gal(F/F_0)` then this returns the `G`-module
1665
`C^-` containing `C`.
1666
1667
EXAMPLES::
1668
1669
sage: C = codes.HammingCode(3,GF(4,'a'))
1670
sage: Cc = C.galois_closure(GF(2))
1671
sage: C; Cc
1672
Linear code of length 21, dimension 18 over Finite Field in a of size 2^2
1673
Linear code of length 21, dimension 20 over Finite Field in a of size 2^2
1674
sage: c = C.basis()[2]
1675
sage: V = VectorSpace(GF(4,'a'),21)
1676
sage: c2 = V([x^2 for x in c.list()])
1677
sage: c2 in C
1678
False
1679
sage: c2 in Cc
1680
True
1681
"""
1682
G = self.gen_mat()
1683
F = self.base_ring()
1684
q = F.order()
1685
q0 = F0.order()
1686
a = log(q,q0) # test if F/F0 is a field extension
1687
if not isinstance(a, Integer):
1688
raise ValueError,"Base field must be an extension of given field %s"%F0
1689
n = len(G.columns())
1690
k = len(G.rows())
1691
G0 = [[x**q0 for x in g.list()] for g in G.rows()]
1692
G1 = [[x for x in g.list()] for g in G.rows()]
1693
G2 = G0+G1
1694
MS = MatrixSpace(F,2*k,n)
1695
G3 = MS(G2)
1696
r = G3.rank()
1697
MS = MatrixSpace(F,r,n)
1698
Grref = G3.echelon_form()
1699
G = MS([Grref.row(i) for i in range(r)])
1700
return LinearCode(G)
1701
1702
def __getitem__(self, i):
1703
r"""
1704
Returns the `i`-th codeword of this code.
1705
1706
The implementation of this depends on the implementation of the
1707
:meth:`.__iter__` method.
1708
1709
The implementation is as follows. Suppose that:
1710
1711
- the primitive element of the base_ring of this code is `a`,
1712
- the prime subfield is `p`,
1713
- the field has order `p^m`,
1714
- the code has dimension `k`,
1715
- and the generator matrix is `G`.
1716
1717
Then the :meth:`.__iter__` method returns the elements in this order:
1718
1719
1. first, the following ordered list is returned:
1720
``[i*a^0 * G[0] for i in range(p)]``
1721
2. Next, the following ordered list is returned:
1722
``[i*a^0 * G[0] + a^1*G[0] for i in range(p)]``
1723
3. This continues till we get
1724
``[(i*a^0 +(p-1)*a^1 +...+ (p-1)*a^(m-1))*G[0] for i in range(p)]``
1725
4. Then, we move to G[1]:
1726
``[i*a^0 * G[0] + a^0*G[1] for i in range(p)]``,
1727
and so on.
1728
Hence the `i`-th element can be obtained by the p-adic expansion
1729
of `i` as ``[i_0, i_1, ...,i_{m-1}, i_m, i_{m+1}, ..., i_{km-1}].``
1730
The element that is generated is:
1731
1732
.. math::
1733
1734
\begin{aligned}
1735
& (i_0 a^0 + i_1 a^1 + \cdots + i_{m-1} a^{m-1}) G[0] + \\
1736
& (i_m a^0 + i_{m+1} a^1 + \cdots + i_{2m-1} a^{m-1}) G[1] + \\
1737
& \vdots\\
1738
& (i_{(k-1)m} a^0 + \cdots + i_{km-1} a^{m-1}) G[k-1]
1739
\end{aligned}
1740
1741
EXAMPLES::
1742
1743
sage: RS = codes.ReedSolomonCode(7, 3, GF(8, 'a'))
1744
sage: RS[24]
1745
(0, a^2 + a, a^2 + a + 1, a^2 + 1, 1, a, a^2)
1746
sage: RS[24] == RS.list()[24]
1747
True
1748
1749
TESTS::
1750
1751
sage: C = random_matrix(GF(25,'a'), 2, 7).row_space()
1752
sage: C = LinearCode(C.basis_matrix())
1753
sage: Clist = C.list()
1754
sage: all([C[i]==Clist[i] for i in xrange(len(C))])
1755
True
1756
1757
Check that only the indices less than the size of the code are
1758
allowed::
1759
1760
sage: C[25**2]
1761
Traceback (most recent call last):
1762
...
1763
IndexError: The value of the index 'i' (=625) must be between
1764
0 and 'q^k -1' (=624), inclusive, where 'q' is the size of the
1765
base field and 'k' is the dimension of the code.
1766
1767
"""
1768
# IMPORTANT: If the __iter__() function implementation is changed
1769
# then the implementation here must also be changed so that
1770
# list(self)[i] and self[i] both return the same element.
1771
1772
from sage.rings.padics.factory import Zp
1773
F = self.base_ring()
1774
maxindex = F.order()**self.dimension()-1
1775
if i < 0 or i > maxindex:
1776
raise IndexError("The value of the index 'i' (={}) must be between "
1777
"0 and 'q^k -1' (={}), inclusive, where 'q' is "
1778
"the size of the base field and 'k' is the "
1779
"dimension of the code.".format(i, maxindex))
1780
1781
a = F.primitive_element()
1782
m = F.degree()
1783
p = F.prime_subfield().order()
1784
A = [a**k for k in xrange(m)]
1785
G = self.gen_mat()
1786
N = self.dimension()*F.degree() # the total length of p-adic vector
1787
Z = Zp(p, N)
1788
ivec = Z(i).padded_list(N)
1789
1790
codeword = 0
1791
row = 0
1792
for g in G:
1793
codeword += sum([ivec[j+row*m]*A[j] for j in xrange(m)])*g
1794
row += 1
1795
return codeword
1796
1797
def gen_mat(self):
1798
r"""
1799
Return a generator matrix of this code.
1800
1801
EXAMPLES::
1802
1803
sage: C1 = codes.HammingCode(3,GF(2))
1804
sage: C1.gen_mat()
1805
[1 0 0 0 0 1 1]
1806
[0 1 0 0 1 0 1]
1807
[0 0 1 0 1 1 0]
1808
[0 0 0 1 1 1 1]
1809
sage: C2 = codes.HammingCode(2,GF(4,"a"))
1810
sage: C2.gen_mat()
1811
[ 1 0 0 a + 1 a]
1812
[ 0 1 0 1 1]
1813
[ 0 0 1 a a + 1]
1814
"""
1815
return self.__gen_mat
1816
1817
def gen_mat_systematic(self):
1818
"""
1819
Return a systematic generator matrix of the code.
1820
1821
A generator matrix of a code is called systematic if it contains
1822
a set of columns forming an identity matrix.
1823
1824
EXAMPLES::
1825
1826
sage: G = matrix(GF(3),2,[1,-1,1,-1,1,1])
1827
sage: code = LinearCode(G)
1828
sage: code.gen_mat()
1829
[1 2 1]
1830
[2 1 1]
1831
sage: code.gen_mat_systematic()
1832
[1 2 0]
1833
[0 0 1]
1834
"""
1835
return self.__gen_mat.echelon_form()
1836
1837
def gens(self):
1838
r"""
1839
Returns the generators of this code as a list of vectors.
1840
1841
EXAMPLES::
1842
1843
sage: C = codes.HammingCode(3,GF(2))
1844
sage: C.gens()
1845
[(1, 0, 0, 0, 0, 1, 1), (0, 1, 0, 0, 1, 0, 1), (0, 0, 1, 0, 1, 1, 0), (0, 0, 0, 1, 1, 1, 1)]
1846
"""
1847
return self.__gens
1848
1849
def genus(self):
1850
r"""
1851
Returns the "Duursma genus" of the code, `\gamma_C = n+1-k-d`.
1852
1853
EXAMPLES::
1854
1855
sage: C1 = codes.HammingCode(3,GF(2)); C1
1856
Linear code of length 7, dimension 4 over Finite Field of size 2
1857
sage: C1.genus()
1858
1
1859
sage: C2 = codes.HammingCode(2,GF(4,"a")); C2
1860
Linear code of length 5, dimension 3 over Finite Field in a of size 2^2
1861
sage: C2.genus()
1862
0
1863
1864
Since all Hamming codes have minimum distance 3, these computations
1865
agree with the definition, `n+1-k-d`.
1866
"""
1867
d = self.minimum_distance()
1868
n = self.length()
1869
k = self.dimension()
1870
gammaC = n+1-k-d
1871
return gammaC
1872
1873
def information_set(self):
1874
"""
1875
Return an information set of the code.
1876
1877
A set of column positions of a generator matrix of a code
1878
is called an information set if the corresponding columns
1879
form a square matrix of full rank.
1880
1881
OUTPUT:
1882
1883
- Information set of a systematic generator matrix of the code.
1884
1885
EXAMPLES::
1886
1887
sage: G = matrix(GF(3),2,[1,-1,0,-1,1,1])
1888
sage: code = LinearCode(G)
1889
sage: code.gen_mat_systematic()
1890
[1 2 0]
1891
[0 0 1]
1892
sage: code.information_set()
1893
(0, 2)
1894
"""
1895
return self.__gen_mat.transpose().pivot_rows()
1896
1897
def is_permutation_automorphism(self,g):
1898
r"""
1899
Returns `1` if `g` is an element of `S_n` (`n` = length of self) and
1900
if `g` is an automorphism of self.
1901
1902
EXAMPLES::
1903
1904
sage: C = codes.HammingCode(3,GF(3))
1905
sage: g = SymmetricGroup(13).random_element()
1906
sage: C.is_permutation_automorphism(g)
1907
0
1908
sage: MS = MatrixSpace(GF(2),4,8)
1909
sage: G = MS([[1,0,0,0,1,1,1,0],[0,1,1,1,0,0,0,0],[0,0,0,0,0,0,0,1],[0,0,0,0,0,1,0,0]])
1910
sage: C = LinearCode(G)
1911
sage: S8 = SymmetricGroup(8)
1912
sage: g = S8("(2,3)")
1913
sage: C.is_permutation_automorphism(g)
1914
1
1915
sage: g = S8("(1,2,3,4)")
1916
sage: C.is_permutation_automorphism(g)
1917
0
1918
"""
1919
basis = self.gen_mat().rows()
1920
H = self.check_mat()
1921
V = H.column_space()
1922
HGm = H*g.matrix()
1923
# raise TypeError, (type(H), type(V), type(basis[0]), type(Gmc))
1924
for c in basis:
1925
if HGm*c != V(0):
1926
return False
1927
return True
1928
1929
@rename_keyword(deprecation=11033, method="algorithm")
1930
def is_permutation_equivalent(self,other,algorithm=None):
1931
"""
1932
Returns ``True`` if ``self`` and ``other`` are permutation equivalent
1933
codes and ``False`` otherwise.
1934
1935
The ``algorithm="verbose"`` option also returns a permutation (if
1936
``True``) sending ``self`` to ``other``.
1937
1938
Uses Robert Miller's double coset partition refinement work.
1939
1940
EXAMPLES::
1941
1942
sage: P.<x> = PolynomialRing(GF(2),"x")
1943
sage: g = x^3+x+1
1944
sage: C1 = codes.CyclicCodeFromGeneratingPolynomial(7,g); C1
1945
Linear code of length 7, dimension 4 over Finite Field of size 2
1946
sage: C2 = codes.HammingCode(3,GF(2)); C2
1947
Linear code of length 7, dimension 4 over Finite Field of size 2
1948
sage: C1.is_permutation_equivalent(C2)
1949
True
1950
sage: C1.is_permutation_equivalent(C2,algorithm="verbose")
1951
(True, (3,4)(5,7,6))
1952
sage: C1 = codes.RandomLinearCode(10,5,GF(2))
1953
sage: C2 = codes.RandomLinearCode(10,5,GF(3))
1954
sage: C1.is_permutation_equivalent(C2)
1955
False
1956
"""
1957
from sage.groups.perm_gps.partn_ref.refinement_binary import NonlinearBinaryCodeStruct
1958
F = self.base_ring()
1959
F_o = other.base_ring()
1960
q = F.order()
1961
G = self.gen_mat()
1962
n = self.length()
1963
n_o = other.length()
1964
if F != F_o or n != n_o:
1965
return False
1966
k = len(G.rows())
1967
MS = MatrixSpace(F,q**k,n)
1968
CW1 = MS(self.list())
1969
CW2 = MS(other.list())
1970
B1 = NonlinearBinaryCodeStruct(CW1)
1971
B2 = NonlinearBinaryCodeStruct(CW2)
1972
ans = B1.is_isomorphic(B2)
1973
if ans!=False:
1974
if algorithm=="verbose":
1975
Sn = SymmetricGroup(n)
1976
return True, Sn([i+1 for i in ans])**(-1)
1977
return True
1978
return False
1979
1980
def is_self_dual(self):
1981
"""
1982
Returns ``True`` if the code is self-dual (in the usual Hamming inner
1983
product) and ``False`` otherwise.
1984
1985
EXAMPLES::
1986
1987
sage: C = codes.ExtendedBinaryGolayCode()
1988
sage: C.is_self_dual()
1989
True
1990
sage: C = codes.HammingCode(3,GF(2))
1991
sage: C.is_self_dual()
1992
False
1993
"""
1994
return self == self.dual_code()
1995
1996
1997
def is_self_orthogonal(self):
1998
"""
1999
Returns ``True`` if this code is self-orthogonal and ``False``
2000
otherwise.
2001
2002
A code is self-orthogonal if it is a subcode of its dual.
2003
2004
EXAMPLES::
2005
2006
sage: C = codes.ExtendedBinaryGolayCode()
2007
sage: C.is_self_orthogonal()
2008
True
2009
sage: C = codes.HammingCode(3,GF(2))
2010
sage: C.is_self_orthogonal()
2011
False
2012
sage: C = QuasiQuadraticResidueCode(11) # optional - gap_packages (Guava package)
2013
sage: C.is_self_orthogonal() # optional - gap_packages (Guava package)
2014
True
2015
"""
2016
return self.is_subcode(self.dual_code())
2017
2018
def is_galois_closed(self):
2019
r"""
2020
Checks if ``self`` is equal to its Galois closure.
2021
2022
EXAMPLES::
2023
2024
sage: C = codes.HammingCode(3,GF(4,"a"))
2025
sage: C.is_galois_closed()
2026
False
2027
"""
2028
F = self.base_ring()
2029
p = F.characteristic()
2030
return self == self.galois_closure(GF(p))
2031
2032
def is_subcode(self, other):
2033
"""
2034
Returns ``True`` if ``self`` is a subcode of ``other``.
2035
2036
EXAMPLES::
2037
2038
sage: C1 = codes.HammingCode(3,GF(2))
2039
sage: G1 = C1.gen_mat()
2040
sage: G2 = G1.matrix_from_rows([0,1,2])
2041
sage: C2 = LinearCode(G2)
2042
sage: C2.is_subcode(C1)
2043
True
2044
sage: C1.is_subcode(C2)
2045
False
2046
sage: C3 = C1.extended_code()
2047
sage: C1.is_subcode(C3)
2048
False
2049
sage: C4 = C1.punctured([1])
2050
sage: C4.is_subcode(C1)
2051
False
2052
sage: C5 = C1.shortened([1])
2053
sage: C5.is_subcode(C1)
2054
False
2055
sage: C1 = codes.HammingCode(3,GF(9,"z"))
2056
sage: G1 = C1.gen_mat()
2057
sage: G2 = G1.matrix_from_rows([0,1,2])
2058
sage: C2 = LinearCode(G2)
2059
sage: C2.is_subcode(C1)
2060
True
2061
"""
2062
G = self.gen_mat()
2063
for r in G.rows():
2064
if not(r in other):
2065
return False
2066
return True
2067
2068
def __len__(self):
2069
r"""
2070
Return the size of this code.
2071
2072
EXAMPLES::
2073
2074
sage: C = codes.HammingCode(3, GF(2))
2075
sage: len(C)
2076
16
2077
"""
2078
return self.base_ring().order()**self.dimension()
2079
2080
def length(self):
2081
r"""
2082
Returns the length of this code.
2083
2084
EXAMPLES::
2085
2086
sage: C = codes.HammingCode(3,GF(2))
2087
sage: C.length()
2088
7
2089
"""
2090
return self.__length
2091
2092
def list(self):
2093
r"""
2094
Return a list of all elements of this linear code.
2095
2096
EXAMPLES::
2097
2098
sage: C = codes.HammingCode(3,GF(2))
2099
sage: Clist = C.list()
2100
sage: Clist[5]; Clist[5] in C
2101
(1, 0, 1, 0, 1, 0, 1)
2102
True
2103
"""
2104
return list(self.__iter__())
2105
2106
def _magma_init_(self, magma):
2107
r"""
2108
Retun a string representation in Magma of this linear code.
2109
2110
EXAMPLES::
2111
2112
sage: C = codes.HammingCode(3,GF(2))
2113
sage: Cm = magma(C) # optional - magma, indirect doctest
2114
sage: Cm.MinimumWeight() # optional - magma
2115
3
2116
2117
"""
2118
G = magma(self.gen_mat())._ref()
2119
s = 'LinearCode(%s)' % G
2120
return s
2121
2122
@rename_keyword(deprecation=11033, method="algorithm")
2123
def minimum_distance(self, algorithm=None):
2124
r"""
2125
Returns the minimum distance of this linear code.
2126
2127
By default, this uses a GAP kernel function (in C and not part of
2128
Guava) written by Steve Linton. If ``algorithm="guava"`` is set and
2129
`q` is 2 or 3 then this uses a very fast program written in C written
2130
by CJ Tjhal. (This is much faster, except in some small examples.)
2131
2132
Raises a ``ValueError`` in case there is no non-zero vector in this
2133
linear code.
2134
2135
The minimum distance of the code is stored once it has been
2136
computed or provided during the initialization of :class:`LinearCode`.
2137
If ``algorithm`` is ``None`` and the stored value of minimum
2138
distance is found, then the stored value will be returned without
2139
recomputing the minimum distance again.
2140
2141
INPUT:
2142
2143
- ``algorithm`` - Method to be used, ``None``, ``"gap"``, or
2144
``"guava"`` (default: ``None``).
2145
2146
OUTPUT:
2147
2148
- Integer, minimum distance of this code
2149
2150
EXAMPLES::
2151
2152
sage: MS = MatrixSpace(GF(3),4,7)
2153
sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]])
2154
sage: C = LinearCode(G)
2155
sage: C.minimum_distance()
2156
3
2157
2158
Once the minimum distance has been computed, it's value is stored.
2159
Hence the following command will return the value instantly,
2160
without further computations.::
2161
2162
sage: C.minimum_distance()
2163
3
2164
2165
If ``algorithm`` is provided, then the minimum distance will be
2166
recomputed even if there is a stored value from a previous run.::
2167
2168
sage: C.minimum_distance(algorithm="gap")
2169
3
2170
sage: C.minimum_distance(algorithm="guava") # optional - gap_packages (Guava package)
2171
3
2172
2173
Another example.::
2174
2175
sage: C = codes.HammingCode(2,GF(4,"a")); C
2176
Linear code of length 5, dimension 3 over Finite Field in a of size 2^2
2177
sage: C.minimum_distance()
2178
3
2179
2180
TESTS::
2181
2182
sage: C = codes.HammingCode(2,GF(4,"a"))
2183
sage: C.minimum_distance(algorithm='something')
2184
Traceback (most recent call last):
2185
...
2186
ValueError: The algorithm argument must be one of None, 'gap' or 'guava'; got 'something'
2187
2188
This shows that ticket :trac:`#6486` has been resolved::
2189
2190
sage: G = matrix(GF(2),[[0,0,0]])
2191
sage: C = LinearCode(G)
2192
sage: C.minimum_distance()
2193
Traceback (most recent call last):
2194
...
2195
ValueError: this linear code contains no non-zero vector
2196
"""
2197
# Special code to handle the case where there is no non-zero vector.
2198
if self.dimension() == 0:
2199
raise ValueError("this linear code contains no non-zero vector")
2200
2201
# If the minimum distance has already been computed or provided by
2202
# the user then simply return the stored value.
2203
# This is done only if algorithm is None.
2204
if self.__distance is not None and algorithm is None:
2205
return self.__distance
2206
if algorithm not in (None, "gap", "guava"):
2207
raise ValueError("The algorithm argument must be one of None, "
2208
"'gap' or 'guava'; got '{0}'".format(algorithm))
2209
2210
#sage: C.minimum_distance_upper_bound() # optional (net connection)
2211
#5
2212
# sage: C.minimum_distance_why() # optional (net connection)
2213
# Ub(10,5) = 5 follows by the Griesmer bound.
2214
F = self.base_ring()
2215
q = F.order()
2216
G = self.gen_mat()
2217
n = self.length()
2218
k = self.dimension()
2219
gapG = gap(G)
2220
if (q == 2 or q == 3) and algorithm=="guava":
2221
C = gapG.GeneratorMatCode(gap(F))
2222
d = C.MinimumWeight()
2223
#print "Running Guava's MinimumWeight ...\n"
2224
return ZZ(d)
2225
Gstr = "%s*Z(%s)^0"%(gapG, q)
2226
self.__distance = min_wt_vec_gap(Gstr,n,k,F).hamming_weight()
2227
return self.__distance
2228
2229
def module_composition_factors(self, gp):
2230
r"""
2231
Prints the GAP record of the Meataxe composition factors module in
2232
Meataxe notation. This uses GAP but not Guava.
2233
2234
EXAMPLES::
2235
2236
sage: MS = MatrixSpace(GF(2),4,8)
2237
sage: G = MS([[1,0,0,0,1,1,1,0],[0,1,1,1,0,0,0,0],[0,0,0,0,0,0,0,1],[0,0,0,0,0,1,0,0]])
2238
sage: C = LinearCode(G)
2239
sage: gp = C.permutation_automorphism_group()
2240
2241
Now type "C.module_composition_factors(gp)" to get the record printed.
2242
"""
2243
F = self.base_ring()
2244
q = F.order()
2245
gens = gp.gens()
2246
G = self.gen_mat()
2247
n = len(G.columns())
2248
MS = MatrixSpace(F,n,n)
2249
mats = [] # initializing list of mats by which the gens act on self
2250
Fn = VectorSpace(F, n)
2251
W = Fn.subspace_with_basis(G.rows()) # this is self
2252
for g in gens:
2253
p = MS(g.matrix())
2254
m = [W.coordinate_vector(r*p) for r in G.rows()]
2255
mats.append(m)
2256
mats_str = str(gap([[list(r) for r in m] for m in mats]))
2257
gap.eval("M:=GModuleByMats("+mats_str+", GF("+str(q)+"))")
2258
print gap("MTX.CompositionFactors( M )")
2259
2260
@rename_keyword(deprecation=11033, method="algorithm")
2261
def permutation_automorphism_group(self, algorithm="partition"):
2262
r"""
2263
If `C` is an `[n,k,d]` code over `F`, this function computes the
2264
subgroup `Aut(C) \subset S_n` of all permutation automorphisms of `C`.
2265
The binary case always uses the (default) partition refinement
2266
algorithm of Robert Miller.
2267
2268
Note that if the base ring of `C` is `GF(2)` then this is the full
2269
automorphism group. Otherwise, you could use
2270
:meth:`~sage.coding.linear_code.LinearCode.automorphism_group_gens`
2271
to compute generators of the full automorphism group.
2272
2273
INPUT:
2274
2275
- ``algorithm`` - If ``"gap"`` then GAP's MatrixAutomorphism function
2276
(written by Thomas Breuer) is used. The implementation combines an
2277
idea of mine with an improvement suggested by Cary Huffman. If
2278
``"gap+verbose"`` then code-theoretic data is printed out at
2279
several stages of the computation. If ``"partition"`` then the
2280
(default) partition refinement algorithm of Robert Miller is used.
2281
Finally, if ``"codecan"`` then the partition refinement algorithm
2282
of Thomas Feulner is used, which also computes a canonical
2283
representative of ``self`` (call
2284
:meth:`~sage.coding.linear_code.LinearCode.canonical_representative`
2285
to access it).
2286
2287
OUTPUT:
2288
2289
- Permutation automorphism group
2290
2291
EXAMPLES::
2292
2293
sage: MS = MatrixSpace(GF(2),4,8)
2294
sage: G = MS([[1,0,0,0,1,1,1,0],[0,1,1,1,0,0,0,0],[0,0,0,0,0,0,0,1],[0,0,0,0,0,1,0,0]])
2295
sage: C = LinearCode(G)
2296
sage: C
2297
Linear code of length 8, dimension 4 over Finite Field of size 2
2298
sage: G = C.permutation_automorphism_group()
2299
sage: G.order()
2300
144
2301
sage: GG = C.permutation_automorphism_group("codecan")
2302
sage: GG == G
2303
True
2304
2305
A less easy example involves showing that the permutation
2306
automorphism group of the extended ternary Golay code is the
2307
Mathieu group `M_{11}`.
2308
2309
::
2310
2311
sage: C = codes.ExtendedTernaryGolayCode()
2312
sage: M11 = MathieuGroup(11)
2313
sage: M11.order()
2314
7920
2315
sage: G = C.permutation_automorphism_group() # long time (6s on sage.math, 2011)
2316
sage: G.is_isomorphic(M11) # long time
2317
True
2318
sage: GG = C.permutation_automorphism_group("codecan") # long time
2319
sage: GG == G # long time
2320
True
2321
2322
Other examples::
2323
2324
sage: C = codes.ExtendedBinaryGolayCode()
2325
sage: G = C.permutation_automorphism_group()
2326
sage: G.order()
2327
244823040
2328
sage: C = codes.HammingCode(5, GF(2))
2329
sage: G = C.permutation_automorphism_group()
2330
sage: G.order()
2331
9999360
2332
sage: C = codes.HammingCode(2,GF(3)); C
2333
Linear code of length 4, dimension 2 over Finite Field of size 3
2334
sage: C.permutation_automorphism_group(algorithm="partition")
2335
Permutation Group with generators [(1,3,4)]
2336
sage: C = codes.HammingCode(2,GF(4,"z")); C
2337
Linear code of length 5, dimension 3 over Finite Field in z of size 2^2
2338
sage: G = C.permutation_automorphism_group(algorithm="partition"); G
2339
Permutation Group with generators [(1,3)(4,5), (1,4)(3,5)]
2340
sage: GG = C.permutation_automorphism_group(algorithm="codecan") # long time
2341
sage: GG == G # long time
2342
True
2343
sage: C.permutation_automorphism_group(algorithm="gap") # optional - gap_packages (Guava package)
2344
sage: C = codes.TernaryGolayCode()
2345
sage: C.permutation_automorphism_group(algorithm="gap") # optional - gap_packages (Guava package)
2346
Permutation Group with generators [(3,4)(5,7)(6,9)(8,11), (3,5,8)(4,11,7)(6,9,10), (2,3)(4,6)(5,8)(7,10), (1,2)(4,11)(5,8)(9,10)]
2347
2348
However, the option ``algorithm="gap+verbose"``, will print out::
2349
2350
Minimum distance: 5 Weight distribution: [1, 0, 0, 0, 0, 132, 132,
2351
0, 330, 110, 0, 24]
2352
2353
Using the 132 codewords of weight 5 Supergroup size: 39916800
2354
2355
in addition to the output of
2356
``C.permutation_automorphism_group(algorithm="gap")``.
2357
"""
2358
F = self.base_ring()
2359
q = F.order()
2360
G = self.gen_mat() if 2*self.dimension() <= self.length() else self.dual_code().gen_mat()
2361
n = len(G.columns())
2362
k = len(G.rows())
2363
if "gap" in algorithm:
2364
gap.LoadPackage('"guava"')
2365
wts = self.spectrum() # bottleneck 1
2366
nonzerowts = [i for i in range(len(wts)) if wts[i]!=0]
2367
Sn = SymmetricGroup(n)
2368
Gp = gap("SymmetricGroup(%s)"%n) # initializing G in gap
2369
Gstr = str(gap(G))
2370
gap.eval("C:=GeneratorMatCode("+Gstr+",GF("+str(q)+"))")
2371
gap.eval("eltsC:=Elements(C)")
2372
if algorithm=="gap+verbose":
2373
print "\n Minimum distance: %s \n Weight distribution: \n %s"%(nonzerowts[1],wts)
2374
stop = 0 # only stop if all gens are autos
2375
for i in range(1,len(nonzerowts)):
2376
if stop == 1:
2377
break
2378
wt = nonzerowts[i]
2379
if algorithm=="gap+verbose":
2380
size = Gp.Size()
2381
print "\n Using the %s codewords of weight %s \n Supergroup size: \n %s\n "%(wts[wt],wt,size)
2382
gap.eval("Cwt:=Filtered(eltsC,c->WeightCodeword(c)=%s)"%wt) # bottleneck 2 (repeated
2383
gap.eval("matCwt:=List(Cwt,c->VectorCodeword(c))") # for each i until stop = 1)
2384
A = gap("MatrixAutomorphisms(matCwt)")
2385
#print "A = ",A, "\n Gp = ", Gp, "\n strGp = ", str(Gp)
2386
G2 = gap("Intersection2(%s,%s)"%(str(A).replace("\n",""),str(Gp).replace("\n",""))) # bottleneck 3
2387
Gp = G2
2388
if Gp.Size()==1:
2389
return PermutationGroup([()])
2390
autgp_gens = Gp.GeneratorsOfGroup()
2391
gens = [Sn(str(x).replace("\n","")) for x in autgp_gens]
2392
stop = 1 # get ready to stop
2393
for x in gens: # if one of these gens is not an auto then don't stop
2394
if not(self.is_permutation_automorphism(x)):
2395
stop = 0
2396
break
2397
G = PermutationGroup(gens)
2398
return G
2399
if algorithm=="partition":
2400
if q == 2:
2401
from sage.groups.perm_gps.partn_ref.refinement_binary import LinearBinaryCodeStruct
2402
B = LinearBinaryCodeStruct(G)
2403
autgp = B.automorphism_group()
2404
L = [[j+1 for j in gen] for gen in autgp[0]]
2405
AutGp = PermutationGroup(L)
2406
else:
2407
from sage.groups.perm_gps.partn_ref.refinement_matrices import MatrixStruct
2408
from sage.matrix.constructor import matrix
2409
weights = {}
2410
for c in self:
2411
wt = c.hamming_weight()
2412
if wt not in weights:
2413
weights[wt] = [c]
2414
else:
2415
weights[wt].append(c)
2416
weights.pop(0)
2417
AutGps = []
2418
for wt, words in weights.iteritems():
2419
M = MatrixStruct(matrix(words))
2420
autgp = M.automorphism_group()
2421
L = [[j+1 for j in gen] for gen in autgp[0]]
2422
G = PermutationGroup(L)
2423
AutGps.append(G)
2424
if len(AutGps) > 0:
2425
AutGp = AutGps[0]
2426
for G in AutGps[1:]:
2427
AutGp = AutGp.intersection(G)
2428
else:
2429
return PermutationGroup([])
2430
return AutGp
2431
if algorithm=="codecan":
2432
gens, _ = self.automorphism_group_gens("permutational")
2433
return PermutationGroup([x.get_perm() for x in gens])
2434
raise NotImplementedError("The only algorithms implemented currently are 'gap', 'gap+verbose', and 'partition'.")
2435
2436
def permuted_code(self, p):
2437
r"""
2438
Returns the permuted code, which is equivalent to ``self`` via the
2439
column permutation ``p``.
2440
2441
EXAMPLES::
2442
2443
sage: C = codes.HammingCode(3,GF(2))
2444
sage: G = C.permutation_automorphism_group(); G
2445
Permutation Group with generators [(4,5)(6,7), (4,6)(5,7), (2,3)(6,7), (2,4)(3,5), (1,2)(5,6)]
2446
sage: g = G("(2,3)(6,7)")
2447
sage: Cg = C.permuted_code(g)
2448
sage: Cg
2449
Linear code of length 7, dimension 4 over Finite Field of size 2
2450
sage: C == Cg
2451
True
2452
"""
2453
F = self.base_ring()
2454
G = self.gen_mat()
2455
n = len(G.columns())
2456
MS = MatrixSpace(F,n,n)
2457
Gp = G*MS(p.matrix().rows())
2458
return LinearCode(Gp)
2459
2460
def punctured(self, L):
2461
r"""
2462
Returns the code punctured at the positions `L`,
2463
`L \subset \{1,2,...,n\}`. If this code `C` is of length `n` in
2464
GF(q) then the code `C^L` obtained from `C` by puncturing at the
2465
positions in `L` is the code of length `n-L` consisting of codewords
2466
of `C` which have their `i-th` coordinate deleted if `i \in L` and
2467
left alone if `i\notin L`:
2468
2469
.. math::
2470
2471
C^L = \{(c_{i_1},...,c_{i_N})\ |\ (c_1,...,c_n)\in C\},
2472
2473
where `\{1,2,...,n\}-T = \{i_1,...,i_N\}`. In particular, if `L=\{j\}`
2474
then `C^L` is simply the code obtainen from `C` by deleting the `j-th`
2475
coordinate of each codeword. The code `C^L` is called the punctured
2476
code at `L`. The dimension of `C^L` can decrease if `|L|>d-1`.
2477
2478
INPUT:
2479
2480
- ``L`` - Subset of `\{1,...,n\}`, where `n` is the length of ``self``
2481
2482
OUTPUT:
2483
2484
- Linear code, the punctured code described above
2485
2486
EXAMPLES::
2487
2488
sage: C = codes.HammingCode(3,GF(2))
2489
sage: C.punctured([1,2])
2490
Linear code of length 5, dimension 4 over Finite Field of size 2
2491
"""
2492
G = self.gen_mat()
2493
GL = G.matrix_from_columns([i for i in range(G.ncols()) if i not in L])
2494
r = GL.rank()
2495
if r < GL.nrows():
2496
GL.echelonize()
2497
GL = GL[:r]
2498
return LinearCode(GL)
2499
2500
def random_element(self, *args, **kwds):
2501
"""
2502
Returns a random codeword; passes other positional and keyword
2503
arguments to ``random_element()`` method of vector space.
2504
2505
OUTPUT:
2506
2507
- Random element of the vector space of this code
2508
2509
EXAMPLES::
2510
2511
sage: C = codes.HammingCode(3,GF(4,'a'))
2512
sage: C.random_element() # random test
2513
(1, 0, 0, a + 1, 1, a, a, a + 1, a + 1, 1, 1, 0, a + 1, a, 0, a, a, 0, a, a, 1)
2514
2515
Passes extra positional or keyword arguments through::
2516
2517
sage: C.random_element(prob=.5, distribution='1/n') # random test
2518
(1, 0, a, 0, 0, 0, 0, a + 1, 0, 0, 0, 0, 0, 0, 0, 0, a + 1, a + 1, 1, 0, 0)
2519
"""
2520
V = self.ambient_space()
2521
S = V.subspace(self.basis())
2522
return S.random_element(*args, **kwds)
2523
2524
def redundancy_matrix(C):
2525
"""
2526
If C is a linear [n,k,d] code then this function returns a
2527
`k \times (n-k)` matrix A such that G = (I,A) generates a code (in
2528
standard form) equivalent to C. If C is already in standard form and
2529
G = (I,A) is its generator matrix then this function simply returns
2530
that A.
2531
2532
OUTPUT:
2533
2534
- Matrix, the redundancy matrix
2535
2536
EXAMPLES::
2537
2538
sage: C = codes.HammingCode(3,GF(2))
2539
sage: C.gen_mat()
2540
[1 0 0 0 0 1 1]
2541
[0 1 0 0 1 0 1]
2542
[0 0 1 0 1 1 0]
2543
[0 0 0 1 1 1 1]
2544
sage: C.redundancy_matrix()
2545
[0 1 1]
2546
[1 0 1]
2547
[1 1 0]
2548
[1 1 1]
2549
sage: C.standard_form()[0].gen_mat()
2550
[1 0 0 0 0 1 1]
2551
[0 1 0 0 1 0 1]
2552
[0 0 1 0 1 1 0]
2553
[0 0 0 1 1 1 1]
2554
sage: C = codes.HammingCode(2,GF(3))
2555
sage: C.gen_mat()
2556
[1 0 1 1]
2557
[0 1 1 2]
2558
sage: C.redundancy_matrix()
2559
[1 1]
2560
[1 2]
2561
"""
2562
n = C.length()
2563
k = C.dimension()
2564
C1 = C.standard_form()[0]
2565
G1 = C1.gen_mat()
2566
return G1.matrix_from_columns(range(k,n))
2567
2568
def sd_duursma_data(C, i):
2569
r"""
2570
Returns the Duursma data `v` and `m` of this formally s.d. code `C`
2571
and the type number `i` in (1,2,3,4). Does *not* check if this code
2572
is actually sd.
2573
2574
INPUT:
2575
2576
- ``i`` - Type number
2577
2578
OUTPUT:
2579
2580
- Pair ``(v, m)`` as in Duursma [D]_
2581
2582
REFERENCES:
2583
2584
.. [D] I. Duursma, "Extremal weight enumerators and ultraspherical
2585
polynomials"
2586
2587
EXAMPLES::
2588
2589
sage: MS = MatrixSpace(GF(2),2,4)
2590
sage: G = MS([1,1,0,0,0,0,1,1])
2591
sage: C = LinearCode(G)
2592
sage: C == C.dual_code() # checks that C is self dual
2593
True
2594
sage: for i in [1,2,3,4]: print C.sd_duursma_data(i)
2595
[2, -1]
2596
[2, -3]
2597
[2, -2]
2598
[2, -1]
2599
"""
2600
n = C.length()
2601
d = C.minimum_distance()
2602
if i == 1:
2603
v = (n-4*d)/2 + 4
2604
m = d-3
2605
if i == 2:
2606
v = (n-6*d)/8 + 3
2607
m = d-5
2608
if i == 3:
2609
v = (n-4*d)/4 + 3
2610
m = d-4
2611
if i == 4:
2612
v = (n-3*d)/2 + 3
2613
m = d-3
2614
return [v,m]
2615
2616
def sd_duursma_q(C,i,d0):
2617
r"""
2618
INPUT:
2619
2620
- ``C`` - sd code; does *not* check if `C` is actually an sd code
2621
- ``i`` - Type number, one of 1,2,3,4
2622
- ``d0`` - Divisor, the smallest integer such that each `A_i > 0` iff
2623
`i` is divisible by `d0`
2624
2625
OUTPUT:
2626
2627
- Coefficients `q_0, q_1, ...` of `q(T)` as in Duursma [D]_
2628
2629
REFERENCES:
2630
2631
- [D] - I. Duursma, "Extremal weight enumerators and ultraspherical
2632
polynomials"
2633
2634
EXAMPLES::
2635
2636
sage: C1 = codes.HammingCode(3,GF(2))
2637
sage: C2 = C1.extended_code(); C2
2638
Linear code of length 8, dimension 4 over Finite Field of size 2
2639
sage: C2.is_self_dual()
2640
True
2641
sage: C2.sd_duursma_q(1,1)
2642
2/5*T^2 + 2/5*T + 1/5
2643
sage: C2.sd_duursma_q(3,1)
2644
3/5*T^4 + 1/5*T^3 + 1/15*T^2 + 1/15*T + 1/15
2645
"""
2646
q = (C.base_ring()).order()
2647
n = C.length()
2648
d = C.minimum_distance()
2649
d0 = C.divisor()
2650
if i==1 or i==2:
2651
if d>d0:
2652
c0 = QQ((n-d)*rising_factorial(d-d0,d0+1)*C.spectrum()[d])/rising_factorial(n-d0-1,d0+2)
2653
else:
2654
c0 = QQ((n-d)*C.spectrum()[d])/rising_factorial(n-d0-1,d0+2)
2655
if i==3 or i==4:
2656
if d>d0:
2657
c0 = rising_factorial(d-d0,d0+1)*C.spectrum()[d]/((q-1)*rising_factorial(n-d0,d0+1))
2658
else:
2659
c0 = C.spectrum()[d]/((q-1)*rising_factorial(n-d0,d0+1))
2660
v = ZZ(C.sd_duursma_data(i)[0])
2661
m = ZZ(C.sd_duursma_data(i)[1])
2662
if m<0 or v<0:
2663
raise ValueError("This case not implemented.")
2664
PR = PolynomialRing(QQ,"T")
2665
T = PR.gen()
2666
if i == 1:
2667
coefs = PR(c0*(1+3*T+2*T**2)**m*(2*T**2+2*T+1)**v).list()
2668
qc = [coefs[j]/binomial(4*m+2*v,m+j) for j in range(2*m+2*v+1)]
2669
q = PR(qc)
2670
if i == 2:
2671
F = ((T+1)**8+14*T**4*(T+1)**4+T**8)**v
2672
coefs = (c0*(1+T)**m*(1+4*T+6*T**2+4*T**3)**m*F).coeffs()
2673
qc = [coefs[j]/binomial(6*m+8*v,m+j) for j in range(4*m+8*v+1)]
2674
q = PR(qc)
2675
if i == 3:
2676
F = (3*T**2+4*T+1)**v*(1+3*T**2)**v
2677
# Note that: (3*T**2+4*T+1)(1+3*T**2)=(T+1)**4+8*T**3*(T+1)
2678
coefs = (c0*(1+3*T+3*T**2)**m*F).coeffs()
2679
qc = [coefs[j]/binomial(4*m+4*v,m+j) for j in range(2*m+4*v+1)]
2680
q = PR(qc)
2681
if i == 4:
2682
coefs = (c0*(1+2*T)**m*(4*T**2+2*T+1)**v).coeffs()
2683
qc = [coefs[j]/binomial(3*m+2*v,m+j) for j in range(m+2*v+1)]
2684
q = PR(qc)
2685
return q/q(1)
2686
2687
def sd_zeta_polynomial(C, typ=1):
2688
r"""
2689
Returns the Duursma zeta function of a self-dual code using the
2690
construction in [D]_.
2691
2692
INPUT:
2693
2694
- ``typ`` - Integer, type of this s.d. code; one of 1,2,3, or
2695
4 (default: 1)
2696
2697
OUTPUT:
2698
2699
- Polynomial
2700
2701
EXAMPLES::
2702
2703
sage: C1 = codes.HammingCode(3,GF(2))
2704
sage: C2 = C1.extended_code(); C2
2705
Linear code of length 8, dimension 4 over Finite Field of size 2
2706
sage: C2.is_self_dual()
2707
True
2708
sage: C2.sd_zeta_polynomial()
2709
2/5*T^2 + 2/5*T + 1/5
2710
sage: C2.zeta_polynomial()
2711
2/5*T^2 + 2/5*T + 1/5
2712
sage: P = C2.sd_zeta_polynomial(); P(1)
2713
1
2714
sage: F.<z> = GF(4,"z")
2715
sage: MS = MatrixSpace(F, 3, 6)
2716
sage: G = MS([[1,0,0,1,z,z],[0,1,0,z,1,z],[0,0,1,z,z,1]])
2717
sage: C = LinearCode(G) # the "hexacode"
2718
sage: C.sd_zeta_polynomial(4)
2719
1
2720
2721
It is a general fact about Duursma zeta polynomials that `P(1) = 1`.
2722
2723
REFERENCES:
2724
2725
- [D] I. Duursma, "Extremal weight enumerators and ultraspherical
2726
polynomials"
2727
"""
2728
d0 = C.divisor()
2729
P = C.sd_duursma_q(typ,d0)
2730
PR = P.parent()
2731
T = FractionField(PR).gen()
2732
if typ == 1:
2733
P0 = P
2734
if typ == 2:
2735
P0 = P/(1-2*T+2*T**2)
2736
if typ == 3:
2737
P0 = P/(1+3*T**2)
2738
if typ == 4:
2739
P0 = P/(1+2*T)
2740
return P0/P0(1)
2741
2742
def shortened(self, L):
2743
r"""
2744
Returns the code shortened at the positions ``L``, where
2745
`L \subset \{1,2,...,n\}`.
2746
2747
Consider the subcode `C(L)` consisting of all codewords `c\in C` which
2748
satisfy `c_i=0` for all `i\in L`. The punctured code `C(L)^L` is
2749
called the shortened code on `L` and is denoted `C_L`. The code
2750
constructed is actually only isomorphic to the shortened code defined
2751
in this way.
2752
2753
By Theorem 1.5.7 in [HP], `C_L` is `((C^\perp)^L)^\perp`. This is used
2754
in the construction below.
2755
2756
INPUT:
2757
2758
- ``L`` - Subset of `\{1,...,n\}`, where `n` is the length of this code
2759
2760
OUTPUT:
2761
2762
- Linear code, the shortened code described above
2763
2764
EXAMPLES::
2765
2766
sage: C = codes.HammingCode(3,GF(2))
2767
sage: C.shortened([1,2])
2768
Linear code of length 5, dimension 2 over Finite Field of size 2
2769
"""
2770
Cd = self.dual_code()
2771
Cdp = Cd.punctured(L)
2772
return Cdp.dual_code()
2773
2774
@rename_keyword(deprecation=11033, method="algorithm")
2775
def spectrum(self, algorithm=None):
2776
r"""
2777
Returns the spectrum of ``self`` as a list.
2778
2779
The default algorithm uses a GAP kernel function (in C) written by
2780
Steve Linton.
2781
2782
INPUT:
2783
2784
- ``algorithm`` - ``None``, ``"gap"``, ``"leon"``, or ``"binary"``;
2785
defaults to ``"gap"`` except in the binary case. If ``"gap"`` then
2786
uses the GAP function, if ``"leon"`` then uses Jeffrey Leon's
2787
software via Guava, and if ``"binary"`` then uses Sage native Cython
2788
code
2789
2790
- List, the spectrum
2791
2792
The optional algorithm (``"leon"``) may create a stack smashing error
2793
and a traceback but should return the correct answer. It appears to run
2794
much faster than the GAP algorithm in some small examples and much
2795
slower than the GAP algorithm in other larger examples.
2796
2797
EXAMPLES::
2798
2799
sage: MS = MatrixSpace(GF(2),4,7)
2800
sage: G = MS([[1,1,1,0,0,0,0],[1,0,0,1,1,0,0],[0,1,0,1,0,1,0],[1,1,0,1,0,0,1]])
2801
sage: C = LinearCode(G)
2802
sage: C.spectrum()
2803
[1, 0, 0, 7, 7, 0, 0, 1]
2804
sage: F.<z> = GF(2^2,"z")
2805
sage: C = codes.HammingCode(2, F); C
2806
Linear code of length 5, dimension 3 over Finite Field in z of size 2^2
2807
sage: C.spectrum()
2808
[1, 0, 0, 30, 15, 18]
2809
sage: C = codes.HammingCode(3,GF(2)); C
2810
Linear code of length 7, dimension 4 over Finite Field of size 2
2811
sage: C.spectrum(algorithm="leon") # optional - gap_packages (Guava package)
2812
[1, 0, 0, 7, 7, 0, 0, 1]
2813
sage: C.spectrum(algorithm="gap")
2814
[1, 0, 0, 7, 7, 0, 0, 1]
2815
sage: C.spectrum(algorithm="binary")
2816
[1, 0, 0, 7, 7, 0, 0, 1]
2817
sage: C = codes.HammingCode(3,GF(3)); C
2818
Linear code of length 13, dimension 10 over Finite Field of size 3
2819
sage: C.spectrum() == C.spectrum(algorithm="leon") # optional - gap_packages (Guava package)
2820
True
2821
sage: C = codes.HammingCode(2,GF(5)); C
2822
Linear code of length 6, dimension 4 over Finite Field of size 5
2823
sage: C.spectrum() == C.spectrum(algorithm="leon") # optional - gap_packages (Guava package)
2824
True
2825
sage: C = codes.HammingCode(2,GF(7)); C
2826
Linear code of length 8, dimension 6 over Finite Field of size 7
2827
sage: C.spectrum() == C.spectrum(algorithm="leon") # optional - gap_packages (Guava package)
2828
True
2829
2830
"""
2831
if algorithm is None:
2832
if self.base_ring().order() == 2:
2833
algorithm = "binary"
2834
else:
2835
algorithm = "gap"
2836
n = self.length()
2837
F = self.base_ring()
2838
G = self.gen_mat()
2839
if algorithm=="gap":
2840
Gstr = G._gap_init_()
2841
spec = wtdist_gap(Gstr,n,F)
2842
return spec
2843
elif algorithm=="binary":
2844
from sage.coding.binary_code import weight_dist
2845
return weight_dist(self.gen_mat())
2846
elif algorithm=="leon":
2847
if not(F.order() in [2,3,5,7]):
2848
raise NotImplementedError("The algorithm 'leon' is only implemented for q = 2,3,5,7.")
2849
# The GAP command DirectoriesPackageLibrary tells the location of the latest
2850
# version of the Guava libraries, so gives us the location of the Guava binaries too.
2851
guava_bin_dir = gap.eval('DirectoriesPackagePrograms("guava")[1]')
2852
guava_bin_dir = guava_bin_dir[guava_bin_dir.index('"') + 1:guava_bin_dir.rindex('"')]
2853
input = code2leon(self)
2854
from sage.misc.misc import tmp_filename
2855
output = tmp_filename()
2856
import os
2857
status = os.system(os.path.join(guava_bin_dir, 'wtdist')
2858
+ ' ' + input + "::code > " + output)
2859
if status != 0:
2860
raise RuntimeError("Problem calling Leon's wtdist program. Install gap_packages*.spkg and run './configure ../..; make'.")
2861
f = open(output); lines = f.readlines(); f.close()
2862
wts = [0]*(n+1)
2863
s = 0
2864
for L in lines:
2865
L = L.strip()
2866
if len(L) > 0:
2867
o = ord(L[0])
2868
if o >= 48 and o <= 57:
2869
wt, num = L.split()
2870
wts[eval(wt)] = eval(num)
2871
return wts
2872
else:
2873
raise NotImplementedError("The only algorithms implemented currently are 'gap', 'leon' and 'binary'.")
2874
2875
def standard_form(self):
2876
r"""
2877
Returns the standard form of this linear code.
2878
2879
An `[n,k]` linear code with generator matrix `G` in standard form is
2880
the row-reduced echelon form of `G` is `(I,A)`, where `I` denotes the
2881
`k \times k` identity matrix and `A` is a `k \times (n-k)` block. This
2882
method returns a pair `(C,p)` where `C` is a code permutation
2883
equivalent to ``self`` and `p` in `S_n`, with `n` the length of `C`,
2884
is the permutation sending ``self`` to `C`. This does not call GAP.
2885
2886
Thanks to Frank Luebeck for (the GAP version of) this code.
2887
2888
EXAMPLES::
2889
2890
sage: C = codes.HammingCode(3,GF(2))
2891
sage: C.gen_mat()
2892
[1 0 0 0 0 1 1]
2893
[0 1 0 0 1 0 1]
2894
[0 0 1 0 1 1 0]
2895
[0 0 0 1 1 1 1]
2896
sage: Cs,p = C.standard_form()
2897
sage: p
2898
()
2899
sage: MS = MatrixSpace(GF(3),3,7)
2900
sage: G = MS([[1,0,0,0,1,1,0],[0,1,0,1,0,1,0],[0,0,0,0,0,0,1]])
2901
sage: C = LinearCode(G)
2902
sage: Cs, p = C.standard_form()
2903
sage: p
2904
(3,7)
2905
sage: Cs.gen_mat()
2906
[1 0 0 0 1 1 0]
2907
[0 1 0 1 0 1 0]
2908
[0 0 1 0 0 0 0]
2909
"""
2910
from sage.coding.code_constructions import permutation_action as perm_action
2911
mat = self.gen_mat()
2912
MS = mat.parent()
2913
A = []
2914
k = len(mat.rows())
2915
M = mat.echelon_form()
2916
d = len(mat.columns())
2917
G = SymmetricGroup(d)
2918
perm = G([()])
2919
for i in range(1,k+1):
2920
r = M.rows()[i-1]
2921
j = r.nonzero_positions()[0]
2922
if j < d and i != j+1:
2923
perm = perm *G([(i,j+1)])
2924
if perm != G([()]):
2925
for i in range(k):
2926
r = M.rows()[i]
2927
A.append(perm_action(perm,r))
2928
if perm == G([()]):
2929
A = M
2930
return LinearCode(MS(A)), perm
2931
2932
def support(self):
2933
r"""
2934
Returns the set of indices `j` where `A_j` is nonzero, where
2935
spectrum(self) = `[A_0,A_1,...,A_n]`.
2936
2937
OUTPUT:
2938
2939
- List of integers
2940
2941
EXAMPLES::
2942
2943
sage: C = codes.HammingCode(3,GF(2))
2944
sage: C.spectrum()
2945
[1, 0, 0, 7, 7, 0, 0, 1]
2946
sage: C.support()
2947
[0, 3, 4, 7]
2948
"""
2949
n = self.length()
2950
F = self.base_ring()
2951
V = VectorSpace(F,n+1)
2952
return V(self.spectrum()).support()
2953
2954
def weight_enumerator(self, names="xy", name2=None):
2955
"""
2956
Returns the weight enumerator of the code.
2957
2958
INPUT:
2959
2960
- ``names`` - String of length 2, containing two variable names
2961
(default: ``"xy"``). Alternatively, it can be a variable name or
2962
a string, or a tuple of variable names or strings.
2963
2964
- ``name2`` - string or symbolic variable (default: ``None``).
2965
If ``name2`` is provided then it is assumed that ``names``
2966
contains only one variable.
2967
2968
OUTPUT:
2969
2970
- Polynomial over `\QQ`
2971
2972
EXAMPLES::
2973
2974
sage: C = codes.HammingCode(3,GF(2))
2975
sage: C.weight_enumerator()
2976
x^7 + 7*x^4*y^3 + 7*x^3*y^4 + y^7
2977
sage: C.weight_enumerator(names="st")
2978
s^7 + 7*s^4*t^3 + 7*s^3*t^4 + t^7
2979
sage: (var1, var2) = var('var1, var2')
2980
sage: C.weight_enumerator((var1, var2))
2981
var1^7 + 7*var1^4*var2^3 + 7*var1^3*var2^4 + var2^7
2982
sage: C.weight_enumerator(var1, var2)
2983
var1^7 + 7*var1^4*var2^3 + 7*var1^3*var2^4 + var2^7
2984
2985
"""
2986
if name2 is not None:
2987
# We assume that actual variable names or strings are provided
2988
# for names if names2 is also provided. That is, names is not
2989
# a tuple or a list. Otherwise, PolynomialRing will return error
2990
names = (names, name2)
2991
spec = self.spectrum()
2992
n = self.length()
2993
R = PolynomialRing(QQ,2,names)
2994
x,y = R.gens()
2995
we = sum([spec[i]*x**(n-i)*y**i for i in range(n+1)])
2996
return we
2997
2998
def zeta_polynomial(self, name="T"):
2999
r"""
3000
Returns the Duursma zeta polynomial of this code.
3001
3002
Assumes that the minimum distances of this code and its dual are
3003
greater than 1. Prints a warning to ``stdout`` otherwise.
3004
3005
INPUT:
3006
3007
- ``name`` - String, variable name (default: ``"T"``)
3008
3009
OUTPUT:
3010
3011
- Polynomial over `\QQ`
3012
3013
EXAMPLES::
3014
3015
sage: C = codes.HammingCode(3,GF(2))
3016
sage: C.zeta_polynomial()
3017
2/5*T^2 + 2/5*T + 1/5
3018
sage: C = best_known_linear_code(6,3,GF(2)) # optional - gap_packages (Guava package)
3019
sage: C.minimum_distance() # optional - gap_packages (Guava package)
3020
3
3021
sage: C.zeta_polynomial() # optional - gap_packages (Guava package)
3022
2/5*T^2 + 2/5*T + 1/5
3023
sage: C = codes.HammingCode(4,GF(2))
3024
sage: C.zeta_polynomial()
3025
16/429*T^6 + 16/143*T^5 + 80/429*T^4 + 32/143*T^3 + 30/143*T^2 + 2/13*T + 1/13
3026
sage: F.<z> = GF(4,"z")
3027
sage: MS = MatrixSpace(F, 3, 6)
3028
sage: G = MS([[1,0,0,1,z,z],[0,1,0,z,1,z],[0,0,1,z,z,1]])
3029
sage: C = LinearCode(G) # the "hexacode"
3030
sage: C.zeta_polynomial()
3031
1
3032
3033
REFERENCES:
3034
3035
- I. Duursma, "From weight enumerators to zeta functions", in
3036
Discrete Applied Mathematics, vol. 111, no. 1-2, pp. 55-73, 2001.
3037
"""
3038
n = self.length()
3039
q = (self.base_ring()).order()
3040
d = self.minimum_distance()
3041
dperp = (self.dual_code()).minimum_distance()
3042
if d == 1 or dperp == 1:
3043
print "\n WARNING: There is no guarantee this function works when the minimum distance"
3044
print " of the code or of the dual code equals 1.\n"
3045
RT = PolynomialRing(QQ,"%s"%name)
3046
R = PolynomialRing(QQ,3,"xy%s"%name)
3047
x,y,T = R.gens()
3048
we = self.weight_enumerator()
3049
A = R(we)
3050
B = A(x+y,y,T)-(x+y)**n
3051
Bs = B.coefficients()
3052
b = [Bs[i]/binomial(n,i+d) for i in range(len(Bs))]
3053
r = n-d-dperp+2
3054
#print B,Bs,b,r
3055
P_coeffs = []
3056
for i in range(len(b)):
3057
if i == 0:
3058
P_coeffs.append(b[0])
3059
if i == 1:
3060
P_coeffs.append(b[1] - (q+1)*b[0])
3061
if i>1:
3062
P_coeffs.append(b[i] - (q+1)*b[i-1] + q*b[i-2])
3063
#print P_coeffs
3064
P = sum([P_coeffs[i]*T**i for i in range(r+1)])
3065
return RT(P)/RT(P)(1)
3066
3067
def zeta_function(self, name="T"):
3068
r"""
3069
Returns the Duursma zeta function of the code.
3070
3071
INPUT:
3072
3073
- ``name`` - String, variable name (default: ``"T"``)
3074
3075
OUTPUT:
3076
3077
- Element of `\QQ(T)`
3078
3079
EXAMPLES::
3080
3081
sage: C = codes.HammingCode(3,GF(2))
3082
sage: C.zeta_function()
3083
(2/5*T^2 + 2/5*T + 1/5)/(2*T^2 - 3*T + 1)
3084
"""
3085
P = self.zeta_polynomial()
3086
q = (self.base_ring()).characteristic()
3087
RT = PolynomialRing(QQ,"%s"%name)
3088
T = RT.gen()
3089
return P/((1-T)*(1-q*T))
3090
3091
weight_distribution = spectrum
3092
3093
def LinearCodeFromVectorSpace(V, d=None):
3094
"""
3095
Simply converts a vector subspace `V` of `GF(q)^n` into a `LinearCode`.
3096
3097
INPUT:
3098
3099
- ``V`` -- The vector space
3100
3101
- ``d`` -- (Optional, default: ``None``) the minimum distance of the
3102
code, if known. This is an optional parameter.
3103
3104
.. note::
3105
The veracity of the minimum distance ``d``, if provided, is not
3106
checked.
3107
3108
EXAMPLES::
3109
3110
sage: V = VectorSpace(GF(2), 8)
3111
sage: L = V.subspace([[1,1,1,1,0,0,0,0],[0,0,0,0,1,1,1,1]])
3112
sage: C = LinearCodeFromVectorSpace(L)
3113
sage: C.gen_mat()
3114
[1 1 1 1 0 0 0 0]
3115
[0 0 0 0 1 1 1 1]
3116
sage: C.minimum_distance()
3117
4
3118
3119
Here, we provide the minimum distance of the code.::
3120
3121
sage: C = LinearCodeFromVectorSpace(L, d=4)
3122
sage: C.minimum_distance()
3123
4
3124
"""
3125
F = V.base_ring()
3126
B = V.basis()
3127
n = len(B[0].list())
3128
k = len(B)
3129
MS = MatrixSpace(F,k,n)
3130
G = MS([B[i].list() for i in range(k)])
3131
return LinearCode(G, d=d)
3132
3133
3134