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


Quelle  qdistrnd.g   Sprache: unbekannt

 
# Functions for finding an upper bound on the distance of a quantum code
# linear over a Galois Field F [for regular qubit code F is GF(2)]
#
# Written by
# Vadim A. Shabashov <vadim.art.shabashov@gmail.com>
# Valerii K. Kozin <kozin.valera@gmail.com>
# Leonid P. Pryadko <leonid.pryadko@gmail.com>



############################
#! @Chapter AllFunctions
#! @Section HelperFunctions



#! @Description Calculate the average of the components of a numerical `vector`
#! @Arguments vector
#DeclareGlobalFunction("QDR_AverageCalc");
BindGlobal("QDR_AverageCalc",
                     function(mult)
                         return 1.0*Sum(mult)/Length(mult);
                     end
                     );





#! @Description Calculate the symplectic weight of a `vector` with
#! an even number of entries from the field `field`.   The elements of
#! the pairs are
#! intercalated: $(a_1, b_1, a_2, b_2,\ldots)$.
#! 
#! **Note: the parity of vector `length` and the format are not verified!!!**
#! @Returns symplectic weight of a vector 
#! @Arguments vector, field
#DeclareGlobalFunction("QDR_SymplVecWeight");        
BindGlobal("QDR_SymplVecWeight",
                     function(vec, F)
                         local wgt, i, len;
    # local variables: wgt - the weight, i - for "for" loop, len - length of vec
                         
                         len := Length(vec);
    #    if (not IsInt(len / 2)) then
    #   Error(" symplectic vector must have even length, = ", len,"\n");
    #    fi;

                         wgt := 0;
                         for i in [1..(len/2)] do
                             if (vec[2*i-1] <> Zero(F) or vec[2*i] <> Zero(F)) then
                                 wgt := wgt + 1;;
                             fi;
                         od;

                         return wgt;
                     end
                     );

#! @Description count the total number of non-zero entries in a matrix.
#! @Arguments matrix
#! @Returns number of non-zero elements
DeclareGlobalFunction("QDR_WeightMat");
InstallGlobalFunction("QDR_WeightMat",
                     function(mat)
                         local NonZeroElem,i,rows;
                         rows:=DimensionsMat(mat)[1];
                         NonZeroElem:=0;
                         for i in [1..rows] do
                             NonZeroElem:=NonZeroElem+WeightVecFFE(mat[i]);
                         od;
                         return NonZeroElem;
                     end
                     );
                      

#! @Description Aux function to print out the relevant probabilities given
#! the list `vector` of multiplicities of the codewords found.  Additional
#! parameters are `n`, the code length, and `num`, the number of
#! repetitions; these are ignored in the present version of the
#! program.  See <Ref Sect="Section_Empirical"/> for 
#! related discussion.
#! @Arguments vector, n, num
#! @Returns nothing
DeclareGlobalFunction("QDR_DoProbOut");
InstallGlobalFunction("QDR_DoProbOut",
                     function(mult,n,num)
                         local s0,s1,s2;
                         Print("<n>=", QDR_AverageCalc(mult));
                         s0:=Length(mult);
                         if s0>1 then
                             s1:=Sum(mult);
                             s2:=Sum(mult, x->x^2);
                             Print(" X^2_",s0-1,"=",Float(s2*s0-s1^2)/s1, "\n");
                         # Here the expression is due to the map to
                         # multinomial distribution (divide by the total) and the quantity is
                         # supposed to be distributed by chi^2 with s0-1 degrees of freedom.
                         else
                             Print("\n");
                         fi;
                     end
                     );

#! @Description Parse a string describing a Galois field
#! Supported formats: `Z(p)`, `GF(q)`, and `GF(q^m)`,
#! where `p` must be a prime, `q` a prime or a power of a prime, and `m` a natural integer.  
#! No spaces are allowed.
#! @Returns the corresponding Galois field
#! @Arguments str
#DeclareGlobalFunction("QDR_ParseFieldStr");
BindGlobal("QDR_ParseFieldStr",
                     function(str)
                         local body, q;                         
                         if EndsWith(str,")") then 
                             if StartsWith(str,"Z(") then 
                                 body := str{[3..Length(str)-1]};
                                 q := Int(body);
                                 if IsInt(q) and IsPrimeInt(q) then
                                     return Z(q);
                                 else
                                     Print("\n Argument of ",str,"should be prime\n");
                                 fi;
                             elif StartsWith(str,"GF(") then 
                                 body := str{[4..Length(str)-1]};
                                 q := Int(body);
                                 if IsInt(q) then 
                                     if IsPrimePowerInt(q) then
                                         return GF(q);
                                     fi;
                                 else 
                                     q := SplitString(body,"^");
                                     if Length(q) = 2 then
                                         if IsInt(Int(q[1])) and 
                                            IsInt(Int(q[2])) and 
                                            IsPrimePowerInt(Int(q[1])^Int(q[2]))
                                         then
                                             return GF(Int(q[1])^Int(q[2]));
                                         fi;
                                     fi;
                                 fi;
                                 Print("\n Argument of ",str,"should be a prime power\n");
                             fi;
                         fi;
                         Error("\n QDR_ParseFieldStr: Invalid argument format str=",str,
                               "\n valid format: 'GF(p)', 'Z(p)', 'GF(p^m)', 'GF(q)'",
                               "\n with 'p' prime, 'm' positive integer, and 'q' a prime power\n");
                     end
                     );

#! @Description Parse string `str` as a polynomial over the field `F`.
#! Only characters in "0123456789*+-^x" are allowed in the string. 
#! In particular, no spaces are allowed.
#! @Returns the corresponding polynomial
#! @Arguments F, str
#DeclareGlobalFunction("QDR_ParsePolyStr");
BindGlobal("QDR_ParsePolyStr", 
          function(F, str)
              local func, new_str;
              # make sure `str` only contains these characters 
              new_str := String(str); # copy
              RemoveCharacters(new_str,"0123456789x*+-^");
              if (Length(new_str) > 0) then 
                  Error("QDR_ParsePolyStr: invalid character(s) [",new_str,"] in polynomial ",str);
              fi;              
              
              func := EvalString(Concatenation("""
                function(F)   
                  local x;       
                  x := Indeterminate(F,"x");
                  return """, str, """;
                end
                """));
              return func(F);
          end);

