Skip to content

Commit

Permalink
Fix NullspaceModQ and renamed it to NullspaceModN
Browse files Browse the repository at this point in the history
Fixes #3614 and adds a manual example demonstrating the fixed behavior.
The old name NullspaceModQ is kept as an alias for backwards compatibility.
Also updated the documentation for NullspaceModN and BasisNullspaceModN.
  • Loading branch information
fingolfin committed Oct 6, 2019
1 parent 8492717 commit 6155776
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 101 deletions.
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

0 comments on commit 6155776

Please sign in to comment.