Spracherkennung für: .gi vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
#############################################################################
##
#A codegen.gi GUAVA library Reinald Baart
#A &Jasper Cramwinckel
#A &Erik Roijackers
## &David Joyner
##
## This file contains info/functions for generating codes
##
## BCHCode modified 9-2004
## added 11-2004:
## comment in GoppaCode
## GeneralizedReedSolomonCode and record fields
## points, degree, ring,
## (added SpecialDecoder field later: SetSpecialDecoder(C, GRSDecoder);)
## EvaluationCode and record fields
## points, basis, ring,
## OnePointAGCode and record fields
## points, curve, multiplicity, ring
## weighted option for GeneralizedReedSolomonCode and record fields
## points, degree, ring, weights
## minor bug in EvaluationCode fixed 11-26-2004
## GeneratorMatCodeNC added 12-18-2004 (after release of guava 2.0)
## added 5-10-2005: SetSpecialDecoder(C, CyclicDecoder); to
## the cyclic codes which are not BCH codes
## in codegen.gi, line 2066, replace C.GeneratorMat
## by C.EvaluationMat
## added 5-13-2005: QQRCode
## added 11-27-2005: CheckMatCodeMutable with *mutable*
## generator and check matrices
## added 1-10-2006: QQRCodeNC Greg Coy and David Joyner
## added 1-2006: FerreroDesignCode, written with Peter Mayr
## added 12-2007 (CJ): ExtendedReedSolomonCode, QuasiCyclicCode,
## CyclicMDSCode, FourNegacirculantSelfDualCode functions.
##
DeclareRepresentation( "IsCodeDefaultRep",
IsAttributeStoringRep and IsComponentObjectRep and IsCode,
["name", "history", "lowerBoundMinimumDistance",
"upperBoundMinimumDistance", "boundsCoveringRadius"]);
DeclareHandlingByNiceBasis( "IsLinearCodeRep", "for linear codes" );
InstallTrueMethod( IsLinearCode, IsLinearCodeRep );
#T The following is of course a hack, as is much of the
#T ``pretend as if you were a vector space'' stuff.
#T (`IsLinearCode' changes harmless codes into vector spaces;
#T `AsLinearCode' would be clean, but now it is too late ...)
InstallTrueMethod( IsFreeLeftModule, IsLinearCodeRep );
### functions to work with NiceBasis functionality for Linear Codes.
InstallHandlingByNiceBasis( "IsLinearCodeRep", rec(
detect:= function( R, gens, V, zero )
return IsCodewordCollection( V );
end,
NiceFreeLeftModuleInfo:= ReturnFalse,
NiceVector:= function( C, w )
return VectorCodeword( w );
end,
UglyVector:= function( C, v )
return Codeword( v, Length( v ), LeftActingDomain( C ) );
end ) );
#############################################################################
##
#F ElementsCode( <L> [, <name> ], <F> ) . . . . . . code from list of words
##
InstallMethod(ElementsCode, "list,name,Field", true,
[IsList,IsString,IsField], 0,
function(L, name, F)
local test, C;
L := Codeword(L, F);
test := WordLength(L[1]);
if ForAny(L, i->WordLength(i) <> test) then
Error("All elements must have the same length");
fi;
test := FamilyObj(L[1]);
if ForAny(L, i->FamilyObj(i) <> test) then
Error ("All elements must have the same family");
fi;
L := Set(L);
C := Objectify(NewType(CollectionsFamily(test), IsCodeDefaultRep), rec());
SetLeftActingDomain(C, F);
SetAsSSortedList(C, L);
C!.name := name;
return C;
end);
InstallOtherMethod(ElementsCode, "list,Field", true, [IsList, IsField], 0,
function(L,F)
return ElementsCode(L, "user defined unrestricted code", F);
end);
InstallOtherMethod(ElementsCode, "list,name,fieldsize", true,
[IsList, IsString, IsInt], 0,
function(L, name, q)
return ElementsCode(L, name, GF(q));
end);
InstallOtherMethod(ElementsCode, "list,size of field", true, [IsList,IsInt], 0,
function(L, q)
return ElementsCode(L, "user defined unrestricted code", GF(q));
end);
##Create a linear code from a list of Codeword generators
LinearCodeByGenerators := function(F, gens)
local V, M, row, i, j;
V:= Objectify( NewType( FamilyObj( gens ),
IsLeftModule and
IsLinearCodeRep and IsCodeDefaultRep ),
rec() );
SetLeftActingDomain( V, F );
SetGeneratorsOfLeftModule( V, AsList( One(F)*gens ) );
SetIsLinearCode(V, true);
SetWordLength(V, Length(gens[1]));
#M:=[];
#for i in [1..Length(gens)] do
# row:=[];
# for j in [1..Length(gens[i])] do
# Append(row,[gens[i][j]]);
# od;
# Append(M, [row]);
#od;
#SetGeneratorMat(V, M); #The calling functions always handle setting the GenMat
return V;
end;
#############################################################################
##
#F RandomCode( <n>, <M> [, <F>] ) . . . . . . . . random unrestricted code
##
InstallMethod(RandomCode, "wordlength,codesize,field", true,
[IsInt, IsInt, IsField], 0,
function(n, M, F)
local L;
if Size(F)^n < M then
Error(Size(F),"^",n," < ",M);
fi;
L := [];
while Length(L) < M do
AddSet(L, List([1..n], i -> Random(F)));
od;
return ElementsCode(L, "random unrestricted code", F);
end);
InstallOtherMethod(RandomCode, "wordlength,codesize", true, [IsInt, IsInt], 0,
function(n, M)
return RandomCode(n, M, GF(2));
end);
InstallOtherMethod(RandomCode, "wordlength,codesize,fieldsize", true,
[IsInt, IsInt, IsInt], 0,
function(n, M, q)
return RandomCode(n, M, GF(q));
end);
#############################################################################
##
#F HadamardCode( <H | n> [, <t>] ) . Hadamard code of <t>'th kind, order <n>
##
InstallMethod(HadamardCode, "matrix, kind (int)", true, [IsMatrix, IsInt], 0,
function(H, t)
local n, vec, C;
n := Length(H);
if H * TransposedMat(H) <> n * IdentityMat(n,n) then
Error("The matrix is not a Hadamard matrix");
fi;
H := (H-1)/(-2);
if t = 1 then
H := TransposedMat(TransposedMat(H){[2..n]});
C := ElementsCode(H, Concatenation("Hadamard code of order ",
String(n)), GF(2) );
C!.lowerBoundMinimumDistance := n/2;
C!.upperBoundMinimumDistance := n/2;
vec := NullVector(n);
# this was ... := NullVector(n+1);
# but this seems to be wrong -- Eric Minkes
vec[1] := 1;
vec[n/2+1] := Size(C) - 1;
SetInnerDistribution(C, vec);
elif t = 2 then
H := ShallowCopy( TransposedMat(TransposedMat(H){[2..n]}) );
Append(H, 1 - H);
C := ElementsCode(H, Concatenation("Hadamard code of order ",
String(n)), GF(2) );
C!.lowerBoundMinimumDistance := n/2 - 1;
C!.upperBoundMinimumDistance := n/2 - 1;
vec := NullVector(n);
vec[1] := 1;
vec[n] := 1;
# this was ... [n+1]...
# but this seems to be wrong -- Eric Minkes
vec[n/2] := Size(C)/2 - 1;
vec[n/2+1] := Size(C)/2 - 1;
SetInnerDistribution(C, vec);
else
Append(H, 1 - H);
C := ElementsCode( H, Concatenation("Hadamard code of order ",
String(n)), GF(2) );
C!.lowerBoundMinimumDistance := n/2;
C!.upperBoundMinimumDistance := n/2;
vec := NullVector(n);
vec[1] := 1;
vec[n+1] := 1;
vec[n/2+1] := Size(C) - 2;
SetInnerDistribution(C, vec);
fi;
return(C);
end);
InstallOtherMethod(HadamardCode, "order, kind (int)", true, [IsInt, IsInt], 0,
function(n, t)
return HadamardCode(HadamardMat(n), t);
end);
InstallOtherMethod(HadamardCode, "matrix", true, [IsMatrix], 0,
function(H)
return HadamardCode(H, 3);
end);
InstallOtherMethod(HadamardCode, "order", true, [IsInt], 0,
function(n)
return HadamardCode(HadamardMat(n), 3);
end);
InstallOtherMethod(HadamardCode, "matrix, kind (string)", true,
[IsMatrix, IsString], 0,
function(H, t)
if t in ["a", "A", "1"] then
return HadamardCode(H, 1);
elif t in ["b", "B", "2"] then
return HadamardCode(H, 2);
else
return HadamardCode(H, 3);
fi;
end);
InstallOtherMethod(HadamardCode, "order, kind (string)", true,
[IsInt, IsString], 0,
function(n, t)
if t in ["a", "A", "1"] then
return HadamardCode(HadamardMat(n), 1);
elif t in ["b", "B", "2"] then
return HadamardCode(HadamardMat(n), 2);
else
return HadamardCode(HadamardMat(n), 3);
fi;
end);
#############################################################################
##
#F ConferenceCode( <n | M> ) . . . . . . . . . . code from conference matrix
##
InstallMethod(ConferenceCode, "matrix", true, [IsMatrix], 0,
function(S)
local n, I, J, F, els, w, wd, C;
n := Length(S);
if S*TransposedMat(S) <> (n-1)*IdentityMat(n) or
TransposedMat(S) <> S then
Error("argument must be a symmetric conference matrix");
fi;
# Normalize S by multiplying rows and columns:
for I in [2..n] do
if S[I][1] <> 1 then
for J in [1..n] do
S[I][J] := S[I][J] * -1;
od;
fi;
od;
for J in [2..n] do
if S[1][J] <> 1 then
for I in [1..n] do
S[I][J] := S[I][J] * -1;
od;
fi;
od;
# Strip first row and first column:
S := List([2..n], i-> S[i]{[2..n]});
n := n - 1;
F := GF(2);
els := [NullWord(n, F)];
I := IdentityMat(n);
J := NullMat(n,n) + 1;
Append(els, Codeword(1/2 * (S+I+J), F));
Append(els, Codeword(1/2 * (-S+I+J), F));
Add( els, Codeword( List([1..n], x -> One(F) ), n, One(F) ) );
C := ElementsCode( els, "conference code", F);
w := Weight(AsSSortedList(C)[2]);
wd := List([1..n+1], x -> 0);
wd[1] := 1; wd[n+1] := 1;
wd[w+1] := Size(C) - 2;
SetWeightDistribution(C, wd);
C!.lowerBoundMinimumDistance := (n-1)/2;
C!.upperBoundMinimumDistance := (n-1)/2;
return C;
end);
InstallOtherMethod(ConferenceCode, "integer", true, [IsInt], 0,
function(n)
local LegendreSym, zero, QRes, E, I, S, F, els, J, w, wd, C;
LegendreSym := function(i)
if i = zero then
return 0;
elif i in QRes then
return 1;
else
return -1;
fi;
end;
if (not IsPrimePowerInt(n)) or (n mod 4 <> 1) then
Error ("n must be a primepower and n mod 4 = 1");
fi;
E := AsSSortedList(GF(n));
zero := E[1];
QRes := [];
for I in E do
AddSet(QRes, I^2);
od;
S := List(E, i->List(E, j->LegendreSym(j-i)));
F := GF(2);
els := [NullWord(n, F)];
I := IdentityMat(n);
J := NullMat(n,n) + 1;
Append(els, Codeword(1/2 * (S+I+J), F));
Append(els, Codeword(1/2 * (-S+I+J), F));
Add( els, Codeword( List([1..n], x -> One(F) ), n, One(F) ) );
C := ElementsCode( els, "conference code", F);
w := Weight(AsSSortedList(C)[2]);
wd := List([1..n+1], x -> 0);
wd[1] := 1; wd[n+1] := 1;
wd[w+1] := Size(C) - 2;
SetWeightDistribution(C, wd);
C!.lowerBoundMinimumDistance := (n-1)/2;
C!.upperBoundMinimumDistance := (n-1)/2;
return C;
end);
#############################################################################
##
#F MOLSCode( [ <n>, ] <q> ) . . . . . . . . . . . . . . . . code from MOLS
##
## MOLSCode([n, ] q) returns a (n, q^2, n-1) code over GF(q)
## by creating n-2 mutually orthogonal latin squares of size q.
## If n is omitted, a wordlength of 4 will be set.
## If there are no n-2 MOLS known, the code will return an error
##
InstallMethod(MOLSCode, "wordlength,size of field", true, [IsInt, IsInt], 0,
function(n,q)
local M, els, i, j, k, wd, C;
M := MOLS(q, n-2);
if M = false then
Error("No ", n-2, " MOLS of order ", q, " are known");
else
els := [];
for i in [1..q] do
for j in [1..q] do
els[(i-1)*q+j] := [];
els[(i-1)*q+j][1] := i-1;
els[(i-1)*q+j][2]:= j-1;
for k in [3..n] do
els[(i-1)*q+j][k]:= M[k-2][i][j];
od;
od;
od;
C := ElementsCode( els, Concatenation("code generated by ",
String(n-2), " MOLS of order ", String(q)), GF(q) );
C!.lowerBoundMinimumDistance := n - 1;
C!.upperBoundMinimumDistance := n - 1;
wd := List( [1..n+1], x -> 0 );
wd[1] := 1;
wd[n] := (q-1) * n;
wd[n+1] := (q-1) * (q + 1 - n);
SetWeightDistribution(C, wd);
return C;
fi;
end);
InstallOtherMethod(MOLSCode, "wordlength,field", true, [IsInt, IsField], 0,
function(n, F)
return MOLSCode(n, Size(F));
end);
InstallOtherMethod(MOLSCode, "fieldsize", true, [IsInt], 0,
function(q)
return MOLSCode(4, q);
end);
InstallOtherMethod(MOLSCode, "field", true, [IsField], 0,
function(F)
return MOLSCode(4, Size(F));
end);
## Was commented out in gap 3.4.4 Guava version.
#############################################################################
##
#F QuadraticCosetCode( <Q> ) . . . . . . . . . . coset of RM(1,m) in R(2,m)
##
## QuadraticCosetCode(Q) returns a coset of the ReedMullerCode of
## order 1 (R(1,m)) in R(2,m) where m is the size of square matrix Q.
## Q is the upper triangular matrix that defines the quadratic part of
## the boolean functions that are in the coset.
##
#QuadraticCosetCode := function(arg)
# local Q, m, V, R, RM1, k, f, C, h, wd;
# if Length(arg) = 1 and IsMat(arg[1]) then
# Q := arg[1];
# else
# Error("usage: QuadraticCosetCode( <mat> )");
# fi;
# m := Length(Q);
# V := Tuples(Elements(GF(2)), m);
# R := V*Q*TransposedMat(V);
# f := List([1..2^m], i->R[i][i]);
# RM1 := Concatenation(NullMat(1,2^m,GF(2))+GF(2).one,
# TransposedMat(Tuples(Elements(GF(2)), m)));
# k := Length(RM1);
# C := rec(
# isDomain := true,
# isCode := true,
# operations := CodeOps,
# baseField := GF(2),
# wordLength := 2^m,
# elements := Codeword(List(Tuples(Elements(GF(2)), k) * RM1, t-> t+f)),
# lowerBoundMinimumDistance := 2^(m-1),
# upperBoundMinimumDistance := 2^(m-1)
# );
# h := RankMat(Q + TransposedMat(Q))/2;
# wd := NullMat(1, 2^m+1)[1];
# wd[2^(m-1) - 2^(m-h-1) + 1] := 2^(2*h);
# wd[2^(m-1) + 1] := 2^(m+1) - 2^(2*h + 1);
# wd[2^(m-1) + 2^(m-h-1) + 1] := 2^(2*h);
# C.weightDistribution := wd;
# C.name := "quadratic coset code";
# return C;
#end;
#############################################################################
##
#F GeneratorMatCode( <G> [, <name> ], <F> ) . . code from generator matrix
##
InstallMethod(GeneratorMatCode, "generator matrix, name, field", true,
[IsMatrix, IsString, IsField], 0,
function(G, name, F)
local C;
if (Length(G) = 0) or (Length(G[1]) = 0) then
Error("Use NullCode to generate a code with dimension 0");
fi;
G := G*One(F);
G := BaseMat(G);
C := LinearCodeByGenerators(F, Codeword(G,F));
SetGeneratorMat(C, G);
SetWordLength(C, Length(G[1]));
C!.name := name;
return C;
end);
InstallOtherMethod(GeneratorMatCode, "generator matrix, field", true,
[IsMatrix, IsField], 0,
function(G, F)
return GeneratorMatCode(G, "code defined by generator matrix", F);
end);
InstallOtherMethod(GeneratorMatCode, "generator matrix, name, size of field",
true, [IsMatrix, IsString, IsInt], 0,
function(G, name, q)
return GeneratorMatCode(G, name, GF(q));
end);
InstallOtherMethod(GeneratorMatCode, "generator matrix, size of field", true,
[IsMatrix, IsInt], 0,
function(G, q)
return GeneratorMatCode(G, "code defined by generator matrix", GF(q));
end);
#############################################################################
##
#F GeneratorMatCodeNC( <G> , <F> ) . . code from generator matrix
##
## same as GeneratorMatCode but does not compute upper + lower bounds
## for the minimum distance or covering radius
##
InstallMethod(GeneratorMatCodeNC, "generator matrix, field", true,
[IsMatrix, IsField], 0,
function(G, F)
return GeneratorMatCode(G, "code defined by generator matrix, NC", F);
end);
#############################################################################
##
#F CheckMatCodeMutable( <H> [, <name> ], <F> ) . . code from check matrix
## The generator matrix is mutable
##
InstallMethod(CheckMatCodeMutable, "check matrix, name, field", true,
[IsMatrix, IsString, IsField], 0,
function(H, name, F)
local G, H2, C, dimC;
if (Length(H) = 0) or (Length(H[1]) = 0) then
Error("use WholeSpaceCode to generate a code with redundancy 0");
fi;
H := VectorCodeword(Codeword(H, F));
H2 := BaseMat(H);
if Length(H2) < Length(H) then
H := H2;
fi;
# Get generator matrix from H
if IsInStandardForm(H, false) then
dimC := Length(H[1]) - Length(H);
if dimC = 0 then
G := [];
else
G := TransposedMat(Concatenation(IdentityMat( dimC, F ),
List(-H, x->x{[1..dimC]})));
fi;
else
G := NullspaceMat(TransposedMat(H));
fi;
if Length(G) = 0 then # Call NullCode. Length(H=I) = n-k, in this case.
# Length(G) = k = 0 => n = Length(H).
C := NullCode(Length(H), F);
C!.name := name;
return C;
fi;
C := LinearCodeByGenerators(F,Codeword(G, F));
SetGeneratorMat(C, ShallowCopy(G));
SetCheckMat(C, ShallowCopy(H));
SetWordLength(C, Length(G[1]));
C!.name := name;
return C;
end);
InstallOtherMethod(CheckMatCodeMutable, "check matrix, field",
true, [IsMatrix, IsField], 0,
function(H, F)
return CheckMatCode(H, "code defined by check matrix", F);
end);
InstallOtherMethod(CheckMatCodeMutable, "check matrix, name, size of field", true, [IsMatrix, IsString, IsInt], 0,
function(H, name, q)
return CheckMatCode(H, name, GF(q));
end);
InstallOtherMethod(CheckMatCodeMutable, "check matrix, size of field",
true, [IsMatrix, IsInt], 0,
function(H, q)
return CheckMatCodeMutable(H, "code defined by check matrix", GF(q));
end);
#############################################################################
##
#F CheckMatCode( <H> [, <name> ], <F> ) . . . . . . code from check matrix
##
InstallMethod(CheckMatCode, "check matrix, name, field", true,
[IsMatrix, IsString, IsField], 0,
function(H, name, F)
local G, H2, C, dimC;
if (Length(H) = 0) or (Length(H[1]) = 0) then
Error("use WholeSpaceCode to generate a code with redundancy 0");
fi;
H := VectorCodeword(Codeword(H, F));
H2 := BaseMat(H);
if Length(H2) < Length(H) then
H := H2;
fi;
# Get generator matrix from H
if IsInStandardForm(H, false) then
dimC := Length(H[1]) - Length(H);
if dimC = 0 then
G := [];
else
G := TransposedMat(Concatenation(IdentityMat( dimC, F ),
List(-H, x->x{[1..dimC]})));
fi;
else
G := NullspaceMat(TransposedMat(H));
fi;
if Length(G) = 0 then # Call NullCode. Length(H=I) = n-k, in this case.
# Length(G) = k = 0 => n = Length(H).
C := NullCode(Length(H), F);
C!.name := name;
return C;
fi;
C := LinearCodeByGenerators(F,Codeword(G, F));
SetGeneratorMat(C, G);
SetCheckMat(C, H);
SetWordLength(C, Length(G[1]));
C!.name := name;
return C;
end);
InstallOtherMethod(CheckMatCode, "check matrix, field", true,
[IsMatrix, IsField], 0,
function(H, F)
return CheckMatCode(H, "code defined by check matrix", F);
end);
InstallOtherMethod(CheckMatCode, "check matrix, name, size of field", true,
[IsMatrix, IsString, IsInt], 0,
function(H, name, q)
return CheckMatCode(H, name, GF(q));
end);
InstallOtherMethod(CheckMatCode, "check matrix, size of field", true,
[IsMatrix, IsInt], 0,
function(H, q)
return CheckMatCode(H, "code defined by check matrix", GF(q));
end);
#############################################################################
##
#F RandomLinearCode( <n>, <k> [, <F>] ) . . . . . . . . random linear code
##
InstallMethod(RandomLinearCode, "n,k,field", true, [IsInt, IsInt, IsField], 0,
function(n, k, F)
if k = 0 then
return NullCode( n, F );
else
return GeneratorMatCode(PermutedCols(List(IdentityMat(k,F), i ->
Concatenation(i,List([k+1..n],j->Random(F)))),
Random(SymmetricGroup(n))), "random linear code", F);
fi;
end);
InstallOtherMethod(RandomLinearCode, "n,k,size of field", true,
[IsInt, IsInt, IsInt], 0,
function(n, k, q)
return RandomLinearCode(n, k, GF(q));
end);
InstallOtherMethod(RandomLinearCode, "n,k", true, [IsInt, IsInt], 0,
function(n, k)
return RandomLinearCode(n, k, GF(2));
end);
#############################################################################
##
#F HammingCode( <r> [, <F>] ) . . . . . . . . . . . . . . . . Hamming code
##
InstallMethod(HammingCode, "r,F", true, [IsInt, IsField], 0,
function(r, F)
local q, H, H2, C, i, j, n, TupAllow, wd;
TupAllow := function(W)
local l;
l := 1;
while (W[l] = Zero(F)) and l < Length(W) do
l := l + 1;
od;
return (W[l] = One(F));
end;
q := Size(F);
if not IsPrimePowerInt(q) then
Error("q must be prime power");
fi;
H := Tuples(AsSSortedList(F), r);
H2 := [];
j := 1;
for i in [1..Length(H)] do
if TupAllow(H[i]) then
H2[j] := H[i];
j := j + 1;
fi;
od;
n := (q^r-1)/(q-1);
C := CheckMatCode(TransposedMat(H2), Concatenation("Hamming (", String(r),
",", String(q), ") code"), F);
C!.lowerBoundMinimumDistance := 3;
C!.upperBoundMinimumDistance := 3;
C!.boundsCoveringRadius := [ 1 ];
SetIsPerfectCode(C, true);
SetIsSelfDualCode(C, false);
SetSpecialDecoder(C, HammingDecoder);
if q = 2 then
SetIsNormalCode(C, true);
wd := [1, 0];
for i in [2..n] do
Add(wd, 1/i * (Binomial(n, i-1) - wd[i] - (n-i+2)*wd[i-1]));
od;
SetWeightDistribution(C, wd);
fi;
return C;
end);
InstallOtherMethod(HammingCode, "r,size of field", true, [IsInt, IsInt], 0,
function(r, q)
return HammingCode(r, GF(q));
end);
InstallOtherMethod(HammingCode, "r", true, [IsInt], 0,
function(r)
return HammingCode(r, GF(2));
end);
#############################################################################
##
#F SimplexCode( <r>, <F> ) . The SimplexCode is the Dual of the HammingCode
##
InstallMethod(SimplexCode, "redundancy, field", true, [IsInt, IsField], 0,
function(r, F)
local C;
C := DualCode( HammingCode(r,F) );
C!.name := "simplex code";
if F = GF(2) then
SetIsNormalCode(C, true);
C!.boundsCoveringRadius := [ 2^(r-1) - 1 ];
fi;
return C;
end);
InstallOtherMethod(SimplexCode, "redundancy, fieldsize", true,[IsInt,IsInt],0,
function(r, q)
return SimplexCode(r, GF(q));
end);
InstallOtherMethod(SimplexCode, "redundancy", true, [IsInt], 0,
function(r)
return SimplexCode(r, GF(2));
end);
#############################################################################
##
#F ReedMullerCode( <r>, <k> ) . . . . . . . . . . . . . . Reed-Muller code
##
## ReedMullerCode(r, k) creates a binary Reed-Muller code of dimension k,
## order r; 0 <= r <= k
##
InstallMethod(ReedMullerCode, "dimension, order", true, [IsInt,IsInt], 0,
function(r,k)
local mat,c,src,dest,index,num,dim,C,wd, h,t,A, bcr;
if r > k then
return ReedMullerCode(k, r); #for compatibility with older versions
#of guava, It used to be
#ReedMullerCode(k, r);
fi;
mat := [ [] ];
num := 2^k;
dim := Sum(List([0..r], x->Binomial(k,x)));
for t in [1..num] do
mat[1][t] := Z(2)^0;
od;
if r > 0 then
Append(mat, TransposedMat(Tuples ([0*Z(2), Z(2)^0], k)));
for t in [2..r] do
for index in Combinations([1..k], t) do
dest := List([1..2^k], i->Product(index, j->mat[j+1][i]));
Append(mat, [dest]);
od;
od;
fi;
C := GeneratorMatCode( mat, Concatenation("Reed-Muller (", String(r), ",",
String(k), ") code"), GF(2) );
C!.lowerBoundMinimumDistance := 2^(k-r);
C!.upperBoundMinimumDistance := 2^(k-r);
SetIsPerfectCode(C, false);
SetIsSelfDualCode(C, (2*r = k-1));
if r = 0 then
wd := List([1..num + 1], x -> 0);
wd[1] := 1;
wd[num+1] := 1;
SetWeightDistribution(C, wd);
elif r = 1 then
wd := List([1..num + 1], x -> 0);
wd[1] := 1;
wd[num + 1] := 1;
wd[num / 2 + 1] := Size(C) - 2;
SetWeightDistribution(C, wd);
elif r = 2 then
wd := List([1..num + 1], x -> 0);
wd[1] := 1;
wd[num + 1] := 1;
for h in [1..QuoInt(k,2)] do
A := 2^(h*(h+1));
for t in [0..2*h-1] do
A := A*(2^(k-t)-1);
od;
for t in [1..h] do
A := A/(2^(2*t)-1);
od;
wd[2^(k-1)+2^(k-1-h)+1] := A;
wd[2^(k-1)-2^(k-1-h)+1] := A;
od;
wd[2^(k-1)+1] := Size(C)-Sum(wd);
SetWeightDistribution(C, wd);
fi;
bcr := BoundsCoveringRadius( C );
if 0 <= r and r <= k-3 then
if IsEvenInt( r ) then
C!.boundsCoveringRadius :=
[ Maximum( 2^(k-r-3)*(r+4), bcr[1] )
.. Maximum( bcr ) ];
else
C!.boundsCoveringRadius :=
[ Maximum( 2^(k-r-3)*(r+5), bcr[ 1 ] )
.. Maximum( bcr ) ];
fi;
fi;
if r = k then
SetCoveringRadius(C, 0);
C!.boundsCoveringRadius := [ 0 ];
elif r = k - 1 then
SetCoveringRadius(C, 1);
C!.boundsCoveringRadius := [ 1 ];
elif r = k - 2 then
SetCoveringRadius(C, 2);
C!.boundsCoveringRadius := [ 2 ];
elif r = k - 3 then
if IsEvenInt( k ) then
SetCoveringRadius(C, k + 2 );
C!.boundsCoveringRadius := [ k + 2 ];
else
SetCoveringRadius(C, k + 1 );
C!.boundsCoveringRadius := [ k + 1 ];
fi;
elif r = 0 then
SetCoveringRadius(C, 2^(k-1) );
C!.boundsCoveringRadius := [ 2^(k-1) ];
elif r = 1 then
if IsEvenInt( k ) then
SetCoveringRadius(C, 2^(k-1) - 2^(k/2-1) );
C!.boundsCoveringRadius := [ 2^(k-1) - 2^(k/2-1) ];
elif k = 5 then
SetCoveringRadius(C, 12 );
C!.boundsCoveringRadius := [ 12 ];
elif k = 7 then
SetCoveringRadius(C, 56 );
C!.boundsCoveringRadius := [ 56 ];
elif k >= 15 then
C!.boundsCoveringRadius := [ 2^(k-1) - 2^((k+1)/2)*27/64
.. 2^(k-1) - 2^( QuoInt(k,2)-1 ) ];
else
C!.boundsCoveringRadius := [ 2^(k-1) - 2^((k+1)/2)/2
.. 2^(k-1) - 2^( QuoInt(k,2)-1 ) ];
fi;
elif r = 2 then
if k = 6 then
SetCoveringRadius(C, 18 );
C!.boundsCoveringRadius := [ 18 ];
elif k = 7 then
C!.boundsCoveringRadius := [ 40 .. 44 ];
elif k = 8 then
C!.boundsCoveringRadius := [ 84
.. Maximum( bcr ) ];
fi;
elif r = 3 then
if k = 7 then
C!.boundsCoveringRadius := [ 20 .. 23 ];
fi;
elif r = 4 then
if k = 8 then
C!.boundsCoveringRadius := [ 22
.. Maximum( bcr ) ];
fi;
fi;
if r = 1 and
( IsEvenInt( k ) or k = 3 or k = 5 or k = 7 ) then
SetIsNormalCode(C, true);
fi;
return C;
end);
#############################################################################
##
#F LexiCode( <M | n>, <d>, <F> ) . . . . . Greedy code with standard basis
##
InstallMethod(LexiCode, "basis,distance,field", true,
[IsMatrix, IsInt, IsField], 0,
function(M, d, F)
local base, n, k, one, zero, elms, Sz, vec, word, i, dist, carry, pos, C;
base := VectorCodeword(Codeword(M, F));
n := Length(base[1]);
k := Length(base);
one := One(F);
zero := Zero(F);
elms := [];
Sz := 0;
vec := NullVector(k,F);
repeat
word := vec * base;
i := 1;
dist := d;
while (dist>=d) and (i <= Sz) do
dist := DistanceVecFFE(word, elms[i]);
i := i + 1;
od;
if dist >= d then
Add(elms,ShallowCopy(word));
Sz := Sz + 1;
fi;
# generate the (lexicographical) next word in F^k
carry := true;
pos := k;
while carry and (pos > 0) do
if vec[pos] = zero then
carry := false;
vec[pos] := one;
else
vec[pos] := PrimitiveRoot(F)^(LogFFE(vec[pos],PrimitiveRoot(F))+1);
if vec[pos] = one then
vec[pos] := zero;
else
carry := false;
fi;
fi;
pos := pos - 1;
od;
until carry;
if Size(F) = 2 then # or even (2^(2^LogInt(LogInt(q,2),2)) = q) ?
C := GeneratorMatCode(elms, "lexicode", F);
else
C := ElementsCode(elms, "lexicode", F);
fi;
C!.lowerBoundMinimumDistance := d;
return C;
end);
InstallOtherMethod(LexiCode, "basis,distance,size of field", true,
[IsMatrix, IsInt, IsInt], 0,
function(M, d, q)
return LexiCode(M, d, GF(q));
end);
InstallOtherMethod(LexiCode, "wordlength,distance,field", true,
[IsInt, IsInt, IsField], 0,
function(n, d, F)
return LexiCode(IdentityMat(n,F), d, F);
end);
InstallOtherMethod(LexiCode, "wordlength,distance,size of field", true,
[IsInt, IsInt, IsInt], 0,
function(n, d, q)
return LexiCode(IdentityMat(n, GF(q)), d, GF(q));
end);
#############################################################################
##
#F GreedyCode( <M>, <d> [, <F>] ) . . . . Greedy code from list of elements
##
InstallMethod(GreedyCode, "matrix,design distance,Field", true,
[IsMatrix, IsInt, IsField], 0,
function(M,d,F)
local space, n, word, elms, Sz, i, dist, C;
space := VectorCodeword(Codeword(M,F));
n := Length(space[1]);
elms := [space[1]];
Sz := 1;
for word in space do
i := 1;
repeat
dist := DistanceVecFFE(word, elms[i]);
i := i + 1;
until dist < d or i > Sz;
if dist >= d then
Add(elms, word);
Sz := Sz + 1;
fi;
od;
C := ElementsCode(elms, "Greedy code, user defined basis", F);
C!.lowerBoundMinimumDistance := d;
return C;
end);
InstallOtherMethod(GreedyCode, "matrix,design distance,size of field", true,
[IsMatrix, IsInt, IsInt], 0,
function(M,d,q)
return GreedyCode(M,d,GF(q));
end);
InstallOtherMethod(GreedyCode, "matrix,design distance", true,
[IsMatrix,IsInt], 0,
function(M,d)
return GreedyCode(M,d,DefaultField(Flat(M)));
end);
#############################################################################
##
#F AlternantCode( <r>, <Y> [, <alpha>], <F> ) . . . . . . . Alternant code
##
InstallMethod(AlternantCode, "redundancy, Y, alpha, field", true,
[IsInt, IsList, IsList, IsField], 0,
function(r, Y, els, F)
local C, n, q, i, temp;
n := Length(Y);
els := Set(VectorCodeword(Codeword(els, F)));
Y := VectorCodeword(Codeword(Y, F) );
if ForAny(Y, i-> i = Zero(F)) then
Error("Y contains zero");
elif Length(els) <> Length(Y) then
Error("<Y> and <alpha> have inequal length or <alpha> is not distinct");
fi;
q := Characteristic(F);
temp := NullMat(n, n, F);
for i in [1..n] do
temp[i][i] := Y[i];
od;
Y := temp;
C := CheckMatCode( BaseMat(VerticalConversionFieldMat( List([0..r-1],
i -> List([1..n], j-> els[j]^i)) * Y)), "alternant code", F );
C!.lowerBoundMinimumDistance := r + 1;
return C;
end);
InstallOtherMethod(AlternantCode, "redundancy, Y, alpha, fieldsize", true,
[IsInt, IsList, IsList, IsInt], 0,
function(r, Y, a, q)
return AlternantCode(r, Y, a, GF(q));
end);
InstallOtherMethod(AlternantCode, "redundancy, Y, field", true,
[IsInt, IsList, IsField], 0,
function(r, Y, F)
return AlternantCode(r, Y, AsSSortedList(F){[2..Length(Y)+1]}, F);
end);
InstallOtherMethod(AlternantCode, "redundancy, Y, fieldsize", true,
[IsInt, IsList, IsInt], 0,
function(r, Y, q)
return AlternantCode(r, Y, AsSSortedList(GF(q)){[2..Length(Y)+1]}, GF(q));
end);
#############################################################################
##
#F GoppaCode( <G>, <L | n> ) . . . . . . . . . . . . . . classical Goppa code
##
InstallGlobalFunction(GoppaCode,
function(arg)
local C, GP, F, L, n, q, m, r, zero, temp;
GP := PolyCodeword(Codeword(arg[1]));
F := CoefficientsRing(DefaultRing(GP));
q := Characteristic(F);
m := Dimension(F);
F := GF(q);
zero := Zero(F);
r := DegreeOfLaurentPolynomial(GP);
# find m
if IsInt(arg[2]) then
n := arg[2];
m := Maximum(m, LogInt(n,q));
repeat
L := Filtered(AsSSortedList(GF(q^m)),i -> Value(GP,i) <> zero);
m := m + 1;
until Length(L) >= n;
m := m - 1;
L := L{[1..n]};
else
L := arg[2];
n := Length(L);
m := Maximum(m, Dimension(DefaultField(L)));
fi;
C := CheckMatCode( BaseMat(VerticalConversionFieldMat( List([0..r-1],
i-> List(L, j-> (j)^i / Value(GP, j) )) )), "classical Goppa code", F);
# Make the code
temp := Factors(GP);
if (q = 2) and (Length(temp) = Length(Set(temp))) then
# second condition checks if the roots of G are distinct
C!.lowerBoundMinimumDistance := Minimum(n, 2*r + 1);
else
C!.lowerBoundMinimumDistance := Minimum(n, r + 1);
fi;
return C;
end);
#############################################################################
##
#F CordaroWagnerCode( <n> ) . . . . . . . . . . . . . . Cordaro-Wagner code
##
InstallMethod(CordaroWagnerCode, "length", true, [IsInt], 0,
function(n)
local r, C, zero, one, F, d, wd;
if n < 2 then
Error("n must be 2 or more");
fi;
r := Int((n+1)/3);
d := (2 * r - Int( (n mod 3) / 2) );
F := GF(2);
zero := Zero(F);
one := One(F);
C := GeneratorMatCode( [Concatenation(List([1..r],i -> zero),
List([r+1..n],i -> one)),
Concatenation(List([r+1..n],i -> one), List([1..r],
i -> zero))], "Cordaro-Wagner code", F );
C!.lowerBoundMinimumDistance := d;
C!.upperBoundMinimumDistance := d;
wd := List([1..n+1], i-> 0);
wd[1] := 1;
wd[2*r+1] := 1;
wd[n-r+1] := wd[n-r+1] + 2;
SetWeightDistribution(C, wd);
return C;
end);
#############################################################################
##
#F GeneralizedSrivastavaCode( <a>, <w>, <z> [, <t>] [, <F>] ) . . . . . .
##
InstallMethod(GeneralizedSrivastavaCode, "a,w,z,t,F", true,
[IsList, IsList, IsList, IsInt, IsField], 0,
function(a,w,z,t,F)
local C, n, s, i, H;
a := VectorCodeword(Codeword(a, F));
w := VectorCodeword(Codeword(w, F));
z := VectorCodeword(Codeword(z, F));
n := Length(a);
s := Length(w);
if Length(Set(Concatenation(a,w))) <> n + s then
Error("<alpha> and w are not distinct");
fi;
if ForAny(z,i -> i = Zero(F)) then
Error("<z> must be nonzero");
fi;
H := [];
for i in List([1..s], index -> List([1..t], vert -> List([1..n],
hor -> z[hor]/(a[hor] - w[index])^vert))) do
Append(H, i);
od;
C := CheckMatCode( BaseMat(VerticalConversionFieldMat(H)),
"generalized Srivastava code", GF(Characteristic(F)) );
C!.lowerBoundMinimumDistance := s + 1;
return C;
end);
InstallOtherMethod(GeneralizedSrivastavaCode, "a,w,z,t,q", true,
[IsList, IsList, IsList, IsInt, IsInt], 0,
function(a, w, z, t, q)
return GeneralizedSrivastavaCode(a, w, z, t, GF(q));
end);
InstallOtherMethod(GeneralizedSrivastavaCode, "a,w,z,t", true,
[IsList, IsList, IsList, IsInt], 0,
function(a, w, z, t)
return GeneralizedSrivastavaCode(a, w, z, t,
DefaultField(Concatenation(a,w,z)));
end);
InstallOtherMethod(GeneralizedSrivastavaCode, "a,w,z,F", true,
[IsList, IsList, IsList, IsField], 0,
function(a, w, z, F)
return GeneralizedSrivastavaCode(a, w, z, 1, F);
end);
InstallOtherMethod(GeneralizedSrivastavaCode, "a, w, z", true,
[IsList, IsList, IsList], 0,
function(a, w, z)
return GeneralizedSrivastavaCode(a, w, z, 1,
DefaultField(Concatenation(a, w, z)));
end);
#############################################################################
##
#F SrivastavaCode( <a>, <w> [, <mu>] [, <F>] ) . . . . . . . Srivastava code
##
InstallMethod(SrivastavaCode, "a,w,mu,F", true,
[IsList,IsList,IsInt, IsField], 0,
function(a, w, mu, F)
local C, n, s, i, zero, TheMat;
a := VectorCodeword(Codeword(a, F));
w := VectorCodeword(Codeword(w, F));
n := Length(a);
s := Length(w);
if Length(Set(Concatenation(a,w))) <> n + s then
Error("the elements of <alpha> and w are not distinct");
fi;
zero := Zero(F);
for i in [1.. n] do
if a[i]^mu = zero then
Error("z[",i,"] = ",a[i],"^",mu," = ",zero);
fi;
od;
TheMat := List([1..s], j -> List([1..n], i -> a[i]^mu/(a[i] - w[j]) ));
C := CheckMatCode( BaseMat(VerticalConversionFieldMat(TheMat)),
"Srivastava code", GF(Characteristic(F)) );
C!.lowerBoundMinimumDistance := s + 1;
return C;
end);
InstallOtherMethod(SrivastavaCode, "a,w,mu,q", true,
[IsList,IsList,IsInt,IsInt], 0,
function(a, w, mu, q)
return SrivastavaCode(a, w, mu, GF(q));
end);
InstallOtherMethod(SrivastavaCode, "a,w,mu", true,
[IsList,IsList,IsInt], 0,
function(a, w, mu)
return SrivastavaCode(a, w, mu, DefaultField(Concatenation(a,w)));
end);
InstallOtherMethod(SrivastavaCode, "a,w,F", true,
[IsList,IsList,IsField], 0,
function(a, w, F)
return SrivastavaCode(a, w, 1, F);
end);
InstallOtherMethod(SrivastavaCode, "a,w", true, [IsList,IsList], 0,
function(a, w)
return SrivastavaCode(a, w, 1, DefaultField(Concatenation(a,w)));
end);
#############################################################################
##
#F ExtendedBinaryGolayCode( ) . . . . . . . . . extended binary Golay code
##
InstallMethod(ExtendedBinaryGolayCode, "only method", true, [], 0,
function()
local C;
C := ExtendedCode(BinaryGolayCode());
C!.name := "extended binary Golay code";
Unbind( C!.history );
SetIsCyclicCode(C, false);
SetIsPerfectCode(C, false);
SetIsSelfDualCode(C, true);
C!.boundsCoveringRadius := [ 4 ];
SetIsNormalCode(C, true);
SetWeightDistribution(C,
[1,0,0,0,0,0,0,0,759,0,0,0,2576,0,0,0,759,0,0,0,0,0,0,0,1]);
#SetAutomorphismGroup(C, M24);
C!.lowerBoundMinimumDistance := 8;
C!.upperBoundMinimumDistance := 8;
return C;
end);
#############################################################################
##
#F ExtendedTernaryGolayCode( ) . . . . . . . . . extended ternary Golay code
##
InstallMethod(ExtendedTernaryGolayCode, "only method", true, [], 0,
function()
local C;
C := ExtendedCode(TernaryGolayCode());
SetIsCyclicCode(C, false);
SetIsPerfectCode(C, false);
SetIsSelfDualCode(C, true);
C!.boundsCoveringRadius := [ 3 ];
SetIsNormalCode(C, true);
C!.name := "extended ternary Golay code";
Unbind( C!.history );
SetWeightDistribution(C, [1,0,0,0,0,0,264,0,0,440,0,0,24]);
#SetAutomorphismGroup(C, M12);
C!.lowerBoundMinimumDistance := 6;
C!.upperBoundMinimumDistance := 6;
return C;
end);
#############################################################################
##
#F BestKnownLinearCode( <n>, <k> [, <F>] ) . returns best known linear code
#F BestKnownLinearCode( <rec> )
##
## L describs how to create a code. L is a list with two elements:
## L[1] is a function and L[2] is a list of arguments for L[1].
## One or more of the arguments of L[2] may again be such descriptions and
## L[2] can be an empty list.
## The field .construction contains such a list or false if the code is not
## yet in the apropiatelibrary file (/tbl/codeq.g)
##
InstallMethod(BestKnownLinearCode, "method for bounds/construction record",
true, [IsRecord], 0,
function(bds)
local MakeCode, C;
# L describs how to create a code. L is a list with two elements:
# L[1] is a function and L[2] is a list of arguments for L[1].
# One or more of the arguments of L[2] may again be such descriptions and
# L[2] can be an empty list.
MakeCode := function(L)
#beware: this is the most beautiful function in GUAVA (according to J)
if IsList(L) and IsBound(L[1]) and IsFunction(L[1]) then
return CallFuncList( L[1], List( L[2], i -> MakeCode(i) ) );
else
return L;
fi;
end;
if not IsBound(bds.construction) then
bds := BoundsMinimumDistance(bds.n, bds.k, bds.q);
fi;
if bds.construction = false then
Print("Code not yet in library\n");
return fail;
else
C := MakeCode(bds.construction);
if LowerBoundMinimumDistance(C) > bds.lowerBound then
Print("New table entry found!\n");
fi;
C!.lowerBoundMinimumDistance := Maximum(bds.lowerBound,
LowerBoundMinimumDistance(C));
C!.upperBoundMinimumDistance := Minimum(bds.upperBound,
UpperBoundMinimumDistance(C));
return C;
fi;
end);
InstallOtherMethod(BestKnownLinearCode, "n, k, q", true,
[IsInt, IsInt, IsInt], 0,
function(n, k, q)
local r;
r := BoundsMinimumDistance(n, k, q);
return BestKnownLinearCode(r);
end);
InstallOtherMethod(BestKnownLinearCode, "n, k, F", true,
[IsInt, IsInt, IsField], 0,
function(n, k, F)
local r;
r := BoundsMinimumDistance(n, k, Size(F));
return BestKnownLinearCode(r);
end);
InstallOtherMethod(BestKnownLinearCode, "n, k", true,
[IsInt, IsInt], 0,
function(n, k)
local r;
r := BoundsMinimumDistance(n, k);
return BestKnownLinearCode(r);
end);
## Helper functions for cyclic code creation
GeneratorMatrixFromPoly := function(p,n)
local coeffs, j, res, r, zero;
coeffs := CoefficientsOfLaurentPolynomial(p);
coeffs := ShiftedCoeffs(coeffs[1], coeffs[2]);
r := DegreeOfLaurentPolynomial(p);
zero := Zero(Field(coeffs));
res := [];
res[1] := [];
# first row
Append(res[1], coeffs);
Append(res[1], List([r+2..n], i->zero));
# 2..last-1
if n-r > 2 then
for j in [2..(n-r-1)] do
res[j] := [];
Append(res[j], List([1..j-1], i->zero));
Append(res[j], coeffs);
Append(res[j], List([r+1+j..n], i->zero));
od;
fi;
# last row
if n-r > 1 then
res[n-r] := [];
Append(res[n-r], List([1..n-r-1], i->zero));
Append(res[n-r], coeffs);
fi;
return res;
end;
CyclicCodeByGenerator := function(F, n, G)
local C, GM;
## for now, using linear code representation.
## Get generator matrix and call linear code creation function
## Note input is a codeword, for consistency.
## Further note GenMatFromPoly doesn't handle NullPoly case well,
## so calling NullMat instead. Once using poly rep, this should be
## unnecessary.
## And GMFP doesn't handle p = x^n-1 case.
if (G = NullWord(n,F)) or
(VectorCodeword(G) = []) or
(G = Codeword(Indeterminate(F)^n-One(F), F)) then
GM := NullMat(1,n,F);
else
GM := GeneratorMatrixFromPoly(PolyCodeword(G), n);
fi;
C := LinearCodeByGenerators(F, Codeword(One(F)*GM, F));
#C := LinearCodeByGenerators(F, One(F)*GM);
SetGeneratorMat(C, GM);
SetIsCyclicCode(C, true);
SetSpecialDecoder(C, CyclicDecoder);
return C;
end;
#############################################################################
##
#F GeneratorPolCode( <G>, <n> [, <name> ], <F> ) . code from generator poly
##
InstallMethod(GeneratorPolCode, "Poly, wordlength,name,field", true,
[IsUnivariatePolynomial, IsInt, IsString, IsField], 0,
function(G, n, name, F)
local R;
#G := PolyCodeword( Codeword(G, F) );
if not IsZero(G) then
G := Gcd(G,(Indeterminate(F)^n-One(F)));
fi;
R := CyclicCodeByGenerator(F, n, Codeword(G, F));
SetGeneratorPol(R, G);
R!.name := name;
return R;
end);
InstallOtherMethod(GeneratorPolCode, "Poly,wordlength,field", true,
[IsUnivariatePolynomial, IsInt, IsField], 0,
function(G, n, F)
return GeneratorPolCode(G,n,"code defined by generator polynomial", F);
end);
InstallOtherMethod(GeneratorPolCode, "Poly,wordlength,name,fieldsize", true,
[IsUnivariatePolynomial, IsInt, IsString, IsInt], 0,
function(G, n, name, q)
return GeneratorPolCode(G, n, name, GF(q));
end);
InstallOtherMethod(GeneratorPolCode, "Poly, wordlength, fieldsize", true,
[IsUnivariatePolynomial, IsInt, IsInt], 0,
function(G, n, q)
return GeneratorPolCode(G, n, "code defined by generator polynomial",
GF(q));
end);
#############################################################################
##
#F CheckPolCode( <H>, <n> [, <name> ], <F> ) . . code from check polynomial
##
InstallMethod(CheckPolCode, "check poly, wordlength, name, field", true,
[IsUnivariatePolynomial, IsInt, IsString, IsField], 0,
function(H, n, name, F)
local R,G;
H := PolyCodeword( Codeword(H, F) );
H := Gcd(H, (Indeterminate(F)^n-One(F)));
# Get generator pol
G := EuclideanQuotient((Indeterminate(F)^n-One(F)), H);
R := CyclicCodeByGenerator(F, n, Codeword(G,F));
SetCheckPol(R, H);
SetGeneratorPol(R, G);
R!.name := name;
return R;
end);
InstallOtherMethod(CheckPolCode, "check poly, wordlength, field", true,
[IsUnivariatePolynomial, IsInt, IsField], 0,
function(H, n, F)
return CheckPolCode(H, n, "code defined by check polynomial", F);
end);
InstallOtherMethod(CheckPolCode, "check poly, wordlength, name, fieldsize",
true, [IsUnivariatePolynomial, IsInt, IsString, IsInt], 0,
function(H, n, name, q)
return CheckPolCode(H, n, name, GF(q));
end);
InstallOtherMethod(CheckPolCode, "check poly, wordlength, fieldsize", true,
[IsUnivariatePolynomial, IsInt, IsInt], 0,
function(H, n, q)
return CheckPolCode(H, n, "code defined by check polynomial", GF(q));
end);
#############################################################################
##
#F RepetitionCode( <n> [, <F>] ) . . . . . . . repetition code of length <n>
##
InstallMethod( RepetitionCode, "wordlength, Field", true, [IsInt, IsField], 0,
function(n, F)
local C, q, wd, p;
q :=Size(F);
p := LaurentPolynomialByCoefficients( ElementsFamily(FamilyObj(F)),
List([1..n], t->One(F)), 0);
C := GeneratorPolCode(p, n, "repetition code", F);
C!.lowerBoundMinimumDistance := n;
C!.upperBoundMinimumDistance := n;
if n = 2 and q = 2 then
SetIsSelfDualCode(C, true);
else
SetIsSelfDualCode(C, false);
fi;
wd := NullVector(n+1);
wd[1] := 1;
wd[n+1] := q-1;
SetWeightDistribution(C, wd);
if n < 260 then
SetAutomorphismGroup(C, SymmetricGroup(n));
fi;
if F = GF(2) then
SetIsNormalCode(C, true);
fi;
if (n mod 2 = 0) or (F <> GF(2)) then
SetIsPerfectCode(C, false);
C!.boundsCoveringRadius := [ Minimum(n-1,QuoInt((q-1)*n,q)) ];
else
C!.boundsCoveringRadius := [ QuoInt(n,2) ];
SetIsPerfectCode(C, true);
fi;
return C;
end);
InstallOtherMethod(RepetitionCode, "wordlength, fieldsize", true,
[IsInt, IsInt], 0,
function(n, q)
return RepetitionCode(n, GF(q));
end);
InstallOtherMethod(RepetitionCode, "wordlength", true, [IsInt], 0,
function(n)
return RepetitionCode(n, GF(2));
end);
#############################################################################
##
#F WholeSpaceCode( <n> [, <F>] ) . . . . . . . . . . returns <F>^<n> as code
##
InstallMethod(WholeSpaceCode, "wordlength, Field", true, [IsInt, IsField], 0,
function(n, F)
local C, index, q;
C := GeneratorPolCode( Indeterminate(F)^0, n, "whole space code", F);
C!.lowerBoundMinimumDistance := 1;
C!.upperBoundMinimumDistance := 1;
SetAutomorphismGroup(C, SymmetricGroup(n));
C!.boundsCoveringRadius := [ 0 ];
if F = GF(2) then
SetIsNormalCode(C, true);
fi;
SetIsPerfectCode(C, true);
SetIsSelfDualCode(C, false);
q := Size(F) - 1;
SetWeightDistribution(C, List([0..n], i-> q^i*Binomial(n, i)) );
return C;
end);
InstallOtherMethod(WholeSpaceCode, "wordlength, fieldsize", true,
[IsInt, IsInt], 0,
function(n, q)
return WholeSpaceCode(n, GF(q));
end);
InstallOtherMethod(WholeSpaceCode, "wordlength", true, [IsInt], 0,
function(n)
return WholeSpaceCode(n, GF(2));
end);
#############################################################################
##
#F CyclicCodes( <n> ) . . returns a list of all cyclic codes of length <n>
##
InstallMethod(CyclicCodes, "wordlength, Field", true,
[IsInt, IsField], 0,
function(n, F)
local f, Pl;
f := Factors(Indeterminate(F) ^ n - One(F));
Pl := List(Combinations(f), c->Product(c)*Indeterminate(F)^0);
return List(Pl, p->GeneratorPolCode(p, n, "enumerated code", F));
end);
InstallOtherMethod(CyclicCodes, "wordlength, k, Field", true,
[IsInt, IsInt, IsField], 0,
function(n, k, F)
local r, f, Pl, codes;
r := n - k;
f := Factors(Indeterminate(F)^n-One(F));
Pl := [];
codes := function(f, g)
local i, tempf;
if Degree(g) < r then
i := 1;
while i <= Length(f) and Degree(g)+Degree(f[i][1]) <= r do
if f[i][2] = 1 then
tempf := f{[ i+1 .. Length(f) ]};
else
tempf := ShallowCopy( f );
tempf[i][2] := f[i][2] - 1;
fi;
codes( tempf, g * f[i][1] );
i := i + 1;
od;
elif Degree(g) = r then
Add( Pl, g );
fi;
end;
codes( Collected( f ), Indeterminate(F)^0 );
return List(Pl, p->GeneratorPolCode(p,n,"enumerated code",F));
end);
InstallOtherMethod(CyclicCodes, "wordlength, fieldsize", true,
[IsInt, IsInt], 0,
function(n, q)
return CyclicCodes(n, GF(q));
end);
InstallOtherMethod(CyclicCodes, "wordlength, k, fieldsize", true,
[IsInt, IsInt, IsInt], 0,
function(n, k, q)
return CyclicCodes(n, k, GF(q));
end);
#############################################################################
##
#F NrCyclicCodes( <n>, <F>) . . . number of cyclic codes of length <n>
##
InstallMethod(NrCyclicCodes, "wordlength, Field", true, [IsInt, IsField], 0,
function(n, F)
return NrCombinations(Factors(Indeterminate(F)^n-One(F)));
end);
InstallOtherMethod(NrCyclicCodes, "wordlength, fieldsize", true,
[IsInt, IsInt], 0,
function(n, q)
return NrCyclicCodes(n, GF(q));
end);
#############################################################################
##
#F BCHCode( <n> [, <b>], <delta> [, <F>] ) . . . . . . . . . . . . BCH code
##
## BCHCode (n [, b ], delta [, F]) returns the BCH code over F with
## wordlength n, designedDistance delta, constructed from powers
## x^b, x^(b+1), ..., x^(b+delta-2), where x is a primitive n'th power root
## of unity; b = 1 by default; the function returns a narrow sense BCH code
## Gcd(n,q) = 1 and 2<=delta<=n-b+1
InstallMethod(BCHCode, "wordlength, start, designed distance, fieldsize", true,
[IsInt, IsInt, IsInt, IsInt], 0,
function(n, start, del, q)
local stop, m, b, C, test, Cyclo, PowerSet, t,
zero, desdist, G, superfl, i, BCHTable;
BCHTable := [ [31,11,11], [63,36,11], [63,30,13], [127,92,11],
[127,85,13], [255,223,9], [255,215,11], [255,207,13],
[255,187,19], [255,171,23], [255,155,27], [255,99,47],
[255,79,55], [255,29,95], [255,21,111] ];
########### increase size of table? - wdj
stop := start + del - 2;
if Gcd(n,q) <> 1 then
Error ("n and q must be relative primes");
fi;
zero := Zero(GF(q));
m := OrderMod(q,n);
b := PrimitiveUnityRoot(q,n);
PowerSet := [start..stop];
G := Indeterminate(GF(q))^0;
while Length(PowerSet) > 0 do
test := PowerSet[1] mod n; ############### changed 8-1-2004
G := G * MinimalPolynomial(GF(q), b^test);
t := (q*test) mod n;
while t <> (test mod n) do ############### changed 7-31-2004
RemoveSet(PowerSet, t);
t := (q*t) mod n;
od;
RemoveSet(PowerSet, test);
od;
######################################
###### This loop computes the product of the
###### min polys of the elements when it should only
###### compute the lcm of them
###### Why not use cyclotomic codests and roots of code?
######################################
C := GeneratorPolCode(G, n, GF(q));
########### this removes extra powers by taking the gcd with x^n-1
SetSpecialDecoder(C, BCHDecoder);
########### this overwrites SetSpecialDecoder(C, CyclicDecoder);
# Calculate Bose distance:
Cyclo := CyclotomicCosets(q,n);
######## why not do this in the above loop?
PowerSet := [];
for t in [start..stop] do
for test in [1..Length(Cyclo)] do
if (t mod n) in Cyclo[test] then ##### added 8-1-2004
AddSet(PowerSet, Cyclo[test]);
fi;
od;
od;
PowerSet := Flat(PowerSet);
while stop + 1 in PowerSet do
stop := stop + 1;
od;
while start - 1 in PowerSet do
start := start - 1;
od;
desdist := stop - start + 2;
if desdist > n then
Error("invalid designed distance");
fi;
# In some cases the true minimumdistance is known:
SetDesignedDistance(C, desdist);
C!.lowerBoundMinimumDistance := desdist;
if (q=2) and (n mod desdist = 0) and (start = 1) then
C!.upperBoundMinimumDistance := desdist;
elif q=2 and desdist mod 2 = 0 and (n=2^m - 1) and (start=1) and
(Sum(List([0..QuoInt(desdist-1, 2) + 1], i -> Binomial(n, i))) >
(n + 1) ^ QuoInt(desdist-1, 2)) then
C!.upperBoundMinimumDistance := desdist;
elif (n = q^m - 1) and (desdist = q^OrderMod(q,desdist) - 1)
and (start=1) then
C!.upperBoundMinimumDistance := desdist;
fi;
# Look up this code in the table
########## table only for q=2^r, add this to if statement
########## to speed this up ?? - wdj
if start=1 then
for i in BCHTable do
if i[1] = n and i[2] = Dimension(C) then
C!.lowerBoundMinimumDistance := i[3];
C!.upperBoundMinimumDistance := i[3];
fi;
od;
fi;
# Calculate minimum of q*desdist - 1 for primitive n.s. BCH code
if q^m - 1 = n and start = 1 then
PowerSet := [start..stop];
superfl := true;
i := PowerSet[Length(PowerSet)] * q mod n;
while superfl do
while i <> PowerSet[Length(PowerSet)] and not i in PowerSet do
i := i * q mod n;
od;
if i = PowerSet[Length(PowerSet)] then
superfl := false;
else
PowerSet := PowerSet{[1..Length(PowerSet)-1]};
i := PowerSet[Length(PowerSet)] * q mod n;
fi;
od;
C!.upperBoundMinimumDistance := Minimum(UpperBoundMinimumDistance(C),
q * (Length(PowerSet) + 1) - 1);
fi;
C!.name := Concatenation("BCH code, delta=",
String(desdist), ", b=", String(start));
return C;
end);
InstallOtherMethod(BCHCode, "wordlength, start, designed distance, Field",
true, [IsInt, IsInt, IsInt, IsField], 0,
function(n, b, del, F)
return BCHCode(n, b, del, Size(F));
end);
InstallOtherMethod(BCHCode, "wordlength, designed distance", true,
[IsInt, IsInt], 0,
function(n, del)
return BCHCode(n, 1, del, 2);
end);
InstallOtherMethod(BCHCode, "wordlength, start, designed distance", true,
[IsInt, IsInt, IsInt], 0,
function(n, b, del)
return BCHCode(n, b, del, 2);
end);
InstallOtherMethod(BCHCode, "wordlength, designed distance, field", true,
[IsInt, IsInt, IsField], 0,
function(n, del, F)
return BCHCode(n, 1, del, Size(F));
end);
#############################################################################
##
#F ReedSolomonCode( <n>, <d> ) . . . . . . . . . . . . . . Reed-Solomon code
##
## ReedSolomonCode (n, d) returns a primitive narrow sense BCH code with
## wordlength n, over alphabet q = n+1, designed distance d
InstallMethod(ReedSolomonCode, "wordlength, designed distance", true,
[IsInt, IsInt], 0,
function(n, d)
local C,b,q,wd,w;
q := n+1;
if not IsPrimePowerInt(q) then
Error("q = n+1 must be a prime power");
fi;
b := Z(q);
C := GeneratorPolCode(Product([1..d-1], i-> (Indeterminate(GF(q))-b^i)), n,
"Reed-Solomon code", GF(q) );
SetRootsOfCode(C, List([1..d-1], i->b^i));
C!.lowerBoundMinimumDistance := d;
C!.upperBoundMinimumDistance := d;
SetDesignedDistance(C, d);
SetSpecialDecoder(C, BCHDecoder);
IsMDSCode(C); # Calculate weightDistribution field
return C;
end);
InstallMethod(ExtendedReedSolomonCode, "wordlength, designed distance", true,
[IsInt, IsInt], 0,
function(n, d)
local i, j, s, C, G, Ce;
C := ReedSolomonCode(n-1, d-1);
G := MutableCopyMatrix( GeneratorMat(C) );
TriangulizeMat(G);
for i in [1..Size(G)] do;
s := 0;
for j in [1..Size(G[i])] do;
s := s + G[i][j];
od;
Append(G[i], [-s]);
od;
Ce := GeneratorMatCodeNC(G, LeftActingDomain(C));
Ce!.name := "extended Reed Solomon code";
Ce!.lowerBoundMinimumDistance := d;
Ce!.upperBoundMinimumDistance := d;
IsMDSCode(Ce);
return Ce;
end);
## RootsCode implementation expunged and rewritten for Guava 3.11
## J. E. Fields 1/15/2012 (with help from WDJ)
#############################################################################
##
#F RootsCode( <n>, <list>, <field> ) code constructed from roots of polynomial
##
## RootsCode (n, rootlist, F) or RootsCode (n, <powerlist>, fieldsize) or
## RootsCode(n, rootlist) returns the
## code with generator polynomial equal to the least common multiple of
## the minimal polynomials of the n'th roots of unity in the list.
## The code has wordlength n.
##
InstallMethod(RootsCode, "method for n, rootlist, field", true, [IsInt, IsList, IsField], 0,
function(n, L, F)
local g, C, num, power, p, q, z, i, j, rootslist, powerlist, max, cc, CC, CCz;
L := Set(L);
q := Size(Field(L));
z := Z(q);
g:=One(F);
if List(L, i->i^n) <> NullVector(Length(L), F) + z^0 then
Error("powers must all be n'th roots of unity");
fi;
p := Characteristic(Field(L));
CC:=CyclotomicCosets(p,q-1);
CCz:=List([1..Length(CC)],i->List(CC[i],j->z^j));
## this is the set of cyclotomic cosets, represented
## as powers of a primitive element z
powerlist := [];
for i in [1..Length(L)] do
for cc in CCz do
if L[i] in cc then
Append(powerlist,[cc]);
fi;
od;
od;
########### add a cyclotomic coset into powerlist
########### if there is an element of L in that coset
g:=Product([1..Length(powerlist)],i->MinimalPolynomial(F,powerlist[i][1]));
C:=GeneratorPolCode(g,n,"code defined by roots",F);
rootslist := [];
for cc in powerlist do
Append(rootslist, cc);
od;
rootslist := Set(rootslist);
SetRootsOfCode(C, rootslist);
# Find the largest number of successive powers for BCH bound
max := 1;
i := 1;
num := Length(powerlist);
for z in [2..num] do
if powerlist[z] <> powerlist[i] + z-i then
max := Maximum(max, z - i);
i := z;
fi;
od;
C!.lowerBoundMinimumDistance := Maximum(max, num+1 - i) + 1;
return C;
end);
InstallOtherMethod(RootsCode, "method for n, rootlist", true, [IsInt, IsList], 0,
function(n, L)
local p,q,z,L1,L2,F;
L1 := Set(L);
p := Characteristic(Field(L1));
z := Z(Size(Field(L1)));
F := GF(p);
#L2 := List([1..Length(L1)],i-> LogFFE(L[i],z));
#Print(L1, p, z, F, L2);
return RootsCode(n, L1, F);
end);
InstallOtherMethod(RootsCode, "method for n, powerlist, fieldsize", true, [IsInt, IsList, IsInt], 0,
function(n, P, q)
# , "method for n, powerlist, fieldsize", true, [IsInt, IsList, IsInt], 0,
local z, L;
z := PrimitiveUnityRoot(q,n);
L := Set(List(P, i->z^i));
return RootsCode(n, L, GF(q));
end);
#############################################################################
##
#F QRCode( <n> [, <F>] ) . . . . . . . . . . . . . . quadratic residue code
##
InstallMethod(QRCode, "modulus, fieldsize", true, [IsInt, IsInt], 0,
function(n, q)
local m, b, Q, N, t, g, lower, upper, C, F, coeffs;
if Jacobi(q,n) <> 1 then
Error("q must be a quadratic residue modulo n");
elif not IsPrimeInt(n) then
Error("n must be a prime");
elif not IsPrimeInt(q) then
Error("q must be a prime");
fi;
m := OrderMod(q,n);
F := GF(q^m);
b := PrimitiveUnityRoot(q,n);
Q := [];
N := [1..n];
for t in [1..n-1] do
AddSet(Q, t^2 mod n);
od;
for t in Q do
RemoveSet(N, t);
od;
g := Product(Q,
i -> LaurentPolynomialByCoefficients(ElementsFamily(FamilyObj(F)),
[-b^i, b^0], 0) );
coeffs := CoefficientsOfLaurentPolynomial(g);
coeffs := ShiftedCoeffs(coeffs[1], coeffs[2]);
C := GeneratorPolCode( LaurentPolynomialByCoefficients(
ElementsFamily(FamilyObj(GF(q))), coeffs, 0),
n, "quadratic residue code", GF(q) );
if RootInt(n)^2 = n then
lower := RootInt(n);
else
lower := RootInt(n)+1;
fi;
if n mod 4 = 3 then
while lower^2-lower+1 < n do
lower := lower + 1;
od;
fi;
if (n mod 8 = 7) and (q = 2) then
while lower mod 4 <> 3 do
lower := lower + 1;
od;
fi;
upper := Weight(Codeword(coeffs));
C!.lowerBoundMinimumDistance := lower;
C!.upperBoundMinimumDistance := upper;
return C;
end);
InstallOtherMethod(QRCode, "modulus, field", true, [IsInt, IsField], 0,
function(n, F)
return QRCode(n, Size(F));
end);
InstallOtherMethod(QRCode, "modulus", true, [IsInt], 0,
function(n)
return QRCode(n, 2);
end);
#############################################################################
##
#F QQRCode( <n> [, <F>] ) . . . . . . . . binary quasi-quadratic residue code
##
## Code of Bazzi-Mittel (see Bazzi, L. and Mitter, S.K. "Some constructions of
## codes from group actions" preprint March 2003 (submitted to IEEE IT)
##
InstallMethod(QQRCode, "Modulus", true, [IsInt], 0,
function(p)
local G0,G,Q,N,QN,i,C,F,QuadraticResidueSupports,NonQuadraticResidueSupports;
# start local functions:
QuadraticResidueSupports:=function(p)
local L,i;
L:=List([1..(p-1)],i->1+Legendre(i,p))/2;
return L;
end;
NonQuadraticResidueSupports:=function(p)
local L,i;
L:=List([1..(p-1)],i->1-Legendre(i,p))/2;
return L;
end;
# end local functions
F:=GF(2);
Q:=[Zero(F)];
Q:=One(F)*Concatenation(Q,QuadraticResidueSupports(p));
N:=[Zero(F)];
N:=One(F)*Concatenation(N,NonQuadraticResidueSupports(p));
QN:=Concatenation(Q,N);
G:=BlockMatrix([[1,1,CirculantMatrix(p,Q)],[1,2,CirculantMatrix(p,N)]],1,2);
if p mod 4 = 1 then
G0:=List([1..(p-1)],i->G[i]);
else
G0:=MatrixByBlockMatrix(G);
fi;
C:=GeneratorMatCode(G0,F);
C!.DoublyCirculant:=G0;
C!.GeneratorMat:=G0;
return C;
end);
#############################################################################
##
#F QQRCodeNC( <n> [, <F>] ) . . . . . . . . binary quasi-quadratic residue code
##
## Code of Bazzi-Mittel (see Bazzi, L. and Mitter, S.K. "Some constructions of
## codes from group actions" preprint March 2003 (submitted to IEEE IT)
##
InstallMethod(QQRCodeNC, "Modulus", true, [IsInt], 0,
function(p)
local G,G0,Q,N,QN,i,C,F,QuadraticResidueSupports,NonQuadraticResidueSupports;
# start local functions:
QuadraticResidueSupports:=function(p)
local L,i;
L:=List([1..(p-1)],i->1+Legendre(i,p))/2;
return L;
end;
NonQuadraticResidueSupports:=function(p)
local L,i;
L:=List([1..(p-1)],i->1-Legendre(i,p))/2;
return L;
end;
# end local functions
F:=GF(2);
Q:=[Zero(F)];
#Q:=[];
Q:=One(F)*Concatenation(Q,QuadraticResidueSupports(p));
N:=[Zero(F)];
#N:=[];
N:=One(F)*Concatenation(N,NonQuadraticResidueSupports(p));
#QN:=Concatenation(Q,N);
G:=BlockMatrix([[1,1,CirculantMatrix(p,N)],[1,2,CirculantMatrix(p,Q)]],1,2);
if p mod 4 = 1 then
G0:=List([1..(p-1)],i->G[i]);
else
G0:=MatrixByBlockMatrix(G);
fi;
C:=GeneratorMatCodeNC(G0,F);
C!.DoublyCirculant:=G0;
C!.GeneratorMat:=G0;
return C;
end);
#############################################################################
##
#F NullCode( <n> [, <F>] ) . . . . . . . . . . . code consisting only of <0>
##
InstallMethod(NullCode, "wordlength, field", true, [IsInt, IsField], 0,
function(n, F)
local C;
C := ElementsCode([NullWord(n,F)], "nullcode", F);
C!.lowerBoundMinimumDistance := n;
C!.upperBoundMinimumDistance := n;
SetMinimumDistance(C, n);
SetWeightDistribution(C, Concatenation([1], NullVector(n)));
SetAutomorphismGroup(C, SymmetricGroup(n));
C!.boundsCoveringRadius := [ n ];
SetCoveringRadius(C, n);
IsCyclicCode(C); # will set all basic linear and cyclic code info
return C;
end);
InstallOtherMethod(NullCode, "wordlength, fieldsize", true, [IsInt, IsInt], 0,
function(n, q)
return NullCode(n, GF(q));
end);
InstallOtherMethod(NullCode, "wordlength", true, [IsInt], 0,
function(n)
return NullCode(n, GF(2));
end);
#############################################################################
##
#F FireCode( <G>, <b> ) . . . . . . . . . . . . . . . . . . . . . Fire code
##
## FireCode (G, b) constructs the Fire code that is capable of correcting any
## single error burst of length b or less.
## G is a primitive polynomial of degree m
##
InstallMethod(FireCode, "poly, burstlength", true,
[IsUnivariatePolynomial, IsInt], 0,
function(G, b)
local m, C, n;
G := PolyCodeword(Codeword(G));
if CoefficientsRing(DefaultRing(G)) <> GF(2) then
Error("polynomial must be over GF(2)");
fi;
if Length(Factors(G)) <> 1 then
Error("polynomial G must be primitive");
fi;
m := DegreeOfLaurentPolynomial(G);
n := Lcm(2^m-1,2*b-1);
C := GeneratorPolCode( G*(Indeterminate(GF(2))^(2*b-1) + One(GF(2))), n,
Concatenation(String(b), " burst error correcting fire code"),
GF(2) );
return C;
end);
#############################################################################
##
#F BinaryGolayCode( ) . . . . . . . . . . . . . . . . . . binary Golay code
##
InstallMethod(BinaryGolayCode, "only method", true, [], 0,
function()
local p,C;
p := LaurentPolynomialByCoefficients(
ElementsFamily(FamilyObj(GF(2))),
Z(2)^0*[1,0,1,0,1,1,1,0,0,0,1,1], 0);
C := CyclicCodeByGenerator(GF(2), 23, Codeword(p));
SetGeneratorPol(C, p);
SetDimension(C, 12);
SetRedundancy(C, 11);
SetSize(C, 2^12);
C!.name := "binary Golay code";
C!.lowerBoundMinimumDistance := 7;
C!.upperBoundMinimumDistance := 7;
SetWeightDistribution(C,
[1,0,0,0,0,0,0,253,506,0,0,1288,1288,0,0,506,253,0,0,0,0,0,0,1]);
C!.boundsCoveringRadius := [ 3 ];
SetIsNormalCode(C, true);
SetIsPerfectCode(C, true);
return C;
end);
#############################################################################
##
#F TernaryGolayCode( ) . . . . . . . . . . . . . . . . . ternary Golay code
##
InstallMethod(TernaryGolayCode, "only method", true, [], 0,
function()
local p, C;
p := LaurentPolynomialByCoefficients(ElementsFamily(FamilyObj(GF(3))),
Z(3)^0*[2,0,1,2,1,1], 0);
C := CyclicCodeByGenerator(GF(3), 11, Codeword(p));
C!.name := "ternary Golay code";
SetGeneratorPol(C, p);
SetRedundancy(C, 5);
SetDimension(C, 6);
SetSize(C, 3^6);
C!.lowerBoundMinimumDistance := 5;
C!.upperBoundMinimumDistance := 5;
SetWeightDistribution(C, [1,0,0,0,0,132,132,0,330,110,0,24]);
SetIsNormalCode(C, true);
SetIsPerfectCode(C, true);
return C;
end);
#############################################################################
##
#F EvaluationCode( <P>, <L>, <R> )
##
## P is a list of n points in F^r
## L is a list of rational functions in r variables
## EvaluationCode returns the image of the evaluation map f->[f(P1),...,f(Pn)],
## as f ranges over the vector space of functions spanned by L.
## The output is the code whose generator matrix has rows (f(P1)...f(Pn)) where
## f is in L and P={P1,..,Pn}
##
InstallMethod(EvaluationCode,"points, basis functions, multivariate poly ring", true,
[IsList, IsList, IsRing], 0,
function(P,L,R)
local i, G, n, C, j, k, varsn,varsd, vars, F, ValueExtended;
#######################
ValueExtended:=function(f,vars,pt)
local df, nf;
df:=DenominatorOfRationalFunction(f*vars[1]^0);
nf:=NumeratorOfRationalFunction(f*vars[1]^0);
#if (varsn=[] and varsd=[]) then return f; fi;
return Value(nf,vars,pt)*Value(df,vars,pt)^(-1);
end;
#######################
vars:=IndeterminatesOfPolynomialRing(R);
F:=CoefficientsRing(R);
n:=Length(P);
k:=Length(L);
G:=ShallowCopy(NullMat(k,n,F));
for i in [1..k] do
for j in [1..n] do
G[i][j]:=ValueExtended(L[i],vars,P[j]);
od;
od;
C:=GeneratorMatCode(G," evaluation code",F);
C!.EvaluationMat:=ShallowCopy(G);
C!.basis:=L;
C!.points:=P;
C!.ring:=R;
return C;
end);
#############################################################################
##
#F GeneralizedReedSolomonCode( <P>, <k>, <R> )
##
## P is a list of n points in F
## k is an integer
## GRSCode returns the image of the evaluation map f->[f(P1),...,f(Pn)],
## as f ranges over the vector space of polynomials in 1 variable
## of degree < k in the ring R.
## The output is the code whose generator matrix has rows (f(P1)...f(Pn)) where
## f = x^j, j<k, and P={P1,..,Pn}
##
InstallMethod(GeneralizedReedSolomonCode,"points, basis functions, univariate poly ring", true,
[IsList, IsInt, IsRing], 0,
function(P,k,R)
local p, L, vars, i, F, f, x, C, R0, P0, G, j, n;
n:=Length(P);
F:=CoefficientsRing(R);
G:=NullMat(k,n,F);
vars:=IndeterminatesOfPolynomialRing(R);
x:=vars[1];
L:=List([0..(k-1)],i->(x^i));
for i in [1..k] do
for j in [1..n] do
G[i][j]:=Value(L[i],vars,[P[j]]);
od;
od;
C:=GeneratorMatCode(G," generalized Reed-Solomon code",F);
C!.GeneratorMat:=ShallowCopy(G);
C!.degree:=k;
C!.points:=P;
C!.ring:=R;
SetSpecialDecoder(C, GeneralizedReedSolomonDecoder);
return C;
end);
#############################################################################
##
#F GeneralizedReedSolomonCode( <P>, <k>, <R> , <wts> )
##
## P is a list of n points in F
## k is an integer
## GRSCode returns the image of the evaluation map f->[f(P1),...,f(Pn)],
## as f ranges over the vector space of polynomials in 1 variable
## of degree < k in the ring R.
## The output is the code whose generator matrix has rows (w1*f(P1),...,wn*f(Pn)) where
## f = x^j, j<k, P={P1,..,Pn}, wts=[w1,...,wn] \in F^n
##
InstallOtherMethod(GeneralizedReedSolomonCode,"points, basis functions, univariate poly ring", true,
[IsList, IsInt, IsRing, IsList], 0,
function(P,k,R,wts)
local p, L, vars, i, F, f, x, C, R0, P0, G, j, n;
n:=Length(P);
F:=CoefficientsRing(R);
G:=NullMat(k,n,F);
vars:=IndeterminatesOfPolynomialRing(R);
x:=vars[1];
L:=List([0..(k-1)],i->(x^i));
for i in [1..k] do
for j in [1..n] do
G[i][j]:=wts[j]*Value(L[i],vars,[P[j]]);
od;
od;
C:=GeneratorMatCode(G," weighted generalized Reed-Solomon code",F);
C!.GeneratorMat:=ShallowCopy(G);
C!.degree:=k;
C!.points:=P;
C!.weights:=wts;
C!.ring:=R;
#SetSpecialDecoder(C, GeneralizedReedSolomonDecoder);
return C;
end);
#############################################################################
##
#F OnePointAGCode( <crv>, <pts>, <m>, <R> )
##
## R = F[x,y] is a polynomial ring over a finite field F
## crv is a polynomial in R representing a plane curve
## pts is a list of points on the curve
## Computes the AG codes associated to the RR space
## L(m*infinity) using Proposition VI.4.1 in Stichtenoth
##
InstallMethod(OnePointAGCode,
"polynomial defining planar curve, points, multiplicity, univariate poly ring",
true, [IsPolynomial, IsList, IsInt, IsRing], 0,
function(crv,pts,m,R)
local F,f,indets,pt,i,j,G,C,degx,degy,basisLD,xx,yy,allpts;
indets := IndeterminatesOfPolynomialRing(R);
xx:=indets[1]; yy:=indets[2];
F:=CoefficientsRing(R);
allpts:=AffinePointsOnCurve(crv,R,F);
if not(IsSubset(allpts,pts)) then
Error("The points given must be on the curve\n");
fi;
degx:=DegreeIndeterminate(crv,xx);
degy:=DegreeIndeterminate(crv,yy);
basisLD:=[];
for i in [0..(degx-1)] do
for j in [0..m] do
if degx*j+degy*i<m+1 then
basisLD:=Concatenation([xx^i*yy^j],basisLD);
fi;
od;
od;
G:=List(pts,pt->List(basisLD,f->Value(f,indets,pt)));
C:=GeneratorMatCode(TransposedMat(G)," one-point AG code",F);
C!.GeneratorMat:=ShallowCopy(TransposedMat(G));
C!.multiplicity:=m;
C!.points:=pts;
C!.curve:=crv;
C!.ring:=R;
return C;
end);
# The FerreroDesign stuff was commented out w/ a message about issues when Sonata
# was not installed. Guava now automatically loads Sonata at startup so I'm re-instating
# these functions. -JEF 1/5/2025
#############################################################################
##
#F FerreroDesignCode( <P>, <m> ) ... code from a Ferrero design
##
##
InstallMethod(FerreroDesignCode,
"binary linear code constructed using a Ferrero design",
true, [IsList, IsInt], 0,
function( P,m)
# **Requires the GAP package SONATA**
# Constructs binary linear code arising from the incdence
# matrix of a design associated to a "Ferrero pair" arising
# from a fixed-point-free (fpf) automorphism groups and Frobenius group.
# The designs that we are looking at (from a Frobenius kernel
# of order v and a Frobenius complement of order k) have
# v*(v-1)/k distinct blocks and they are all of size k.
# Moreover each of the v points occurs in exactly v-1distinct
# blocks. Hence the rows and the columns of the incidence
# matrix M of the design are always of constant weight.
# Take a Frobenius (G,+) group with kernel K and complement H.
# Consider the design D with point set K and block set
# { a^H + b | a, b in K, a <> 0 }.
# Here a^H denotes the orbit of a under conjugation by elements
# of H. Every planar near-ring design of type "*" can be obtained
# in this way from groups. A group K together with a group of
# automorphism H of K such that the semidirect product KH is a
# Frobenius group with complement H is called a Ferrero pair (K, H)
# in SONATA.
#
# INPUT: P is a list of prime powers describing an abelian group G
# m > 0 is an integer such that G admits a cyclic fpf
# automorphism group of size m
# This means that for all q = p^k in P, OrderMod( p, m ) must divide q
# (see the SONATA documentation for FpfAutomorphismGroupsCyclic).
# OUTPUT: The binary linear code whose generator matrix is the
# incidence matrix of a design associated to a "Ferrero pair" arising
# from the fixed-point-free (fpf) automorphism group of G.
# The pair (H,K) is called a Ferraro pair and the semidirect product KH is a
# Frobenius group with complement H.
# AUTHORS: Peter Mayr and David Joyner
local C, f, H, K, M, D;
LoadPackage("sonata");
f := FpfAutomorphismGroupsCyclic( P, m );
K := f[2];
H := Group( f[1][1] );
D := DesignFromFerreroPair( K, H, "*" );
M := IncidenceMat( D );
C := GeneratorMatCode(M*Z(2), GF(2));
return C;
end);
#Having trouble getting GUAVA to load without errors if
#SONATA is not installed. Uncomment this and reload if you
#have SONATA.
# The function below is now superceded by the method above...
#FerreroDesignCode:=function( P,m)
# local C, f, H, K, M, D;
# LoadPackage("sonata");
# f := FpfAutomorphismGroupsCyclic( P, m );
# K := f[2];
# H := Group( f[1][1] );
# D := DesignFromFerreroPair( K, H, "*" );
# M := IncidenceMat( D );
# C:=GeneratorMatCode(M*Z(2), GF(2));
# return C;
#end;
#############################################################################
##
#F QuasiCyclicCode( <G>, <s>, <F> ) . . . . . . . . . . . quasi cyclic code
##
## QuasiCyclicCode ( <G>, <s>, <F> ) generates a rate 1/m quasi-cyclic
## codes. Note that <G> is a list of univariate polynomial and m is the
## cardinality of this list. The integer s is the size of the circulant
## and it is not necessarily equal to the code dimension, i.e. k <= s.
## The associated field is <F>.
##
InstallMethod(QuasiCyclicCode, "linear quasi-cyclic code", true,
[IsList, IsInt, IsField], 0,
function( L1, s, F )
#
# A rate 1/m quasi-cyclic code contains m circulant matrices, each of
# the same size, and in this case they are all s x s circulant matrices.
# Each circulant can be specified by a univariate polynomial.
#
local i, m, v, M, C;
# Determine the cardinality of the list L1
m:=Size(L1);
if (m < 2) then
Error("The cardinality of <G> must be at least 2\n");
fi;
# Make sure that all the list elements are univariate polynomials
for i in [1..m] do;
if (IsUnivariatePolynomial(L1[i]) = false) then
Error("All list elements must be univariate polynomials\n");
fi;
if (Degree(L1[i]) >= s) then
Error("The degree of the polynomial must be less than s\n");
fi;
od;
# Convert each univariate polynomial into a circulant matrix and
# concatenate them to generate a generator matrix
M:=[];
for i in [1..m] do;
v:=ShallowCopy( CoefficientsOfUnivariatePolynomial(L1[i]) );
Append( v, List([1..(s - (Degree(L1[i])+1))], i->Zero(F)) );
M:=Concatenation( M, CirculantMatrix(s, v) );
od;
C := GeneratorMatCode( TransposedMat(M), F );
C!.name := "quasi-cyclic code";
return C;
end);
InstallOtherMethod(QuasiCyclicCode, "binary linear quasi-cyclic code",
true, [IsList, IsInt], 0,
function( L1, s )
local i, j, m, a, t, v, L2, LUT;
LUT:=[ "000", "001", "010", "011", "100", "101", "110", "111" ];
# Determine the cardinality of the list L1
m := Size(L1);
if (m < 2) then
Error("The cardinality of <G> must be at least 2\n");
fi;
L2 := [];
for i in [1..m] do;
if (IsInt(L1[i]) = false) then
Error("All list elements must be in octal\n");
fi;
a := String(L1[i]);
v := [];
for j in [1..Length(a)] do;
t := INT_CHAR(a[j]) - 48; # Conversion of ASCII character to integer
if (t > 7) then
Error("All list elements must be in octal\n");
fi;
Append(v, LUT[t+1]);
od;
Append(L2, [ReciprocalPolynomial(PolyCodeword(Codeword(v)))]);
od;
return QuasiCyclicCode( L2, s, GF(2) );
end);
#####################################################################
##
#F CyclicMDSCode( <q>, <m>, <k> ) . . . . . . . . . cyclic MDS code
##
## Construct a [q^m + 1, k, q^m - k + 2] cyclic MDS code over GF(q^m)
##
InstallMethod(CyclicMDSCode, "method for linear code", true,
[IsInt, IsInt, IsInt], 0,
function(q, m, k)
local i, j, l, x, a, r, g, G, F, CS, C, dmin;
if (k < 1) or (k > q^m + 1) then
Error("Incorrect parameter, 1 <= k <= q^m+1.\n");
fi;
if IsEvenInt(k) and IsOddInt(q^m) then
Error("Cannot construct such code, k must be odd for odd field size.\n");
fi;
F := GF(q^m);
x := Indeterminate(F, "x");
a := PrimitiveUnityRoot(F, q^m+1); # Primitive (q^m + 1)-st root of unity
CS := CyclotomicCosets(q^m, q^m + 1);
dmin := q^m - k + 2;
# R. Roth's book (Prob. 8.15, pp. 262)
# If q^m is odd, there exists [q^m + 1, k, q^m - k + 2] cyclic MDS codes for
# odd values of k in the range 1 <= k <= q^m. This is because the cyclotomic
# cosets of q^m mod q^m + 1 are
# { 0, [1,q^m], [2,q^m-2], ..., [(q^m-1)/2, (q^m+3)/2], (q^m+1)/2 }.
# There are two single elements in the above cosets, { 0 } and { (q^m+1)/2 }.
# If k is odd, dmin = q^m - k + 2 is even and delta = dmin-1 is odd (BCH bound).
# This can be easily obtained by including either { 0 } or { (q^m+1)/2 }.
# On the other hand, if k is even, dmin is odd and delta is even. With reference
# to the above cyclotomic cosets, we cannot have exactly delta consecutive integers.
# (Does this definitely mean this kind of code cannot be constructed??)
#
# If q^m is even, there exists [q^m + 1, k, q^m - k + 2] cyclic MDS codes for
# any value of k in the range 1 <= k <= q^m+1. This is because the cyclotomic
# cosets of q^m mod q^m + 1 are
# { 0, [1,q^m], [2,q^m-2], ..., [q^m/2, 1 + q^m/2] }.
# Consequently, we can easily construct a set of odd or even consecutive integers
# using the cyclotomic cosets above.
if IsEvenInt(k) then
g := (x + a^0);
r := [ a^0 ];
for i in [1..((dmin-2)/2)] do;
g := g * (x + a^(CS[i+1][1])) * (x + a^(CS[i+1][2]));
r := Concatenation(r, [ a^(CS[i+1][1]), a^(CS[i+1][2]) ]);
od;
else
if IsOddInt(q^m) then
g := (x + a^(CS[Size(CS)][1]));
r := [ a^(CS[Size(CS)][1]) ];
j := Size(CS)-1;
l := (dmin-2)/2;
else
g := 1;
r := [];
j := Size(CS);
l := (dmin-1)/2;
fi;
for i in [0..l-1] do;
g := g * (x + a^(CS[j-i][1])) * (x + a^(CS[j-i][2]));
r := Concatenation(r, [ a^(CS[j-i][1]), a^(CS[j-i][2]) ]);
od;
fi;
G := GeneratorMatrixFromPoly(g, q^m + 1);
C := GeneratorMatCodeNC(G, F);
C!.name := "MDS code";
# We know these bounds as it is an MDS code
C!.lowerBoundMinimumDistance := dmin;
C!.upperBoundMinimumDistance := dmin;
# Tell it that it is a cyclic code
SetIsCyclicCode(C, true);
SetGeneratorPol(C, g);
# Also tell it that it is an MDS code
IsMDSCode(C);
return C;
end);
#######################################################################
##
#F FourNegacirculantSelfDualCode( <ax>, <bx>, <k> ) . . self-dual code
##
## Construct a [2*k, k, d] self-dual code over F using Harada's
## construction. See:
##
## 1. M. Harada and T. Nishimura, "An extremal singly even self
## dual code of length 88", Advances in Mathematics of
## Communications, vol 1, no. 2, pp. 261--267, 2007
##
## 2. M. Harada, W. Holzmann, H. Kharaghani and M. Khorvash,
## "Extremal ternary self-dual codes constructed from
## negacirculant matrices", Graph and Combinatorics, vol 23,
## pp. 401--417, 2007
##
## 3. M. Harada, "An extremal doubly even self-dual code of
## length 112", preprint
##
## The generator matrix of the code has the following form:
##
## - -
## | : A : B |
## G = | I :------:-----|
## | : -B^T : A^T |
## - -
##
## Note that the matrices A, B, A^T and B^T are k/2 * k/2
## negacirculant matrices.
##
__G_FourNegacirculantSelfDualCode := function(ax, bx, k)
local i, v, m, x, FA, FB, A, AT, B, BT, G;
if IsOddInt(k) then
Error("k must be an even integer\n");
fi;
m := k/2;
# Determine field size
FA := Field(VectorCodeword(Codeword(ax)));
FB := Field(VectorCodeword(Codeword(bx)));
if FA <> FB then
Error("Polynomials a(x) and b(x) must have elements from the same field\n");
fi;
x := Indeterminate(FA);
#v := MutableCopyMatrix( CoefficientsOfUnivariatePolynomial(ax) );
#MutableCopyMatrix expects a MATRIX, not a LIST
v := ShallowCopy( CoefficientsOfUnivariatePolynomial(ax) );
Append( v, List([1..(m - (Degree(ax)+1))], i->Zero(FA)) );
A := NegacirculantMatrix(m, v*One(FA));
AT:= TransposedMat(A);
#v := MutableCopyMatrix( CoefficientsOfUnivariatePolynomial(bx) );
#ditto
v := ShallowCopy( CoefficientsOfUnivariatePolynomial(bx) );
Append( v, List([1..(m - (Degree(bx)+1))], i->Zero(FA)) );
B := NegacirculantMatrix(m, v*One(FA));
BT:= TransposedMat(-B);
G := IdentityMat(k, One(FA));
# [ A | B ]
for i in [1..m] do;
Append(G[i], A[i]);
Append(G[i], B[i]);
od;
# [ B^T | A^T ]
for i in [1..m] do;
Append(G[m+i], BT[i]);
Append(G[m+i], AT[i]);
od;
return G;
end;
InstallMethod(FourNegacirculantSelfDualCode, "method for binary linear code", true,
[IsUnivariatePolynomial, IsUnivariatePolynomial, IsInt], 0,
function(ax, bx, k)
local G, C, F;
# Obtain the generator matrix
G := __G_FourNegacirculantSelfDualCode(ax, bx, k);
F := Field(VectorCodeword(Codeword(ax)));
C := GeneratorMatCode(G, "four-negacirculant self-dual code", F);
C!.GeneratorMat := ShallowCopy(G);
if (IsSelfDualCode(C) = false) then
Error("Polynomials a(x) and b(x) do not produce a self-dual code\n");
fi;
return C;
end);
# Faster version - no minimum distance and covering radius estimation
InstallMethod(FourNegacirculantSelfDualCodeNC, "method for binary linear code", true,
[IsUnivariatePolynomial, IsUnivariatePolynomial, IsInt], 0,
function(ax, bx, k)
local G, C, F;
# Obtain the generator matrix
G := __G_FourNegacirculantSelfDualCode(ax, bx, k);
F := Field(VectorCodeword(Codeword(ax)));
C := GeneratorMatCodeNC(G, F);
C!.name := "four-negacirculant self-dual code";
C!.GeneratorMat := ShallowCopy(G);
C!.lowerBoundMinimumDistance := 1;
C!.upperBoundMinimumDistance := k+1;
C!.boundsCoveringRadius := [ 0, WordLength(C) ];
if (IsSelfDualCode(C) = false) then
Error("Polynomials a(x) and b(x) do not produce a self-dual code\n");
fi;
return C;
end);
###########################################################################
##
#F QCLDPCCodeFromGroup( <m>, <j>, <k> ) . . Regular quasi-cyclic LDPC code
##
## Construct a regular (j,k) quasi-cyclic low-density parity-check (LDPC)
## code over GF(2) based on the multiplicative group of integer modulo m.
## If m is a prime, the size of the group is equal to Phi(m) = m - 1,
## otherwise it is equal to Phi(m). For details, refer to the paper by:
##
## R. Tanner, D. Sridhara, A. Sridharan, T. Fuja and D. Costello,
## "LDPC block and convolutional codes based on circulant matrices",
## IEEE Trans. Inform. Theory, vol. 50, no. 12, pp. 2966--2984, 2004
##
## NOTE that j and k must divide Phi(m).
##
InstallMethod(QCLDPCCodeFromGroup, "method for binary linear code", true,
[IsInt, IsInt, IsInt], 0,
function(m, j, k)
local r, c, a, b, p, P, H, M, C, PermutationMatrix;
##
##----------------- start of private functions ---------------------
##
## PermutationMatrix - a private function for QCLDPCCodeFromGroup
PermutationMatrix := function(m, i)
local s, P, L;
if i = 0 or i > m then
Error("invalid value of i, 1 \\le i \\le ", m, "\n");
fi;
P := [];
L := List([1..m], i->Zero(GF(2))); L[i] := One(GF(2));
Append(P, [ L ]);
for s in [2..m] do;
L := RightRotateList(L);
Append(P, [ L ]);
od;
return P;
end;
##
##------------------ end of private functions ----------------------
##
p := Phi(m);
if (p mod j <> 0) then
Error(j, " does not divide ", p, "=Phi(", m, ")\n");
fi;
if (p mod k <> 0) then
Error(k, " does not divide ", p, "=Phi(", m, ")\n");
fi;
a := Position( List([1..m-1], i->OrderMod(i, m) ), k );
b := Position( List([1..m-1], i->OrderMod(i, m) ), j );
P := [];
for r in [0..j-1] do;
Append(P, [ List([0..k-1], i->a^i*b^r mod m) ]);
od;
H := [];
for r in [1..j] do;
M := [];
for c in [1..k] do;
M := TransposedMat( Concatenation( TransposedMat(M), TransposedMat( PermutationMatrix(m, P[r][c]) ) ) );
od;
Append(H, M);
od;
C := CheckMatCode( H, GF(2) );
C!.CheckMat := H;
C!.name := "low-density parity-check code";
C!.upperBoundMinimumDistance := Factorial(j+1);
return C;
end);