#! @Description Create a header string describing the field `F`
#! for use in the function `WriteMTXE`.
#! If `F` is a prime Galois field, just specify it: 
#! @BeginCode
#! % Field: GF(p)
#! @EndCode
#! For an extension field $\mathop{\rm GF}(p^m)$ with $p$ prime and $m>1$, also give 
#! the primitive polynomial **which should not contain any spaces**.  For example,  
#! @BeginCode
#! % Field: GF(7^4) PrimitiveP(x): x^4-2*x^2-3*x+3
#! @EndCode
#! See Chapter <Ref Chap="Chapter_FileFormat"/> for details.
#! @Returns the created header string 
#! @Arguments F
#DeclareGlobalFunction("QDR_FieldHeaderStr");
BindGlobal("QDR_FieldHeaderStr",
                     function(F) # field F
                         local p,m, poly,lis,i,j, b, str, out;
                         if not IsField(F) then 
                             Error("\n Argument must be a Galois Field! F=",F,"\n");
                         fi;                         
                         p:=Characteristic(F);    
                         # for some reason DegreeOverPrimeField does
                         # not work
                         m:=DegreeFFE(PrimitiveElement(F));  # field GF(p^m);          
                         str:="";
                         out:=OutputTextString(str,false);; 
                         PrintTo(out,"% Field: ", F);  # this is it for a prime field
                         if not IsPrimeField(F) then   
                             poly:=DefiningPolynomial(F);                         
                             lis:=CoefficientsOfUnivariatePolynomial(poly);
                             PrintTo(out," PrimitiveP(x): ");                             
                             for i in [0..m] do 
                                 j:=m-i;    # degree     
                                 b:=IntFFESymm(lis[j+1]);
                                 if b<>0 then 
                                     if AbsInt(b)<>1 then 
                                         if b>0 then PrintTo(out,"+",b); else PrintTo(out,b); fi;
                                         if j>1 then PrintTo(out,"*x^",j); 
                                         elif j=1 then PrintTo(out,"*x");
                                         fi;
                                     else 
                                         if b>0 then 
                                             if j<m then PrintTo(out,"+"); fi;
                                         else PrintTo(out,"-"); fi;            
                                         if j>1 then PrintTo(out,"x^",j); 
                                         elif j=1 then PrintTo(out,"x");
                                         else PrintTo(out,"1"); # j=0 abd abs(b)=1
                                         fi;
                                     fi;
                                 fi;    
                             od;
                             
                             CloseStream(out);
                         fi;
                         
                         return str;
                     end                     
                     );

#! @Description Process the field header (second line in the MTXE file
#! format), including the field, PrimitiveP record, and anything else.
#! Supported format options:
#! @BeginCode FieldHeaderA
#! Field: `field` PrimitiveP(x): `polynomial` Format: `format`
#! @EndCode
#! @InsertCode FieldHeaderA
#! 
#! Here the records should be separated by one or more spaces;
#! while `field`, `polynomial`, and `format` **should not contain any spaces.**
#! Any additional records in this line will be silently ignored.
#! 
#! The `field` option should specify a valid field, $\mathop{\rm GF}(q)$ or
#! $\mathop{\rm GF}(p^m)$, where $q>1$ should be a power of the prime $p$. 
#! 
#! The `polynomial` should be a valid expanded monic
#! polynomial with integer coefficients, with a single independent
#! variable `x`; it should contain no spaces.  An error will be
#! signaled if `polynomial` is not a valid primitive polynomial of the `field`.
#! This argument is optional;  by default, Conway polynomial will be used.
#!
#! The optional `format` string (**not implemented**) should be "AdditiveInt" (the default
#! for prime fields), "PowerInt" (the default for extension fields
#! with $m>1$) or "VectorInt".  
#! 
#! `AdditiveInt` indicates that values listed
#! are expected to be in the corresponding prime field and should be
#! interpreted as integers mod $p$.  
#! `PowerInt` indicates that field elements are
#! represented as integers powers of the primitive element, root of
#! the primitive polynomial, or $-1$ for the zero field element.  
#! `VectorInt` corresponds to encoding coefficients of a degree-$(m-1)$ $p$-ary
#! polynomial representing field elements into a $p$-ary integer.  In
#! this notation, any negative value will be taken mod $p$, thus $-1$
#! will be interpreted as $p-1$, the additive inverse of the field $1$.
#! 
#! On input, `recs` should contain a list of tokens obtained by
#! splitting the field record line;
#! `optF` should be assigned to `ValueOption("field")` or `fail`.
#! 
#! @Arguments recs, optF
#! @Returns the list [Field, ConversionDegree, FormatIndex] (plus anything else we
#! may need in the future); the list is to be used as the second
#! parameter in `QDR_ProcEntry()`  
#DeclareGlobalFunction("QDR_ProcessFieldHeader");
BindGlobal("QDR_ProcessFieldHeader",
                     function(recs,optF)
                         local m,F,Fp,poly,x,ic,is,a;
    
                         if (Length(recs)>2 and recs[1][1]='%' and recs[2]="Field:") then
                             F:=QDR_ParseFieldStr(recs[3]);
                             if not IsField(F) then
                                 Error("invalid input file field '",recs[3],"' given\n");
                             fi;
                         fi;
                         
                         # compare with the field option
                         if optF <> fail then
                             if not IsField(optF) then
                                 Error("invalid option 'field'=",optF,"\n");
                             else # default field is specified
                                 if IsBound(F) then
                                     if F<>optF then
                                         Error("field mismatch: file='",F,
                                               "' given='",optF,"'\n");
                                     fi;
                                 else
                                     F:=optF;
                                 fi;
                             fi;
                         elif not IsBound(F) then
                             F:=GF(2);                            
                         fi;
                         
                         # check if a PrimitiveP is specified (only if the field is prime).
                         if IsPrimeField(F) then
                             return [F,1,0]; # field, degree=1, format="AdditiveInt"
                         fi;    
                         ic:=1; is:=1; # set default conversion degree        
                         if Length(recs)>3 then # analyze primitive polynomial
                             if StartsWith(recs[4],"PrimitiveP(x)") then 
                                 # process primitive polynomial here 
                                 if Length(recs)=4 then 
                                     Error("Polynomial must be separated by space(s) ",recs[4],"\n");
                                 fi;
                                 if not EndsWith(recs[4],"):") then 
                                     Error("Invalid entry ",recs[4],"\n");
                                 fi;                                 
                                 
                                 poly:=QDR_ParsePolyStr(recs[5]);
                                 
                                 if not IsUnivariatePolynomial(poly) then
                                     Error("Univariate polynomial expected ",recs[5],"\n");
                                 fi;
                                 Fp:=PrimeField(F);                
                                 poly:=poly*One(Fp);
                                 if not IsPrimitivePolynomial(Fp,poly) then 
                                     Error("Polynomial ",recs[5], " must be primitive in ",Fp,"\n");
                                 fi;
                                 m:=DegreeFFE(PrimitiveElement(F));            
                                 if not DegreeOfLaurentPolynomial(poly)=m then 
                                     Error("Polynomial degree ",recs[5], " should be ",m,"\n");
                                 fi;
                                 a:=PrimitiveRoot(F); 
                                 for ic in [1..Size(F)-2] do
                                     if Value(poly,a^ic) = Zero(Fp) then 
                                         break; # will terminate here for sure
                                     fi;        # since `poly` is primitive.
                                 od; 
                                 is:= 1/ic mod (Size(F)-1);
                                 Unbind(poly);
                                 
                             fi;
                         fi;
    
                         # todo: process `format` here 
                         
                         return [F,is,2]; # field, degree, format="PowerInt"
                     end
                     );

