Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  codegen.gi   Sprache: unbekannt

 
Spracherkennung für: .gi vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

#############################################################################
##
#A  codegen.gi              GUAVA library                       Reinald Baart
#A                                                        &Jasper Cramwinckel
#A                                                           &Erik Roijackers
##                                                          &David Joyner
##
##  This file contains info/functions for generating codes
##
##  BCHCode modified 9-2004
##  added 11-2004:
##  comment in GoppaCode
##  GeneralizedReedSolomonCode and record fields
##      points, degree, ring,
##  (added SpecialDecoder field later: SetSpecialDecoder(C, GRSDecoder);)
##  EvaluationCode and record fields
##      points, basis, ring,
##  OnePointAGCode and record fields
##      points, curve, multiplicity, ring
##  weighted option for GeneralizedReedSolomonCode and record fields
##      points, degree, ring, weights
##  minor bug in EvaluationCode fixed 11-26-2004
##  GeneratorMatCodeNC added 12-18-2004 (after release of guava 2.0)
##  added 5-10-2005:  SetSpecialDecoder(C, CyclicDecoder);  to
##    the cyclic codes which are not BCH codes
##    in codegen.gi, line 2066, replace C.GeneratorMat
##      by C.EvaluationMat
##  added 5-13-2005: QQRCode
##  added 11-27-2005: CheckMatCodeMutable with *mutable*
##              generator and check matrices
##  added 1-10-2006: QQRCodeNC  Greg Coy and David Joyner
##  added 1-2006: FerreroDesignCode, written with Peter Mayr
##  added 12-2007 (CJ): ExtendedReedSolomonCode, QuasiCyclicCode,
##    CyclicMDSCode, FourNegacirculantSelfDualCode functions.
##

DeclareRepresentation( "IsCodeDefaultRep",
               IsAttributeStoringRep and IsComponentObjectRep and IsCode,
               ["name", "history", "lowerBoundMinimumDistance",
                "upperBoundMinimumDistance", "boundsCoveringRadius"]);

DeclareHandlingByNiceBasis( "IsLinearCodeRep", "for linear codes" );

InstallTrueMethod( IsLinearCode, IsLinearCodeRep );

#T The following is of course a hack, as is much of the
#T ``pretend as if you were a vector space'' stuff.
#T (`IsLinearCode' changes harmless codes into vector spaces;
#T `AsLinearCode' would be clean, but now it is too late ...)
InstallTrueMethod( IsFreeLeftModule, IsLinearCodeRep );

### functions to work with NiceBasis functionality for Linear Codes.
InstallHandlingByNiceBasis( "IsLinearCodeRep", rec(
    detect:= function( R, gens, V, zero )
      return IsCodewordCollection( V );
      end,

    NiceFreeLeftModuleInfo:= ReturnFalse,

    NiceVector:= function( C, w )
      return VectorCodeword( w );
      end,

    UglyVector:= function( C, v )
      return Codeword( v, Length( v ), LeftActingDomain( C ) );
    end ) );


#############################################################################
##
#F  ElementsCode( <L> [, <name> ], <F> )  . . . . . . code from list of words
##

InstallMethod(ElementsCode, "list,name,Field", true,
    [IsList,IsString,IsField], 0,
function(L, name, F)
    local test, C;
    L := Codeword(L, F);
    test := WordLength(L[1]);
    if ForAny(L, i->WordLength(i) <> test) then
        Error("All elements must have the same length");
    fi;
    test := FamilyObj(L[1]);
    if ForAny(L, i->FamilyObj(i) <> test) then
        Error ("All elements must have the same family");
    fi;
    L := Set(L);
    C := Objectify(NewType(CollectionsFamily(test), IsCodeDefaultRep), rec());
    SetLeftActingDomain(C, F);
    SetAsSSortedList(C, L);
    C!.name := name;
    return C;
end);

InstallOtherMethod(ElementsCode, "list,Field", true, [IsList, IsField], 0,
function(L,F)
    return ElementsCode(L, "user defined unrestricted code", F);
end);

InstallOtherMethod(ElementsCode, "list,name,fieldsize", true,
    [IsList, IsString, IsInt], 0,
function(L, name, q)
    return ElementsCode(L, name, GF(q));
end);

InstallOtherMethod(ElementsCode, "list,size of field", true, [IsList,IsInt], 0,
function(L, q)
    return ElementsCode(L, "user defined unrestricted code", GF(q));
end);

##Create a linear code from a list of Codeword generators
LinearCodeByGenerators := function(F, gens)

    local V, M, row, i, j;
    V:= Objectify( NewType( FamilyObj( gens ),
                            IsLeftModule and
                IsLinearCodeRep and IsCodeDefaultRep ),
                   rec() );
    SetLeftActingDomain( V, F );
    SetGeneratorsOfLeftModule( V, AsList( One(F)*gens ) );
    SetIsLinearCode(V, true);
    SetWordLength(V, Length(gens[1]));
    #M:=[];
    #for i in [1..Length(gens)] do
    #    row:=[];
    #    for j in [1..Length(gens[i])] do
    #        Append(row,[gens[i][j]]);
    #    od;
    #    Append(M, [row]);
    #od;
    #SetGeneratorMat(V, M);  #The calling functions always handle setting the GenMat
    return V;

end;


#############################################################################
##
#F  RandomCode( <n>, <M> [, <F>] )  . . . . . . . .  random unrestricted code
##
InstallMethod(RandomCode, "wordlength,codesize,field", true,
    [IsInt, IsInt, IsField], 0,
function(n, M, F)
    local L;
    if Size(F)^n < M then
        Error(Size(F),"^",n," < ",M);
    fi;
    L := [];
    while Length(L) < M do
        AddSet(L, List([1..n], i -> Random(F)));
    od;
    return ElementsCode(L, "random unrestricted code", F);
end);

InstallOtherMethod(RandomCode, "wordlength,codesize", true, [IsInt, IsInt], 0,
function(n, M)
    return RandomCode(n, M, GF(2));
end);

InstallOtherMethod(RandomCode, "wordlength,codesize,fieldsize", true,
    [IsInt, IsInt, IsInt], 0,
function(n, M, q)
    return RandomCode(n, M, GF(q));
end);


#############################################################################
##
#F  HadamardCode( <H | n> [, <t>] ) . Hadamard code of <t>'th kind, order <n>
##

InstallMethod(HadamardCode, "matrix, kind (int)", true, [IsMatrix, IsInt], 0,
function(H, t)
    local n, vec, C;
    n := Length(H);
    if H * TransposedMat(H) <> n * IdentityMat(n,n) then
        Error("The matrix is not a Hadamard matrix");
    fi;
    H := (H-1)/(-2);
    if t = 1 then
        H := TransposedMat(TransposedMat(H){[2..n]});
        C := ElementsCode(H, Concatenation("Hadamard code of order ",
                          String(n)), GF(2) );
        C!.lowerBoundMinimumDistance := n/2;
        C!.upperBoundMinimumDistance := n/2;
        vec := NullVector(n);
        # this was ... := NullVector(n+1);
        # but this seems to be wrong -- Eric Minkes
        vec[1] := 1;
        vec[n/2+1] := Size(C) - 1;
        SetInnerDistribution(C, vec);
    elif t  = 2 then
        H := ShallowCopy( TransposedMat(TransposedMat(H){[2..n]}) );
        Append(H, 1 - H);
        C := ElementsCode(H, Concatenation("Hadamard code of order ",
                                          String(n)), GF(2) );
        C!.lowerBoundMinimumDistance := n/2 - 1;
        C!.upperBoundMinimumDistance := n/2 - 1;
        vec := NullVector(n);
        vec[1] := 1;
        vec[n] := 1;
        # this was ... [n+1]...
        # but this seems to be wrong -- Eric Minkes
        vec[n/2] := Size(C)/2 - 1;
        vec[n/2+1] := Size(C)/2 - 1;
        SetInnerDistribution(C, vec);
    else
        Append(H, 1 - H);
        C := ElementsCode( H, Concatenation("Hadamard code of order ",
                               String(n)), GF(2) );
        C!.lowerBoundMinimumDistance := n/2;
        C!.upperBoundMinimumDistance := n/2;
        vec := NullVector(n);
        vec[1] := 1;
        vec[n+1] := 1;
        vec[n/2+1] := Size(C) - 2;
        SetInnerDistribution(C, vec);
    fi;
    return(C);
end);

InstallOtherMethod(HadamardCode, "order, kind (int)", true, [IsInt, IsInt], 0,
function(n, t)
    return HadamardCode(HadamardMat(n), t);
end);

InstallOtherMethod(HadamardCode, "matrix", true, [IsMatrix], 0,
function(H)
    return HadamardCode(H, 3);
end);

InstallOtherMethod(HadamardCode, "order", true, [IsInt], 0,
function(n)
    return HadamardCode(HadamardMat(n), 3);
end);

InstallOtherMethod(HadamardCode, "matrix, kind (string)", true,
    [IsMatrix, IsString], 0,
function(H, t)
    if t in ["a", "A", "1"] then
        return HadamardCode(H, 1);
    elif t in ["b", "B", "2"] then
        return HadamardCode(H, 2);
    else
        return HadamardCode(H, 3);
    fi;
end);

InstallOtherMethod(HadamardCode, "order, kind (string)", true,
    [IsInt, IsString], 0,
function(n, t)
    if t in ["a", "A", "1"] then
        return HadamardCode(HadamardMat(n), 1);
    elif t in ["b", "B", "2"] then
        return HadamardCode(HadamardMat(n), 2);
    else
        return HadamardCode(HadamardMat(n), 3);
    fi;
end);

#############################################################################
##
#F  ConferenceCode( <n | M> ) . . . . . . . . . . code from conference matrix
##

InstallMethod(ConferenceCode, "matrix", true, [IsMatrix], 0,
function(S)
    local n, I, J, F, els, w, wd, C;
    n := Length(S);
    if S*TransposedMat(S) <> (n-1)*IdentityMat(n) or
       TransposedMat(S) <> S then
       Error("argument must be a symmetric conference matrix");
    fi;
    # Normalize S by multiplying rows and columns:
    for I in [2..n] do
        if S[I][1] <> 1 then
            for J in [1..n] do
                S[I][J] := S[I][J] * -1;
            od;
        fi;
    od;
    for J in [2..n] do
        if S[1][J] <> 1 then
            for I in [1..n] do
                S[I][J] := S[I][J] * -1;
            od;
        fi;
    od;
    # Strip first row and first column:
    S := List([2..n], i-> S[i]{[2..n]});
    n := n - 1;

    F := GF(2);
    els := [NullWord(n, F)];
    I := IdentityMat(n);
    J := NullMat(n,n) + 1;
    Append(els, Codeword(1/2 * (S+I+J), F));
    Append(els, Codeword(1/2 * (-S+I+J), F));
    Add( els, Codeword( List([1..n], x -> One(F) ), n, One(F) ) );
    C := ElementsCode( els, "conference code", F);
    w := Weight(AsSSortedList(C)[2]);
    wd := List([1..n+1], x -> 0);
    wd[1] := 1; wd[n+1] := 1;
    wd[w+1] := Size(C) - 2;
    SetWeightDistribution(C, wd);
    C!.lowerBoundMinimumDistance := (n-1)/2;
    C!.upperBoundMinimumDistance := (n-1)/2;
    return C;
end);

InstallOtherMethod(ConferenceCode, "integer", true, [IsInt], 0,
function(n)
    local LegendreSym, zero, QRes, E, I, S, F, els, J, w, wd, C;

    LegendreSym := function(i)
        if i = zero then
            return 0;
        elif i in QRes then
            return 1;
        else
            return -1;
        fi;
    end;

    if (not IsPrimePowerInt(n)) or (n mod 4 <> 1) then
        Error ("n must be a primepower and n mod 4 = 1");
    fi;
    E := AsSSortedList(GF(n));
    zero := E[1];
    QRes := [];
    for I in E do
        AddSet(QRes, I^2);
    od;
    S := List(E, i->List(E, j->LegendreSym(j-i)));


    F := GF(2);
    els := [NullWord(n, F)];
    I := IdentityMat(n);
    J := NullMat(n,n) + 1;
    Append(els, Codeword(1/2 * (S+I+J), F));
    Append(els, Codeword(1/2 * (-S+I+J), F));
    Add(   els, Codeword( List([1..n], x -> One(F) ), n, One(F) ) );
    C := ElementsCode( els, "conference code", F);
    w := Weight(AsSSortedList(C)[2]);
    wd := List([1..n+1], x -> 0);
    wd[1] := 1; wd[n+1] := 1;
    wd[w+1] := Size(C) - 2;
    SetWeightDistribution(C, wd);
    C!.lowerBoundMinimumDistance := (n-1)/2;
    C!.upperBoundMinimumDistance := (n-1)/2;
    return C;
end);


