|
#############################################################################
##
#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(),
--> --------------------
--> maximum size reached
--> --------------------
[ Verzeichnis aufwärts0.63unsichere Verbindung
Übersetzung europäischer Sprachen durch Browser
]
|