#! @Description Convert a string entry which should represent an integer
#! to the Galois Field element as specified in the `fmt`.
#! * `str` is the string representing an integer.
#! * `fmt` is a list  [Field, ConversionDegree, FormatIndex]
#!   - `Field` is the Galois field $\mathop{\rm GF}(p^m)$ of the code
#!   - `ConversionDegree` $c$ : every element $x$ read is replaces with
#!     $x^c$.  This may be needed if a non-standard primitive
#!     polynomial is used to define the field. 
#!   - `FormatIndex` in {0,1,2}. `0` indicates no conversion (just a
#!     modular integer).  `1` indicates that the integer represents
#!     a power of the primitive element, or $-1$ for 0.  `2`
#!     indicates that the integer encodes coordinates of a length $m$
#!     vector as the digits of a $p$-ary integer (**not yet implemented**).
#! * `FileName`, `LineNo` are the line number and the name of the
#!   input file; these are used to signal an error.
#!
#! @Returns the converted field element 
#! @Arguments str, fmt, FileName, LineNo
#DeclareGlobalFunction("QDR_ProcEntry");
BindGlobal("QDR_ProcEntry",
                     function(str,fmt,FileName,LineNo)
                         local ival, fval;
                         ival:=Int(str);
                         if ival=fail then 
                             Error("\n",FileName,":",LineNo,"Invalid entry '",str,
                                   "', expected an integer\n");
                         fi;
                         if fmt[3]=0 then 
                             fval:=ival*One(fmt[1]);
                         elif fmt[3]=1 then 
                             if ival=-1 then 
                                 fval:=Zero(fmt[1]);
                             else
                                 fval:=PrimitiveElement(fmt[1])^ival;
                             fi;
                         else
                             Error("FormatIndex=",fmt[3]," value not supported\n");
                         fi;
                         return fval^fmt[2];    
                     end
                     );


#! @Subsection Examples

#! @Section IOFunctions 