#############################################################################
##
#F  MOLSCode( [ <n>, ] <q> )  . . . . . . . . . . . . . . . .  code from MOLS
##
##  MOLSCode([n, ] q) returns a (n, q^2, n-1) code over GF(q)
##  by creating n-2 mutually orthogonal latin squares of size q.
##  If n is omitted, a wordlength of 4 will be set.
##  If there are no n-2 MOLS known, the code will return an error
##

InstallMethod(MOLSCode, "wordlength,size of field", true, [IsInt, IsInt], 0,
function(n,q)
    local M, els, i, j, k, wd, C;
    M := MOLS(q, n-2);
    if M = false then
        Error("No ", n-2, " MOLS of order ", q, " are known");
    else
        els := [];
        for i in [1..q] do
            for j in [1..q] do
                els[(i-1)*q+j] := [];
                els[(i-1)*q+j][1] := i-1;
                els[(i-1)*q+j][2]:= j-1;
                for k in [3..n] do
                    els[(i-1)*q+j][k]:= M[k-2][i][j];
                od;
            od;
        od;
        C := ElementsCode( els, Concatenation("code generated by ",
                         String(n-2), " MOLS of order ", String(q)), GF(q) );
        C!.lowerBoundMinimumDistance := n - 1;
        C!.upperBoundMinimumDistance := n - 1;
        wd := List( [1..n+1], x -> 0 );
        wd[1] := 1;
        wd[n] := (q-1) * n;
        wd[n+1] := (q-1) * (q + 1 - n);
        SetWeightDistribution(C, wd);
        return C;
    fi;
end);

InstallOtherMethod(MOLSCode, "wordlength,field", true, [IsInt, IsField], 0,
function(n, F)
    return MOLSCode(n, Size(F));
end);

InstallOtherMethod(MOLSCode, "fieldsize", true, [IsInt], 0,
function(q)
    return MOLSCode(4, q);
end);

InstallOtherMethod(MOLSCode, "field", true, [IsField], 0,
function(F)
    return MOLSCode(4, Size(F));
end);


## Was commented out in gap 3.4.4 Guava version.

#############################################################################
##
#F  QuadraticCosetCode( <Q> ) . . . . . . . . . .  coset of RM(1,m) in R(2,m)
##
##  QuadraticCosetCode(Q) returns a coset of the ReedMullerCode of
##  order 1 (R(1,m)) in R(2,m) where m is the size of square matrix Q.
##  Q is the upper triangular matrix that defines the quadratic part of
##  the boolean functions that are in the coset.
##
#QuadraticCosetCode := function(arg)
#    local Q, m, V, R, RM1, k, f, C, h, wd;
#    if Length(arg) = 1 and IsMat(arg[1]) then
#        Q := arg[1];
#    else
#        Error("usage: QuadraticCosetCode( <mat> )");
#    fi;
#    m := Length(Q);
#    V := Tuples(Elements(GF(2)), m);
#    R := V*Q*TransposedMat(V);
#    f := List([1..2^m], i->R[i][i]);
#    RM1 := Concatenation(NullMat(1,2^m,GF(2))+GF(2).one,
#                   TransposedMat(Tuples(Elements(GF(2)), m)));
#    k := Length(RM1);
#    C := rec(
#             isDomain := true,
#             isCode := true,
#             operations := CodeOps,
#             baseField := GF(2),
#             wordLength := 2^m,
#    elements := Codeword(List(Tuples(Elements(GF(2)), k) * RM1, t-> t+f)),
#             lowerBoundMinimumDistance := 2^(m-1),
#             upperBoundMinimumDistance := 2^(m-1)
#            );
#    h := RankMat(Q + TransposedMat(Q))/2;
#    wd := NullMat(1, 2^m+1)[1];
#    wd[2^(m-1) - 2^(m-h-1) + 1] := 2^(2*h);
#    wd[2^(m-1) + 1] := 2^(m+1) - 2^(2*h + 1);
#    wd[2^(m-1) + 2^(m-h-1) + 1] := 2^(2*h);
#    C.weightDistribution := wd;
#    C.name := "quadratic coset code";
#    return C;
#end;


#############################################################################
##
#F  GeneratorMatCode( <G> [, <name> ], <F> )  . .  code from generator matrix
##

InstallMethod(GeneratorMatCode, "generator matrix, name, field", true,
    [IsMatrix, IsString, IsField], 0,
function(G, name, F)
    local C;
    if (Length(G) = 0) or (Length(G[1]) = 0) then
        Error("Use NullCode to generate a code with dimension 0");
    fi;
    G := G*One(F);
    G := BaseMat(G);
    C := LinearCodeByGenerators(F, Codeword(G,F));
    SetGeneratorMat(C, G);
    SetWordLength(C, Length(G[1]));
    C!.name := name;
    return C;
end);

InstallOtherMethod(GeneratorMatCode, "generator matrix, field", true,
    [IsMatrix, IsField], 0,
function(G, F)
    return GeneratorMatCode(G, "code defined by generator matrix", F);
end);

InstallOtherMethod(GeneratorMatCode, "generator matrix, name, size of field",
    true, [IsMatrix, IsString, IsInt], 0,
function(G, name, q)
    return GeneratorMatCode(G, name, GF(q));
end);

InstallOtherMethod(GeneratorMatCode, "generator matrix, size of field", true,
    [IsMatrix, IsInt], 0,
function(G, q)
    return GeneratorMatCode(G, "code defined by generator matrix", GF(q));
end);

#############################################################################
##
#F  GeneratorMatCodeNC( <G> , <F> )  . .  code from generator matrix
##
## same as GeneratorMatCode but does not compute upper + lower bounds
##  for the minimum distance or covering radius
##

InstallMethod(GeneratorMatCodeNC, "generator matrix, field", true,
    [IsMatrix, IsField], 0,
function(G, F)
    return GeneratorMatCode(G, "code defined by generator matrix, NC", F);
end);



#############################################################################
##
#F  CheckMatCodeMutable( <H> [, <name> ], <F> )  . . code from check matrix
##                                               The generator matrix is mutable
##

InstallMethod(CheckMatCodeMutable, "check matrix, name, field", true,
    [IsMatrix, IsString, IsField], 0,
function(H, name, F)
    local G, H2, C, dimC;
    if (Length(H) = 0)  or (Length(H[1]) = 0) then
        Error("use WholeSpaceCode to generate a code with redundancy 0");
    fi;
    H := VectorCodeword(Codeword(H, F));
    H2 := BaseMat(H);
    if Length(H2) < Length(H) then
        H := H2;
    fi;

    # Get generator matrix from H
    if IsInStandardForm(H, false) then
        dimC := Length(H[1]) - Length(H);
        if dimC = 0 then
            G := [];
        else
            G := TransposedMat(Concatenation(IdentityMat( dimC, F ),
                            List(-H, x->x{[1..dimC]})));
        fi;
    else
        G := NullspaceMat(TransposedMat(H));
    fi;
    if Length(G) = 0 then  # Call NullCode. Length(H=I) = n-k, in this case.
                           # Length(G) = k = 0 => n = Length(H).
        C := NullCode(Length(H), F);
        C!.name := name;
        return C;
    fi;

    C := LinearCodeByGenerators(F,Codeword(G, F));
    SetGeneratorMat(C, ShallowCopy(G));
    SetCheckMat(C, ShallowCopy(H));
    SetWordLength(C, Length(G[1]));
    C!.name := name;
    return C;
end);

InstallOtherMethod(CheckMatCodeMutable, "check matrix, field",
true, [IsMatrix, IsField], 0,
function(H, F)
    return CheckMatCode(H, "code defined by check matrix", F);
end);

InstallOtherMethod(CheckMatCodeMutable, "check matrix, name, size of field", true, [IsMatrix, IsString, IsInt], 0,
function(H, name, q)
    return CheckMatCode(H, name, GF(q));
end);

InstallOtherMethod(CheckMatCodeMutable, "check matrix, size of field",
true, [IsMatrix, IsInt], 0,
function(H, q)
    return CheckMatCodeMutable(H, "code defined by check matrix", GF(q));
end);



#############################################################################
##
#F  CheckMatCode( <H> [, <name> ], <F> )  . . . . . .  code from check matrix
##

InstallMethod(CheckMatCode, "check matrix, name, field", true,
    [IsMatrix, IsString, IsField], 0,
function(H, name, F)
    local G, H2, C, dimC;
    if (Length(H) = 0)  or (Length(H[1]) = 0) then
        Error("use WholeSpaceCode to generate a code with redundancy 0");
    fi;
    H := VectorCodeword(Codeword(H, F));
    H2 := BaseMat(H);
    if Length(H2) < Length(H) then
        H := H2;
    fi;

    # Get generator matrix from H
    if IsInStandardForm(H, false) then
        dimC := Length(H[1]) - Length(H);
        if dimC = 0 then
            G := [];
        else
            G := TransposedMat(Concatenation(IdentityMat( dimC, F ),
                            List(-H, x->x{[1..dimC]})));
        fi;
    else
        G := NullspaceMat(TransposedMat(H));
    fi;
    if Length(G) = 0 then  # Call NullCode. Length(H=I) = n-k, in this case.
                           # Length(G) = k = 0 => n = Length(H).
        C := NullCode(Length(H), F);
        C!.name := name;
        return C;
    fi;

    C := LinearCodeByGenerators(F,Codeword(G, F));
    SetGeneratorMat(C, G);
    SetCheckMat(C, H);
    SetWordLength(C, Length(G[1]));
    C!.name := name;
    return C;
end);

InstallOtherMethod(CheckMatCode, "check matrix, field", true,
    [IsMatrix, IsField], 0,
function(H, F)
    return CheckMatCode(H, "code defined by check matrix", F);
end);

InstallOtherMethod(CheckMatCode, "check matrix, name, size of field", true,
    [IsMatrix, IsString, IsInt], 0,
function(H, name, q)
    return CheckMatCode(H, name, GF(q));
end);

InstallOtherMethod(CheckMatCode, "check matrix, size of field", true,
    [IsMatrix, IsInt], 0,
function(H, q)
    return CheckMatCode(H, "code defined by check matrix", GF(q));
end);


#############################################################################
##
#F  RandomLinearCode( <n>, <k> [, <F>] )  . . . . . . . .  random linear code
##

InstallMethod(RandomLinearCode, "n,k,field", true, [IsInt, IsInt, IsField], 0,
function(n, k, F)
    if k = 0 then
        return NullCode( n, F );
    else
        return GeneratorMatCode(PermutedCols(List(IdentityMat(k,F), i ->
                   Concatenation(i,List([k+1..n],j->Random(F)))),
                   Random(SymmetricGroup(n))), "random linear code", F);
    fi;
end);

InstallOtherMethod(RandomLinearCode, "n,k,size of field", true,
    [IsInt, IsInt, IsInt], 0,
function(n, k, q)
    return RandomLinearCode(n, k, GF(q));
end);

InstallOtherMethod(RandomLinearCode, "n,k", true, [IsInt, IsInt], 0,
function(n, k)
    return RandomLinearCode(n, k, GF(2));
end);


#############################################################################
##
#F  HammingCode( <r> [, <F>] )  . . . . . . . . . . . . . . . .  Hamming code
##

InstallMethod(HammingCode, "r,F", true, [IsInt, IsField], 0,
function(r, F)
    local q, H, H2, C, i, j, n, TupAllow, wd;

    TupAllow := function(W)
        local l;
        l := 1;
        while (W[l] = Zero(F)) and l < Length(W) do
            l := l + 1;
        od;
        return (W[l] = One(F));
    end;

    q := Size(F);
    if not IsPrimePowerInt(q) then
        Error("q must be prime power");
    fi;
    H := Tuples(AsSSortedList(F), r);
    H2 := [];
    j := 1;
    for i in [1..Length(H)] do
        if TupAllow(H[i]) then
            H2[j] := H[i];
            j := j + 1;
        fi;
    od;
    n := (q^r-1)/(q-1);
    C := CheckMatCode(TransposedMat(H2), Concatenation("Hamming (", String(r),
                 ",", String(q), ") code"), F);
    C!.lowerBoundMinimumDistance := 3;
    C!.upperBoundMinimumDistance := 3;
    C!.boundsCoveringRadius := [ 1 ];
    SetIsPerfectCode(C, true);
    SetIsSelfDualCode(C, false);
    SetSpecialDecoder(C, HammingDecoder);
    if q = 2 then
        SetIsNormalCode(C, true);
        wd := [1, 0];
        for i in [2..n] do
            Add(wd, 1/i * (Binomial(n, i-1) - wd[i] - (n-i+2)*wd[i-1]));
        od;
        SetWeightDistribution(C, wd);
    fi;
    return C;
end);

InstallOtherMethod(HammingCode, "r,size of field", true, [IsInt, IsInt], 0,
function(r, q)
    return HammingCode(r, GF(q));
end);

InstallOtherMethod(HammingCode, "r", true, [IsInt], 0,
function(r)
    return HammingCode(r, GF(2));
end);


#############################################################################
##
#F  SimplexCode( <r>, <F> ) .  The SimplexCode is the Dual of the HammingCode
##

