Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bug NullspaceModQ that could lead to wrong results; also added support for arbitrary moduli, and renamed it to NullspaceModN #3690

Merged
merged 1 commit into from
Oct 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions doc/ref/matrix.xml
Original file line number Diff line number Diff line change
Expand Up @@ -549,14 +549,15 @@ written over finite fields.
<Section Label="Inverse and Nullspace of an Integer Matrix Modulo an Ideal">
<Heading>Inverse and Nullspace of an Integer Matrix Modulo an Ideal</Heading>

The following two operations deal with matrices over a ring,
The following operations deal with matrices over a ring,
but only care about the residues of their entries modulo some ring element.
In the case of the integers and a prime number <M>p</M>, say,
this is effectively computation in a matrix over the prime field
in characteristic <M>p</M>.

<#Include Label="InverseMatMod">
<#Include Label="NullspaceModQ">
<#Include Label="BasisNullspaceModN">
<#Include Label="NullspaceModN">

</Section>

Expand Down
43 changes: 28 additions & 15 deletions lib/matrix.gd
Original file line number Diff line number Diff line change
Expand Up @@ -1524,43 +1524,56 @@ DeclareGlobalFunction( "NullMat" );

#############################################################################
##
#F NullspaceModQ( <E>, <q> ) . . . . . . . . . . . .nullspace of <E> mod <q>
#F NullspaceModN( <M>, <n> ) . . . . . . . . . . . .nullspace of <M> mod <n>
##
## <#GAPDoc Label="NullspaceModQ">
## <#GAPDoc Label="NullspaceModN">
## <ManSection>
## <Func Name="NullspaceModQ" Arg='E, q'/>
## <Func Name="NullspaceModQ" Arg='M, q'/>
## <Func Name="NullspaceModN" Arg='M, n'/>
##
## <Description>
## <A>E</A> must be a matrix of integers and <A>q</A> a prime power.
## Then <Ref Func="NullspaceModQ"/> returns the set of all vectors of integers modulo
## <A>q</A>, which solve the homogeneous equation system given by <A>E</A> modulo <A>q</A>.
## <A>M</A> must be a matrix of integers and <A>n</A> a positive integer.
## Then <Ref Func="NullspaceModN"/> returns the set of all vectors of
## integers modulo <A>n</A>, which solve the homogeneous equation system
## <A>v</A> <A>M</A> = 0 modulo <A>n</A>.
## <P/>
## <Ref Func="NullspaceModQ"/> is a synonym for <Ref Func="NullspaceModN"/>.
## <Example><![CDATA[
## gap> mat:= [ [ 1, 3 ], [ 1, 2 ], [ 1, 1 ] ];; NullspaceModQ( mat, 5 );
## [ [ 0, 0, 0 ], [ 1, 3, 1 ], [ 2, 1, 2 ], [ 4, 2, 4 ], [ 3, 4, 3 ] ]
## gap> NullspaceModN( [ [ 2 ] ], 8 );
## [ [ 0 ], [ 4 ] ]
## gap> NullspaceModN( [ [ 2, 1 ], [ 0, 2 ] ], 6 );
## [ [ 0, 0 ], [ 0, 3 ] ]
## gap> mat:= [ [ 1, 3 ], [ 1, 2 ], [ 1, 1 ] ];;
## gap> NullspaceModN( mat, 5 );
## [ [ 0, 0, 0 ], [ 1, 3, 1 ], [ 2, 1, 2 ], [ 3, 4, 3 ], [ 4, 2, 4 ] ]
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareGlobalFunction( "NullspaceModQ" );
DeclareGlobalFunction( "NullspaceModN" );
DeclareSynonym( "NullspaceModQ", NullspaceModN );


#############################################################################
##
#F BasisNullspaceModN( <M>, <n> ) . . . . . . . . nullspace of <E> mod <n>
#F BasisNullspaceModN( <M>, <n> ) . . basis of the nullspace of <M> mod <n>
##
## <#GAPDoc Label="BasisNullspaceModN">
## <ManSection>
## <Func Name="BasisNullspaceModN" Arg='M, n'/>
##
## <Description>
## <A>M</A> must be a matrix of integers modulo <A>n</A> and <A>n</A> a positive integer.
## Then 'NullspaceModQ' returns a set <A>B</A> of vectors such that every <A>v</A>
## such that <A>v</A> <A>M</A> = 0 modulo <A>n</A> can be expressed by a Z-linear combination
## of elements of <A>M</A>.
## <A>M</A> must be a matrix of integers and <A>n</A> a positive integer.
## Then <Ref Func="BasisNullspaceModN"/> returns a set <A>B</A> of vectors
## such that every vector <A>v</A> of integer modulo <A>n</A> satisfying
## <A>v</A> <A>M</A> = 0 modulo <A>n</A> can be expressed by a Z-linear
## combination of elements of <A>B</A>.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareGlobalFunction ("BasisNullspaceModN");
DeclareGlobalFunction( "BasisNullspaceModN" );