#! @Returns a list [`field`, `pair`, `Matrix`, `array_of_comment_strings`]
#! @Arguments FilePath [,pair] : field:=GF(2)
#!
#! @Description Read matrix from an MTX file, an extended version of Matrix Market eXchange 
#! coordinate format supporting finite Galois fields and
#! two-block matrices 
#! $ (A|B) $ 
#! with columns 
#! $A=(a_1, a_2, \ldots , a_n)$ 
#! and 
#! $B=(b_1, b_2, \ldots , b_n)$, see Chapter <Ref Chap="Chapter_FileFormat"/>.
#!
#! * `FilePath` name of existing file storing the matrix
#! * `pair` (optional argument): specifies column ordering;
#!          must correlate with the variable `type` in the file
#!      * `pair=0` for regular single-block matrices (e.g., CSS) `type=integer` (if `pair` not
#!            specified, `pair`=0 is set by default for `integer`) 
#!      * `pair=1` intercalated columns with `type=integer`
#!            $ (a_1, b_1, a_2, b_2,\ldots) $ 
#!      * `pair=2` grouped columns with `type=integer`
#!            $ (a_1, a_2, \ldots, a_n\;    b_1, b_2,\ldots, b_n) $ 
#!      * `pair=3` this is the only option for `type=complex` with elements 
#!            specified as "complex" pairs 
#! * `field` (Options stack):  Galois field, default: $\mathop{\rm GF}(2)$.
#! **Must** match that given in the file (if any).
#! __Notice__: with `pair`=1 and `pair`=2, the number of matrix columns
#! specified in the file must be even, twice the block length of the
#! code.  **This version of the format is deprecated and should be avoided.**
#!
#! 1st line of file must read:
#! @BeginCode LineOne
#! %%MatrixMarket matrix coordinate `type` general 
#! @EndCode
#! @InsertCode LineOne
#!  with `type` being either `integer` or `complex`
#!
#! 2nd line (optional) may contain:
#!
#! @BeginCode LineTwoA
#! % Field: `valid_field_name_in_Gap` 
#! @EndCode
#! @InsertCode LineTwoA
#! or
#! @BeginCode LineTwoB
#! % Field: `valid_field_name_in_Gap` PrimitiveP(x): `polynomial` 
#! @EndCode
#! @InsertCode LineTwoB
#! 
#! Any additional entries in the second line are silently ignored.  By
#! default, $\mathop{\rm GF}(2)$ is assumed;
#! the default can be overriden
#! by the optional `field` argument.   If the field is specified both
#! in the file and by the optional argument, the corresponding values
#! must match.  Primitive polynomial (if any) is only checked in the case of 
#! an extension field; it is silently ignored for a prime field.
#!
#! See Chapter <Ref Chap="Chapter_FileFormat"/> for the details of how the elements
#! of the group are represented depending on whether the field is a prime
#! field ($ q $ a prime) or an extension field with $ q=p^m $, $p$ prime, and $m>1$.
#! 
#DeclareGlobalFunction("ReadMTXE");
BindGlobal("ReadMTXE",
                     function(StrPath, opt... ) # supported option: "field"
                         local input, data, fmt, line, pair, F, rowsG, colsG, G, G1, i, infile,
                               iCommentStart,iComment;
                         # local variables:
                         # input - file converted to a string
                         # data - input separated into records (list of lists)
                         # fmt  - array returned by QDR_ProcessFieldHeader
                         # pair - 0,1,2 (integer) or 3 (complex), see input variables
                         #        indicates if we store matrix in the compressed form,
                         #              using complex representation a+i*b
                         #        (normal form if pair=integer and compressed form if pair=complex),
                         # F - Galois field, over which we are working
                         # rowsG - number of rows in G
                         # colsG - number of columns in G
                         # G - matrix read
                         # G1 - aux matrix with permuted columns
                         # i - dummy for "for" loop
                         # iCommentStart, iComment - range of line numbers for comment section
                         
                         infile := InputTextFile(StrPath);
                         input := ReadAll(infile);;                        # read the file in
                         CloseStream(infile);
                         data := SplitString(input, "\n");;         # separate into lines
                         line := SplitString(data[1], " ");;         # separate into records
                         
                         # check the header line
                         if Length(line)<5 or line[1]<>"%%MatrixMarket" or 
                            line[2]<>"matrix" or line[3]<>"coordinate" or
                            (line[4]<>"integer" and line[4]<>"complex") or line[5]<>"general"
                         then
                             Display(data[1]);
                             Error("Invalid header! This software supports MTX files containing", 
                                   "a general matrix\n",
                                   "\twith integer or complex values in coordinate format.\n");
                         fi;
                         
                         # analyze the 2nd (opt) argument
                         if (Length(opt)>1) then
                             Error("Too many arguments!\n");
                         elif (Length(opt)=1) then
                             pair:=Int(opt[1]); # must be an integer
                             if line[4]="complex" and pair<>3 then
                                 Error("complex matrix must have pair=3, not ",pair,"\n");
                             fi;
                             if line[4]="integer" then
                                 if pair<0 or pair>2 then
                                     Error("integer matrix must have 0<=pair<=2, not ",pair,"\n");
                                 fi;
                             fi;
                         else # no opt specified
                             if line[4]="complex" then pair:=3; else pair:=0; fi;
                         fi;
                         
                         # process the field argument in the second line, if any 
                         line := SplitString(data[2], " ");; # separate into records
                         if (Length(line)>2 and line[1][1]='%' and line[2]="Field:") then
                             iCommentStart:=3; # second line is a format line, not needed
                         else
                             iCommentStart:=2; # this was a regular comment 
                         fi;
                         
                         fmt:=QDR_ProcessFieldHeader(line,ValueOption("field"));
                         F:=fmt[1];

                         # search for the end of top comment section (including any empty lines):
                         iComment := iCommentStart;
                         while Length(data[iComment + 1]) = 0 or data[iComment + 1, 1] = '%' do
                             iComment := iComment + 1;
                             if Length(data[iComment]) = 0 then
                                 data[iComment]:="%"; # suppress empty comment lines
                             fi;
                         od;
                         
                         for i in [iComment+1..Length(data)] do
                             data[i] := SplitString(data[i], " ");; # separate into records
                         od;
                         
                         # Parameters (dimensions and number of non-zero elemments) of G
                         rowsG := Int(data[iComment + 1, 1]);;
                         colsG := Int(data[iComment + 1, 2]);;
                         if pair=3 then colsG:=colsG*2; fi; # complex matrix
                         
                         G := NullMat(rowsG, colsG, F);;    # empty matrix
    
                         # Then we fill G with the elements from data (no more empty / comment lines allowed)
                         if (pair <>3 ) then                      
                             for i in [(iComment + 2)..Length(data)] do
                                 G[Int(data[i,1]), Int(data[i,2])] := 
                                     QDR_ProcEntry(data[i,3],fmt,StrPath,i);                                 
                             od;
                         else # pair=3 
                             for i in [(iComment + 2)..Length(data)] do
                                 G[Int(data[i,1]),2*Int(data[i,2])-1]:=
                                     QDR_ProcEntry(data[i,3],fmt,StrPath,i);                                 
                                 G[Int(data[i,1]),2*Int(data[i,2])]:=
                                     QDR_ProcEntry(data[i,4],fmt,StrPath,i);                                 
                             od;
                         fi;
                         
                         if pair=2 then # reorder the columns
                             G1 := TransposedMatMutable(G);
                             G:=[];
                             for i in [1..(colsG/2)] do
                                 Add(G,G1[i]);
                                 Add(G,G1[i+colsG/2]);
                             od;
                             G := TransposedMatMutable(G);;
                             pair:=1;
                         elif pair=3 then
                             pair:=1;
                         fi;
                         return [F,pair,G,data{[iCommentStart..iComment]}];
                     end
                     );