InstallMethod(SimplexCode, "redundancy, field", true, [IsInt, IsField], 0,
function(r, F)
    local C;
    C := DualCode( HammingCode(r,F) );
    C!.name := "simplex code";
    if F = GF(2) then
        SetIsNormalCode(C, true);
        C!.boundsCoveringRadius := [ 2^(r-1) - 1 ];
    fi;
    return C;
end);

InstallOtherMethod(SimplexCode, "redundancy, fieldsize", true,[IsInt,IsInt],0,
function(r, q)
    return SimplexCode(r, GF(q));
end);

InstallOtherMethod(SimplexCode, "redundancy", true, [IsInt], 0,
function(r)
    return SimplexCode(r, GF(2));
end);


#############################################################################
##
#F  ReedMullerCode( <r>, <k> )  . . . . . . . . . . . . . .  Reed-Muller code
##
##  ReedMullerCode(r, k) creates a binary Reed-Muller code of dimension k,
##  order r; 0 <= r <= k
##

InstallMethod(ReedMullerCode, "dimension, order", true, [IsInt,IsInt], 0,
function(r,k)
    local mat,c,src,dest,index,num,dim,C,wd, h,t,A, bcr;

    if r > k then
        return ReedMullerCode(k, r); #for compatibility with older versions
                                     #of guava, It used to be
                                     #ReedMullerCode(k, r);
    fi;
    mat := [ [] ];
    num := 2^k;
    dim := Sum(List([0..r], x->Binomial(k,x)));
    for t in [1..num] do
        mat[1][t] := Z(2)^0;
    od;
    if r > 0 then
        Append(mat, TransposedMat(Tuples ([0*Z(2), Z(2)^0], k)));
        for t in [2..r] do
            for index in Combinations([1..k], t) do
                dest := List([1..2^k], i->Product(index, j->mat[j+1][i]));
                Append(mat, [dest]);
            od;
        od;
    fi;
    C := GeneratorMatCode( mat, Concatenation("Reed-Muller (", String(r), ",",
            String(k), ") code"), GF(2) );
    C!.lowerBoundMinimumDistance := 2^(k-r);
    C!.upperBoundMinimumDistance := 2^(k-r);
    SetIsPerfectCode(C, false);
    SetIsSelfDualCode(C, (2*r = k-1));
    if r = 0 then
        wd := List([1..num + 1], x -> 0);
        wd[1] := 1;
        wd[num+1] := 1;
        SetWeightDistribution(C, wd);
    elif r = 1 then
        wd := List([1..num + 1], x -> 0);
        wd[1] := 1;
        wd[num + 1] := 1;
        wd[num / 2 + 1] := Size(C) - 2;
        SetWeightDistribution(C, wd);
    elif r = 2 then
        wd := List([1..num + 1], x -> 0);
        wd[1] := 1;
        wd[num + 1] := 1;
        for h in [1..QuoInt(k,2)] do
            A := 2^(h*(h+1));
            for t in [0..2*h-1] do
                A := A*(2^(k-t)-1);
            od;
            for t in [1..h] do
                A := A/(2^(2*t)-1);
            od;
            wd[2^(k-1)+2^(k-1-h)+1] := A;
            wd[2^(k-1)-2^(k-1-h)+1] := A;
        od;
        wd[2^(k-1)+1] := Size(C)-Sum(wd);
        SetWeightDistribution(C, wd);
    fi;

    bcr := BoundsCoveringRadius( C );

    if 0 <= r and r <= k-3 then
        if IsEvenInt( r ) then
            C!.boundsCoveringRadius :=
              [ Maximum( 2^(k-r-3)*(r+4), bcr[1] )
                .. Maximum( bcr ) ];
        else
            C!.boundsCoveringRadius :=
              [ Maximum( 2^(k-r-3)*(r+5), bcr[ 1 ] )
                .. Maximum( bcr ) ];
        fi;
    fi;

    if r = k then
        SetCoveringRadius(C, 0);
        C!.boundsCoveringRadius := [ 0 ];
    elif r = k - 1 then
        SetCoveringRadius(C, 1);
        C!.boundsCoveringRadius := [ 1 ];
    elif r = k - 2 then
        SetCoveringRadius(C, 2);
        C!.boundsCoveringRadius := [ 2 ];
    elif r = k - 3 then
        if IsEvenInt( k ) then
            SetCoveringRadius(C, k + 2 );
            C!.boundsCoveringRadius := [ k + 2 ];
        else
            SetCoveringRadius(C,  k + 1 );
            C!.boundsCoveringRadius := [ k + 1 ];
        fi;
    elif r = 0 then
        SetCoveringRadius(C,  2^(k-1) );
        C!.boundsCoveringRadius := [ 2^(k-1) ];
    elif r = 1 then
        if IsEvenInt( k ) then
            SetCoveringRadius(C,  2^(k-1) - 2^(k/2-1) );
            C!.boundsCoveringRadius := [ 2^(k-1) - 2^(k/2-1) ];
        elif k = 5 then
            SetCoveringRadius(C,  12 );
            C!.boundsCoveringRadius := [ 12 ];
        elif k = 7 then
            SetCoveringRadius(C,  56 );
            C!.boundsCoveringRadius := [ 56 ];
        elif k >= 15 then
            C!.boundsCoveringRadius := [ 2^(k-1) - 2^((k+1)/2)*27/64
                                        .. 2^(k-1) - 2^( QuoInt(k,2)-1 ) ];
        else
            C!.boundsCoveringRadius := [ 2^(k-1) - 2^((k+1)/2)/2
                                        .. 2^(k-1) - 2^( QuoInt(k,2)-1 ) ];
        fi;
    elif r = 2 then
        if k = 6 then
            SetCoveringRadius(C,  18 );
            C!.boundsCoveringRadius := [ 18 ];
        elif k = 7 then
            C!.boundsCoveringRadius := [ 40 .. 44 ];
        elif k = 8 then
            C!.boundsCoveringRadius := [ 84
              .. Maximum( bcr ) ];
        fi;
    elif r = 3 then
        if k = 7 then
            C!.boundsCoveringRadius := [ 20 .. 23 ];
        fi;
    elif r = 4 then
        if k = 8 then
            C!.boundsCoveringRadius := [ 22
              .. Maximum( bcr ) ];
        fi;
    fi;

    if r = 1 and
       ( IsEvenInt( k ) or k = 3 or k = 5 or k = 7 ) then
        SetIsNormalCode(C, true);
    fi;

    return C;
end);


#############################################################################
##
#F  LexiCode( <M | n>, <d>, <F> )  . . . . .  Greedy code with standard basis
##

InstallMethod(LexiCode, "basis,distance,field", true,
    [IsMatrix, IsInt, IsField], 0,
function(M, d, F)
    local base, n, k, one, zero, elms, Sz, vec, word, i, dist, carry, pos, C;
    base := VectorCodeword(Codeword(M, F));
    n := Length(base[1]);
    k := Length(base);
    one := One(F);
    zero := Zero(F);
    elms := [];
    Sz := 0;
    vec := NullVector(k,F);
    repeat
        word := vec * base;
        i := 1;
        dist := d;
        while (dist>=d) and (i <= Sz) do
            dist := DistanceVecFFE(word, elms[i]);
            i := i + 1;
            od;
            if dist >= d then
                Add(elms,ShallowCopy(word));
                Sz := Sz + 1;
            fi;
            # generate the (lexicographical) next word in F^k
            carry := true;
            pos := k;
            while carry and (pos > 0) do
            if vec[pos] = zero then
                carry := false;
                vec[pos] := one;
            else
                vec[pos] := PrimitiveRoot(F)^(LogFFE(vec[pos],PrimitiveRoot(F))+1);
                if vec[pos] = one then
                    vec[pos] := zero;
                else
                    carry := false;
                fi;
            fi;
            pos := pos - 1;
        od;
    until carry;
    if Size(F) = 2 then  # or even (2^(2^LogInt(LogInt(q,2),2)) = q) ?
        C := GeneratorMatCode(elms, "lexicode", F);
    else
        C := ElementsCode(elms, "lexicode", F);
    fi;
    C!.lowerBoundMinimumDistance := d;
    return C;
end);

InstallOtherMethod(LexiCode, "basis,distance,size of field", true,
    [IsMatrix, IsInt, IsInt], 0,
function(M, d, q)
    return LexiCode(M, d, GF(q));
end);

InstallOtherMethod(LexiCode, "wordlength,distance,field", true,
    [IsInt, IsInt, IsField], 0,
function(n, d, F)
    return LexiCode(IdentityMat(n,F), d, F);
end);

InstallOtherMethod(LexiCode, "wordlength,distance,size of field", true,
    [IsInt, IsInt, IsInt], 0,
function(n, d, q)
    return LexiCode(IdentityMat(n, GF(q)), d, GF(q));
end);


#############################################################################
##
#F  GreedyCode( <M>, <d> [, <F>] )  . . . . Greedy code from list of elements
##

InstallMethod(GreedyCode, "matrix,design distance,Field", true,
    [IsMatrix, IsInt, IsField], 0,
function(M,d,F)
    local space, n, word, elms, Sz, i, dist, C;
    space := VectorCodeword(Codeword(M,F));
    n := Length(space[1]);
    elms := [space[1]];
    Sz := 1;
    for word in space do
        i := 1;
        repeat
            dist := DistanceVecFFE(word, elms[i]);
            i := i + 1;
        until dist < d or i > Sz;
        if dist >= d then
            Add(elms, word);
            Sz := Sz + 1;
        fi;
    od;
    C := ElementsCode(elms, "Greedy code, user defined basis", F);
    C!.lowerBoundMinimumDistance := d;
    return C;
end);

InstallOtherMethod(GreedyCode, "matrix,design distance,size of field", true,
    [IsMatrix, IsInt, IsInt], 0,
function(M,d,q)
    return GreedyCode(M,d,GF(q));
end);

InstallOtherMethod(GreedyCode, "matrix,design distance", true,
    [IsMatrix,IsInt], 0,
function(M,d)
    return GreedyCode(M,d,DefaultField(Flat(M)));
end);


#############################################################################
##
#F  AlternantCode( <r>, <Y> [, <alpha>], <F> )  . . . . . . .  Alternant code
##

InstallMethod(AlternantCode, "redundancy, Y, alpha, field", true,
    [IsInt, IsList, IsList, IsField], 0,
function(r, Y, els, F)
    local C, n, q, i, temp;
    n := Length(Y);
    els := Set(VectorCodeword(Codeword(els, F)));
    Y := VectorCodeword(Codeword(Y, F) );

    if ForAny(Y, i-> i = Zero(F)) then
        Error("Y contains zero");
    elif Length(els) <> Length(Y) then
        Error("<Y> and <alpha> have inequal length or <alpha> is not distinct");
    fi;
    q := Characteristic(F);
    temp := NullMat(n, n, F);
    for i in [1..n] do
        temp[i][i] := Y[i];
    od;
    Y := temp;
    C := CheckMatCode( BaseMat(VerticalConversionFieldMat( List([0..r-1],
                 i -> List([1..n], j-> els[j]^i)) * Y)), "alternant code", F );
    C!.lowerBoundMinimumDistance := r + 1;
    return C;
end);

InstallOtherMethod(AlternantCode, "redundancy, Y, alpha, fieldsize", true,
    [IsInt, IsList, IsList, IsInt], 0,
function(r, Y, a, q)
    return AlternantCode(r, Y, a, GF(q));
end);

InstallOtherMethod(AlternantCode, "redundancy, Y, field", true,
    [IsInt, IsList, IsField], 0,
function(r, Y, F)
    return AlternantCode(r, Y, AsSSortedList(F){[2..Length(Y)+1]}, F);
end);

InstallOtherMethod(AlternantCode, "redundancy, Y, fieldsize", true,
    [IsInt, IsList, IsInt], 0,
function(r, Y, q)
    return AlternantCode(r, Y, AsSSortedList(GF(q)){[2..Length(Y)+1]}, GF(q));
end);


#############################################################################
##
#F  GoppaCode( <G>, <L | n> ) . . . . . . . . . . . . . . classical Goppa code
##

InstallGlobalFunction(GoppaCode,
function(arg)
    local C, GP, F, L, n, q, m, r, zero, temp;

    GP := PolyCodeword(Codeword(arg[1]));
    F := CoefficientsRing(DefaultRing(GP));
    q := Characteristic(F);
    m := Dimension(F);
    F := GF(q);
    zero := Zero(F);
    r := DegreeOfLaurentPolynomial(GP);

    # find m
    if IsInt(arg[2]) then
        n := arg[2];
        m := Maximum(m, LogInt(n,q));
        repeat
            L := Filtered(AsSSortedList(GF(q^m)),i -> Value(GP,i) <> zero);
            m := m + 1;
        until Length(L) >= n;
        m := m - 1;
        L := L{[1..n]};
    else
        L := arg[2];
        n := Length(L);
        m := Maximum(m, Dimension(DefaultField(L)));
    fi;
    C := CheckMatCode( BaseMat(VerticalConversionFieldMat( List([0..r-1],
                 i-> List(L, j-> (j)^i / Value(GP, j) )) )), "classical Goppa code", F);

    # Make the code
    temp := Factors(GP);
    if (q = 2) and (Length(temp) = Length(Set(temp))) then
    # second condition checks if the roots of G are distinct
        C!.lowerBoundMinimumDistance := Minimum(n, 2*r + 1);
    else
        C!.lowerBoundMinimumDistance := Minimum(n, r + 1);
    fi;
    return C;
end);