#############################################################################
Expand Down
93 changes: 9 additions & 84 deletions lib/matrix.gi
Original file line number Diff line number Diff line change
Expand Up @@ -3313,97 +3313,22 @@ end );

#############################################################################
##
#F NullspaceModQ( <E>, <q> ) . . . . . . . . . . . nullspace of <E> mod <q>
##
## <E> must be a matrix of integers modulo <q> and <q> a prime power. Then
## 'NullspaceModQ' returns the set of all vectors of integers modulo <q>,
## which solve the homogeneous equation system given by <E> modulo <q>.
##
InstallGlobalFunction( NullspaceModQ, function( E, q )
local facs, # factors of <q>
p, # prime of facs
pex, # p-power
n, # <q> = p^n
field, # field with p elements
B, # E over GF(p)
null, # basis of nullspace of B
elem, # all elements solving E mod p^i-1
e, # one elem
r, # inhomogenous part mod p^i-1
newelem, # all elements solving E mod p^i
sol, # solution of E * x = r mod p^i
ran,
new, o,
j, i,k;

# factorize q
facs := Factors(Integers, q );
p := facs[1];
n := Length( facs );
field := GF(p);

# solve homogeneous system mod p
B := One( field ) * E;
null := NullspaceMat( B );
if null = [] then
return [ListWithIdenticalEntries (NrRows(E),0)];
fi;
#F NullspaceModN( <M>, <n> ) . . . . . . . . . . . nullspace of <M> mod <n>
##
InstallGlobalFunction( NullspaceModN, function( M, n )
local B, coeffs;

# set up
elem := List( AsList( FreeLeftModule(field,null,"basis") ),
x -> List( x, IntFFE ) );
#T !
newelem := [ ];
o := One( field );

ran:=[1..Length(null[1])];
# run trough powers
for i in [ 2..n ] do
pex:=p^(i-1);
for e in elem do
#r := o * ( - (e * E) / (p ^ ( i - 1 ) ) );
r := o * ( - (e * E) / pex );
sol := SolutionMat( B, r );
if sol <> fail then

# accessing the elements of the compact vector `sol'
# frequently would be very expensive
sol:=List(sol,IntFFE);

for j in [ 1..Length( elem ) ] do
#new := e + ( p^(i-1) * List( o * elem[j] + sol, IntFFE ) );
new:=ShallowCopy(e);
for k in ran do
#new[k]:=new[k]+pex * IntFFE(o*elem[j,k]+ sol[k]);
new[k]:=new[k]+pex * ((elem[j,k]+ sol[k]) mod p);
od;
#T !
MakeImmutable(new); # otherwise newelem does not remember
# it is sorted!
AddSet( newelem, new );
od;
fi;
od;
if Length( newelem ) = 0 then
return [];
fi;
elem := newelem;
newelem := [ ];
od;
return elem;
B := BasisNullspaceModN(M, n);
coeffs := Cartesian(ListWithIdenticalEntries(Length(B), [0..n-1]));
return Set(coeffs, c -> c * B mod n);
end );


#############################################################################
##
#F BasisNullspaceModN( <M>, <n> ) . . . . . . . . nullspace of <E> mod <n>
##
## <M> must be a matrix of integers modulo <n> and <n> a positive integer.
## Then 'BasisNullspaceModN' returns a set <B> of vectors such that every <v>
## such that <v> <M> = 0 modulo <n> can be expressed by a Z-linear combination
## of elements of <M>.
#F BasisNullspaceModN( <M>, <n> ) . . basis of the nullspace of <M> mod <n>
##
InstallGlobalFunction (BasisNullspaceModN, function (M, n)
InstallGlobalFunction( BasisNullspaceModN, function( M, n )
local snf, null, nullM, i, gcdex;

# if n is a prime, Gaussian elimination is fastest
Expand Down