#! @Arguments StrPath, pair, matrix [,comment[,comment]] : field:=GF(2)
#! @Returns no output
#! @Description 
#! Export a `matrix` in Extended MatrixMarket format, with options
#! specified by the `pair` argument.  
#!
#! * `StrPath` - name of the file to be created;
#! * `pair`: parameter to control the file format details, must match the storage
#!    `type` of the matrix. 
#!   - `pair=0` for regular matrices (e.g., CSS) with `type=integer` 
#!   - `pair=1` for intercalated columns $ (a_1, b_1, a_2, b_2, \ldots) $
#!              with `type=integer` (**deprecated**)
#!   - `pair=2` for grouped columns with `type=integer` **(this is not supported!)**
#!   - `pair=3` for columns specified in pairs with `type=complex`.
#! * Columns of the input `matrix` must be intercalated unless `pair=0`
#! * optional `comment`: one or more strings (or a single list of
#!   strings) to be output after the MTX header line.  
#!
#! The second line specifying the field will be generated
#! automatically **only** if the GAP Option `field` is present.
#! As an option, the line can also be  entered explicitly
#! as the first line of the comments, e.g., `"% Field: GF(256)"`
#!
#! 
#! See Chapter <Ref Chap="Chapter_FileFormat"/> for the details of how the elements
#! of the group are represented depending on whether the field is a prime
#! field ($ q $ a prime) or an extension field with $ q=p^m $, $ m>1 $.
#! 
#DeclareGlobalFunction("WriteMTXE");
BindGlobal("WriteMTXE", # function (StrPath,pair,G,comment...)
          function (StrPath,pair,G,comment...) # supported option: field [default: GF(2)]
              local F, dims, rows, cols, nonzero, i, row, pos, filename;
              # F - field to be used (default: no field specified)
              # dims - dimensions of matrix G
              # rows and cols - number of rows and columns of the matrix G
              # nonzero - number of lines needed to store all nonzero elements of matrix with
              # pair parameter as given
              # i - for "for" loop
              # i, row and pos - temporary variables
              
              # see if the field is specified
              if ValueOption("field")<>fail then
                  if not IsField(ValueOption("field")) then
                      Error("invalid option 'field'=",ValueOption("field"),"\n");
                  else # default field is specified
                      F:=ValueOption("field");
                  fi;
              else
                  F:=GF(2); # default
              fi;
              
              # We check pair parameter
              if (pair <0 ) or (pair>3) or (pair=2) then
                  Error("\n", "Parameter pair=",pair," not supported, must be in {0,1,3}", "\n");
              fi;
              
              # full file name with extension
              if EndsWith(UppercaseString(StrPath),".MTX") then
                  filename:=StrPath;
              else
                  filename := Concatenation(StrPath, ".mtx");
              fi;
              
              if (pair=3) then row:="complex"; else row:="integer"; fi;
              
              # Header of the MatrixMarket
              PrintTo(filename, "%%MatrixMarket matrix coordinate ", row, " general", "\n");
              if ValueOption("field")<>fail then AppendTo(filename,QDR_FieldHeaderStr(F), "\n"); fi;

              for i in [1..Length(comment)] do
                  if comment[i,1]<>'%' then
                      AppendTo(filename, "% ", comment[i], "\n");
                  else
                      AppendTo(filename, comment[i], "\n");
                  fi;
              od;
              if IsPrime(Size(F)) then
                  AppendTo(filename,"% Values Z(",Size(F),") are given\n");
              else
                  AppendTo(filename,"% Powers of GF(",Size(F),") primitive element and -1 for Zero are given\n");
              fi;
              
              # Matrix dimensions
              dims := DimensionsMat(G);;
              rows := dims[1];;
              cols := dims[2];;
              
              # count non-zero elements depending on the 'pair' parameter
              nonzero := 0;
              if (pair = 3) then
                  for i in [1..rows] do
                      nonzero := nonzero + QDR_SymplVecWeight(G[i], F);;
                  od;
              else
                  for i in [1..rows] do
                      nonzero := nonzero + WeightVecFFE(G[i]);;
                  od;
              fi;
              
              if (pair < 3) then
                  # write dimensions of the matrix and number of line containing nonzero elements
                  AppendTo(filename, rows, " ", cols, " ", nonzero, "\n");
                  
                  # Finally, write nonzero elements and their positions according to pair parameter and field F.
                  if IsPrime(Size(F)) then # this includes binary field
                      for i in [1..rows] do
                          row := G[i];;
                          
                          pos := PositionNonZero(row, 0);;
                          while pos <= cols do
                              AppendTo(filename, i, " ", pos, " ", Int(row[pos]), "\n");
                              pos := PositionNonZero(row, pos);;
                          od;
                      od;
                  else # extension field
                      for i in [1..rows] do
                          row := G[i];;
                          
                          pos := PositionNonZero(row, 0);;
                          while pos <= cols do
                              AppendTo(filename, i, " ", pos, " ", 
                                       LogFFE(row[pos], PrimitiveElement(F)), "\n");
                              pos := PositionNonZero(row, pos);;
                          od;
                      od;
                  fi;
              else # pair=3
                  # write dimensions of the matrix and number of line containing nonzero elements
                  AppendTo(filename, rows, " ", cols/2," ", nonzero, "\n");
                  # Finally, write nonzero elements and their positions according to pair parameter and field F.
                  if IsPrime(Size(F)) then
                      for i in [1..rows] do
                          row := G[i];;
                          pos := PositionNonZero(row, 0);;
                          while pos <= cols do
                              # For Ai = 0
                              if IsInt(pos/2) then
                                  AppendTo(filename, i, " ", pos/2, " ", 0, " ", Int(row[pos]), "\n");
                                  pos := PositionNonZero(row, pos);;
                              # For Ai != 0
                              else
                                  AppendTo(filename, i, " ", (pos+1)/2, " ", Int(row[pos]), " ", Int(row[pos + 1]), "\n");
                                  pos := PositionNonZero(row, pos + 1);;
                              fi;
                          od;
                      od;
                  else # extension field
                      for i in [1..rows] do
                          row := G[i];;
                          
                          pos := PositionNonZero(row, 0);;
                          while pos <= cols do
                              # For Ai = 0
                              if IsInt(pos/2) then
                                  AppendTo(filename, i, " ", pos/2, " ", -1, " ", LogFFE(row[pos], PrimitiveElement(F)), "\n");
                                  pos := PositionNonZero(row, pos);;
                              # For Ai != 0
                              else
                                  # Check if Bi = 0
                                  if (row[pos + 1] = Zero(F)) then
                                      AppendTo(filename, i, " ", (pos+1)/2, " ", LogFFE(row[pos], PrimitiveElement(F)), " ", -1, "\n");
                                  else
                                      AppendTo(filename, i, " ", (pos+1)/2, " ", LogFFE(row[pos], PrimitiveElement(F)),
                                               " ", LogFFE(row[pos + 1], PrimitiveElement(F)), "\n");
                                  fi;
                                  
                                  pos := PositionNonZero(row, pos + 1);;
                              fi;
                          od;
                      od;
                  fi;
              fi;
              # Print("File ", filename, " was created\n");
          end
          );