#############################################################################
##
#F  CordaroWagnerCode( <n> )  . . . . . . . . . . . . . . Cordaro-Wagner code
##

InstallMethod(CordaroWagnerCode, "length", true, [IsInt], 0,
function(n)
    local r, C, zero, one, F, d, wd;
    if n < 2 then
        Error("n must be 2 or more");
    fi;
    r := Int((n+1)/3);
    d := (2 * r - Int( (n mod 3) / 2) );
    F := GF(2);
    zero := Zero(F);
    one := One(F);
    C := GeneratorMatCode( [Concatenation(List([1..r],i -> zero),
                     List([r+1..n],i -> one)),
                     Concatenation(List([r+1..n],i -> one), List([1..r],
                             i -> zero))], "Cordaro-Wagner code", F );
    C!.lowerBoundMinimumDistance := d;
    C!.upperBoundMinimumDistance := d;
    wd := List([1..n+1], i-> 0);
    wd[1] := 1;
    wd[2*r+1] := 1;
    wd[n-r+1] := wd[n-r+1] + 2;
    SetWeightDistribution(C, wd);
    return C;
end);


#############################################################################
##
#F  GeneralizedSrivastavaCode( <a>, <w>, <z> [, <t>] [, <F>] )  . . . . . .
##

InstallMethod(GeneralizedSrivastavaCode, "a,w,z,t,F", true,
    [IsList, IsList, IsList, IsInt, IsField], 0,
function(a,w,z,t,F)
    local C, n, s, i, H;
    a := VectorCodeword(Codeword(a, F));
    w := VectorCodeword(Codeword(w, F));
    z := VectorCodeword(Codeword(z, F));
    n := Length(a);
    s := Length(w);
    if Length(Set(Concatenation(a,w))) <> n + s then
        Error("<alpha> and w are not distinct");
    fi;
    if ForAny(z,i -> i = Zero(F)) then
        Error("<z> must be nonzero");
    fi;

    H := [];
    for i in List([1..s], index -> List([1..t], vert -> List([1..n],
            hor -> z[hor]/(a[hor] - w[index])^vert))) do
        Append(H, i);
    od;
    C := CheckMatCode( BaseMat(VerticalConversionFieldMat(H)),
                 "generalized Srivastava code", GF(Characteristic(F)) );
    C!.lowerBoundMinimumDistance := s + 1;
    return C;
end);

InstallOtherMethod(GeneralizedSrivastavaCode, "a,w,z,t,q", true,
    [IsList, IsList, IsList, IsInt, IsInt], 0,
function(a, w, z, t, q)
    return GeneralizedSrivastavaCode(a, w, z, t, GF(q));
end);

InstallOtherMethod(GeneralizedSrivastavaCode, "a,w,z,t", true,
    [IsList, IsList, IsList, IsInt], 0,
function(a, w, z, t)
    return GeneralizedSrivastavaCode(a, w, z, t,
                DefaultField(Concatenation(a,w,z)));
end);

InstallOtherMethod(GeneralizedSrivastavaCode, "a,w,z,F", true,
    [IsList, IsList, IsList, IsField], 0,
function(a, w, z, F)
    return GeneralizedSrivastavaCode(a, w, z, 1, F);
end);

InstallOtherMethod(GeneralizedSrivastavaCode, "a, w, z", true,
    [IsList, IsList, IsList], 0,
function(a, w, z)
    return GeneralizedSrivastavaCode(a, w, z, 1,
                DefaultField(Concatenation(a, w, z)));
end);


#############################################################################
##
#F  SrivastavaCode( <a>, <w> [, <mu>] [, <F>] ) . . . . . . . Srivastava code
##

InstallMethod(SrivastavaCode, "a,w,mu,F", true,
    [IsList,IsList,IsInt, IsField], 0,
function(a, w, mu, F)
    local C, n, s, i, zero, TheMat;
    a := VectorCodeword(Codeword(a, F));
    w := VectorCodeword(Codeword(w, F));
    n := Length(a);
    s := Length(w);
    if Length(Set(Concatenation(a,w))) <> n + s then
        Error("the elements of <alpha> and w are not distinct");
    fi;
    zero := Zero(F);
    for i in [1.. n] do
        if a[i]^mu = zero then
            Error("z[",i,"] = ",a[i],"^",mu," = ",zero);
        fi;
    od;
    TheMat := List([1..s], j -> List([1..n], i -> a[i]^mu/(a[i] - w[j]) ));
    C := CheckMatCode( BaseMat(VerticalConversionFieldMat(TheMat)),
                 "Srivastava code", GF(Characteristic(F)) );
    C!.lowerBoundMinimumDistance := s + 1;
    return C;
end);

InstallOtherMethod(SrivastavaCode, "a,w,mu,q", true,
    [IsList,IsList,IsInt,IsInt], 0,
function(a, w, mu, q)
    return SrivastavaCode(a, w, mu, GF(q));
end);

InstallOtherMethod(SrivastavaCode, "a,w,mu", true,
    [IsList,IsList,IsInt], 0,
function(a, w, mu)
    return SrivastavaCode(a, w, mu, DefaultField(Concatenation(a,w)));
end);

InstallOtherMethod(SrivastavaCode, "a,w,F", true,
    [IsList,IsList,IsField], 0,
function(a, w, F)
    return SrivastavaCode(a, w, 1, F);
end);

InstallOtherMethod(SrivastavaCode, "a,w", true, [IsList,IsList], 0,
function(a, w)
    return SrivastavaCode(a, w, 1, DefaultField(Concatenation(a,w)));
end);


#############################################################################
##
#F  ExtendedBinaryGolayCode( )  . . . . . . . . .  extended binary Golay code
##
InstallMethod(ExtendedBinaryGolayCode, "only method", true, [], 0,
function()
    local C;
    C := ExtendedCode(BinaryGolayCode());
    C!.name := "extended binary Golay code";
    Unbind( C!.history );
    SetIsCyclicCode(C, false);
    SetIsPerfectCode(C, false);
    SetIsSelfDualCode(C, true);
    C!.boundsCoveringRadius := [ 4 ];
    SetIsNormalCode(C, true);
    SetWeightDistribution(C,
      [1,0,0,0,0,0,0,0,759,0,0,0,2576,0,0,0,759,0,0,0,0,0,0,0,1]);
    #SetAutomorphismGroup(C, M24);
    C!.lowerBoundMinimumDistance := 8;
    C!.upperBoundMinimumDistance := 8;
    return C;
end);


#############################################################################
##
#F  ExtendedTernaryGolayCode( ) . . . . . . . . . extended ternary Golay code
##
InstallMethod(ExtendedTernaryGolayCode, "only method", true, [], 0,
function()
    local C;
    C := ExtendedCode(TernaryGolayCode());
    SetIsCyclicCode(C, false);
    SetIsPerfectCode(C, false);
    SetIsSelfDualCode(C, true);
    C!.boundsCoveringRadius := [ 3 ];
    SetIsNormalCode(C, true);
    C!.name := "extended ternary Golay code";
    Unbind( C!.history );
    SetWeightDistribution(C, [1,0,0,0,0,0,264,0,0,440,0,0,24]);
    #SetAutomorphismGroup(C, M12);
    C!.lowerBoundMinimumDistance := 6;
    C!.upperBoundMinimumDistance := 6;
    return C;
end);


#############################################################################
##
#F  BestKnownLinearCode( <n>, <k> [, <F>] ) .  returns best known linear code
#F  BestKnownLinearCode( <rec> )
##
##  L describs how to create a code. L is a list with two elements:
##  L[1] is a function and L[2] is a list of arguments for L[1].
##  One or more of the arguments of L[2] may again be such descriptions and
##  L[2] can be an empty list.
##  The field .construction contains such a list or false if the code is not
##  yet in the apropiatelibrary file (/tbl/codeq.g)
##

InstallMethod(BestKnownLinearCode, "method for bounds/construction record",
    true, [IsRecord], 0,
function(bds)
    local MakeCode, C;

    # L describs how to create a code. L is a list with two elements:
    # L[1] is a function and L[2] is a list of arguments for L[1].
    # One or more of the arguments of L[2] may again be such descriptions and
    # L[2] can be an empty list.
    MakeCode := function(L)
        #beware: this is the most beautiful function in GUAVA (according to J)
        if IsList(L) and IsBound(L[1]) and IsFunction(L[1]) then
            return CallFuncList( L[1], List( L[2], i -> MakeCode(i) ) );
        else
            return L;
        fi;
    end;

    if not IsBound(bds.construction) then
        bds := BoundsMinimumDistance(bds.n, bds.k, bds.q);
    fi;
    if bds.construction = false then
        Print("Code not yet in library\n");
        return fail;
    else
        C := MakeCode(bds.construction);
        if LowerBoundMinimumDistance(C) > bds.lowerBound then
            Print("New table entry found!\n");
        fi;
        C!.lowerBoundMinimumDistance := Maximum(bds.lowerBound,
                                               LowerBoundMinimumDistance(C));
        C!.upperBoundMinimumDistance := Minimum(bds.upperBound,
                                               UpperBoundMinimumDistance(C));
        return C;
    fi;
end);

InstallOtherMethod(BestKnownLinearCode, "n, k, q", true,
    [IsInt, IsInt, IsInt], 0,
function(n, k, q)
    local r;
    r := BoundsMinimumDistance(n, k, q);
    return BestKnownLinearCode(r);
end);

InstallOtherMethod(BestKnownLinearCode, "n, k, F", true,
    [IsInt, IsInt, IsField], 0,
function(n, k, F)
    local r;
    r := BoundsMinimumDistance(n, k, Size(F));
    return BestKnownLinearCode(r);
end);

InstallOtherMethod(BestKnownLinearCode, "n, k", true,
    [IsInt, IsInt], 0,
function(n, k)
    local r;
    r := BoundsMinimumDistance(n, k);
    return BestKnownLinearCode(r);
end);



## Helper functions for cyclic code creation
GeneratorMatrixFromPoly := function(p,n)
    local coeffs, j, res, r, zero;
    coeffs := CoefficientsOfLaurentPolynomial(p);
    coeffs := ShiftedCoeffs(coeffs[1], coeffs[2]);
    r := DegreeOfLaurentPolynomial(p);
    zero := Zero(Field(coeffs));
    res := [];
    res[1] := [];
    # first row
    Append(res[1], coeffs);
    Append(res[1], List([r+2..n], i->zero));
    # 2..last-1
    if n-r > 2 then
        for j in [2..(n-r-1)] do
            res[j] := [];
            Append(res[j], List([1..j-1], i->zero));
            Append(res[j], coeffs);
            Append(res[j], List([r+1+j..n], i->zero));
        od;
    fi;
    # last row
    if n-r > 1 then
        res[n-r] := [];
        Append(res[n-r], List([1..n-r-1], i->zero));
        Append(res[n-r], coeffs);
    fi;
    return res;
end;


CyclicCodeByGenerator := function(F, n, G)
    local C, GM;
    ## for now, using linear code representation.
    ## Get generator matrix and call linear code creation function
    ## Note input is a codeword, for consistency.
    ## Further note GenMatFromPoly doesn't handle NullPoly case well,
    ## so calling NullMat instead.  Once using poly rep, this should be
    ## unnecessary.
    ## And GMFP doesn't handle p = x^n-1 case.

    if (G = NullWord(n,F)) or
       (VectorCodeword(G) = []) or
       (G = Codeword(Indeterminate(F)^n-One(F), F)) then
        GM := NullMat(1,n,F);
    else
        GM := GeneratorMatrixFromPoly(PolyCodeword(G), n);
    fi;
    C := LinearCodeByGenerators(F, Codeword(One(F)*GM, F));
    #C := LinearCodeByGenerators(F, One(F)*GM);
    SetGeneratorMat(C, GM);
    SetIsCyclicCode(C, true);
        SetSpecialDecoder(C, CyclicDecoder);
    return C;
end;


#############################################################################
##
#F  GeneratorPolCode( <G>, <n> [, <name> ], <F> ) .  code from generator poly
##

InstallMethod(GeneratorPolCode, "Poly, wordlength,name,field", true,
    [IsUnivariatePolynomial, IsInt, IsString, IsField], 0,
function(G, n, name, F)
    local R;
    #G := PolyCodeword( Codeword(G, F) );
    if not IsZero(G) then
        G := Gcd(G,(Indeterminate(F)^n-One(F)));
    fi;
    R := CyclicCodeByGenerator(F, n, Codeword(G, F));
    SetGeneratorPol(R, G);
    R!.name := name;
    return R;
end);

