Spracherkennung für: .gi vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
#############################################################################
##
#A codeops.gi GUAVA Reinald Baart
#A &Jasper Cramwinckel
#A &Erik Roijackers
## &David Joyner
##
## All the code operations
##
## changes 2003-2004 to MinimumDistance by David Joyner, Aron Foster
## bug in MinimumDistance corrected 9-29-2004 by wdj
## moved Decode and PermutationDecode to decoders.gi on 10-2004
## added HasGeneratorMat to GeneratorMat function 11-2-2004
## another bug in MinimumDistance (discovered by Jason McGowan)
## corrected 11-9-2004 by wdj
## slight changes to MinimumWeightWords (11-26-2005)
## wdj (9-14-2007): bug fix to MinimumDistance
## added MinimumDistanceCodeword
## 20 Dec 07 14:24 (CJ) added IsDoublyEvenCode, IsSinglyEvenCode
## and IsEvenCode functions
## 18 Dec 2008 (wdj) bugfix for MinimumDistanceLeon reported by
## Jorge Ernesto PÉREZ CHAMORRO
##
## 05 Nov 2024 (jef) The infix '+' operation between codes was documented in the manual but apparently never implemented.
## WRONG - it's on line 1382 - it's just not being selected...
#############################################################################
##
#F WordLength( <C> ) . . . . . . . . . . . . length of the codewords of <C>
##
InstallOtherMethod(WordLength, "generic code", true, [IsCode], 0,
function(C)
return WordLength(AsSSortedList(C)[1]) ;
end);
# This comment from GAP3 version.
#In a linear code, the wordlength must always be included
#because the wordlength cannot always be calculated (NullCode)
#
#InstallOtherMethod(WordLength, "method for linear codes", true,
# [IsLinearCode], 0,
#function(C)
# if HasGeneratorMat(C) then
# return Length( GeneratorMat(C)[1] );
# else
# return Length( CheckMat(C)[1] );
# fi;
#end);
#############################################################################
##
#F IsLinearCode( <C> ) . . . . . . . . . . . . . . . checks if <C> is linear
##
## If so, the record fields will be adjusted to the linear type
##
InstallMethod(IsLinearCode, "method for unrestricted codes", true, [IsCode], 0,
function(C)
local gen, k, F, q;
F := LeftActingDomain(C);
q := Size(F);
k := LogInt(Size(C),q);
# first the trivial cases:
if ( HasWeightDistribution(C) and
HasInnerDistribution(C)
and (WeightDistribution(C) <> InnerDistribution(C)) )
or ( q^k <> Size(C) )
or (not NullWord(WordLength(C), F) in C) then
return false; #is cool
else
gen:=BaseMat(VectorCodeword(AsSSortedList(C)));
if Length(gen) <> k then
return false; # is cool as ice
else
SetFilterObj(C, IsLinearCodeRep);
SetGeneratorMat(C, gen);
if Length(gen) = 0 then # special case for Nullcode
SetGeneratorsOfLeftModule(C, [AsSSortedList(C)[1]]);
else
SetGeneratorsOfLeftModule(C, AsList(Codeword(gen,F)));
fi;
if HasInnerDistribution(C) then
SetWeightDistribution(C, InnerDistribution(C));
fi;
return true;
fi;
fi;
end);
InstallOtherMethod(IsLinearCode, "method for generic object", true,
[IsObject], 0,
function(obj)
return IsCode(obj) and IsLinearCode(obj);
end);
#############################################################################
##
#F IsFinite( <C> ) . . . . . . . . . . . . . . . . . . . . . . . . . . . .
##
##
InstallTrueMethod(IsFinite, IsCode);
#############################################################################
##
#F Dimension( <C> ) . . . . . . . . . . . . . . . . . . . . . . . . . . .
##
##
InstallOtherMethod(Dimension, "method for unrestricted codes", true,
[IsCode], 0,
function(C)
if IsLinearCode(C) then
return Dimension(C);
else
Error("dimension is only defined for linear codes");
fi;
end);
InstallOtherMethod(Dimension, "method for linear codes", true,
[IsLinearCode], 0,
function(C)
return Length(GeneratorMat(C));
end);
InstallOtherMethod(Dimension, "method for cyclic codes", true,
[IsCyclicCode], 0,
function(C)
if HasGeneratorPol(C) then
return WordLength(C) - DegreeOfLaurentPolynomial( GeneratorPol(C) );
elif HasCheckPol(C) then
return DegreeOfLaurentPolynomial( CheckPol(C) );
else
Error("Attempting to find the dim of a cyclic code with neither a gen. poly. nor a check poly...\n");
fi;
end);
#############################################################################
##
#F Size( <C> ) . . . . . . . . . . . returns the number of codewords of <C>
##
##
InstallMethod(Size, "method for unrestricted codes", true, [IsCode], 0,
function(C)
return Length(AsSSortedList(C));
end);
#############################################################################
##
#F AsSSortedList( <C> ) . . . . . . . . returns the list of codewords of <C>
## AsList( <C> )
##
## Codes created with ElementsCode must have AsSSortedList set.
## Linear codes use the vector space / FLM method to calculate.
## AsList defaults to AsSSortedList.
InstallMethod(AsList, "method for unrestricted codes", true, [IsCode], 0,
function(C)
return AsSSortedList(C);
end);
#############################################################################
##
#F Redundancy( <C> ) . . . . . . . . . . . . . . . . . . . . . . . . . . .
##
##
InstallMethod(Redundancy, "method for unrestricted codes", true, [IsCode], 0,
function(C)
if IsLinearCode(C) then
return Redundancy(C);
else
Error("redundancy is only defined for linear codes");
fi;
end);
InstallMethod(Redundancy, "method for linear codes", true, [IsLinearCode], 0,
function(C)
return WordLength(C) - Dimension(C);
end);
#############################################################################
##
#F GeneratorMat(C) . . . . . finds the generator matrix belonging to code C
##
## Pre: C should contain a generator or check matrix
##
InstallMethod(GeneratorMat, "method for unrestricted code", true, [IsCode], 0,
function(C)
if IsLinearCode(C) then
return GeneratorMat(C);
else
Error("non-linear codes don't have a generator matrix");
fi;
end);
InstallMethod(GeneratorMat, "method for linear code", true, [IsLinearCode], 0,
function(C)
local G;
if HasGeneratorMat(C) then return C!.GeneratorMat; fi;
if not HasCheckMat( C ) then
return List( BasisVectors( Basis( C ) ), x -> VectorCodeword( x ) );
fi;
if CheckMat(C) = [] then
G := IdentityMat(Dimension(C), LeftActingDomain(C));
elif IsInStandardForm(CheckMat(C), false) then
G := TransposedMat(Concatenation(IdentityMat(
Dimension(C), LeftActingDomain(C) ),
List(-CheckMat(C), x->x{[1..Dimension(C) ]})));
else
G := NullspaceMat(TransposedMat(CheckMat(C)));
fi;
return ShallowCopy(G);
end);
InstallMethod(GeneratorMat, "method for cyclic code", true, [IsCyclicCode], 0,
function(C)
local F, G, p, n, i, R, zero, coeffs;
if HasGeneratorMat(C) then return C!.GeneratorMat; fi;
#To be inspected:
#if HasCheckMat(C) and IsInStandardForm(CheckMat(C), false) then
# G := TransposedMat(Concatenation(IdentityMat(Dimension(C),
# LeftActingDomain(C)),
# List(-CheckMat(C), x->x{[1..Dimension(C)]})));
#else
F := LeftActingDomain(C);
p := GeneratorPol(C);
n := WordLength(C);
G := [];
zero := Zero(F);
coeffs := CoefficientsOfLaurentPolynomial(p);
coeffs := ShiftedCoeffs(coeffs[1], coeffs[2]);
for i in [1..Dimension(C)] do
R := NullVector(i-1, F);
Append(R, coeffs);
Append(R, NullVector(n-Length(R), F));
G[i] := R;
od;
#fi;
return ShallowCopy(G);
end);
#############################################################################
##
#F CheckMat( <C> ) . . . . . . . finds the check matrix belonging to code C
##
## Pre: <C> should be a linear code
##
InstallMethod(CheckMat, "method for unrestricted codes", true, [IsCode], 0,
function(C)
if IsLinearCode(C) then
return CheckMat(C);
else
Error("non-linear codes don't have a check matrix");
fi;
end);
InstallMethod(CheckMat, "method for linear code", true, [IsLinearCode], 0,
function(C)
local H;
if GeneratorMat(C) = [] then
H := IdentityMat(WordLength(C), LeftActingDomain(C));
elif IsInStandardForm(GeneratorMat(C), true) then
H := TransposedMat(Concatenation(List(-GeneratorMat(C),
x-> x{[Dimension(C)+1 .. WordLength(C) ]}),
IdentityMat(Redundancy(C), LeftActingDomain(C) )));
else
H := NullspaceMat(TransposedMat(GeneratorMat(C)));
fi;
return ShallowCopy(H);
end);
InstallMethod(CheckMat, "method for cyclic code", true, [IsCyclicCode], 0,
function(C)
local F, H, p, n, i, R, zero, coeffs;
#if HasGeneratorMat(C) and IsInStandardForm(GeneratorMat(C), true) then
# H := TransposedMat(Concatenation(List(-GeneratorMat(C), x->
# x{[Dimension(C)+1..WordLength(C)]}),
# IdentityMat(Redundancy(C), LeftActingDomain(C))));
#else
F := LeftActingDomain(C);
H := [];
p := CheckPol(C);
p := Indeterminate(F)^Dimension(C)*Value(p,Indeterminate(F)^-1);
n := WordLength(C);
zero := Zero(F);
coeffs := CoefficientsOfLaurentPolynomial(p);
coeffs := ShiftedCoeffs(coeffs[1], coeffs[2]);
for i in [1..Redundancy(C)] do
R := NullVector(i-1, F);
Append(R, coeffs);
Append(R, NullVector(n-Length(R), F));
H[i] := R;
od;
#fi;
return ShallowCopy(H);
end);
#############################################################################
##
#F IsCyclicCode( <C> ) . . . . . . . . . . . . . . . . . . . . . . . . . .
##
InstallOtherMethod(IsCyclicCode, "method for unrestricted codes",
true, [IsCode], 0,
function(C)
if IsLinearCode(C) then
return IsCyclicCode(C);
else
return false;
fi;
end);
InstallMethod(IsCyclicCode, "method for linear codes", true, [IsLinearCode], 0,
function(C)
local C1, F, L, Gp;
F := LeftActingDomain(C);
L := List(GeneratorMat(C),
g->LaurentPolynomialByCoefficients(
ElementsFamily(FamilyObj(F)),One(F)*g, 0 ));
Add(L, Indeterminate(F)^WordLength(C) - One(F));
Gp := Gcd(L);
if Redundancy(C) = DegreeOfLaurentPolynomial(Gp) then
SetGeneratorPol(C, Gp);
return true;
else
return false; #so the code is not cyclic
fi;
end);
InstallOtherMethod(IsCyclicCode, "method for generic objects", true,
[IsObject], 0,
function(obj)
return IsCode(obj) and IsLinearCode(obj) and IsCyclicCode(obj);
end);
#############################################################################
##
#F GeneratorPol( <C> ) . . . . . . . . returns the generator polynomial of C
##
## Pre: C must have a generator or check polynomial
##
InstallMethod(GeneratorPol, "method for unrestricted codes", true, [IsCode], 0,
function(C)
if IsCyclicCode(C) then
return GeneratorPol(C);
else
Error("generator polynomial is only defined for cyclic codes");
fi;
end);
InstallMethod(GeneratorPol, "method for cyclic codes", true, [IsCyclicCode], 0,
function(C)
local F, n;
F := LeftActingDomain(C);
n := WordLength(C);
return EuclideanQuotient(One(F)*(Indeterminate(F)^n-1),CheckPol(C));
end);
#############################################################################
##
#F CheckPol( <C> ) . . . . . . . . returns the parity check polynomial of C
##
## Pre: C must have a generator or check polynomial
##
InstallMethod(CheckPol, "method for unrestricted codes", true, [IsCode], 0,
function(C)
if IsCyclicCode(C) then
return CheckPol(C);
else
Error("generator polynomial is only defined for cyclic codes");
fi;
end);
InstallMethod(CheckPol, "method for cyclic codes", true, [IsCyclicCode], 0,
function(C)
local F, n;
F := LeftActingDomain(C);
n := WordLength(C);
return EuclideanQuotient((Indeterminate(F)^n-One(F)),GeneratorPol(C));
end);
#############################################################################
##
#F MinimumDistanceCodeword( <C> [, <w>] ) . . . . determines a codeword
## having minimum distance to w
## (w= zero vector is the default)
##
##wdj,9-14-2007
InstallMethod(MinimumDistanceCodeword, "attribute method for linear codes", true,
[IsLinearCode], 0,
function(C)
local k, i, j, G, F, zero, AClosestVec, minwt, num, n, closestvec;
F := LeftActingDomain(C);
n := WordLength(C);
zero := Zero(F)*NullVector(n);
G := GeneratorMat(C);
minwt:=n;
closestvec := zero;
for i in [1..Length(G)] do
AClosestVec:=AClosestVectorCombinationsMatFFEVecFFE(G, F, zero, i, 1);
if WeightVecFFE(AClosestVec)<minwt then
minwt := WeightVecFFE(AClosestVec);
closestvec := AClosestVec;
fi;
od;
return(closestvec);
end);
#
# This _was_ an InstallOtherMethod for MinimumDistance but the methods
# for that (including one with the same filter list as this) are encoded
# further down in this file. On close inspection notice that it is
# returning a codeword -- it _should_ have been an InstallOtherMethod
# for MinimumDistanceCodeword -- JEF 6/22/11
#
InstallOtherMethod(MinimumDistanceCodeword, "linear code, word", true,
[IsLinearCode, IsCodeword], 0,
function(C, word)
local k, i, j, G, F, zero, AClosestVec, minwt, num, n, closestvec;
Print("linear code, vector (first in file) \n");
F := LeftActingDomain(C);
n := WordLength(C);
zero := Zero(F)*NullVector(n);
G := GeneratorMat(C);
minwt:=n;
closestvec := word;
for i in [1..Length(G)] do
AClosestVec:=AClosestVectorCombinationsMatFFEVecFFE(G, F, word, i, 1);
if WeightVecFFE(AClosestVec)<minwt then
minwt := WeightVecFFE(AClosestVec);
closestvec := AClosestVec;
fi;
od;
return(closestvec);
end);
#############################################################################
##
#F MinimumDistance( <C> [, <w>] ) . . . . determines the minimum distance
##
## MinimumDistance( <C> ) determines the minimum distance of <C>
## MinimumDistance( <C>, <w> ) determines the minimum distance to a word <w>
##
InstallMethod(MinimumDistance, "attribute method for unrestricted codes", true,
[IsCode], 0,
function(C)
local W, El, F, n, zero, d, DD, w;
#Print("unrestricted code\n");
if IsBound(C!.upperBoundMinimumDistance) and
IsBound(C!.lowerBoundMinimumDistance) and
C!.upperBoundMinimumDistance = C!.lowerBoundMinimumDistance then
return C!.lowerBoundMinimumDistance;
elif IsCyclicCode(C) or IsLinearCode(C) then
return MinimumDistance(C);
fi;
W := VectorCodeword(AsSSortedList(C));
El := W; # so not a copy!
F := LeftActingDomain(C);
n := WordLength(C);
zero := Zero(F);
d := n;
DD := NullVector(n+1);
for w in W do
DD := DD + DistancesDistributionVecFFEsVecFFE(El, w);
od;
d := PositionProperty([2..n+1], i->DD[i] <> 0);
C!.lowerBoundMinimumDistance := d;
C!.upperBoundMinimumDistance := d;
return d;
end);
InstallMethod(MinimumDistance, "attribute method for linear codes", true,
[IsLinearCode], 0,
function(C)
local k, i, j, G, F, zero, AClosestVec, minwt, num, n;
if IsBound(C!.upperBoundMinimumDistance) and
IsBound(C!.lowerBoundMinimumDistance) and
C!.upperBoundMinimumDistance = C!.lowerBoundMinimumDistance then
return C!.lowerBoundMinimumDistance;
fi;
F := LeftActingDomain(C);
n := WordLength(C);
zero := Zero(F)*NullVector(n);
G := GeneratorMat(C);
minwt:=n;
for i in [1..Length(G)] do
AClosestVec:=AClosestVectorCombinationsMatFFEVecFFE(G, F, zero, i, 1);
if WeightVecFFE(AClosestVec)<minwt then
minwt := WeightVecFFE(AClosestVec);
fi;
od;
C!.lowerBoundMinimumDistance := minwt;
C!.upperBoundMinimumDistance := minwt;
return(minwt);
end);
InstallMethod(MinimumDistance, "attribute method for cyclic code", true,
[IsCyclicCode], 0,
function(C)
local md;
#Print("cyclic code\n");
if IsBound(C!.lowerBoundMinimumDistance) and
IsBound(C!.upperBoundMinimumDistance) and
C!.lowerBoundMinimumDistance = C!.upperBoundMinimumDistance then
return C!.lowerBoundMinimumDistance;
else
md := MinimumDistance( PuncturedCode( C ) ) + 1;
C!.lowerBoundMinimumDistance := md;
C!.upperBoundMinimumDistance := md;
return md;
fi;
end);
## Should be a better way to set up the Other methods, given
## how much overlap there is with attribute methods. For now, though,
## this works.
InstallOtherMethod(MinimumDistance, "unrestricted code, word", true,
[IsCode, IsCodeword], 0,
function(C, word)
local W, El, F, n, zero, d, w, DD;
#Print("unrestricted code, vector\n");
if IsLinearCode(C) then
return MinimumDistance(C, word);
fi;
if word in C then
return 0;
fi;
W := [VectorCodeword(Codeword(word, C))];
El := VectorCodeword(AsSSortedList(C));
F := LeftActingDomain(C);
n := WordLength(C);
zero := Zero(F);
d := n;
DD := NullVector(n+1);
for w in W do
DD := DD + DistancesDistributionVecFFEsVecFFE(El, w);
od;
d := PositionProperty([2..n+1], i->DD[i] <> 0);
return d;
end);
InstallOtherMethod(MinimumDistance, "linear code, word", true,
[IsLinearCode, IsCodeword], 0,
function(C, word)
local Mat, n, k, zero, UP, G, W, multiple, weight,
ThisGIsDone, #is true as the latest matrix is converted
Icount, #number of corrected generatormatrices
i, #first rownumber which could be added to I
l, #columnnumber which could be used
IdentityColumns,
j, CurW, UMD, w, q, tmp, F;
# Print("linear code, vector (second in file) \n");
k := Dimension(C);
n := WordLength(C);
zero := Zero(LeftActingDomain(C));
q := Size(LeftActingDomain(C));
F := LeftActingDomain(C);
w := VectorCodeword(word);
if w in C then
return 0;
elif k = 0 then
return Weight(Codeword(w));
elif HasSyndromeTable(C) then
j := 1;
w := VectorCodeword( Syndrome(C, w) );
for i in [ 0 .. k - 1 ] do
if w[ k - i ] <> zero then
j := j + q^i * ( LogFFE( w[ k - i ] ) + 1 );
fi;
od;
return Weight(SyndromeTable(C)[j][1]);
fi;
UMD := Weight(Codeword(w));
#this must be so, because the kernel function
#can not find this distance
CurW := 0;
Mat := ShallowCopy(GeneratorMat(C));
i := 1;
## The next lines could go etwas faster for cyclic codes by weighting the
## generator polynomial, but a copy of this function must be made in the
## CycCodeOps, which makes it harder to make changes.
if q = 2 then
multiple := 2;
repeat
weight := 0;
for j in Mat[i] do
if not j = zero then
weight := weight + 1;
fi;
od;
multiple := Gcd( multiple, weight );
i := i + 1;
until multiple = 1 or i > k;
else
multiple := 1;
fi;
# we now know that the weight of all the elements are a multiple of multiple
UP := List([1..n], i->false); #which columns are already used
G := [];
W := [];
Icount := 0;
repeat
ThisGIsDone := false;
i := 1; # i is the row of the identitymatrix it
l := 1; # is trying to make
IdentityColumns := [];
while not ThisGIsDone and (l <= n) do
if not UP[l] then # try this column if it is not already used
j := i;
while (j <= k) and (Mat[j][l] = zero) do
j := j + 1; # go down in the matrix until a nonzero
od; # entry is found
if j <= k then
if j > i then
tmp := Mat[i];
Mat[i] := Mat[j];
Mat[j] := tmp;
fi;
Mat[i] := Mat[i]/Mat[i][l];
for j in Concatenation([1..i-1], [i+1..k]) do
if Mat[j][l] <> zero then
Mat[j] := Mat[j] - Mat[j][l]*Mat[i];
fi;
od;
UP[l] := true;
Add(IdentityColumns, l);
i := i + 1;
ThisGIsDone := ( i > k );
fi;
fi;
l := l + 1;
od;
if ThisGIsDone then
Icount := Icount + 1;
Add( G, Mat{[1..k]}{Difference([1..n],IdentityColumns)} );
w := w-w{IdentityColumns}*Mat;
Add(W,w{Difference([1..n], IdentityColumns)} );
UMD := Minimum( UMD, WeightCodeword( Codeword( w ) ) );
## G_i is generator matrix i
## W_i has zeros in IdentityColumns,
## but has same distance to code because
## only a codeword is added
fi;
until not ThisGIsDone or ( Icount = Int( n / k ) );
while CurW <= ( UMD - multiple ) / Icount do
i := 0;
repeat
i := i + 1;
UMD := Minimum( UMD, DistanceVecFFE( W[i],
AClosestVectorCombinationsMatFFEVecFFE(
G[i], F, W[i], CurW, CurW*(Icount-1) )
) + CurW );
until (i = Length(G)) or (UMD = CurW*Icount);
CurW := CurW + 1;
od;
return UMD;
end);
InstallMethod(MinimumDistanceLeon, "attribute method for linear codes", true,
[IsLinearCode], 0,
function(C)
local majority,G0, Gp, Gpt, Gt, L, k, i, j, dimMat, Grstr, J, d1, arrayd1, Combo, rows, row, rowSum, G, F, zero, AClosestVec, s, p, num;
F:=LeftActingDomain(C);
if F<>GF(2) then Print("Code must be binary. Quitting. \n"); return(0); fi;
G := MutableCopyMatrix(GeneratorMat(C));
if (IsInStandardForm(G)=false) then
PutStandardForm(G);
fi;
p:=5; #these seem to be optimal values
num:=8; #these seem to be optimal values
dimMat := DimensionsMat(G);
s := dimMat[2]-dimMat[1];
arrayd1:=[];
for k in [1..num] do
##Permute the columns randomly
Gt := TransposedMat(G);
Gp := NullMat(dimMat[2],dimMat[1]);
L := SymmetricGroup(dimMat[2]);
L := Random(L);
L:=List([1..dimMat[2]],i->OnPoints(i,L));
for i in [1..dimMat[2]] do
Gp[i] := Gt[L[i]];
od;
Gp := TransposedMat(Gp);
Gp := ShallowCopy(Gp);
##Use gaussian elimination on the new matrix
TriangulizeMat(Gp);
##generate the restricted code (I|Z) from Gp=(I|Z|B)
Gpt := TransposedMat(Gp);
Grstr := NullMat(s,dimMat[1]);
for i in [dimMat[1]+1..dimMat[1]+s] do
Grstr[i-dimMat[1]] := Gpt[i];
od;
Grstr := TransposedMat(Grstr);
zero := Zero(F)*Grstr[1];
##search for all rows of weight p
J := []; #col number of codewords to compute the length of
for i in [1..p] do
AClosestVec:=AClosestVectorCombinationsMatFFEVecFFE(Grstr, F, zero, i, 1);
if WeightVecFFE(AClosestVec) > 0 then
Add(J, [AClosestVec,i]);
fi;
od;
d1:=dimMat[2];
for rows in J do
d1:=Minimum(WeightVecFFE(rows[1])+rows[2],d1);
od;
arrayd1[k]:=d1;
od;
if AbsoluteValue(Sum(arrayd1)/Length(arrayd1)-Int(Sum(arrayd1)/Length(arrayd1)))<1/2 then
majority:=Int(Sum(arrayd1)/Length(arrayd1));
else
majority:=Int(Sum(arrayd1)/Length(arrayd1))+1;
fi;
return(majority);
end);
InstallOtherMethod(MinimumDistanceLeon, "attribute method for linear codes, integer, integer", true,
[IsLinearCode, IsInt, IsInt], 0,
function(C,p,num)
# p = 5 seems to be optimal
# num = 8 seems to be optimal
local majority,G0, Gp, Gpt, Gt, L, k, i, j, dimMat, Grstr, J, d1, arrayd1, Combo, rows, row, rowSum, G, F, zero, AClosestVec, s;
G := MutableCopyMatrix(GeneratorMat(C));
if (IsInStandardForm(G)=false) then
PutStandardForm(G);
fi;
F:=LeftActingDomain(C);
if F<>GF(2) then Print("Code must be binary. Quitting. \n"); return(0); fi;
dimMat := DimensionsMat(G);
s := dimMat[2]-dimMat[1];
arrayd1:=[];
for k in [1..num] do
##Permute the columns randomly
Gt := TransposedMat(G);
Gp := NullMat(dimMat[2],dimMat[1]);
L := SymmetricGroup(dimMat[2]);
L := Random(L);
L:=List([1..dimMat[2]],i->OnPoints(i,L));
for i in [1..dimMat[2]] do
Gp[i] := Gt[L[i]];
od;
Gp := TransposedMat(Gp);
Gp := ShallowCopy(Gp);
##Use gaussian elimination on the new matrix
TriangulizeMat(Gp);
##generate the restricted code (I|Z) from Gp=(I|Z|B)
Gpt := TransposedMat(Gp);
Grstr := NullMat(s,dimMat[1]);
for i in [dimMat[1]+1..dimMat[1]+s] do
Grstr[i-dimMat[1]] := Gpt[i];
od;
Grstr := TransposedMat(Grstr);
zero := Zero(F)*Grstr[1];
##search for all rows of weight p
J := []; #col number of codewords to compute the length of
for i in [1..p] do
AClosestVec:=AClosestVectorCombinationsMatFFEVecFFE(Grstr, F, zero, i, 1);
if WeightVecFFE(AClosestVec) > 0 then
Add(J, [AClosestVec,i]);
fi;
od;
d1:=dimMat[2];
for rows in J do
d1:=Minimum(WeightVecFFE(rows[1])+rows[2],d1);
od;
arrayd1[k]:=d1;
od;
if AbsoluteValue(Sum(arrayd1)/Length(arrayd1)-Int(Sum(arrayd1)/Length(arrayd1)))<1/2 then
majority:=Int(Sum(arrayd1)/Length(arrayd1));
else
majority:=Int(Sum(arrayd1)/Length(arrayd1))+1;
fi;
return(majority);
end);
#############################################################################
##
#F LowerBoundMinimumDistance( arg ) . . . . . . . . . . . . . . . . . . .
##
##LR - Is there a better way to handle HasMD case, without reset?
InstallMethod(LowerBoundMinimumDistance, "method for unrestricted codes",
true, [IsCode], 0,
function(C)
if HasMinimumDistance(C) then
C!.lowerBoundMinimumDistance := MinimumDistance(C);
elif not IsBound(C!.lowerBoundMinimumDistance) then
if Size(C) = 1 then
C!.lowerBoundMinimumDistance := WordLength(C);
else
C!.lowerBoundMinimumDistance := 1;
fi;
fi;
return C!.lowerBoundMinimumDistance;
end);
InstallMethod(LowerBoundMinimumDistance, "method for linear code", true,
[IsLinearCode], 0,
function(C)
if HasMinimumDistance(C) then
C!.lowerBoundMinimumDistance := MinimumDistance(C);
elif not IsBound(C!.lowerBoundMinimumDistance) then
if Dimension(C) = 0 then
C!.lowerBoundMinimumDistance := WordLength(C);
elif Dimension(C) = 1 then
C!.lowerBoundMinimumDistance:= Weight(Codeword(GeneratorMat(C)[1]));
else
C!.lowerBoundMinimumDistance := 1;
fi;
fi;
return C!.lowerBoundMinimumDistance;
end);
InstallMethod(LowerBoundMinimumDistance, "method for cyclic codes", true,
[IsCyclicCode], 0,
function(C)
if HasMinimumDistance(C) then
C!.lowerBoundMinimumDistance := MinimumDistance(C);
elif not IsBound(C!.lowerBoundMinimumDistance) then
if Dimension(C) = 0 then
C!.lowerBoundMinimumDistance := WordLength(C);
elif Dimension(C) = 1 then
C!.lowerBoundMinimumDistance := Weight(Codeword(GeneratorPol(C)));
else
C!.lowerBoundMinimumDistance := 1;
fi;
fi;
return C!.lowerBoundMinimumDistance;
end);
InstallOtherMethod(LowerBoundMinimumDistance, "n, k, q", true,
[IsInt, IsInt, IsInt], 0,
function(n, k, q)
local r;
r := BoundsMinimumDistance(n, k, q, true);
return r.lowerBound;
end);
InstallOtherMethod(LowerBoundMinimumDistance, "n, k", true,
[IsInt, IsInt], 0,
function(n, k)
local r;
r := BoundsMinimumDistance(n, k, 2, true);
return r.lowerBound;
end);
InstallOtherMethod(LowerBoundMinimumDistance, "n, k, F", true,
[IsInt, IsInt, IsField], 0,
function(n, k, F)
local r;
r := BoundsMinimumDistance(n, k, Size(F), true);
return r.lowerBound;
end);
#############################################################################
##
#F UpperBoundMinimumDistance( arg ) . . . . . . . . . . . . . . . . . . .
##
##LR - is there a better way to handle HasMD case, without reset?
InstallMethod(UpperBoundMinimumDistance, "method for unrestricted codes",
true, [IsCode], 0,
function(C)
if HasMinimumDistance(C) then
C!.upperBoundMinimumDistance := MinimumDistance(C);
elif not IsBound(C!.upperBoundMinimumDistance) then
C!.upperBoundMinimumDistance := WordLength(C);
fi;
return C!.upperBoundMinimumDistance;
end);
InstallMethod(UpperBoundMinimumDistance, "method for linear codes", true,
[IsLinearCode], 0,
function(C)
local ubmd;
if HasMinimumDistance(C) then
C!.upperBoundMinimumDistance := MinimumDistance(C);
else
if not IsBound(C!.upperBoundMinimumDistance) then
ubmd := WordLength(C);
else
ubmd := C!.upperBoundMinimumDistance;
fi;
if MinimumWeightOfGenerators(C) < ubmd then
ubmd := MinimumWeightOfGenerators(C);
fi;
if UpperBoundOptimalMinimumDistance(C) < ubmd then
ubmd := UpperBoundOptimalMinimumDistance(C);
fi;
C!.upperBoundMinimumDistance := ubmd;
fi;
return C!.upperBoundMinimumDistance;
end);
InstallOtherMethod(UpperBoundMinimumDistance, "n, k, q", true,
[IsInt, IsInt, IsInt], 0,
function(n, k, q)
local r;
r := BoundsMinimumDistance(n, k, q, false);
return r.upperBound;
end);
InstallOtherMethod(UpperBoundMinimumDistance, "n,k", true,
[IsInt, IsInt], 0,
function(n, k)
local r;
r := BoundsMinimumDistance(n, k, 2, false);
return r.upperBound;
end);
InstallOtherMethod(UpperBoundMinimumDistance, "n,k,F", true,
[IsInt, IsInt, IsField], 0,
function(n, k, F)
local r;
r := BoundsMinimumDistance(n, k, Size(F), false);
return r.upperBound;
end);
#############################################################################
##
#F UpperBoundOptimalMinimumDistance( arg ) . . . . . . . . . . . . . . . .
##
## UpperBoundMinimumDistance of optimal code with given parameters
##
InstallMethod(UpperBoundOptimalMinimumDistance, "method for unrestricted code",
true, [IsCode], 0,
function(C)
local r;
r := BoundsMinimumDistance(WordLength(C), Dimension(C),
Size(LeftActingDomain(C)), false);
return r.upperBound;
end);
#############################################################################
##
#F MinimumWeightOfGenerators( arg ) . . . . . . . . . . . . . . . . . . . .
##
##
InstallMethod(MinimumWeightOfGenerators, "linear codes", true,
[IsLinearCode], 0,
function(C)
local zero, mwg, sum, element, row;
zero := Zero(LeftActingDomain(C));
mwg := WordLength(C);
if Dimension(C) > 0 then
# minimumWeightOfGenerators for null codes is n
for row in GeneratorMat(C) do
sum := 0;
for element in row do
if element <> zero then
sum := sum + 1;
fi;
od;
if sum < mwg then
mwg := sum;
fi;
od;
fi;
return mwg;
end);
InstallMethod(MinimumWeightOfGenerators, "method for cyclic codes", true,
[IsCyclicCode], 0,
function(C)
if Dimension(C) > 0 then
# minimumWeightOfGenerators of null codes is n
return Weight(Codeword(GeneratorPol(C)));
else
return WordLength(C);
fi;
end);
#############################################################################
##
#F MinimumWeightWords( <C> ) . . . returns the code words of minimum weight
##
InstallMethod(MinimumWeightWords, "method for unrestricted code", true,
[IsCode], 0,
function(C)
local curmin, res, e, w, zerovec, d;
if IsLinearCode(C) then
return MinimumWeightWords(C);
fi;
curmin := WordLength(C);
if not HasWeightDistribution(C) then
res := [];
for e in AsSSortedList(C) do
w := Weight(e);
if w < curmin and w <> 0 then
# New minimum weight found
curmin := w;
res := [ e ];
elif w = curmin then
Add(res, e);
fi;
od;
return res;
else
# Find the minimum weight
d := MinimumDistance(C);
return Filtered(AsSSortedList(C), e -> Weight(e) = d);
fi;
end);
InstallMethod(MinimumWeightWords, "method for linear code", true,
[IsLinearCode], 0,
function(C)
local d, G, res, vector, count, i, t, k, q, M, zerovec;
d := MinimumDistance(C); # Equal to minimum weight
G := GeneratorMat(C);
k := Dimension(C);
q := Size(LeftActingDomain(C));
M := Size(C);
res := [];
vector := NullVector(WordLength(C), LeftActingDomain(C));
zerovec := ShallowCopy(vector);
count := 1;
while count < M do
# Calculate next word in the code
i := k;
t := count;
while t mod q = 0 do
t := t / q;
i := i - 1;
od;
vector := vector + G[i];
if DistanceVecFFE(vector, zerovec) = d then
# This word has minimum weight
Add(res, Codeword(vector));
fi;
count := count + 1;
od;
return res;
end);
#############################################################################
##
#F WeightDistribution( <C> ) . . . returns the weight distribution of a code
##
InstallMethod(WeightDistribution, "method for unrestricted code", true,
[IsCode], 0,
function (C)
local El, nl, newwd;
if IsLinearCode(C) then
return WeightDistribution(C);
fi;
El := VectorCodeword(AsSSortedList(C));
nl := VectorCodeword(NullWord(C));
newwd := DistancesDistributionVecFFEsVecFFE(El, nl);
return newwd;
end);
InstallMethod(WeightDistribution, "method for linear code", true,
[IsLinearCode], 0,
function(C)
local G, nl, k, n, q, F, wd, newwd, oldrow, newrow, i, j;
n := WordLength(C);
k := Dimension(C);
q := Size(LeftActingDomain(C));
F := LeftActingDomain(C);
nl := VectorCodeword(NullWord(C));
if k = 0 then
G := NullVector(n+1);
G[1] := 1;
newwd := G;
elif k = n then
newwd := List([0..n], i->Binomial(n, i));
elif k <= Int(n/2) then
G := One(F)*ShallowCopy(GeneratorMat(C));
newwd := DistancesDistributionMatFFEVecFFE(G, F, nl);
else
G := One(F)*ShallowCopy(CheckMat(C));
wd := DistancesDistributionMatFFEVecFFE(G, F, nl);
newwd := [Sum(wd)];
oldrow := List([1..n+1], i->1);
newrow := [];
for i in [2..n+1] do
newrow[1] := Binomial(n, i-1) * (q-1)^(i-1);
for j in [2..n+1] do
newrow[j] := newrow[j-1] - (q-1) * oldrow[j] - oldrow[j-1];
od;
newwd[i] := newrow * wd;
oldrow := ShallowCopy(newrow);
od;
newwd:= newwd / (q ^ Redundancy(C));
fi;
return newwd;
end);
#############################################################################
##
#F InnerDistribution( <C> ) . . . . . . the inner distribution of the code
##
## The average distance distribution of distances between all codewords
##
InstallMethod(InnerDistribution, "method for unrestricted code", true,
[IsCode], 0,
function (C)
local ID, c, El;
El := VectorCodeword(AsSSortedList(C));
ID := List([1..WordLength(C)+1], i->0);
for c in El do
ID := ID + DistancesDistributionVecFFEsVecFFE(El, c);
od;
return ID/Size(C);
end);
InstallMethod(InnerDistribution, "method for linear codes", true,
[IsLinearCode], 0,
function (C)
return WeightDistribution(C);
end);
#############################################################################
##
#F OuterDistribution( <C> ) . . . . . . . . . . . . . . . . . . . . . . .
##
## the number of codewords on a distance i from all elements of GF(q)^n
##
InstallOtherMethod(OuterDistribution, "method for unrestricted code", true,
[IsCode], 0,
function (C)
local gen, q, n, F, zero, Els, res, vector, t, large, count, dd;
if IsLinearCode(C) then
return OuterDistribution(C);
fi;
q := Size(LeftActingDomain(C));
n := WordLength(C);
F := LeftActingDomain(C);
zero := Zero(F);
Els := VectorCodeword(AsSSortedList(C));
res := [[NullWord(C),WeightDistribution(C)]];
vector := NullVector(n, F);
t := n;
gen := Z(q);
large := One(F);
for count in [2..q^n] do
t := n;
while vector[t] = large do
vector[t] := zero;
t := t-1;
od;
if vector[t] = zero then
vector[t] := gen;
else
vector[t] := vector[t] * gen;
fi;
dd := DistancesDistributionVecFFEsVecFFE(Els, vector);
Add(res, [Codeword(vector), dd]);
od;
return res;
end);
InstallMethod(OuterDistribution, "method for linear codes", true,
[IsLinearCode], 0,
function(C)
local STentry, dtw, E, res, i;
E := AsSSortedList(C);
res := [];
for STentry in List(SyndromeTable(C), i -> i[1]) do
dtw := DistancesDistribution(C, STentry);
for i in E do
Add(res, [VectorCodeword(STentry) + i, dtw]);
od;
od;
return res;
end);
#############################################################################
##
#F InformationWord( Code, c ) . . . "decodes" a codeword c in C to the
## information "message" word m, so m*C=c
InstallMethod(InformationWord, "code, codeword", true, [IsCode, IsCodeword], 1,
function(C, c)
local m;
if not(c in C) then Error( "ERROR: codeword must belong to code" ); fi;
if not(IsLinearCode(C)) then return "ERROR: code must be linear"; fi;
m := SolutionMat(List(GeneratorMat(C),List), VectorCodeword(c));
return Codeword(m);
end);
#############################################################################
##
#F IsSelfDualCode( <C> ) . . . . . . . . . determines whether C is self dual
##
## i.o.w. each codeword is orthogonal to all codewords (including itself)
##
InstallMethod(IsSelfDualCode, "method for unrestricted code", true,
[IsCode], 0,
function(C)
if IsCyclicCode(C) or IsLinearCode(C) then
return IsSelfDualCode(C);
else
return false;
fi;
end);
InstallMethod(IsSelfDualCode, "method for linear code", true,
[IsLinearCode], 0,
function(C)
if IsCyclicCode(C) then
return IsSelfDualCode(C);
elif Redundancy(C) <> Dimension(C) then
return false; #so the code is not self dual
else
return (GeneratorMat(C)*TransposedMat(GeneratorMat(C)) =
NullMat(Dimension(C),Dimension(C),LeftActingDomain(C)));
fi;
end);
InstallMethod(IsSelfDualCode, "method for cyclic codes", true,
[IsCyclicCode], 0,
function(C)
local r;
if Redundancy(C) <> Dimension(C) then
return false; #so the code is not self dual
else
r := ReciprocalPolynomial(GeneratorPol(C),Redundancy(C));
r := r/LeadingCoefficient(r);
return CheckPol(C) = r;
fi;
end);
#############################################################################
##
#F CodewordVector( <l>, <C> )
##
## only valid if C is linear!
##
InstallOtherMethod(CodewordVector,"vector and unrestricted code", true,
[IsList, IsCode], 0,
function(l, C)
if IsLinearCode(C) then
return CodewordVector(l,C);
else
Error("<r> is a non-linear code");# encoding not possible
fi;
end);
InstallOtherMethod(CodewordVector,"vector and linear code", true,
[IsList, IsLinearCode], 0,
function(l, C)
local s, i, k;
if IsCyclicCode(C) then
return CodewordVector(l,C);
else
l := VectorCodeword(Codeword(l, Dimension(C), LeftActingDomain(C)));
if GeneratorMat(C) = [] then
return NullMat(Length(l), WordLength(C), LeftActingDomain(C));
else
return Codeword(l*GeneratorMat(C), C);
fi;
fi;
end);
InstallOtherMethod(CodewordVector, "<list of codewords|vector>,cyclic code",
true, [IsList, IsCyclicCode], 0,
function(l, C)
local F, p;
F := LeftActingDomain(C);
l := Codeword(l, Dimension(C), F);
if IsList(l) and not IsCodeword(l) then
return List(l, i->CodewordVector(i,C));
else
return Codeword(PolyCodeword(l) * GeneratorPol(C), C);
fi;
end);
InstallOtherMethod(CodewordVector, "method for poly and cyclic code", true,
[IsUnivariatePolynomial, IsCyclicCode], 0,
function(p, C)
local F, w;
F := LeftActingDomain(C);
w := Codeword(p, Dimension(C), F);
return Codeword(PolyCodeword(w) * GeneratorPol(C), C);
end);
InstallOtherMethod(\*, "list with code", true, [IsList, IsCode], 0,
CodewordVector);
InstallOtherMethod(\*, "poly with code", true,
[IsUnivariatePolynomial, IsCode], 0, CodewordVector);
InstallOtherMethod(\*, "method for two codes", true, [IsCode, IsCode], 0,
function(C1, C2)
return DirectProductCode(C1, C2);
end);
#############################################################################
##
#F \+( <l>, <C> ) . . . . . . . . . . . . . . . . . . . . . . . . . . . .
##
##
InstallOtherMethod(\+, "method for codeword+code", true,
[IsCodeword, IsCode], 0,
function(w, C)
return CosetCode(C, w);
end);
InstallOtherMethod(\+, "method for code+codeword", true,
[IsCode, IsCodeword], 0,
function(C, w)
return CosetCode(C, w);
end);
InstallOtherMethod(\+, "method for two codes", ReturnTrue,
[IsCodeDefaultRep, IsCodeDefaultRep], 25,
function(C1, C2)
return DirectSumCode(C1, C2);
end);
InstallOtherMethod(\+, "method for two linear codes", ReturnTrue,
[IsLinearCode, IsLinearCode], 26,
function(C1, C2)
return DirectSumCode(C1, C2);
end);
#############################################################################
##
#F \in( <l>, <C> ) . . . . . . true if the vector is an element of the code
##
##
InstallMethod(\in, "method for codeword in unrestricted code", true,
[IsCodeword, IsCode], 0,
function(w, C)
if WordLength(w) <> WordLength(C) then
return false;
else
return w in AsSSortedList(C);
fi;
end);
InstallMethod(\in, "method for list of codewords in unrestricted code", true,
[IsList, IsCode], 0,
function(l, C)
return ForAll(l, w->w in C);
end);
InstallMethod(\in, "method for unrestricted code in unrestricted code", true,
[IsCode, IsCode], 0,
function(C1, C2)
local l;
l := ShallowCopy(AsSSortedList(C1));
return ForAll(l, w->w in C2);
end);
InstallMethod(\in, "method for codeword in linear code", true,
[IsCodeword, IsLinearCode], 0,
function(w, C)
if WordLength(w) <> WordLength(C) then
return false;
elif GeneratorMat(C) = [] then
return w = 0*w;
elif CheckMat(C) = [] then #Code is WholeSpace, just check field.
return ForAll(VectorCodeword(w), x->x in LeftActingDomain(C));
else
return CheckMat(C)*w = 0*w;
fi;
end);
InstallMethod(\in, "method for linear code in linear code", true,
[IsLinearCode, IsLinearCode], 0,
function(C1, C2)
local l;
l := ShallowCopy(GeneratorMat(C1));
return ForAll(l, w-> Codeword(w) in C2);
end);
InstallMethod(\in, "method for codeword in cyclic code", true,
[IsCodeword, IsCyclicCode], 0,
function(w, C)
return PolyCodeword(w) mod GeneratorPol(C) =
0 * Indeterminate(LeftActingDomain(C));
end);
InstallMethod(\in, "method for cyclic code in cyclic code", true,
[IsCyclicCode, IsCyclicCode], 0,
function(C1, C2)
return GeneratorPol(C1) mod GeneratorPol(C2) =
0 * Indeterminate(LeftActingDomain(C2));
end);
#############################################################################
##
#F \=( <C1>, <C2> ) . . . . . tests if Set(AsList(C1))=Set(AsList(C2))
##
## Post: returns a boolean
##
InstallMethod(\=, "method for unrestricted code = unrestricted code", true,
[IsCode, IsCode], 0,
function(C1, C2)
local field, fields;
if (IsLinearCode(C1) and IsLinearCode(C2)) or
(IsCyclicCode(C1) and IsCyclicCode(C2)) then
return C1 = C2;
elif IsLinearCode(C1) or IsLinearCode(C2) then
return false; ##one is linear, the other is not, so not equal
fi;
if Set(AsSSortedList(C1)) = Set(AsSSortedList(C2)) then
fields := [WeightDistribution, InnerDistribution,
IsLinearCode, IsPerfectCode,
IsSelfDualCode, OuterDistribution, IsCyclicCode,
AutomorphismGroup, MinimumDistance, CoveringRadius];
for field in fields do
if not Tester(field)(C1) then
if Tester(field)(C2) then
Setter(field)(C1, field(C2));
fi;
else
if not Tester(field)(C2) then
Setter(field)(C2, field(C1));
fi;
fi;
od;
if not IsBound(C1!.boundsCoveringRadius) then
if IsBound(C2!.boundsCoveringRadius) then
C1!.boundsCoveringRadius := C2!.boundsCoveringRadius;
fi;
else
if not IsBound(C2!.boundsCoveringRadius) then
C2!.boundsCoveringRadius := C1!.boundsCoveringRadius;
fi;
fi;
C1!.lowerBoundMinimumDistance := Maximum(LowerBoundMinimumDistance(C1),
LowerBoundMinimumDistance(C2));
C2!.lowerBoundMinimumDistance := C1!.lowerBoundMinimumDistance;
C1!.upperBoundMinimumDistance := Minimum(UpperBoundMinimumDistance(C1),
UpperBoundMinimumDistance(C2));
C2!.upperBoundMinimumDistance := C1!.upperBoundMinimumDistance;
return true;
else
return false; #so C1 is not equal to C2
fi;
end);
InstallMethod(\=, "method for linear code = linear code", true,
[IsLinearCode, IsLinearCode], 0,
function(C1, C2)
local field, fields;
if IsCyclicCode(C1) and IsCyclicCode(C2) then
return C1 = C2;
elif IsCyclicCode(C1) or IsCyclicCode(C2) then
return false; ##one is cyclic, the other is not, so not equal.
fi;
if BaseMat(GeneratorMat(C1))=BaseMat(GeneratorMat(C2)) then
fields := [WeightDistribution, InnerDistribution,
IsLinearCode, IsPerfectCode,
IsSelfDualCode, OuterDistribution, IsCyclicCode,
AutomorphismGroup, MinimumDistance, CoveringRadius];
for field in fields do
if not Tester(field)(C1) then
if Tester(field)(C2) then
Setter(field)(C1, field(C2));
fi;
else
if not Tester(field)(C2) then
Setter(field)(C2, field(C1));
fi;
fi;
od;
if not IsBound(C1!.boundsCoveringRadius) then
if IsBound(C2!.boundsCoveringRadius) then
C1!.boundsCoveringRadius := C2!.boundsCoveringRadius;
fi;
else
if not IsBound(C2!.boundsCoveringRadius) then
C2!.boundsCoveringRadius := C1!.boundsCoveringRadius;
fi;
fi;
C1!.lowerBoundMinimumDistance := Maximum(LowerBoundMinimumDistance(C1),
LowerBoundMinimumDistance(C2));
C2!.lowerBoundMinimumDistance := C1!.lowerBoundMinimumDistance;
C1!.upperBoundMinimumDistance := Minimum(UpperBoundMinimumDistance(C1),
UpperBoundMinimumDistance(C2));
C2!.upperBoundMinimumDistance := C1!.upperBoundMinimumDistance;
return true;
else
return false; #so l is not equal to r
fi;
end);
InstallMethod(\=, "method for cyclic code = cyclic code", true,
[IsCyclicCode, IsCyclicCode], 0,
function(C1, C2)
local field, fields, bmdl, bmdr;
if GeneratorPol(C1) = GeneratorPol(C2) then
fields := [WeightDistribution, InnerDistribution,
IsLinearCode, IsPerfectCode,
IsSelfDualCode, OuterDistribution, IsCyclicCode,
AutomorphismGroup, MinimumDistance, CoveringRadius,
RootsOfCode];
for field in fields do
if not Tester(field)(C1) then
if Tester(field)(C2) then
Setter(field)(C1, field(C2));
fi;
else
if not Tester(field)(C2) then
Setter(field)(C2, field(C1));
fi;
fi;
od;
if not IsBound(C1!.boundsCoveringRadius) then
if IsBound(C2!.boundsCoveringRadius) then
C1!.boundsCoveringRadius := C2!.boundsCoveringRadius;
fi;
else
if not IsBound(C2!.boundsCoveringRadius) then
C2!.boundsCoveringRadius := C1!.boundsCoveringRadius;
fi;
fi;
C1!.lowerBoundMinimumDistance := Maximum(LowerBoundMinimumDistance(C1),
LowerBoundMinimumDistance(C2));
C2!.lowerBoundMinimumDistance := C1!.lowerBoundMinimumDistance;
C1!.upperBoundMinimumDistance := Minimum(UpperBoundMinimumDistance(C1),
UpperBoundMinimumDistance(C2));
C2!.upperBoundMinimumDistance := C1!.upperBoundMinimumDistance;
return true;
else
return false; #so l is not equal to r
fi;
end);
#############################################################################
##
#F SyndromeTable ( <C> ) . . . . . . . . . . . . . . . a Syndrome table of C
##
InstallMethod(SyndromeTable, "method for unrestricted code", true,
[IsCode], 0,
function(C)
if IsLinearCode(C) then
return SyndromeTable(C);
else
Error("the syndrome table is not defined for non-linear codes");
fi;
end);
InstallMethod(SyndromeTable, "method for linear code", true,
[IsLinearCode], 0,
function(C)
local H, L, F;
H := CheckMat(C);
if H = [] then
return [];
fi;
F := LeftActingDomain(C);
L := GuavaCosetLeadersMatFFE(List(H,List), F);
H := TransposedMat(H);
return Codeword(List(L, l-> [l, l*H]), F);
end);
#############################################################################
##
#F StandardArray( <C> ) . . . . . . . . . . . . a standard array for code C
##
## Post: returns a 3D-matrix. The first row contains all the codewords of C.
## The other rows contain the cosets, preceded by their coset leaders.
##
InstallMethod(StandardArray, "method for unrestricted code", true,
[IsCode], 0,
function(C)
if IsLinearCode(C) then
return StandardArray(C);
else
Error("a standard array is not defined for non-linear codes");
fi;
end);
InstallMethod(StandardArray, "method for linear code", true, [IsLinearCode], 0,
function(C)
local Els;
Els := AsSSortedList(C);
if CheckMat(C) = [] then
return [Els];
fi;
return List(Set(GuavaCosetLeadersMatFFE(CheckMat(C), LeftActingDomain(C))),
row -> List(Els, column -> row + column));
end);
#############################################################################
##
#F AutomorphismGroup( <C> ) . . . . . . . . the automorphism group of code
##
## The automorphism group is the largest permutation group of degree n such
## that for each permutation in the group C' = C
##
InstallOtherMethod(AutomorphismGroup, "method for unrestricted codes", true,
[IsCode], 0,
function(C)
local path;
path := DirectoriesPackagePrograms( "guava" );
if ForAny( ["desauto", "leonconv", "wtdist"],
f -> Filename( path, f ) = fail ) then
Print("desauto not loaded ... switching to PermutationGroup ...\n");
return PermutationGroup(C);
fi;
if Size(LeftActingDomain(C)) > 2 then
Print("This command calculates automorphism groups for binary codes only\n");
Print("... automatically switching to PermutationGroup ...\n");
return PermutationGroup(C);
elif IsLinearCode(C) then
return AutomorphismGroup(C);
else
return MatrixAutomorphisms(VectorCodeword(AsSSortedList(C)),
[], Group( () ));
fi;
end);
InstallOtherMethod(AutomorphismGroup, "method for linear codes", true,
[IsLinearCode], 0,
function(C)
local incode, inV, outgroup, infile,Ccalc,path;
path := DirectoriesPackagePrograms( "guava" );
if ForAny( ["desauto", "leonconv", "wtdist"],
f -> Filename( path, f ) = fail ) then
Print("desauto not loaded ... switching to PermutationGroup ...\n");
return PermutationGroup(C);
fi;
if Size(LeftActingDomain(C)) > 2 then
Print("This command calculates automorphism groups for binary codes only\n");
Print("... automatically switching to PermutationGroup ...\n");
return PermutationGroup(C);
fi;
incode := TmpName(); PrintTo( incode, "\n" );
inV := TmpName(); PrintTo( inV, "\n" );
outgroup := TmpName(); PrintTo( outgroup, "\n" );
infile := TmpName(); PrintTo( infile, "\n" );
# Calculate with dual code if it is smaller:
if Dimension(C) > QuoInt(WordLength(C), 2) then
Ccalc := DualCode(C);
else
Ccalc := ShallowCopy(C);
fi;
GuavaToLeon(Ccalc, incode);
Process(DirectoryCurrent(),
Filename(path, "wtdist"),
InputTextNone(),
OutputTextNone(),
["-q", Concatenation(incode,"::code"), MinimumDistance(Ccalc), Concatenation(inV, "::code")]
);
#Exec(Filename(DirectoriesPackagePrograms("guava"), "wtdist"),
# Concatenation("-q ",incode,"::code ",
# String(MinimumDistance(Ccalc))," ",inV,"::code"));
Process(DirectoryCurrent(),
Filename(path, "desauto"),
InputTextNone(),
OutputTextNone(),
["-code", "-q", Concatenation(incode,"::code"), Concatenation(inV, "::code"), outgroup]
);
#Exec(Filename(DirectoriesPackagePrograms("guava"), "desauto"),
# Concatenation("-code -q ",
# incode,"::code ",inV,"::code ",outgroup));
Process(DirectoryCurrent(),
Filename(path, "leonconv"),
InputTextNone(),
OutputTextNone(),
["-a", outgroup, infile]
);
#Exec(Filename(DirectoriesPackagePrograms("guava"), "leonconv"),
# Concatenation("-a ",outgroup," ", infile));
Read(infile);
#RemoveFiles(incode,inV,outgroup,infile);
return GUAVA_TEMP_VAR;
end);
## If the new partition backtrack algorithms are implemented, the previous
## function can be replaced by the next:
#InstallOtherMethod(AutomorphismGroup, "method for linear code", true,
# [IsLinearCode], 0,
#function(C)
# local Ccalc, InvSet;
# if Dimension(C) > QuoInt(WordLength(C), 2) then
# Ccalc := DualCode(C);
# else
# Ccalc := ShallowCopy(C);
# fi;
# InvSet := VectorCodeword(MinimumWeightWords(Ccalc));
# return AutomorphismGroupBinaryLinearCode(Ccalc, InvSet);
#end);
#############################################################################
##
## PermutationGroup( <C> ) . . . . . . PermutationGroup of non-binary code
##
## confusing name?
InstallMethod(PermutationGroup, "attribute method for linear codes", true,
[IsLinearCode], 0,
function(C)
local G0, Gell, G1, G2, Gt, L, k, i, j, G, F, A, aut, n, Sn, ell;
Print("\n To be deprecated. Please use PermutationAutomorphismGroup.\n");
F:=LeftActingDomain(C);
G1 := GeneratorMat(C);
G := List(G1,ShallowCopy);
k:=DimensionsMat(G)[1];
n:=DimensionsMat(G)[2];
TriangulizeMat(G);
Gt := TransposedMat(G);
Sn := SymmetricGroup(n);
A:=[];
for ell in Sn do
G2:= NullMat(n,k);
for j in [1..n] do
G2[j]:=Gt[OnPoints(j,ell)];
od; # j
Gell := TransposedMat(G2);
G0 := List(Gell,ShallowCopy);
TriangulizeMat(G0);
if G = G0 then Add(A, ell); fi;
od; # ell
if Length(A)>0 then
aut := Group(A);
else aut:=Group(());
fi;
return(aut);
end);
#############################################################################
##
## PermutationAutomorphismGroup( <C> ) . . Permutation automorphism
## group of linear (possibly non-binary) code
##
##
InstallMethod(PermutationAutomorphismGroup, "attribute method for linear codes", true,
[IsLinearCode], 0,
function(C)
local G0, Gell, G1, G2, Gt, L, k, i, j, G, F, A, aut, n, Sn, ell;
F:=LeftActingDomain(C);
G1 := GeneratorMat(C);
G := List(G1,ShallowCopy);
k:=DimensionsMat(G)[1];
n:=DimensionsMat(G)[2];
TriangulizeMat(G);
Gt := TransposedMat(G);
Sn := SymmetricGroup(n);
A:=[];
for ell in Sn do
G2:= NullMat(n,k);
for j in [1..n] do
G2[j]:=Gt[OnPoints(j,ell)];
od; # j
Gell := TransposedMat(G2);
G0 := List(Gell,ShallowCopy);
TriangulizeMat(G0);
if G = G0 then Add(A, ell); fi;
od; # ell
if Length(A)>0 then
aut := Group(A);
else aut:=Group(());
fi;
return(aut);
end);
#############################################################################
##
#F IsSelfOrthogonalCode( <C> ) . . . . . . . . . . . . . . . . . . . . . .
##
InstallTrueMethod(IsSelfOrthogonalCode, IsSelfDualCode);
InstallMethod(IsSelfOrthogonalCode, "method for unrestricted code", true,
[IsCode], 0,
function(C)
local El, M, zero, i, j, IsSO;
if IsLinearCode(C) then
return IsSelfOrthogonalCode(C);
fi;
El := AsSSortedList(C);
M := Size(C);
zero := Zero(LeftActingDomain(C));
i := 1; IsSO := true;
while (i <= M-1) and IsSO do
j := i+1;
while (j <= M) and (El[i]*El[j] = zero) do
j := j + 1;
od;
if j <= M then
IsSO := false;
fi;
i := i + 1;
od;
return IsSO;
end);
InstallMethod(IsSelfOrthogonalCode, "method for linear code", true,
[IsLinearCode], 0,
function(C)
local G, k;
G := GeneratorMat(C);
k := Dimension(C);
return G*TransposedMat(G) = NullMat(k,k,LeftActingDomain(C));
end);
#############################################################################
##
#F IsDoublyEvenCode( <C> ) . . . . . . . . . . . . . . . . . . . . . . . .
##
## Return true if and only if the code C is a binary linear code which has
## all codewords of weight divisible by 4 only.
##
## If a binary linear code is self-orthogonal and the weight of each row
## in its generator matrix is divisibly by 4, the code is doubly-even
## (see Theorem 1.4.8 in W. C. Huffman and V. Pless, "Fundamentals of
## error-correcting codes", Cambridge Univ. Press, 2003.)
##
InstallMethod(IsDoublyEvenCode, "method for binary linear code", true,
[IsLinearCode], 0,
function(C)
local G, i;
if LeftActingDomain(C)<>GF(2) then
Error("Code must be binary\n");
fi;
G:=GeneratorMat(C);
for i in [1..Size(G)] do;
if Weight(Codeword(G[i])) mod 4 <> 0 then
return false;
fi;
od;
return IsSelfOrthogonalCode(C);
end);
#############################################################################
##
#F IsSinglyEvenCode( <C> ) . . . . . . . . . . . . . . . . . . . . . . . .
##
## Return true if and only if the code C is a self-orthogonal binary linear
## code which is not doubly-even.
##
InstallMethod(IsSinglyEvenCode, "method for binary linear code", true,
[IsLinearCode], 0,
function(C)
if LeftActingDomain(C)<>GF(2) then
Error("Code must be binary\n");
fi;
return (IsSelfOrthogonalCode(C)) and (not IsDoublyEvenCode(C));
end);
#############################################################################
##
#F IsEvenCode( <C> ) . . . . . . . . . . . . . . . . . . . . . . . . . . . .
##
## Return true if and only if the code C is a binary linear code which has
## even weight codewords--regardless whether or not it is self-orgthogonal.
##
InstallMethod(IsEvenCode, "method for binary linear code", true,
[IsLinearCode], 0,
function(C)
if LeftActingDomain(C)<>GF(2) then
Error("Code must be binary\n");
fi;
return (C = EvenWeightSubcode(C));
end);
#############################################################################
##
#F CodeIsomorphism( <C1>, <C2> ) . . the permutation that translates C1 into
#F C2 if C1 and C2 are equivalent, or false otherwise
##
InstallMethod(CodeIsomorphism, "method for two unrestricted codes", true,
[IsCode, IsCode], 0,
function(C1, C2)
local tp, field;
if WordLength(C1) <> WordLength(C2) or Size(C1) <> Size(C2)
or MinimumDistance(C1) <> MinimumDistance(C2)
or LeftActingDomain(C1) <> LeftActingDomain(C2) then
return false; #I think this is what we want (see IsEquivalentCode)
elif C1=C2 then
return ();
elif IsLinearCode(C1) and IsLinearCode(C2) then
return CodeIsomorphism(C1, C2 );
fi;
tp := TransformingPermutations(VectorCodeword(AsSSortedList(C1)),
VectorCodeword(AsSSortedList(C2)));
if tp <> false then
for field in [WeightDistribution, InnerDistribution,
IsPerfectCode, IsSelfDualCode] do
if not Tester(field)(C1) then
if Tester(field)(C2) then
Setter(field)(C1, field(C2));
fi;
else
if not Tester(field)(C2) then
Setter(field)(C2, field(C1));
fi;
fi;
od;
if not IsBound(C1!.boundsCoveringRadius) then
if IsBound(C2!.boundsCoveringRadius) then
C1!.boundsCoveringRadius := C2!.boundsCoveringRadius;
fi;
else
if not IsBound(C2!.boundsCoveringRadius) then
C2!.boundsCoveringRadius := C1!.boundsCoveringRadius;
fi;
fi;
C1!.lowerBoundMinimumDistance := Maximum(LowerBoundMinimumDistance(C1),
LowerBoundMinimumDistance(C2));
C2!.lowerBoundMinimumDistance := LowerBoundMinimumDistance(C1);
C1!.upperBoundMinimumDistance := Minimum(UpperBoundMinimumDistance(C1),
UpperBoundMinimumDistance(C2));
C2!.upperBoundMinimumDistance := UpperBoundMinimumDistance(C1);
return tp.columns;
else
return false; #yes, this is right
fi;
end);
InstallMethod(CodeIsomorphism, "method for two linear codes", true,
[IsLinearCode, IsLinearCode], 0,
function(C1, C2)
local code1,code2,cwcode1,cwcode2,output,infile, field;
if WordLength(C1) <> WordLength(C2) or Size(C1) <> Size(C2)
or MinimumDistance(C1) <> MinimumDistance(C2)
or LeftActingDomain(C1) <> LeftActingDomain(C2) then
return false; #I think this is what we want (see IsEquivalentCode)
elif C1=C2 then
return ();
elif LeftActingDomain(C1) <> GF(2) then
Error("GUAVA can only calculate equivalence over GF(2)");
fi;
code1 := TmpName(); PrintTo( code1, "\n" );
code2 := TmpName(); PrintTo( code2, "\n" );
cwcode1 := TmpName(); PrintTo( cwcode1, "\n" );
cwcode2 := TmpName(); PrintTo( cwcode2, "\n" );
output := TmpName(); PrintTo( output, "\n" );
infile := TmpName(); PrintTo( infile, "\n" );
GuavaToLeon(C1, code1);
GuavaToLeon(C2, code2);
#Exec(Filename(DirectoriesPackagePrograms("guava"), "wtdist"),
# Concatenation("-q ",code1,"::code ",
# String(MinimumDistance(C1))," ",cwcode1,"::code"));
Process(DirectoryCurrent(),
Filename(DirectoriesPackagePrograms("guava"), "wtdist"),
InputTextNone(),
OutputTextNone(),
["-q", Concatenation(code1,"::code"),
MinimumDistance(C1), Concatenation(cwcode1, "::code")]
);
#Exec(Filename(DirectoriesPackagePrograms("guava"), "wtdist"),
# Concatenation("-q ",code2,"::code ",
# String(MinimumDistance(C2))," ",cwcode2,"::code"));
Process(DirectoryCurrent(),
Filename(DirectoriesPackagePrograms("guava"), "wtdist"),
InputTextNone(),
OutputTextNone(),
["-q", Concatenation(code2,"::code"),
MinimumDistance(C2), Concatenation(cwcode2, "::code")]
);
#Exec(Filename(DirectoriesPackagePrograms("guava"), "desauto"),
# Concatenation("-iso -code -q ",
# code1,"::code ",code2,"::code ",cwcode1,"::code ",
# cwcode2,"::code ",output));
Process(DirectoryCurrent(),
Filename(DirectoriesPackagePrograms("guava"), "desauto"),
InputTextNone(),
OutputTextNone(),
["-iso", "-code", "-q",
Concatenation(code1,"::code"),
Concatenation(code2,"::code"),
Concatenation(cwcode1, "::code"),
Concatenation(cwcode2, "::code"),
output]
);
#Exec(Filename(DirectoriesPackagePrograms("guava"), "leonconv"),
# Concatenation("-e ",output," ",
# infile));
Process(DirectoryCurrent(),
Filename(DirectoriesPackagePrograms("guava"), "leonconv"),
InputTextNone(),
OutputTextNone(),
["-e", output, infile]
);
Read(infile);
RemoveFiles(code1,code2,cwcode1,cwcode2,output,infile);
if not IsPerm(GUAVA_TEMP_VAR) then
return false; #it is good that false is returned
else
for field in [WeightDistribution,
IsPerfectCode,
IsSelfDualCode] do
if not Tester(field)(C1) then
if Tester(field)(C2) then
Setter(field)(C1, field(C2));
fi;
else
if not Tester(field)(C2) then
Setter(field)(C2, field(C1));
fi;
fi;
od;
if not IsBound(C1!.boundsCoveringRadius) then
if IsBound(C2!.boundsCoveringRadius) then
C1!.boundsCoveringRadius := C2!.boundsCoveringRadius;
fi;
else
if not IsBound(C2!.boundsCoveringRadius) then
C2!.boundsCoveringRadius := C1!.boundsCoveringRadius;
fi;
fi;
C1!.lowerBoundMinimumDistance := Maximum(LowerBoundMinimumDistance(C1),
LowerBoundMinimumDistance(C2));
C2!.lowerBoundMinimumDistance := LowerBoundMinimumDistance(C1);
C1!.upperBoundMinimumDistance := Minimum(UpperBoundMinimumDistance(C1),
UpperBoundMinimumDistance(C2));
C2!.upperBoundMinimumDistance := UpperBoundMinimumDistance(C1);
return GUAVA_TEMP_VAR;
fi;
end);
## If the new partition backtrack algorithms are implemented, the previous
## function can be replaced by the next:
#InstallMethod(CodeIsomorphism, "method for linear codes", true,
# [IsLinearCode, IsLinearCode], 0,
#function (C1, C2)
# local field, InvSet1, InvSet2, P;
# if WordLength(C1) <> WordLength(C2) or Size(C1) <> Size(C2)
# or MinimumDistance(C1) <> MinimumDistance(C2)
# or LeftActingDomain(C1) <> LeftActingDomain(C2) then
# return false; #I think this is what we want (see IsEquivalentCode)
# elif C1=C2 then
# return ();
# elif LeftActingDomain(C1) <> GF(2) then
# Error("GUAVA can only calculate equivalence over GF(2)");
# fi;
# InvSet1 := VectorCodeword(MinimumWeightWords(C1));
# InvSet2 := VectorCodeword(MinimumWeightWords(C2));
# P := AutomorphismGroupBinaryLinearCode(C1, InvSet1, C2, InvSet2);
# if not IsPerm(P) then
# return false; #it is good that false is returned
# else
# for field in [WeightDistribution,
# IsPerfectCode,
# IsSelfDualCode] do
# if not Tester(field)(C1) then
# if Tester(field)(C2) then
# Setter(field)(C1, field(C2));
# fi;
# else
# if not Tester(field)(C2) then
# Setter(field)(C2, field(C1));
# fi;
# fi;
# od;
#
# if not IsBound(C1!.boundsCoveringRadius) then
# if IsBound(C2!.boundsCoveringRadius) then
# C1!.boundsCoveringRadius := C2!.boundsCoveringRadius;
# fi;
# else
# if not IsBound(C2!.boundsCoveringRadius) then
# C2!.boundsCoveringRadius := C1!.boundsCoveringRadius;
# fi;
# fi;
# C1!.lowerBoundMinimumDistance := Maximum(LowerBoundMinimumDistance(C1),
# LowerBoundMinimumDistance(C2));
# C2!.lowerBoundMinimumDistance := LowerBoundMinimumDistance(C1);
# C1!.upperBoundMinimumDistance := Minimum(UpperBoundMinimumDistance(C1),
# UpperBoundMinimumDistance(C2));
# C2!.upperBoundMinimumDistance := UpperBoundMinimumDistance(C1);
# return P;
# fi;
#end);
#############################################################################
##
#F IsEquivalent( <C1>, <C2> ) . . . . . . true if C1 and C2 are equivalent
##
## that is if there exists a permutation that transforms C1 into C2.
## If returnperm is true, this permutation (if it exists) is returned;
## else the function only returns true or false. Has a global dispatcher.
##
InstallMethod(IsEquivalent, "method for unrestricted codes", true,
[IsCode, IsCode], 0,
function (C1, C2 )
return not IsBool( CodeIsomorphism( C1, C2 ) );
end);
#############################################################################
##
#F RootsOfCode( <C> ) . . . . the roots of the generator polynomial of <C>
##
## It finds the roots by trying all elements of the extension field
##
InstallMethod(RootsOfCode, "method for unrestricted code", true,
[IsCode], 0,
function(C)
if IsCyclicCode(C) then
return RootsOfCode(C);
else
Error("the roots of a code are only defined for cyclic codes");
fi;
end);
InstallMethod(RootsOfCode, "method for cyclic code", true, [IsCyclicCode], 0,
function(C)
local a, roots, zero, i, t, G;
G := GeneratorPol(C);
a := PrimitiveUnityRoot(Size(LeftActingDomain(C)), WordLength(C));
roots := [];
zero := 0*a;
t := a^0;
for i in [0..WordLength(C)-1] do
if Value(G, t) = zero then
Add(roots, t);
fi;
t := t * a;
od;
return(Set(roots));
end);
#############################################################################
##
#F DistancesDistribution( <C>, <w> ) . . . distribution of distances from a
#F word w to all codewords of C
##
InstallMethod(DistancesDistribution,
"method for unrestricted code and codeword",
true, [IsCode, IsCodeword], 0,
function(C, w)
local El;
if IsLinearCode(C) then
return DistancesDistribution(C,w);
fi;
El := VectorCodeword(AsSSortedList(C));
w := VectorCodeword(w);
return DistancesDistributionVecFFEsVecFFE(El,w);
end);
InstallMethod(DistancesDistribution, "method for linear code and codeword",
true, [IsLinearCode, IsCodeword], 0,
function(C, w)
local F, G;
F := LeftActingDomain(C);
G := One(F)*ShallowCopy(GeneratorMat(C));
w := VectorCodeword(w);
return DistancesDistributionMatFFEVecFFE(G, LeftActingDomain(C), w);
end);
#############################################################################
##
#F Syndrome( <C>, <c> ) . . . . . . . the syndrome of word <c> in code <C>
##
InstallMethod(Syndrome, "method for unrestricted code and codeword", true,
[IsCode, IsCodeword], 0,
function(C, c)
if not IsLinearCode(C) then
Error("argument must be a linear code");
else
return Syndrome(C,c);
fi;
end);
InstallMethod(Syndrome, "method for linear code and codeword", true,
[IsLinearCode, IsCodeword], 0,
function(C, c)
if CheckMat(C) = [] then
return [Zero(LeftActingDomain(C))];
else
return CheckMat(C) * Codeword(c,C);
fi;
end);
#############################################################################
##
#F CodewordNr( <C>, <i> ) . . . . . . . . . . . . . . . . . elements(C)[i]
##
InstallMethod(CodewordNr, "method for unrestricted code and position list",
true, [IsCode, IsList], 0,
function(C, l)
local returnlist;
if IsLinearCode(C) then
return CodewordNr(C,l);
fi;
l := Set(l);
returnlist := (Length(l) > 1);
if (l[1] < 1) or (l[Length(l)] > Size(C)) then
Error("range: 1..", String(Size(C)));
fi;
if returnlist then
return AsSSortedList(C){l};
else
return Flat(AsSSortedList(C){l})[1];
fi;
end);
DoCodewordNr:=function(C, l)
local index, source, i, result, q, returnlist, F, kmin;
if IsList(l) then
l := Set(l);
returnlist:=true;
else
l:=[l];
returnlist:=false;
fi;
if (l[1] < 1) or (l[Length(l)] > Size(C)) then
Error("range: 1..", String(Size(C)));
fi;
if HasAsSSortedList(C) then
if returnlist then
return AsSSortedList(C){l};
else
return AsSSortedList(C)[l[1]];
fi;
else
result := [];
q := Size(LeftActingDomain(C));
F := LeftActingDomain(C);
kmin := Dimension(C) - 1;
for index in l do
source := [];
i := index-1;
while i >= 1 do
Add(source, i mod q);
i := Int(i / q);
od;
for i in [Length(source)..kmin] do
Add(source, 0);
od;
Add(result, CodewordVector(Reversed(source),C));
od;
if returnlist then
return result;
else
return result[1];
fi;
fi;
end;
InstallOtherMethod(CodewordNr, "method for unrestricted code and int position",
true, [IsCode, IsInt], 0,DoCodewordNr);
InstallMethod(CodewordNr, "method for linear code and position list", true,
[IsLinearCode, IsList], 0, DoCodewordNr);
#############################################################################
##
#F String( <C> ) . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
##
##
InstallMethod(String, "method for code", true, [IsCode], 0,
function(C)
return CodeDescription(C);
end);
#############################################################################
##
#F CodeDescription( <C> ) . . . . . . . . . . . . . . . . . . . . . . . . .
##
##
InstallMethod(CodeDescription, "method for an unrestricted code",
true, [IsCode], 0,
function(C)
local n, x, lbmd, ubmd, line;
line := "a";
if Int(WordLength(C)/(10^LogInt(WordLength(C),10))) = 8
or WordLength( C ) = 11 or WordLength( C ) = 18 then
Append(line, "n");
fi;
Append(line,Concatenation(" (",String(WordLength(C)),",",
String(Size(C)),","));
lbmd := String( LowerBoundMinimumDistance(C));
ubmd := String( UpperBoundMinimumDistance(C));
if lbmd = ubmd then
Append(line, lbmd );
else
Append( line, Concatenation( lbmd, "..", ubmd ) );
fi;
Append( line, ")" );
# Call to BoundsCoveringRadius checks HasCoveringRadius first.
# No need to repeat here. Similar for LBMD, UBMD, above.
if Length( BoundsCoveringRadius( C ) ) = 1 then
SetCoveringRadius(C, BoundsCoveringRadius(C)[1]);
Append( line, String( BoundsCoveringRadius(C)[ 1 ] ) );
else
Append( line, Concatenation(
String( BoundsCoveringRadius(C)[ 1 ] ),
"..",
String( BoundsCoveringRadius(C)[
Length( BoundsCoveringRadius(C) ) ] ) ) );
fi;
Append( line, " " );
if not IsBound( C!.name ) then
C!.name := "unknown unrestricted code";
fi;
Append( line, C!.name );
if not IsBound( C!.history ) then
Append(line,Concatenation(" over GF(", String(Size(LeftActingDomain(C))),")"));
fi;
IsString( line );
return line;
end);
InstallMethod(CodeDescription, "method for linear code",
true, [IsLinearCode], 0,
function(C)
local lbmd, ubmd, line;
line := "a linear [";
line := Concatenation( line, String(WordLength(C)), ",",
String(Dimension(C)), "," );
lbmd := String( LowerBoundMinimumDistance(C) );
ubmd := String( UpperBoundMinimumDistance(C) );
if lbmd = ubmd then
Append(line, lbmd );
else
Append(line,Concatenation( lbmd, "..", ubmd ) );
fi;
Append( line, "]" );
if Length( BoundsCoveringRadius( C ) ) = 1 then
Append( line, String( BoundsCoveringRadius(C)[ 1 ] ) );
else
Append( line, Concatenation(
String( BoundsCoveringRadius(C)[ 1 ] ),
"..",
String( Maximum( BoundsCoveringRadius(C) ) ) ) );
fi;
Append( line, " " );
if not IsBound( C!.name ) then
C!.name := "unknown linear code";
fi;
Append( line, C!.name );
if not IsBound( C!.history ) then
Append(line,Concatenation(" over GF(", String(Size(LeftActingDomain(C))),")"));
fi;
IsString( line );
return line;
end);
InstallMethod(CodeDescription, "method for cyclic codes",
true, [IsCyclicCode], 0,
function(C)
local n, x, lbmd, ubmd, line;
line:="a cyclic [";
Append( line, Concatenation( String(WordLength(C)), ",",
String(Dimension(C)), "," ));
lbmd := String( LowerBoundMinimumDistance(C) );
ubmd := String( UpperBoundMinimumDistance(C) );
if lbmd = ubmd then
Append(line, lbmd );
else
Append(line,Concatenation( lbmd, "..", ubmd ) );
fi;
Append( line, "]" );
if Length( BoundsCoveringRadius( C ) ) = 1 then
Append( line, String( BoundsCoveringRadius(C)[ 1 ] ) );
else
Append( line, Concatenation(
String( BoundsCoveringRadius(C)[ 1 ] ),
"..",
String( BoundsCoveringRadius(C)[
Length( BoundsCoveringRadius(C) ) ] ) ) );
fi;
Append( line, " " );
if not IsBound( C!.name ) then
C!.name := "unknown cyclic code";
fi;
Append( line, C!.name );
if not IsBound( C!.history ) then
Append(line,Concatenation(" over GF(", String(Size(LeftActingDomain(C))),")"));
fi;
IsString( line );
return line;
end);
#############################################################################
##
#F Print( <C> ) . . . . . . . . . . . . . prints short information about C
##
##
InstallMethod(PrintObj, "method for codes", true, [IsCode], 0,
function(C)
if HasCoveringRadius(C) and HasMinimumDistance(C) then
Print(String(C)); # sets for future use
else
Print(CodeDescription(C)); # allows to change as bmd, bcr updated
fi;
end);
InstallMethod(PrintObj, "method for linear code", true,
[IsFreeLeftModule and IsLinearCodeRep], 0,
function(C)
if HasCoveringRadius(C) and HasMinimumDistance(C) then
Print(String(C)); #sets for future use
else
Print(CodeDescription(C)); # allows to change as bcr, bmd updated
fi;
end);
InstallMethod(ViewObj, "method for codes", true, [IsCode], 0,
function(C)
if HasCoveringRadius(C) and HasMinimumDistance(C) then
Print(String(C)); # sets for future use
else
Print(CodeDescription(C)); # allows to change as bcr, bmd updated
fi;
end);
InstallMethod(ViewObj, "method for linear code", true,
[IsFreeLeftModule and IsLinearCodeRep], 0,
function(C)
local line;
if HasCoveringRadius(C) and HasMinimumDistance(C) then
Print(String(C)); #sets for future use
elif (IsBound(C!.name) and C!.name="random linear code") then
line := Concatenation( "a [", String(WordLength(C)), ",",String(Dimension(C)), "," );
Append(line,Concatenation( "?] randomly generated code over GF(",String(Size(LeftActingDomain(C))),")") );
Print(line);
elif (IsBound(C!.name) and C!.name="code defined by generator matrix, NC") then
line := Concatenation( "a [", String(WordLength(C)), ",",String(Dimension(C)), "," );
Append(line,Concatenation( "?] randomly generated code over GF(",String(Size(LeftActingDomain(C))),")") );
Print(line);
else
Print(CodeDescription(C)); # allows to change as bcr, bmd updated
fi;
end);
#############################################################################
##
#F Display( <C> ) . . . . . . . . . . . . prints the history of the code C
##
##
InstallMethod(Display, "method for codes", true, [IsCode], 0,
function(C)
local d;
for d in History(C) do
Print(d,"\n");
od;
end);
#############################################################################
##
#F Save( <filename>, <C>, <var-name> ) . . . . . writes the code C to a file
##
## with variable name var-name. It can be read back by calling
## Read (filename); the code then has the name var-name.
## All fields of the code record are stored except for the operations field
## and, in case of a linear or cyclic code, the elements.
## Pre: filename is accessible for writing
##
InstallMethod(Save, "method for unrestricted code", true,
[IsString, IsCode, IsString], 0,
function(filename, C, codename)
local fld, attr_list, attr;
PrintTo(filename, "\n# GUAVA code #\n");
##LR - need proper code creation statement here!
AppendTo(filename, codename, " := rec(\n");
attr_list := [CheckMat, CheckPol, CodeDensity, CodeNorm,
CoordinateNorm, CoveringRadius, DesignedDistance,
Dimension, GeneratorMat, GeneratorPol,
GeneratorsOfLeftModule,
InnerDistribution, IsAffineCode, IsAlmostAffineCode,
IsCyclicCode, IsGriesmerCode, IsLinearCode,
IsMDSCode, IsNormalCode, IsPerfectCode,
IsSelfComplementaryCode, IsSelfDualCode,
IsSelfOrthogonalCode,
LeftActingDomain, MinimumDistance,
MinimumWeightOfGenerators, MinimumWeightWords,
OuterDistribution, Redundancy,
RootsOfCode, SpecialCoveringRadius, SpecialDecoder,
StandardArray, SyndromeTable,
UpperBoundOptimalMinimumDistance,
WeightDistribution, WordLength ];
for attr in attr_list do
if Tester(attr)(C) then
AppendTo(filename, "Set", NameFunction(attr), "(", codename, ", ",
attr(C), ");\n");
fi;
od;
for fld in ["boundsCoveringRadius", "lowerBoundMinimumDistance",
"upperBoundMinimumDistance"] do
if IsBound(C!.(fld)) then
AppendTo(filename, codename, "!.", fld, ":=", C!.(fld), ";\n" );
fi;
od;
if (not HasIsLinearCode(C)) or (not IsLinearCode(C)) then
AppendTo(filename,
"SetAsSSortedList(", codename, ", ", "Codeword(",
VectorCodeword(AsSSortedList(C)),");\n");
fi;
AppendTo(filename, "C!.name := \"", C!.name,"\";\n");
end);
#############################################################################
##
#F History( <C> ) . . . . . . . . . . . . . . . shows the history of a code
##
InstallMethod(History, "method for codes", true, [IsCode], 0,
function(C)
local s;
if not IsBound(C!.history) then
return [CodeDescription(C)];
else
s := String(Concatenation(CodeDescription(C), " of"));
return Concatenation( [s], C!.history);
fi;
end);
######################################################################################
##
#F MinimumDistanceRandom( <C>, <num>, <s> )
##
## This is a simpler version than Leon's method, which does not put G in st form.
## (this works welland is in some cases faster than the st form one)
## Input: C is a linear code
## num is an integer >0 which represents the number of iterations
## s is an integer between 1 and n which represents the columns considered
## in the algorithm.
## Output: an integer >= min dist(C), and hopefully equal to it!
## a codework of that weight
##
## Algorithm: randomly permute the columns of the gen mat G of C
## by a permutation rho - call new mat Gp
## break Gp into (A,B), where A is kxs and B is kx(n-s)
## compute code C_A generated by rows of A
## find min weight codeword c_A of C_A and w_A=wt(c_A)
## using AClosestVectorCombinationsMatFFEVecFFECoords
## extend c_A to a corresponding codeword c_p in C_Gp
## return c=rho^(-1)(c_p) and wt=wt(c_p)=wt(c)
##
InstallMethod(MinimumDistanceRandom, "attribute method for linear codes", true,
[IsLinearCode,IsInt,IsInt], 0,
function(C,num,s)
local A,HasZeroRow,majority,G0, Gp, Gpt, Gt, L, k, n, i, j, m, dimMat, J, d1,M,
arrayd1, Combo, rows, row, rowSum, G, F, zero, AClosestVec, B, ZZ, p, numrow0,
bigwtrow,bigwtvec, x, d, v, ds, vecs,rho,perms,g,newv,pos,rowcombos,v1,v2;
# returns the estimated distance, and corresponding vector of that weight
Print("\n This is a probabilistic algorithm which may return the wrong answer.\n");
G0 := GeneratorMat(C);
p:=5; #this seems to be an optimal value
# it's the max number of rows used in Z to find a small
# codewd in C_Z
G := List(G0,ShallowCopy);
F:=LeftActingDomain(C);
dimMat := DimensionsMat(G);
n:=dimMat[2];
k:=dimMat[1];
if n=k then
C!.lowerBoundMinimumDistance := 1;
C!.upperBoundMinimumDistance := 1;
return 1;
fi; # added 11-2004
if s > n-1 then
Print("Resetting s to ",n-2," ... \n");
s:=n-k;
fi;
arrayd1:=[n];
numrow0:=0; # initialize
perms:=[]; # initialize
for m in [1..num] do
##Permute the columns of C randomly
Gt := TransposedMat(G);
Gp := NullMat(n,k);
L := SymmetricGroup(n);
rho := Random(L);
L:=List([1..n],i->OnPoints(i,rho));
for i in [1..n] do
Gp[i] := Gt[L[i]];
od;
Gp := TransposedMat(Gp);
Gp := List(Gp,ShallowCopy);
##generate the matrix A from Gp=(A|B)
Gpt := TransposedMat(Gp);
A := NullMat(s,k);
for i in [1..s] do
A[i] := Gpt[i];
od;
A := TransposedMat(A);
##generate the matrix B from Gp=(A|B)
Gpt := TransposedMat(Gp);
B := NullMat(n-s,k);
for i in [s+1..n] do
B[i-s] := Gpt[i];
od;
B := TransposedMat(B);
zero := Zero(F)*A[1];
if (s<n-k and A=Zero(F)*A) then
Error("This method fails for these parameters. Try increasing s.\n");
fi;
if (s=n and A=Zero(F)*A) then
return 1;
fi;
## search for all rows of weight p
## J is the list of all triples representing the codeword in C which
## corresponds to AClosestVec[1].
J := []; #col number of codewords to compute the length of
for i in [1..p] do
AClosestVec:=AClosestVectorCombinationsMatFFEVecFFECoords(A, F, zero, i, 1);
### AClosestVec[1]=ZZ*AClosestVec[2]...
v1:=AClosestVec[2]*Gp;
v2:=Permuted(v1,(rho)^(-1));
Add(J,[WeightVecFFE(v2),Codeword(v2,n,F),AClosestVec[2]]);
od;
ds:=List(J,x->x[1]);
vecs:=List(J,x->x[2]);
rowcombos:=List(J,x->x[3]);
d:=Minimum(ds);
i:=Position(ds,d);
arrayd1[m]:=[d,vecs[i],rowcombos[i]];
perms[m]:=rho;
od; ## m
ds:=List(arrayd1,x->x[1]);
vecs:=List(arrayd1,x->x[2]);
rowcombos:=List(arrayd1,x->x[3]);
d:=MostCommonInList(ds);
pos:=Position(ds,d);
v:=vecs[pos];
L:=List([1..n],i->OnPoints(i,perms[pos]^(-1)));
newv:=Codeword(List(L,i->v[L[i]]));
return([d,newv]);
end);
############################################################################
#F MinimumWeight( <C> )
##
## This function calls an external C program to compute the minimum Hamming
## weight of a linear code over GF(2) and GF(3). The external program is
## "minimum-weight"
##
## Author: CJ, Tjhai
##
InstallMethod(MinimumWeight, "attribute method for linear codes", true,
[IsLinearCode], 0,
function(C)
## Since this function calls an external program, we need to write the code
## into a generator matrix format recognised by this external program
local r, c, q, k, n, G, path, param, tmpFile, tmpOutFile;
path := DirectoriesPackagePrograms( "guava" );
if ForAny( ["minimum-weight"], f->Filename( path, f ) = fail ) then
Print("The executable `minimum-weight' is not present in ", path, " ... switching to MinimumDistance ...\n");
return MinimumDistance(C);
fi;
if Size(LeftActingDomain(C)) > 3 then
Print("Code must either be binary or ternary. Quitting. \n"); return(0);
fi;
G := GeneratorMat(C);; G := ShallowCopy(G); TriangulizeMat(G);
k := DimensionsMat(G)[1];
n := DimensionsMat(G)[2];
#path := DirectoriesPackagePrograms( "guava" );; #seems unnecessary -- already done above...
tmpFile := TmpName(); tmpOutFile := TmpName();
PrintTo(tmpFile, k, " ", n, " ", Size(LeftActingDomain(C)), "\n");
for r in [1..k] do;
for c in [1..n] do;
AppendTo(tmpFile, IntFFE(G[r][c]), " ");
od;
AppendTo(tmpFile, "\n");
od;
# Build the parameters required for the external program
# FYI, here is the usage string for the external program:
#usage: C:\gap4r8\pkg\guava-3.13\bin\i686-pc-cygwin-gcc-default32\minimum-weight.exe options [generator matrix file]
# -h --help Display this help screen
# -c --cyclic Indicate that the code is cyclic
# -l --lower-bound [x] Known lower-bound on the minimum distance
# -m --mod [x] Constraint on minimum weight codeword
# 1 : 0 mod 2
# 2 : 1 mod 2
# 3 : 3 mod 4
# 4 : 0 mod 4
# 5 : 0 mod 3
param := ["--out", tmpOutFile];
if IsCyclicCode(C) then
Add(param, "--cyclic");
fi;
if IsBound(C!.lowerBoundMinimumDistance) then
Add(param, "--lower-bound");
Add(param, C!.lowerBoundMinimumDistance);
fi;
if LeftActingDomain(C) = GF(2) then
if IsEvenCode(C) then
Add(param, "--mod");
if IsDoublyEvenCode(C) then
Add(param, 4);
else
Add(param, 1);
fi;
else
Add(param, "--mod");
Add(param, 2);
fi;
elif LeftActingDomain(C) = GF(3) then
if IsSelfOrthogonalCode(C) then
Add(param, "--mod");
Add(param, 5);
fi;
fi;
Add(param, tmpFile);
## Now call the external program
Process(DirectoryCurrent(),
Filename(path, "minimum-weight"),
InputTextNone(),
OutputTextNone(),
param
);
Read(tmpOutFile);
RemoveFiles(tmpFile, tmpOutFile);
C!.lowerBoundMinimumDistance := GUAVA_TEMP_VAR;
C!.upperBoundMinimumDistance := GUAVA_TEMP_VAR;
return GUAVA_TEMP_VAR;
end);
#This is a copy of CosetLeadersMatFFE(mat,f) from gap/lib/listcoef.gi
# for experimentation purposes...
InstallMethod(GuavaCosetLeadersMatFFE,"generic",IsCollsElms,
[IsMatrix,IsFFECollection and IsField],0,
function(mat,f)
local q, leaders, tofind, n,m, t, vl, i, felts, fds,
fdps, v,j,x, w, rrecord, nzfelts, weight, ok8;
rrecord := function(v,w)
local sy,x,u;
sy := NumberFFVector(v,q);
if not IsBound(leaders[sy+1]) then
for x in nzfelts do
sy := NumberFFVector(v*x,q);
u := w*x;
MakeImmutable(u);
leaders[sy+1] := u;
od;
return q-1;
fi;
return 0;
end;
leaders:=[];
q := Size(f);
n := Length(mat[1]);
m := Length(mat);
tofind := q^m;
t := TransposedMat(mat);
vl := [];
vl[m+1] := false;
felts := AsSSortedList(f);
Assert(2, felts[1] = Zero(f));
nzfelts := felts{[2..q]};
fds := List([2..q], i->felts[i] - felts[i-1]);
Add(fds, - Sum(fds));
Add(fds, - One(f));
fdps := List(fds, x-> Position(fds,x));
for i in [1..n] do
v := t[i];
vl[i] := [];
for j in [1..q+1] do
if fdps[j] < j then
Add(vl[i], vl[i][fdps[j]]);
else
Add(vl[i], v*fds[j]);
fi;
od;
Add(vl[i],false);
od;
v := ListWithIdenticalEntries(n, felts[1]);
w := ZeroOp(t[1]);
if 2 <= q and q < 256 then
# 8 bit case, need to get all vectors over the right field
ok8 := true;
if q <> ConvertToVectorRepNC(v,q) then
v := PlainListCopy(v);
ok8 := ok8 and q = ConvertToVectorRepNC(v,q);
fi;
if ok8 and q <> ConvertToVectorRepNC(w,q) then
w := PlainListCopy(w);
ok8 := ok8 and q = ConvertToVectorRepNC(w,q);
fi;
for x in vl{[1..n]} do
for i in [1..q+1] do
if ok8 and q <> ConvertToVectorRepNC(x[i],q) then
x[i] := PlainListCopy(x[i]);
ok8 := ok8 and q = ConvertToVectorRepNC(x[i],q);
fi;
od;
od;
else
ok8 := false;
fi;
leaders := [Immutable(v)];
# this line checks that the required number of coset leaders
# CAN be stored in a plain list
leaders[tofind+1] := false;
tofind := tofind -1;
weight := 0;
while tofind > 0 do
weight := weight + 1;
if weight > n then
Error("not all cosets found");
fi;
if q = 2 then
tofind := tofind - COSET_LEADERS_INNER_GF2( vl, weight,
tofind, leaders);
#elif ok8 then
# Print(tofind, "\n");
# tofind := tofind - COSET_LEADERS_INNER_8BITS( vl, weight,
# tofind, leaders, felts);
else
#Print(tofind, "\n");
tofind := tofind - CosetLeadersInner(vl, v, w, weight, 1,
rrecord, felts, q, tofind);
fi;
od;
Unbind(leaders[q^m+1]);
return leaders;
end);