#! @Section HelperFunctions

#! @Arguments matrix, field
#! @Description Given a two-block `matrix` with intercalated columns 
#! $ (a_1, b_1, a_2, b_2, \ldots) $,  calculate the corresponding check matrix `H` with
#! columns $ (-b_1, a_1, -b_2, a_2, \ldots) $.  
#! 
#! The parity of the number of columns is verified. 
#! @Returns `H` (the check matrix constructed)
#!
#DeclareGlobalFunction("QDR_MakeH");
BindGlobal("QDR_MakeH",
                     function(G, F)
                          
                         local dims, i, H;
                         # local variables: dims - dimensions of G matrix, i - for "for" loop,
                         # H - *** TRANSPOSED *** check matrix
                         
                         dims := DimensionsMat(G);;
                          
                         # Checking that G has even number of columns
                         if (Gcd(dims[2] , 2) = 1) then
                             Error("\n", "Generator Matrix G has odd number of columns!", "\n");
                         fi;
                         
                         # Introducing check matrix
                         H := TransposedMatMutable(G);;
                         for i in [1..(dims[2]/2)] do
                             H[2*i] := (-1) * H[2*i];; #H = (A1,-B1,A2,-B2,...)^T
                             H := Permuted(H, (2*i-1,2*i));; # H = (-B1,A1,-B2,A2,...)^T.
                         od;
                         
                         return TransposedMatMutable(H);
                     end
                     );

#! @Section DistanceFunctions 

#! @Description
#!  Computes an upper bound on the distance $d_Z$ of the
#!  $q$-ary code with stabilizer generator matrices $H_X$, $H_Z$ whose rows
#!  are assumed to be orthogonal (**orthogonality is not verified**).
#!  Details of the input parameters 
#!  * `HX`, `HZ`: the input matrices with elements in the Galois `field` $F$
#!  * `num`: number of information sets to construct (should be large)
#!  * `mindist` - the algorithm stops when distance equal or below `mindist`
#!     is found and returns the result with negative sign.  Set
#!     `mindist` to 0 if you want the actual distance.   
#!  * `debug`: optional integer argument containing debug bitmap (default: `0`)
#!    * 1 (0s  bit set) : print 1st of the vectors found
#!    * 2 (1st bit set) : check orthogonality of matrices and of the final vector
#!    * 4 (2nd bit set) : show occasional progress update
#!    * 8 (3rd bit set) : maintain cw count and estimate the success probability
#!  * `field` (Options stack): Galois field, default: $\mathop{\rm GF}(2)$.   
#!  * `maxav` (Options stack): if set, terminate when $\langle n\rangle$>`maxav`, 
#!    see Section <Ref Sect="Section_Empirical"/>.  Not set by default.
#!  See Section <Ref Sect="Section_SimpleVersion"/> for the
#!  description of the algorithm.  
#! @Arguments HX, HZ, num, mindist[, debug] :field:=GF(2), maxav:=fail
#! @Returns An upper bound on the CSS distance $d_Z$
#DeclareGlobalFunction("DistRandCSS");
BindGlobal("DistRandCSS",
                     function (GX,GZ,num,mindist,opt...) # supported options: field, maxav
                         
                         local DistBound, i, j, dimsWZ, rowsWZ, colsWZ, F, debug, pos, CodeWords, mult,
                               VecCount,  maxav, WZ, WZ1, WZ2, WX,
                               TempVec, FirstVecFound, TempWeight, per; 

                         if ValueOption("field")<>fail then
                             if not IsField(ValueOption("field")) then
                                 Error("invalid option 'field'=",ValueOption("field"),"\n");
                             else # field is specified
                                 F:=ValueOption("field");
                             fi;
                         else
                             F:=GF(2); # default
                         fi;

                         debug := [0,0,0,0];;     # Debug bitmap
                         if (Length(opt) > 0) then
                             debug := debug + CoefficientsQadic(opt[1], 2);;
                         fi;

                         if ValueOption("maxav")<>fail then
                             maxav:=Float(ValueOption("maxav"));
#                             debug[4]:=1;
                         fi;


                         if debug[2]=1 then # check the orthogonality
                             if QDR_WeightMat(GX*TransposedMat(GZ))>0 then
                                 Error("DistRandCSS: input matrices should have orthogonal rows!\n");
                             fi;
                         fi;

                         WZ:=NullspaceMat(TransposedMatMutable(GX)); # generator matrix
                         WX:=NullspaceMat(TransposedMatMutable(GZ)); 
                         dimsWZ:=DimensionsMat(WZ);
                         rowsWZ:=dimsWZ[1]; colsWZ:=dimsWZ[2];
                         DistBound:=colsWZ+1; # +1 to ensure that at least one codeword is recorded
                         for i in [1..num] do
                             per:=Random(SymmetricGroup(colsWZ));
                             WZ1:=PermutedCols(WZ,per);# apply random col permutation
                             WZ2:=TriangulizedMat(WZ1); # reduced row echelon form
                             WZ2:=PermutedCols(WZ2,Inverse(per)); # return cols to orig order
                             for j in [1..rowsWZ] do
                                 TempVec:=WZ2[j]; # this samples low-weight vectors from the code
                                 TempWeight:=WeightVecFFE(TempVec);
                                 if (TempWeight > 0) and (TempWeight <= DistBound) then
                                     if WeightVecFFE(WX*TempVec)>0 then # lin-indep from rows of GX
                                         if debug[2]=1 then # Check that H*c = 0
                                             if (WeightVecFFE(GX * TempVec) > 0) then
                                                 Print("\nError: codeword found is not orthogonal to rows of HX!\n");
                                                 if (colsWZ <= 100) then
                                                     Print("The improper vector is:\n");
                                                     Display(TempVec);
                                                 fi;
                                                 Error("\n");
                                             fi;
                                         fi;
                                         
                                         if TempWeight < DistBound then # new min-weight vector found
                                             DistBound:=TempWeight;
                                             VecCount:=1; # reset the overall count of vectors
                                             if debug[4] = 1  or ValueOption("maxav")<> fail then
                                                 CodeWords := [TempVec];;
                                                 mult := [1];;
                                             fi;                                             
                                             if debug[1] = 1 then
                                                 FirstVecFound := TempVec;;
                                             fi;
                                             
                                         elif TempWeight=DistBound then
                                             VecCount:=VecCount+1;
                                             if debug[4] = 1  or ValueOption("maxav")<> fail then
                                                 pos := Position(CodeWords, TempVec);;
                                                 if ((pos = fail) and (Length(mult) < 100)) then
                                                     Add(CodeWords, TempVec);
                                                     Add(mult, 1);
                                                 elif (pos <> fail) then
                                                     mult[pos] := mult[pos] + 1;;
                                                 fi;
                                             fi;
                                         fi;
                                     fi;
                                 fi;
                                 if DistBound <= mindist then
                                     if debug[1]=1 then
                                         Print("\n", "Distance ",DistBound,"<=",mindist,
                                               " too small, exiting!\n");
                                     fi;
                                     return -DistBound;  # terminate immediately
                                 fi;

                             od ;

                             if ((debug[3] = 1) and (RemInt(i, 200) = 0)) then
                                 Print("Round ", i, " of ", num, "; lowest wgt = ", DistBound, " count=", VecCount, "\n");                                 
                                 if debug[4]=1 then
                                     Print("Average number of times vectors with the lowest weight were found = ",
                                           QDR_AverageCalc(mult), "\n");
                                     Print("Number of different vectors = ",Length(mult), "\n");
                                 fi;
                             fi;

                             if ValueOption("maxav")<>fail then
                                 if QDR_AverageCalc(mult)>maxav then break; fi;
                             fi;
                         od;


                         if (debug[1] = 1) then # print additional information
                             Print(i," rounds of ", num," were made.", "\n");
                             if colsWZ <= 100 then
                                 Print("First vector found with lowest weight:\n");
                                 Display([FirstVecFound]);
                             fi;
                             Print("Minimum weight vector found ", VecCount, " times\n");
                             Print("[[", colsWZ, ",",colsWZ-RankMat(GX)-RankMat(GZ),",",
                                   DistBound, "]];", "  Field: ", F, "\n");
                         fi;
                         
                         if (debug[4] = 1) then
#                             Display(CodeWords);                             
                             QDR_DoProbOut(mult,colsWZ,i);
                         fi;
                         
                         return DistBound;
                         
                     end
                     );