InstallOtherMethod(GeneratorPolCode, "Poly,wordlength,field", true,
    [IsUnivariatePolynomial, IsInt, IsField], 0,
function(G, n, F)
    return GeneratorPolCode(G,n,"code defined by generator polynomial", F);
end);

InstallOtherMethod(GeneratorPolCode, "Poly,wordlength,name,fieldsize", true,
    [IsUnivariatePolynomial, IsInt, IsString, IsInt], 0,
function(G, n, name, q)
    return GeneratorPolCode(G, n, name, GF(q));
end);

InstallOtherMethod(GeneratorPolCode, "Poly, wordlength, fieldsize", true,
    [IsUnivariatePolynomial, IsInt, IsInt], 0,
function(G, n, q)
    return GeneratorPolCode(G, n, "code defined by generator polynomial",
                            GF(q));
end);


#############################################################################
##
#F  CheckPolCode( <H>, <n> [, <name> ], <F> ) . .  code from check polynomial
##

InstallMethod(CheckPolCode, "check poly, wordlength, name, field", true,
    [IsUnivariatePolynomial, IsInt, IsString, IsField], 0,
function(H, n, name, F)
    local R,G;
    H := PolyCodeword( Codeword(H, F) );
    H := Gcd(H, (Indeterminate(F)^n-One(F)));
    # Get generator pol
    G := EuclideanQuotient((Indeterminate(F)^n-One(F)), H);

    R := CyclicCodeByGenerator(F, n, Codeword(G,F));
    SetCheckPol(R, H);
    SetGeneratorPol(R, G);
    R!.name := name;
    return R;
end);

InstallOtherMethod(CheckPolCode, "check poly, wordlength, field", true,
    [IsUnivariatePolynomial, IsInt, IsField], 0,
function(H, n, F)
    return CheckPolCode(H, n, "code defined by check polynomial", F);
end);

InstallOtherMethod(CheckPolCode, "check poly, wordlength, name, fieldsize",
    true, [IsUnivariatePolynomial, IsInt, IsString, IsInt], 0,
function(H, n, name, q)
    return CheckPolCode(H, n, name, GF(q));
end);

InstallOtherMethod(CheckPolCode, "check poly, wordlength, fieldsize", true,
    [IsUnivariatePolynomial, IsInt, IsInt], 0,
function(H, n, q)
    return CheckPolCode(H, n, "code defined by check polynomial", GF(q));
end);


#############################################################################
##
#F  RepetitionCode( <n> [, <F>] ) . . . . . . . repetition code of length <n>
##

InstallMethod( RepetitionCode, "wordlength, Field", true, [IsInt, IsField], 0,
function(n, F)
    local C, q, wd, p;
    q :=Size(F);
    p := LaurentPolynomialByCoefficients( ElementsFamily(FamilyObj(F)),
                    List([1..n], t->One(F)), 0);
    C := GeneratorPolCode(p, n, "repetition code", F);
    C!.lowerBoundMinimumDistance := n;
    C!.upperBoundMinimumDistance := n;
    if n = 2 and q = 2 then
        SetIsSelfDualCode(C, true);
    else
        SetIsSelfDualCode(C, false);
    fi;
    wd := NullVector(n+1);
    wd[1] := 1;
    wd[n+1] := q-1;
    SetWeightDistribution(C, wd);
    if n < 260 then
        SetAutomorphismGroup(C, SymmetricGroup(n));
    fi;
    if F = GF(2) then
        SetIsNormalCode(C, true);
    fi;
    if (n mod 2 = 0) or (F <> GF(2)) then
        SetIsPerfectCode(C, false);
        C!.boundsCoveringRadius := [ Minimum(n-1,QuoInt((q-1)*n,q)) ];
    else
        C!.boundsCoveringRadius := [ QuoInt(n,2) ];
        SetIsPerfectCode(C, true);
    fi;
    return C;
end);

InstallOtherMethod(RepetitionCode, "wordlength, fieldsize", true,
    [IsInt, IsInt], 0,
function(n, q)
    return RepetitionCode(n, GF(q));
end);

InstallOtherMethod(RepetitionCode, "wordlength", true, [IsInt], 0,
function(n)
    return RepetitionCode(n, GF(2));
end);


#############################################################################
##
#F  WholeSpaceCode( <n> [, <F>] ) . . . . . . . . . . returns <F>^<n> as code
##

InstallMethod(WholeSpaceCode, "wordlength, Field", true, [IsInt, IsField], 0,
function(n, F)
    local C, index, q;
    C := GeneratorPolCode( Indeterminate(F)^0, n, "whole space code", F);
    C!.lowerBoundMinimumDistance := 1;
    C!.upperBoundMinimumDistance := 1;
    SetAutomorphismGroup(C, SymmetricGroup(n));
    C!.boundsCoveringRadius := [ 0 ];
    if F = GF(2) then
        SetIsNormalCode(C, true);
    fi;
    SetIsPerfectCode(C, true);
    SetIsSelfDualCode(C, false);
    q := Size(F) - 1;
    SetWeightDistribution(C, List([0..n], i-> q^i*Binomial(n, i)) );
    return C;
end);

InstallOtherMethod(WholeSpaceCode, "wordlength, fieldsize", true,
    [IsInt, IsInt], 0,
function(n, q)
    return WholeSpaceCode(n, GF(q));
end);

InstallOtherMethod(WholeSpaceCode, "wordlength", true, [IsInt], 0,
function(n)
    return WholeSpaceCode(n, GF(2));
end);


#############################################################################
##
#F  CyclicCodes( <n> )  . .  returns a list of all cyclic codes of length <n>
##

InstallMethod(CyclicCodes, "wordlength, Field", true,
    [IsInt, IsField], 0,
function(n, F)
    local f, Pl;
    f := Factors(Indeterminate(F) ^ n - One(F));
    Pl := List(Combinations(f), c->Product(c)*Indeterminate(F)^0);
    return List(Pl, p->GeneratorPolCode(p, n, "enumerated code", F));
end);

InstallOtherMethod(CyclicCodes, "wordlength, k, Field", true,
    [IsInt, IsInt, IsField], 0,
function(n, k, F)
    local r, f, Pl, codes;
    r := n - k;
    f := Factors(Indeterminate(F)^n-One(F));
    Pl := [];

    codes := function(f, g)
       local i, tempf;
       if Degree(g) < r then
           i := 1;
           while i <= Length(f) and Degree(g)+Degree(f[i][1]) <= r do
               if f[i][2] = 1 then
                   tempf := f{[ i+1 .. Length(f) ]};
               else
                   tempf := ShallowCopy( f );
                   tempf[i][2] := f[i][2] - 1;
               fi;
               codes( tempf, g * f[i][1] );
               i := i + 1;
           od;
       elif Degree(g) = r then
           Add( Pl, g );
       fi;
    end;

    codes( Collected( f ), Indeterminate(F)^0 );
    return List(Pl, p->GeneratorPolCode(p,n,"enumerated code",F));
end);

InstallOtherMethod(CyclicCodes, "wordlength, fieldsize", true,
    [IsInt, IsInt], 0,
function(n, q)
    return CyclicCodes(n, GF(q));
end);

InstallOtherMethod(CyclicCodes, "wordlength, k, fieldsize", true,
    [IsInt, IsInt, IsInt], 0,
function(n, k, q)
    return CyclicCodes(n, k, GF(q));
end);


#############################################################################
##
#F  NrCyclicCodes( <n>, <F>)  . . .  number of cyclic codes of length <n>
##

InstallMethod(NrCyclicCodes, "wordlength, Field", true, [IsInt, IsField], 0,
function(n, F)
    return NrCombinations(Factors(Indeterminate(F)^n-One(F)));
end);

InstallOtherMethod(NrCyclicCodes, "wordlength, fieldsize", true,
    [IsInt, IsInt], 0,
function(n, q)
    return NrCyclicCodes(n, GF(q));
end);


#############################################################################
##
#F  BCHCode( <n> [, <b>], <delta> [, <F>] ) . . . . . . . . . . . .  BCH code
##
##  BCHCode (n [, b ], delta [, F]) returns the BCH code over F with
##  wordlength n, designedDistance delta, constructed from powers
##  x^b, x^(b+1), ..., x^(b+delta-2), where x is a primitive n'th power root
##  of unity; b = 1 by default; the function returns a narrow sense BCH code
##  Gcd(n,q) = 1 and 2<=delta<=n-b+1

InstallMethod(BCHCode, "wordlength, start, designed distance, fieldsize", true,
    [IsInt, IsInt, IsInt, IsInt], 0,
function(n, start, del, q)
    local stop, m, b, C, test, Cyclo, PowerSet, t,
          zero, desdist, G, superfl, i, BCHTable;

    BCHTable := [ [31,11,11], [63,36,11], [63,30,13], [127,92,11],
                  [127,85,13], [255,223,9], [255,215,11], [255,207,13],
                  [255,187,19], [255,171,23], [255,155,27], [255,99,47],
                  [255,79,55], [255,29,95], [255,21,111] ];
########### increase size of table? - wdj
    stop := start + del - 2;
    if Gcd(n,q) <> 1 then
        Error ("n and q must be relative primes");
    fi;
    zero := Zero(GF(q));
    m := OrderMod(q,n);
    b := PrimitiveUnityRoot(q,n);
    PowerSet := [start..stop];
    G := Indeterminate(GF(q))^0;
    while Length(PowerSet) > 0 do
        test := PowerSet[1] mod n; ############### changed 8-1-2004
        G := G * MinimalPolynomial(GF(q), b^test);
        t := (q*test) mod n;
        while t <> (test mod n) do ############### changed 7-31-2004
            RemoveSet(PowerSet, t);
            t := (q*t) mod n;
        od;
        RemoveSet(PowerSet, test);
    od;
######################################
###### This loop computes the product of the
###### min polys of the elements when it should only
###### compute the lcm of them
###### Why not use cyclotomic codests and roots of code?
######################################
    C := GeneratorPolCode(G, n, GF(q));
########### this removes extra powers by taking the gcd with x^n-1
    SetSpecialDecoder(C, BCHDecoder);
########### this overwrites     SetSpecialDecoder(C, CyclicDecoder);
    # Calculate Bose distance:
    Cyclo := CyclotomicCosets(q,n);
######## why not do this in the above loop?
    PowerSet := [];
    for t in [start..stop] do
        for test in [1..Length(Cyclo)] do
            if (t mod n) in Cyclo[test] then ##### added 8-1-2004
                AddSet(PowerSet, Cyclo[test]);
            fi;
        od;
    od;
    PowerSet := Flat(PowerSet);
    while stop + 1 in PowerSet do
        stop := stop + 1;
    od;
    while start - 1 in PowerSet do
        start := start - 1;
    od;
    desdist := stop - start + 2;
    if desdist > n then
        Error("invalid designed distance");
    fi;
    # In some cases the true minimumdistance is known:
    SetDesignedDistance(C, desdist);
    C!.lowerBoundMinimumDistance := desdist;
    if (q=2) and (n mod desdist = 0) and (start = 1) then
        C!.upperBoundMinimumDistance := desdist;
    elif q=2 and desdist mod 2 = 0 and (n=2^m - 1) and (start=1) and
      (Sum(List([0..QuoInt(desdist-1, 2) + 1], i -> Binomial(n, i))) >
       (n + 1) ^ QuoInt(desdist-1, 2)) then
        C!.upperBoundMinimumDistance := desdist;
    elif (n = q^m - 1) and (desdist = q^OrderMod(q,desdist) - 1)
      and (start=1) then
        C!.upperBoundMinimumDistance := desdist;
    fi;
    # Look up this code in the table
########## table only for q=2^r, add this to if statement
########## to speed this up ?? - wdj
    if start=1 then
        for i in BCHTable do
            if i[1] = n and i[2] = Dimension(C) then
                C!.lowerBoundMinimumDistance := i[3];
                C!.upperBoundMinimumDistance := i[3];
            fi;
        od;
    fi;
    # Calculate minimum of q*desdist - 1 for primitive n.s. BCH code
    if q^m - 1 = n and start = 1 then
        PowerSet := [start..stop];
        superfl := true;
        i := PowerSet[Length(PowerSet)] * q mod n;
        while superfl do
            while i <> PowerSet[Length(PowerSet)] and not i in PowerSet do
                i := i * q mod n;
            od;
            if i = PowerSet[Length(PowerSet)] then
                superfl := false;
            else
                PowerSet := PowerSet{[1..Length(PowerSet)-1]};
                i := PowerSet[Length(PowerSet)] * q mod n;
            fi;
        od;
        C!.upperBoundMinimumDistance := Minimum(UpperBoundMinimumDistance(C),
                        q * (Length(PowerSet) + 1) - 1);
    fi;
    C!.name := Concatenation("BCH code, delta=",
                      String(desdist), ", b=", String(start));
    return C;
end);

InstallOtherMethod(BCHCode, "wordlength, start, designed distance, Field",
    true, [IsInt, IsInt, IsInt, IsField], 0,
function(n, b, del, F)
    return BCHCode(n, b, del, Size(F));
end);

InstallOtherMethod(BCHCode, "wordlength, designed distance", true,
    [IsInt, IsInt], 0,
function(n, del)
    return BCHCode(n, 1, del, 2);
end);

InstallOtherMethod(BCHCode, "wordlength, start, designed distance", true,
    [IsInt, IsInt, IsInt], 0,
function(n, b, del)
    return BCHCode(n, b, del, 2);
end);

InstallOtherMethod(BCHCode, "wordlength, designed distance, field", true,
    [IsInt, IsInt, IsField], 0,
function(n, del, F)
    return BCHCode(n, 1, del, Size(F));
end);


#############################################################################
##
#F  ReedSolomonCode( <n>, <d> ) . . . . . . . . . . . . . . Reed-Solomon code
##
##  ReedSolomonCode (n, d) returns a primitive narrow sense BCH code with
##  wordlength n, over alphabet q = n+1, designed distance d

InstallMethod(ReedSolomonCode, "wordlength, designed distance", true,
    [IsInt, IsInt], 0,
function(n, d)
    local C,b,q,wd,w;
    q := n+1;
    if not IsPrimePowerInt(q) then
        Error("q = n+1 must be a prime power");
    fi;
    b := Z(q);

    C := GeneratorPolCode(Product([1..d-1], i-> (Indeterminate(GF(q))-b^i)), n,
                 "Reed-Solomon code", GF(q) );
    SetRootsOfCode(C, List([1..d-1], i->b^i));
    C!.lowerBoundMinimumDistance := d;
    C!.upperBoundMinimumDistance := d;
    SetDesignedDistance(C, d);
    SetSpecialDecoder(C, BCHDecoder);
    IsMDSCode(C);       # Calculate weightDistribution field
    return C;
end);

InstallMethod(ExtendedReedSolomonCode, "wordlength, designed distance", true,
    [IsInt, IsInt], 0,
function(n, d)
    local i, j, s, C, G, Ce;
    C := ReedSolomonCode(n-1, d-1);
    G := MutableCopyMatrix( GeneratorMat(C) );
    TriangulizeMat(G);
    for i in [1..Size(G)] do;
        s := 0;
        for j in [1..Size(G[i])] do;
            s := s + G[i][j];
        od;
        Append(G[i], [-s]);
    od;
    Ce := GeneratorMatCodeNC(G, LeftActingDomain(C));
    Ce!.name := "extended Reed Solomon code";
    Ce!.lowerBoundMinimumDistance := d;
    Ce!.upperBoundMinimumDistance := d;
    IsMDSCode(Ce);
    return Ce;
end);

## RootsCode implementation expunged and rewritten for Guava 3.11
## J. E. Fields 1/15/2012 (with help from WDJ)
#############################################################################
##
#F  RootsCode( <n>, <list>, <field> ) code constructed from roots of polynomial
##
##  RootsCode (n, rootlist, F) or RootsCode (n, <powerlist>, fieldsize) or
##  RootsCode(n, rootlist) returns the
##  code with generator polynomial equal to the least common multiple of
##  the minimal polynomials of the n'th roots of unity in the list.
##  The code has wordlength n.
##

InstallMethod(RootsCode, "method for n, rootlist, field", true, [IsInt, IsList, IsField], 0,
function(n, L, F)
    local g, C, num, power, p, q, z, i, j, rootslist, powerlist, max, cc, CC, CCz;
    L := Set(L);
    q := Size(Field(L));
    z := Z(q);
    g:=One(F);
    if List(L, i->i^n) <> NullVector(Length(L), F) + z^0 then
       Error("powers must all be n'th roots of unity");
    fi;
    p := Characteristic(Field(L));
    CC:=CyclotomicCosets(p,q-1);
    CCz:=List([1..Length(CC)],i->List(CC[i],j->z^j));
    ##  this is the set of cyclotomic cosets, represented
    ##  as powers of a primitive element z
    powerlist := [];
    for i in [1..Length(L)] do
     for cc in CCz do
       if L[i] in cc then
            Append(powerlist,[cc]);
       fi;
     od;
    od;
    ########### add a cyclotomic coset into powerlist
    ########### if there is an element of L in that coset
    g:=Product([1..Length(powerlist)],i->MinimalPolynomial(F,powerlist[i][1]));
    C:=GeneratorPolCode(g,n,"code defined by roots",F);

    rootslist := [];
    for cc in powerlist do
        Append(rootslist, cc);
    od;
    rootslist := Set(rootslist);
    SetRootsOfCode(C, rootslist);

    # Find the largest number of successive powers for BCH bound
    max := 1;
    i := 1;
    num := Length(powerlist);
    for z in [2..num] do
        if powerlist[z] <> powerlist[i] + z-i then
            max := Maximum(max, z - i);
            i := z;
        fi;
    od;
    C!.lowerBoundMinimumDistance := Maximum(max, num+1 - i) + 1;
return C;
end);


InstallOtherMethod(RootsCode, "method for n, rootlist", true, [IsInt, IsList], 0,
function(n, L)
local p,q,z,L1,L2,F;
      L1 := Set(L);
      p := Characteristic(Field(L1));
      z := Z(Size(Field(L1)));
      F := GF(p);
      #L2 := List([1..Length(L1)],i-> LogFFE(L[i],z));
      #Print(L1, p, z, F, L2);
      return RootsCode(n, L1, F);
end);

InstallOtherMethod(RootsCode, "method for n, powerlist, fieldsize", true, [IsInt, IsList, IsInt], 0,
function(n, P, q)
# , "method for n, powerlist, fieldsize", true,  [IsInt, IsList, IsInt], 0,
local z, L;
        z := PrimitiveUnityRoot(q,n);
        L := Set(List(P, i->z^i));
        return RootsCode(n, L, GF(q));
end);

#############################################################################
##
#F  QRCode( <n> [, <F>] ) . . . . . . . . . . . . . .  quadratic residue code
##

InstallMethod(QRCode, "modulus, fieldsize", true, [IsInt, IsInt], 0,
function(n, q)
    local m, b, Q, N, t, g, lower, upper, C, F, coeffs;
    if Jacobi(q,n) <> 1 then
        Error("q must be a quadratic residue modulo n");
    elif not IsPrimeInt(n) then
        Error("n must be a prime");
    elif not IsPrimeInt(q) then
        Error("q must be a prime");
    fi;
    m := OrderMod(q,n);
    F := GF(q^m);
    b := PrimitiveUnityRoot(q,n);
    Q := [];
    N := [1..n];
    for t in [1..n-1] do
        AddSet(Q, t^2 mod n);
    od;
    for t in Q do
        RemoveSet(N, t);
    od;
    g := Product(Q,
      i -> LaurentPolynomialByCoefficients(ElementsFamily(FamilyObj(F)),
                            [-b^i, b^0], 0)  );
    coeffs := CoefficientsOfLaurentPolynomial(g);
    coeffs := ShiftedCoeffs(coeffs[1], coeffs[2]);
    C := GeneratorPolCode( LaurentPolynomialByCoefficients(
                    ElementsFamily(FamilyObj(GF(q))), coeffs, 0),
                n, "quadratic residue code", GF(q) );
    if RootInt(n)^2 = n then
        lower := RootInt(n);
    else
        lower := RootInt(n)+1;
    fi;
    if n mod 4 = 3 then
        while lower^2-lower+1 < n do
            lower := lower + 1;
        od;
    fi;
    if (n mod 8 = 7) and (q = 2) then
        while lower mod 4 <> 3 do
            lower := lower + 1;
        od;
    fi;
    upper := Weight(Codeword(coeffs));
    C!.lowerBoundMinimumDistance := lower;
    C!.upperBoundMinimumDistance := upper;
    return C;
end);

InstallOtherMethod(QRCode, "modulus, field", true, [IsInt, IsField], 0,
function(n, F)
    return QRCode(n, Size(F));
end);

InstallOtherMethod(QRCode, "modulus", true, [IsInt], 0,
function(n)
    return QRCode(n, 2);
end);

#############################################################################
##
#F  QQRCode( <n> [, <F>] ) . . . . . . . . binary quasi-quadratic residue code
##
## Code of Bazzi-Mittel (see Bazzi, L. and Mitter, S.K. "Some constructions of
##  codes from group actions" preprint March 2003 (submitted to IEEE IT)
##

InstallMethod(QQRCode, "Modulus", true, [IsInt], 0,
function(p)
local G0,G,Q,N,QN,i,C,F,QuadraticResidueSupports,NonQuadraticResidueSupports;

# start local functions:
QuadraticResidueSupports:=function(p)
 local L,i;
 L:=List([1..(p-1)],i->1+Legendre(i,p))/2;
 return L;
 end;
 NonQuadraticResidueSupports:=function(p)
 local L,i;
 L:=List([1..(p-1)],i->1-Legendre(i,p))/2;
 return L;
 end;
# end local functions

 F:=GF(2);
 Q:=[Zero(F)];
 Q:=One(F)*Concatenation(Q,QuadraticResidueSupports(p));
 N:=[Zero(F)];
 N:=One(F)*Concatenation(N,NonQuadraticResidueSupports(p));
 QN:=Concatenation(Q,N);
 G:=BlockMatrix([[1,1,CirculantMatrix(p,Q)],[1,2,CirculantMatrix(p,N)]],1,2);
 if p mod 4 = 1 then
     G0:=List([1..(p-1)],i->G[i]);
 else
    G0:=MatrixByBlockMatrix(G);
 fi;
 C:=GeneratorMatCode(G0,F);
 C!.DoublyCirculant:=G0;
 C!.GeneratorMat:=G0;
 return C;
end);

#############################################################################
##
#F  QQRCodeNC( <n> [, <F>] ) . . . . . . . . binary quasi-quadratic residue code
##
## Code of Bazzi-Mittel (see Bazzi, L. and Mitter, S.K. "Some constructions of
##  codes from group actions" preprint March 2003 (submitted to IEEE IT)
##

InstallMethod(QQRCodeNC, "Modulus", true, [IsInt], 0,
function(p)
local G,G0,Q,N,QN,i,C,F,QuadraticResidueSupports,NonQuadraticResidueSupports;

# start local functions:
QuadraticResidueSupports:=function(p)
 local L,i;
 L:=List([1..(p-1)],i->1+Legendre(i,p))/2;
 return L;
 end;
 NonQuadraticResidueSupports:=function(p)
 local L,i;
 L:=List([1..(p-1)],i->1-Legendre(i,p))/2;
 return L;
 end;
# end local functions

 F:=GF(2);
 Q:=[Zero(F)];
 #Q:=[];
 Q:=One(F)*Concatenation(Q,QuadraticResidueSupports(p));
 N:=[Zero(F)];
 #N:=[];
 N:=One(F)*Concatenation(N,NonQuadraticResidueSupports(p));
 #QN:=Concatenation(Q,N);
 G:=BlockMatrix([[1,1,CirculantMatrix(p,N)],[1,2,CirculantMatrix(p,Q)]],1,2);
 if p mod 4 = 1 then
     G0:=List([1..(p-1)],i->G[i]);
 else
    G0:=MatrixByBlockMatrix(G);
 fi;
 C:=GeneratorMatCodeNC(G0,F);
 C!.DoublyCirculant:=G0;
 C!.GeneratorMat:=G0;
 return C;
end);

#############################################################################
##
#F  NullCode( <n> [, <F>] ) . . . . . . . . . . . code consisting only of <0>
##

InstallMethod(NullCode, "wordlength, field", true, [IsInt, IsField], 0,
function(n, F)
    local C;
    C := ElementsCode([NullWord(n,F)], "nullcode", F);
    C!.lowerBoundMinimumDistance := n;
    C!.upperBoundMinimumDistance := n;
    SetMinimumDistance(C, n);
    SetWeightDistribution(C, Concatenation([1], NullVector(n)));
    SetAutomorphismGroup(C, SymmetricGroup(n));
    C!.boundsCoveringRadius := [ n ];
    SetCoveringRadius(C, n);
    IsCyclicCode(C);   # will set all basic linear and cyclic code info
    return C;
end);

InstallOtherMethod(NullCode, "wordlength, fieldsize", true, [IsInt, IsInt], 0,
function(n, q)
    return NullCode(n, GF(q));
end);

InstallOtherMethod(NullCode, "wordlength", true, [IsInt], 0,
function(n)
    return NullCode(n, GF(2));
end);


#############################################################################
##
#F  FireCode( <G>, <b> )  . . . . . . . . . . . . . . . . . . . . . Fire code
##
##  FireCode (G, b) constructs the Fire code that is capable of correcting any
##  single error burst of length b or less.
##  G is a primitive polynomial of degree m
##