#! @Description
#!  Computes an upper bound on the distance $d$ of the
#!  $F$-linear stabilizer code with generator matrix $G$ whose rows
#!  are assumed to be symplectic-orthogonal, see Section <Ref
#!  Subsect="Subsection_AlgorithmGeneric"/> (**orthogonality is not verified**). 
#!
#!  Details of the input parameters:
#!  * `G`: the input matrix with elements in the Galois `field` $F$
#!    with $2n$ columns $(a_1,b_1,a_2,b_2,\ldots,a_n,b_n)$.
#!  The remaining options are identical to those in the function
#!  `DistRandCSS` <Ref Sect="Section_DistanceFunctions"/>.
#!  * `num`: number of information sets to construct (should be large)
#!  * `mindist` - the algorithm stops when distance equal or smaller than `mindist`
#!     is found - set it to 0 if you want the actual distance
#!  * `debug`: optional integer argument containing debug bitmap (default: `0`)
#!    * 1 (0s  bit set) : print 1st of the vectors found
#!    * 2 (1st bit set) : check orthogonality of matrices and of the final vector
#!    * 4 (2nd bit set) : show occasional progress update
#!    * 8 (3rd bit set) : maintain cw count and estimate the success probability
#!  * `field` (Options stack): Galois field, default: $\mathop{\rm GF}(2)$.   
#!  * `maxav` (Options stack): if set, terminate when $\langle n\rangle$>`maxav`, 
#!       see Section <Ref Sect="Section_Empirical"/>.  Not set by default.
#! @Arguments G, num, mindist[, debug] :field:=GF(2), maxav:=fail
#! @Returns An upper bound on the code distance $d$
#DeclareGlobalFunction("DistRandStab");
BindGlobal("DistRandStab",
                     function(G,num,mindist,opt...) # supported options: field, maxav
    local F, debug, CodeWords, mult, TempPos, dims, H, i, l, j, W, V, dimsW,
          rows, cols, DistBound, FirstVecFound, VecCount, per, W1, W2, TempVec, TempWeight,maxav,
                     per1, per2;
    # CodeWords - if debug[4] = 1, record the first 100 different CWs with the lowest weight found so far
    # mult - number of times codewords from CodeWords were found
    # TempPos - temporary variable corresponding to the position of TempVec in CodeWords
    # dims - dimensions of matrix G
    # H - check matrix
    # i, l and j - for "for" loop
    # W and V - are vector spaces ortogonal to rows of H and G correspondingly
    # dimsW - dimensions of W (W presented as a matrix, with row being basis vectors)
    # rows and cols are parts of dimW
    # DistBound - upper bound, we are looking for
    # VecCount - number of times vectors with the current lowest weight were found so far.
    # per - is for permutations, which we are using in the code
    # W1, W2, TempVec, TempWeight - temporary variables
    # per1, per2 - auxiliary variables for taking permutation on pairs
    # maxav - a maximal average value of multiplicities of found vectors of the lowest weight

    if ValueOption("field")<>fail then
        if not IsField(ValueOption("field")) then
            Error("invalid option 'field'=",ValueOption("field"),"\n");
        else # field is specified
            F:=ValueOption("field");
        fi;
    else
        F:=GF(2); # default
    fi;

    # Debug parameter
    debug := [0,0,0,0];;
    if (Length(opt) > 0) then
      debug := debug + CoefficientsQadic(opt[1], 2);;
    fi;

    if ValueOption("maxav")<>fail then
      maxav:=Float(ValueOption("maxav"));
#      debug[4]:=1;
    fi;


    # Dimensions of generator matrix
    dims := DimensionsMat(G);

    # Create the check-matrix
    H := QDR_MakeH(G, F);; # this also verifies cols = even

    # optionally check for orthogonality
    if (debug[2] = 1) then
             if QDR_WeightMat(G * TransposedMat(H))>0 then
                Error("\n", "Problem with ortogonality GH^T!", "\n");
             fi;
    fi;

    # Below we are getting vector spaces W and V ortogonal to the columns of H and G correspondingly.
    W := NullspaceMat(TransposedMatMutable(H));;
    V := NullspaceMat(TransposedMatMutable(G));;

    # There we found dimentions of vector space W (how many vectors in a basis and their length).
    dimsW := DimensionsMat(W);;
    rows := dimsW[1];;
    cols := dimsW[2];;

    DistBound := cols + 1;;     # Initial bound on code distance

    # The main part of algorithm.
    for i in [1..num] do
      #Print(i);
        ## We start by creating random permutation for columns in W.
        # per1 := ListPerm(Random(SymmetricGroup(cols/2)), cols/2);;  # random permutation of length cols/2
        # per2 := []; #  We extend the permutation, so it works now on pairs
        # for l in [1..cols/2] do
        #    Append(per2, [2*per1[l]-1, 2*per1[l]]);  # per2 contains the permutation we want as a list
        # od;
        # per := PermList(per2); # this is a permutation of length 2n moving pairs

      per := Random(SymmetricGroup(cols));;

      W1 := PermutedCols(W, per);; # Perform that permutation.
      W2 := TriangulizedMat(W1);; # Reduced row echelon form
      W2 := PermutedCols(W2,Inverse(per));; # Inverse permutation

      for j in [1..rows] do
              # We take one of the sample vectors for this iteration. It supposed to be low-weight.
        TempVec := W2[j];;
        TempWeight := QDR_SymplVecWeight(TempVec, F);;

              # check if this vector is a logical operator).
              # First, rough check:
        if (TempWeight > 0) and (TempWeight <= DistBound) then
          if (WeightVecFFE(V * TempVec) > 0) then # linear independence from rows of G
            if debug[2]=1 then # Check that H*c = 0
              if (WeightVecFFE(H * TempVec) > 0) then
                Print("\nSomething wrong: cw found is not orthogonal to rows of H!\n");
                      if (Length(TempVec) <= 100) then
                        Print("The improper vector is:\n");
                        Display(TempVec);
                      fi;
                      Error("\n");
              fi;
            fi;

            if (TempWeight < DistBound) then

              DistBound := TempWeight;; # min weight found
              VecCount := 1;; # reset the overall count of vectors of such weight

                                # Recording all discovered codewords of minimum weight and their multiplicities
              if debug[4] = 1 or ValueOption("maxav")<>fail then
                  CodeWords := [TempVec];;
                  mult := [1];;
              fi;                 
              if debug[1] = 1 then
                  FirstVecFound := TempVec;;
              fi;

                      # If we already received such a weight (up to now - it is minimal),
            # we want to update number of vectors, corresponding to it
            elif (TempWeight = DistBound) then
              VecCount := VecCount + 1;;

                              # Recording of the first 100 different discovered codewords of
              # minimum weight with their multiplicities
              if debug[4] = 1 or ValueOption("maxav")<>fail then
                  TempPos := Position(CodeWords, TempVec);
                  if ((TempPos = fail) and (Length(mult) < 100)) then
                      Add(CodeWords, TempVec);
                      Add(mult, 1);
                  elif (TempPos <> fail) then
                      mult[TempPos] := mult[TempPos] + 1;;
                  fi;
              fi;

           fi;

                     # Specific terminator, if we don't care for distances below a particular value.
           if (DistBound <= mindist) then # not interesting, exit immediately!
               if debug[1]=1 then
                   Print("\n", "The found distance ",DistBound,"<=",mindist,
                         " too small, exiting!\n");
               fi;               
             return -DistBound;
           fi;
        fi;
      fi;
    od;
    # Optional progress info
    if ((debug[3] = 1) and (RemInt(i, 200) = 0)) then
        Print("Round ", i, " of ", num, "; lowest wgt = ", DistBound, " count=", VecCount, "\n");
        if debug[4]=1 then
            Print("Average number of times vectors with the lowest weight were found = ", QDR_AverageCalc(mult), "\n");
            Print("Number of different vectors = ",Length(mult), "\n");
        fi;
    fi;

    if ValueOption("maxav")<>fail then
        if QDR_AverageCalc(mult)>maxav then break; fi;
    fi;
    od;


    if (debug[1] = 1) then # print additional information
        Print(i," rounds of ", num," were made.", "\n");
        if cols <= 100 then
            Print("First vector found with lowest weight:\n");
            Display([FirstVecFound]);
        fi;        
        Print("Miimum weight vector found ", VecCount, " times\n");
      Print("[[", cols/2, ",",cols/2 - RankMat(G), ",", DistBound, "]];", "  Field: ", F, "\n");
  fi;

  if (debug[4] = 1) then
      QDR_DoProbOut(mult,cols,i);
  fi;
  
  return DistBound;

                     end
                     );


#! @Chapter AllFunctions
#! @Section HelperFunctions

# Many of the examples are dealing with quantum cyclic codes.  The
# following function is convenient to define the corresponding
# stabilizer generator matrices

#! @Arguments poly, m, n, field
#! @Returns `m` by `2*n` circulant matrix constructed from the polynomial coefficients
#! @Description Given the polynomial `poly` $a_0+b_0 x+a_1x^2+b_1x^3
#! +\ldots$ with coefficients from the field `F`, 
#! constructs the corresponding `m` by 2`n` double circulant matrix
#! obtained by `m` repeated cyclic shifts of the coefficients' vector
#! by $s=2$ positions at a time. 
#DeclareGlobalFunction("QDR_DoCirc");
BindGlobal("QDR_DoCirc",
          function(poly,m,n,F)
              local v,perm,j,deg,mat;
              v:=CoefficientsOfUnivariatePolynomial(poly);
              #    F:=DefaultField(v);
              deg:=Length(v);
              if (n>deg) then
                  v:=Concatenation(v,ListWithIdenticalEntries(n-deg,0*One(F)));
              fi;
              mat:=[v];
              perm:=Concatenation([n],[1..n-1]);
              for j in [2..m] do
                  v:=v{perm};
                  v:=v{perm}; # this creates a quantum code
                  Append(mat,[v]);
              od;
              return mat;
          end);


[ Dauer der Verarbeitung: 0.7 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


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