InstallMethod(FireCode, "poly, burstlength", true,
    [IsUnivariatePolynomial, IsInt], 0,
function(G, b)
    local m, C, n;
    G := PolyCodeword(Codeword(G));
    if CoefficientsRing(DefaultRing(G)) <> GF(2) then
        Error("polynomial must be over GF(2)");
    fi;
    if Length(Factors(G)) <> 1 then
        Error("polynomial G must be primitive");
    fi;
    m := DegreeOfLaurentPolynomial(G);
    n := Lcm(2^m-1,2*b-1);
    C := GeneratorPolCode( G*(Indeterminate(GF(2))^(2*b-1) + One(GF(2))), n,
                 Concatenation(String(b), " burst error correcting fire code"),
                 GF(2) );
    return C;
end);

#############################################################################
##
#F  BinaryGolayCode( )  . . . . . . . . . . . . . . . . . . binary Golay code
##
InstallMethod(BinaryGolayCode, "only method", true, [], 0,
function()
    local p,C;
    p := LaurentPolynomialByCoefficients(
                    ElementsFamily(FamilyObj(GF(2))),
                    Z(2)^0*[1,0,1,0,1,1,1,0,0,0,1,1], 0);
    C := CyclicCodeByGenerator(GF(2), 23, Codeword(p));
    SetGeneratorPol(C, p);
    SetDimension(C, 12);
    SetRedundancy(C, 11);
    SetSize(C, 2^12);
    C!.name := "binary Golay code";
    C!.lowerBoundMinimumDistance := 7;
    C!.upperBoundMinimumDistance := 7;
    SetWeightDistribution(C,
        [1,0,0,0,0,0,0,253,506,0,0,1288,1288,0,0,506,253,0,0,0,0,0,0,1]);
    C!.boundsCoveringRadius := [ 3 ];
    SetIsNormalCode(C, true);
    SetIsPerfectCode(C, true);
    return C;
end);


#############################################################################
##
#F  TernaryGolayCode( ) . . . . . . . . . . . . . . . . .  ternary Golay code
##
InstallMethod(TernaryGolayCode, "only method", true, [], 0,
function()
    local p, C;
    p := LaurentPolynomialByCoefficients(ElementsFamily(FamilyObj(GF(3))),
                Z(3)^0*[2,0,1,2,1,1], 0);
    C := CyclicCodeByGenerator(GF(3), 11, Codeword(p));
    C!.name := "ternary Golay code";
    SetGeneratorPol(C, p);
    SetRedundancy(C, 5);
    SetDimension(C, 6);
    SetSize(C, 3^6);
    C!.lowerBoundMinimumDistance := 5;
    C!.upperBoundMinimumDistance := 5;
    SetWeightDistribution(C, [1,0,0,0,0,132,132,0,330,110,0,24]);
    SetIsNormalCode(C, true);
    SetIsPerfectCode(C, true);
    return C;
end);


#############################################################################
##
#F   EvaluationCode( <P>, <L>, <R> )
##
##   P is a list of n points in F^r
##   L is a list of rational functions in r variables
##   EvaluationCode returns the image of the evaluation map f->[f(P1),...,f(Pn)],
##   as f ranges over the vector space of functions spanned by L.
##   The output is the code whose generator matrix has rows (f(P1)...f(Pn)) where
##   f is in L and P={P1,..,Pn}
##
InstallMethod(EvaluationCode,"points, basis functions, multivariate poly ring", true,
[IsList, IsList, IsRing], 0,
function(P,L,R)
 local i, G, n, C, j, k, varsn,varsd, vars, F, ValueExtended;
#######################
  ValueExtended:=function(f,vars,pt)
   local df, nf;
   df:=DenominatorOfRationalFunction(f*vars[1]^0);
   nf:=NumeratorOfRationalFunction(f*vars[1]^0);
   #if (varsn=[] and varsd=[]) then return f; fi;
  return Value(nf,vars,pt)*Value(df,vars,pt)^(-1);
  end;
#######################
 vars:=IndeterminatesOfPolynomialRing(R);
 F:=CoefficientsRing(R);
 n:=Length(P);
 k:=Length(L);
 G:=ShallowCopy(NullMat(k,n,F));
 for i in [1..k] do
  for j in [1..n] do
       G[i][j]:=ValueExtended(L[i],vars,P[j]);
  od;
 od;
 C:=GeneratorMatCode(G," evaluation code",F);
 C!.EvaluationMat:=ShallowCopy(G);
 C!.basis:=L;
 C!.points:=P;
 C!.ring:=R;
 return C;
end);

#############################################################################
##
#F    GeneralizedReedSolomonCode( <P>, <k>, <R> )
##
##   P is a list of n points in F
##   k is an integer
##   GRSCode returns the image of the evaluation map f->[f(P1),...,f(Pn)],
##   as f ranges over the vector space of polynomials in 1 variable
##   of degree < k in the ring R.
##   The output is the code whose generator matrix has rows (f(P1)...f(Pn)) where
##   f = x^j, j<k, and P={P1,..,Pn}
##
InstallMethod(GeneralizedReedSolomonCode,"points, basis functions, univariate poly ring", true,
[IsList, IsInt, IsRing], 0,
function(P,k,R)
local p, L, vars, i, F, f, x, C, R0, P0, G, j, n;
 n:=Length(P);
 F:=CoefficientsRing(R);
 G:=NullMat(k,n,F);
 vars:=IndeterminatesOfPolynomialRing(R);
 x:=vars[1];
 L:=List([0..(k-1)],i->(x^i));
 for i in [1..k] do
  for j in [1..n] do
       G[i][j]:=Value(L[i],vars,[P[j]]);
  od;
 od;
 C:=GeneratorMatCode(G," generalized Reed-Solomon code",F);
 C!.GeneratorMat:=ShallowCopy(G);
 C!.degree:=k;
 C!.points:=P;
 C!.ring:=R;
 SetSpecialDecoder(C, GeneralizedReedSolomonDecoder);
 return C;
end);

#############################################################################
##
#F    GeneralizedReedSolomonCode( <P>, <k>, <R> , <wts> )
##
##   P is a list of n points in F
##   k is an integer
##   GRSCode returns the image of the evaluation map f->[f(P1),...,f(Pn)],
##   as f ranges over the vector space of polynomials in 1 variable
##   of degree < k in the ring R.
##   The output is the code whose generator matrix has rows (w1*f(P1),...,wn*f(Pn)) where
##   f = x^j, j<k, P={P1,..,Pn}, wts=[w1,...,wn] \in F^n
##
InstallOtherMethod(GeneralizedReedSolomonCode,"points, basis functions, univariate poly ring", true,
[IsList, IsInt, IsRing, IsList], 0,
function(P,k,R,wts)
local p, L, vars, i, F, f, x, C, R0, P0, G, j, n;
 n:=Length(P);
 F:=CoefficientsRing(R);
 G:=NullMat(k,n,F);
 vars:=IndeterminatesOfPolynomialRing(R);
 x:=vars[1];
 L:=List([0..(k-1)],i->(x^i));
 for i in [1..k] do
  for j in [1..n] do
       G[i][j]:=wts[j]*Value(L[i],vars,[P[j]]);
  od;
 od;
 C:=GeneratorMatCode(G," weighted generalized Reed-Solomon code",F);
 C!.GeneratorMat:=ShallowCopy(G);
 C!.degree:=k;
 C!.points:=P;
 C!.weights:=wts;
 C!.ring:=R;
#SetSpecialDecoder(C, GeneralizedReedSolomonDecoder);
 return C;
end);

#############################################################################
##
#F    OnePointAGCode( <crv>, <pts>, <m>, <R> )
##
## R = F[x,y] is a polynomial ring over a finite field F
## crv is a polynomial in R representing a plane curve
## pts is a list of points on the curve
## Computes the AG codes associated to the RR space
## L(m*infinity) using Proposition VI.4.1 in Stichtenoth
##
InstallMethod(OnePointAGCode,
"polynomial defining planar curve, points, multiplicity, univariate poly ring",
true, [IsPolynomial, IsList, IsInt, IsRing], 0,
function(crv,pts,m,R)
 local F,f,indets,pt,i,j,G,C,degx,degy,basisLD,xx,yy,allpts;
 indets := IndeterminatesOfPolynomialRing(R);
 xx:=indets[1]; yy:=indets[2];
 F:=CoefficientsRing(R);
 allpts:=AffinePointsOnCurve(crv,R,F);
 if not(IsSubset(allpts,pts)) then
   Error("The points given must be on the curve\n");
 fi;
 degx:=DegreeIndeterminate(crv,xx);
 degy:=DegreeIndeterminate(crv,yy);
 basisLD:=[];
 for i in [0..(degx-1)] do
  for j in [0..m] do
   if degx*j+degy*i<m+1 then
    basisLD:=Concatenation([xx^i*yy^j],basisLD);
   fi;
  od;
 od;
 G:=List(pts,pt->List(basisLD,f->Value(f,indets,pt)));
 C:=GeneratorMatCode(TransposedMat(G)," one-point AG code",F);
 C!.GeneratorMat:=ShallowCopy(TransposedMat(G));
 C!.multiplicity:=m;
 C!.points:=pts;
 C!.curve:=crv;
 C!.ring:=R;
 return C;
end);

# The FerreroDesign stuff was commented out w/ a message about issues when Sonata 
# was not installed.  Guava now automatically loads Sonata at startup so I'm re-instating
# these functions. -JEF 1/5/2025

#############################################################################
##
#F    FerreroDesignCode( <P>, <m> )  ... code from a Ferrero design
##
##
InstallMethod(FerreroDesignCode,
"binary linear code constructed using a Ferrero design",
true, [IsList, IsInt], 0,
function( P,m)
# **Requires the GAP package SONATA**
# Constructs binary linear code arising from the incdence
# matrix of a design associated to a "Ferrero pair" arising
# from a fixed-point-free (fpf) automorphism groups and Frobenius group.
# The designs that we are looking at (from a Frobenius kernel
# of order v and a Frobenius complement of order k) have
# v*(v-1)/k distinct blocks and they are all of size k.
# Moreover each of the v points occurs in exactly v-1distinct
# blocks. Hence the rows and the columns of the incidence
# matrix M of the design are always of constant weight.
# Take a Frobenius (G,+) group with kernel K and complement H.
# Consider the design D with point set K and block set
# { a^H + b | a, b in K, a <> 0 }.
# Here a^H denotes the orbit of a under conjugation by elements
# of H. Every planar near-ring design of type "*" can be obtained
# in this way from groups. A group K together with a group of
# automorphism H of K such that the semidirect product KH is a
# Frobenius group with complement H is called a Ferrero pair (K, H)
# in SONATA.
#
# INPUT: P is a list of prime powers describing an abelian group G
#        m > 0 is an integer such that G admits a cyclic fpf
#        automorphism group of size m
# This means that for all q = p^k in P, OrderMod( p, m ) must divide q
# (see the SONATA documentation for FpfAutomorphismGroupsCyclic).
# OUTPUT: The binary linear code whose generator matrix is the
#         incidence matrix of a design associated to a "Ferrero pair" arising
#         from the fixed-point-free (fpf) automorphism group of G.
# The pair (H,K) is called a Ferraro pair and the semidirect product KH is a
# Frobenius group with complement H.
# AUTHORS: Peter Mayr and David Joyner
    local C, f, H, K, M, D;
    LoadPackage("sonata");
    f := FpfAutomorphismGroupsCyclic( P, m );
    K := f[2];
    H := Group( f[1][1] );
    D := DesignFromFerreroPair( K, H, "*" );
    M := IncidenceMat( D );
    C := GeneratorMatCode(M*Z(2), GF(2));
    return C;
end);


#Having trouble getting GUAVA to load without errors if
#SONATA is not installed. Uncomment this and reload if you
#have SONATA.

# The function below is now superceded by the method above...

#FerreroDesignCode:=function( P,m)
#    local C, f, H, K, M, D;
#    LoadPackage("sonata");
#    f := FpfAutomorphismGroupsCyclic( P, m );
#    K := f[2];
#    H := Group( f[1][1] );
#    D := DesignFromFerreroPair( K, H, "*" );
#    M := IncidenceMat( D );
#    C:=GeneratorMatCode(M*Z(2), GF(2));
#    return C;
#end;

#############################################################################
##
#F  QuasiCyclicCode( <G>, <s>, <F> ) . . . . . . . . . . . quasi cyclic code
##
##  QuasiCyclicCode ( <G>, <s>, <F> ) generates a rate 1/m quasi-cyclic
##  codes. Note that <G> is a list of univariate polynomial and m is the
##  cardinality of this list. The integer s is the size of the circulant
##  and it is not necessarily equal to the code dimension, i.e. k <= s.
##  The associated field is <F>.
##
InstallMethod(QuasiCyclicCode, "linear quasi-cyclic code", true,
    [IsList, IsInt, IsField], 0,
function( L1, s, F )
    #
    # A rate 1/m quasi-cyclic code contains m circulant matrices, each of
    # the same size, and in this case they are all s x s circulant matrices.
    # Each circulant can be specified by a univariate polynomial.
    #
    local i, m, v, M, C;

    # Determine the cardinality of the list L1
    m:=Size(L1);
    if (m < 2) then
        Error("The cardinality of <G> must be at least 2\n");
    fi;

    # Make sure that all the list elements are univariate polynomials
    for i in [1..m] do;
        if (IsUnivariatePolynomial(L1[i]) = false) then
            Error("All list elements must be univariate polynomials\n");
        fi;
        if (Degree(L1[i]) >= s) then
            Error("The degree of the polynomial must be less than s\n");
        fi;
    od;

    # Convert each univariate polynomial into a circulant matrix and
    # concatenate them to generate a generator matrix
    M:=[];
    for i in [1..m] do;
        v:=ShallowCopy( CoefficientsOfUnivariatePolynomial(L1[i]) );
        Append( v, List([1..(s - (Degree(L1[i])+1))], i->Zero(F)) );
        M:=Concatenation( M, CirculantMatrix(s, v) );
    od;
    C := GeneratorMatCode( TransposedMat(M), F );
    C!.name := "quasi-cyclic code";
    return C;
end);

InstallOtherMethod(QuasiCyclicCode, "binary linear quasi-cyclic code",
    true, [IsList, IsInt], 0,
function( L1, s )

    local i, j, m, a, t, v, L2, LUT;

    LUT:=[ "000", "001", "010", "011", "100", "101", "110", "111" ];

    # Determine the cardinality of the list L1
    m := Size(L1);
    if (m < 2) then
        Error("The cardinality of <G> must be at least 2\n");
    fi;

    L2 := [];
    for i in [1..m] do;
        if (IsInt(L1[i]) = false) then
            Error("All list elements must be in octal\n");
        fi;
        a := String(L1[i]);
        v := [];
        for j in [1..Length(a)] do;
            t := INT_CHAR(a[j]) - 48;   # Conversion of ASCII character to integer
            if (t > 7) then
                Error("All list elements must be in octal\n");
            fi;
            Append(v, LUT[t+1]);
        od;
        Append(L2, [ReciprocalPolynomial(PolyCodeword(Codeword(v)))]);
    od;

    return QuasiCyclicCode( L2, s, GF(2) );
end);

#####################################################################
##
#F CyclicMDSCode( <q>, <m>, <k> ) . . . . . . . . . cyclic MDS code
##
## Construct a [q^m + 1, k, q^m - k + 2] cyclic MDS code over GF(q^m)
##
InstallMethod(CyclicMDSCode, "method for linear code", true,
    [IsInt, IsInt, IsInt], 0,
function(q, m, k)
    local i, j, l, x, a, r, g, G, F, CS, C, dmin;

    if (k < 1) or (k > q^m + 1) then
        Error("Incorrect parameter, 1 <= k <= q^m+1.\n");
    fi;
    if IsEvenInt(k) and IsOddInt(q^m) then
        Error("Cannot construct such code, k must be odd for odd field size.\n");
    fi;

    F    := GF(q^m);
    x    := Indeterminate(F, "x");
    a    := PrimitiveUnityRoot(F, q^m+1);   # Primitive (q^m + 1)-st root of unity
    CS   := CyclotomicCosets(q^m, q^m + 1);
    dmin := q^m - k + 2;

    # R. Roth's book (Prob. 8.15, pp. 262)
    # If q^m is odd, there exists [q^m + 1, k, q^m - k + 2] cyclic MDS codes for
    # odd values of k in the range 1 <= k <= q^m. This is because the cyclotomic
    # cosets of q^m mod q^m + 1 are
    #    { 0, [1,q^m], [2,q^m-2], ..., [(q^m-1)/2, (q^m+3)/2], (q^m+1)/2 }.
    # There are two single elements in the above cosets, { 0 } and { (q^m+1)/2 }.
    # If k is odd, dmin = q^m - k + 2 is even and delta = dmin-1 is odd (BCH bound).
    # This can be easily obtained by including either { 0 } or { (q^m+1)/2 }.
    # On the other hand, if k is even, dmin is odd and delta is even. With reference
    # to the above cyclotomic cosets, we cannot have exactly delta consecutive integers.
    # (Does this definitely mean this kind of code cannot be constructed??)
    #
    # If q^m is even, there exists [q^m + 1, k, q^m - k + 2] cyclic MDS codes for
    # any value of k in the range 1 <= k <= q^m+1. This is because the cyclotomic
    # cosets of q^m mod q^m + 1 are
    #    { 0, [1,q^m], [2,q^m-2], ..., [q^m/2, 1 + q^m/2] }.
    # Consequently, we can easily construct a set of odd or even consecutive integers
    # using the cyclotomic cosets above.

    if IsEvenInt(k) then
        g := (x + a^0);
        r := [ a^0 ];
        for i in [1..((dmin-2)/2)] do;
            g := g * (x + a^(CS[i+1][1])) * (x + a^(CS[i+1][2]));
            r := Concatenation(r, [ a^(CS[i+1][1]), a^(CS[i+1][2]) ]);
        od;
    else
        if IsOddInt(q^m) then
            g := (x + a^(CS[Size(CS)][1]));
            r := [ a^(CS[Size(CS)][1]) ];
            j := Size(CS)-1;
            l := (dmin-2)/2;
        else
            g := 1;
            r := [];
            j := Size(CS);
            l := (dmin-1)/2;
        fi;
        for i in [0..l-1] do;
            g := g * (x + a^(CS[j-i][1])) * (x + a^(CS[j-i][2]));
            r := Concatenation(r, [ a^(CS[j-i][1]), a^(CS[j-i][2]) ]);
        od;
    fi;

    G := GeneratorMatrixFromPoly(g, q^m + 1);
    C := GeneratorMatCodeNC(G, F);

    C!.name := "MDS code";

    # We know these bounds as it is an MDS code
    C!.lowerBoundMinimumDistance := dmin;
    C!.upperBoundMinimumDistance := dmin;

    # Tell it that it is a cyclic code
    SetIsCyclicCode(C, true);
    SetGeneratorPol(C, g);

    # Also tell it that it is an MDS code
    IsMDSCode(C);

    return C;
end);

#######################################################################
##
#F FourNegacirculantSelfDualCode( <ax>, <bx>, <k> ) . . self-dual code
##
## Construct a [2*k, k, d] self-dual code over F using Harada's
## construction. See:
##
##    1. M. Harada and T. Nishimura, "An extremal singly even self
##       dual code of length 88", Advances in Mathematics of
##       Communications, vol 1, no. 2, pp. 261--267, 2007
##
##    2. M. Harada, W. Holzmann, H. Kharaghani and M. Khorvash,
##       "Extremal ternary self-dual codes constructed from
##       negacirculant matrices", Graph and Combinatorics, vol 23,
##       pp. 401--417, 2007
##
##    3. M. Harada, "An extremal doubly even self-dual code of
##       length 112", preprint
##
## The generator matrix of the code has the following form:
##
##        -                   -
##        |       :   A  :  B  |
##    G = |   I   :------:-----|
##        |       : -B^T : A^T |
##        -                   -
##
## Note that the matrices A, B, A^T and B^T are k/2 * k/2
## negacirculant matrices.
##
__G_FourNegacirculantSelfDualCode := function(ax, bx, k)
    local i, v, m, x, FA, FB, A, AT, B, BT, G;

    if IsOddInt(k) then
        Error("k must be an even integer\n");
    fi;

    m := k/2;

    # Determine field size
    FA := Field(VectorCodeword(Codeword(ax)));
    FB := Field(VectorCodeword(Codeword(bx)));
    if FA <> FB then
        Error("Polynomials a(x) and b(x) must have elements from the same field\n");
    fi;

    x := Indeterminate(FA);

    #v := MutableCopyMatrix( CoefficientsOfUnivariatePolynomial(ax) );
    #MutableCopyMatrix expects a MATRIX, not a LIST
    v := ShallowCopy( CoefficientsOfUnivariatePolynomial(ax) );
    Append( v, List([1..(m - (Degree(ax)+1))], i->Zero(FA)) );
    A := NegacirculantMatrix(m, v*One(FA));
    AT:= TransposedMat(A);

    #v := MutableCopyMatrix( CoefficientsOfUnivariatePolynomial(bx) );
    #ditto
    v := ShallowCopy( CoefficientsOfUnivariatePolynomial(bx) );
    Append( v, List([1..(m - (Degree(bx)+1))], i->Zero(FA)) );
    B := NegacirculantMatrix(m, v*One(FA));
    BT:= TransposedMat(-B);

    G := IdentityMat(k, One(FA));

    # [ A | B ]
    for i in [1..m] do;
        Append(G[i], A[i]);
        Append(G[i], B[i]);
    od;

    # [ B^T | A^T ]
    for i in [1..m] do;
        Append(G[m+i], BT[i]);
        Append(G[m+i], AT[i]);
    od;

    return G;
end;

InstallMethod(FourNegacirculantSelfDualCode, "method for binary linear code", true,
    [IsUnivariatePolynomial, IsUnivariatePolynomial, IsInt], 0,
function(ax, bx, k)
    local G, C, F;

    # Obtain the generator matrix
    G := __G_FourNegacirculantSelfDualCode(ax, bx, k);
    F := Field(VectorCodeword(Codeword(ax)));

    C := GeneratorMatCode(G, "four-negacirculant self-dual code", F);
    C!.GeneratorMat := ShallowCopy(G);

    if (IsSelfDualCode(C) = false) then
        Error("Polynomials a(x) and b(x) do not produce a self-dual code\n");
    fi;

    return C;
end);

# Faster version - no minimum distance and covering radius estimation
InstallMethod(FourNegacirculantSelfDualCodeNC, "method for binary linear code", true,
    [IsUnivariatePolynomial, IsUnivariatePolynomial, IsInt], 0,
function(ax, bx, k)
    local G, C, F;

    # Obtain the generator matrix
    G := __G_FourNegacirculantSelfDualCode(ax, bx, k);
    F := Field(VectorCodeword(Codeword(ax)));

    C := GeneratorMatCodeNC(G, F);
    C!.name := "four-negacirculant self-dual code";
    C!.GeneratorMat := ShallowCopy(G);
    C!.lowerBoundMinimumDistance := 1;
    C!.upperBoundMinimumDistance := k+1;
    C!.boundsCoveringRadius := [ 0, WordLength(C) ];

    if (IsSelfDualCode(C) = false) then
        Error("Polynomials a(x) and b(x) do not produce a self-dual code\n");
    fi;

    return C;
end);

###########################################################################
##
#F QCLDPCCodeFromGroup( <m>, <j>, <k> ) . . Regular quasi-cyclic LDPC code
##
## Construct a regular (j,k) quasi-cyclic low-density parity-check (LDPC)
## code over GF(2) based on the multiplicative group of integer modulo m.
## If m is a prime, the size of the group is equal to Phi(m) = m - 1,
## otherwise it is equal to Phi(m). For details, refer to the paper by:
##
##   R. Tanner, D. Sridhara, A. Sridharan, T. Fuja and D. Costello,
##   "LDPC block and convolutional codes based on circulant matrices",
##   IEEE Trans. Inform. Theory, vol. 50, no. 12, pp. 2966--2984, 2004
##
## NOTE that j and k must divide Phi(m).
##
InstallMethod(QCLDPCCodeFromGroup, "method for binary linear code", true,
 [IsInt, IsInt, IsInt], 0,
function(m, j, k)
    local r, c, a, b, p, P, H, M, C, PermutationMatrix;

    ##
    ##----------------- start of private functions ---------------------
    ##
    ## PermutationMatrix - a private function for QCLDPCCodeFromGroup
    PermutationMatrix := function(m, i)
        local s, P, L;
        if i = 0 or i > m then
            Error("invalid value of i, 1 \\le i \\le ", m, "\n");
        fi;
        P := [];
        L := List([1..m], i->Zero(GF(2))); L[i] := One(GF(2));
        Append(P, [ L ]);
        for s in [2..m] do;
            L := RightRotateList(L);
            Append(P, [ L ]);
        od;
        return P;
    end;
    ##
    ##------------------ end of private functions ----------------------
    ##

    p := Phi(m);
    if (p mod j <> 0) then
        Error(j, " does not divide ", p, "=Phi(", m, ")\n");
    fi;
    if (p mod k <> 0) then
        Error(k, " does not divide ", p, "=Phi(", m, ")\n");
    fi;

    a := Position( List([1..m-1], i->OrderMod(i, m) ), k );
    b := Position( List([1..m-1], i->OrderMod(i, m) ), j );

    P := [];
    for r in [0..j-1] do;
        Append(P, [ List([0..k-1], i->a^i*b^r mod m) ]);
    od;

    H := [];
    for r in [1..j] do;
        M := [];
        for c in [1..k] do;
            M := TransposedMat( Concatenation( TransposedMat(M), TransposedMat( PermutationMatrix(m, P[r][c]) ) ) );
        od;
        Append(H, M);
    od;
    C := CheckMatCode( H, GF(2) );
    C!.CheckMat := H;
    C!.name := "low-density parity-check code";
    C!.upperBoundMinimumDistance := Factorial(j+1);
    return C;
end);

[Dauer der Verarbeitung: 0.49 Sekunden, vorverarbeitet 2026-04-27]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge