Skip to content

Commit ea252d0

Browse files
fingolfincdwensley
authored andcommitted
Make the meataxe faster by using AddMatrix, AddVector, MultMatrix, MultVector (gap-system#6289)
Consider this setup: gap> n:=10;; # increase this to make the effect even stronger gap> G:=GL(56,GF(25));; gap> H:=Subgroup(G, Concatenation(GeneratorsOfGroup(G),List([1..n],i->PseudoRandom(G))));; gap> dn:=g ->DirectSumGModule(NaturalGModule(g),NaturalGModule(g));; gap> gap> Reset(GlobalMersenneTwister,1);;Reset(GlobalRandomSource,1);; Then before this PR: gap> MTX.Indecomposition(dn(H));; time; 9326 After this PR: gap> MTX.Indecomposition(dn(H));; time; 3845 To achieve a substantial speedup beyond this probably requires algorithmic improvements.
1 parent adb7bb3 commit ea252d0

File tree

4 files changed

+117
-41
lines changed

4 files changed

+117
-41
lines changed

lib/matobj.gi

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,6 +1931,18 @@ InstallEarlyMethod( AddMatrix,
19311931
fi;
19321932
end );
19331933

1934+
InstallMethod( AddMatrix, "for a mutable IsRowListMatrix and a IsRowListMatrix",
1935+
[ IsRowListMatrix and IsMutable, IsRowListMatrix ],
1936+
function( dstmat, srcmat )
1937+
local i;
1938+
if DimensionsMat(dstmat) <> DimensionsMat(srcmat) then
1939+
Error("AddMatrix: matrices must have the same dimensions");
1940+
fi;
1941+
for i in [1..NrRows(dstmat)] do
1942+
AddRowVector(dstmat[i], srcmat[i]);
1943+
od;
1944+
end );
1945+
19341946
InstallMethod( AddMatrix, "for a mutable 8bit matrix and an 8bit matrix",
19351947
[ Is8BitMatrixRep and IsMutable, Is8BitMatrixRep ],
19361948
function( dstmat, srcmat )
@@ -1939,7 +1951,7 @@ InstallMethod( AddMatrix, "for a mutable 8bit matrix and an 8bit matrix",
19391951
Error("AddMatrix: matrices must have the same dimensions");
19401952
fi;
19411953
for i in [1..NrRows(dstmat)] do
1942-
ADD_COEFFS_VEC8BIT_2(dstmat[i], srcmat[i]);
1954+
ADD_ROWVECTOR_VEC8BITS_2(dstmat[i], srcmat[i]);
19431955
od;
19441956
end );
19451957

@@ -1977,6 +1989,18 @@ InstallEarlyMethod( AddMatrix,
19771989
fi;
19781990
end );
19791991

1992+
InstallMethod( AddMatrix, "for a mutable IsRowListMatrix, an IsRowListMatrix, and a scalar",
1993+
[ IsRowListMatrix and IsMutable, IsRowListMatrix, IsScalar ],
1994+
function( dstmat, srcmat, scalar )
1995+
local i;
1996+
if DimensionsMat(dstmat) <> DimensionsMat(srcmat) then
1997+
Error("AddMatrix: matrices must have the same dimensions");
1998+
fi;
1999+
for i in [1..NrRows(dstmat)] do
2000+
AddRowVector(dstmat[i], srcmat[i], scalar);
2001+
od;
2002+
end );
2003+
19802004
InstallMethod( AddMatrix, "for a mutable 8bit matrix, an 8bit matrix, and a scalar",
19812005
[ Is8BitMatrixRep and IsMutable, Is8BitMatrixRep, IsFFE ],
19822006
function( dstmat, srcmat, scalar )
@@ -1985,7 +2009,7 @@ InstallMethod( AddMatrix, "for a mutable 8bit matrix, an 8bit matrix, and a scal
19852009
Error("AddMatrix: matrices must have the same dimensions");
19862010
fi;
19872011
for i in [1..NrRows(dstmat)] do
1988-
ADD_COEFFS_VEC8BIT_3(dstmat[i], srcmat[i], scalar);
2012+
ADD_ROWVECTOR_VEC8BITS_3(dstmat[i], srcmat[i], scalar);
19892013
od;
19902014
end );
19912015

@@ -2017,6 +2041,15 @@ InstallEarlyMethod( MultMatrixRight,
20172041
fi;
20182042
end );
20192043

2044+
InstallMethod( MultMatrixRight, "for a mutable IsRowListMatrix and a scalar",
2045+
[ IsRowListMatrix and IsMutable, IsScalar ],
2046+
function( mat, scalar )
2047+
local i;
2048+
for i in [1..NrRows(mat)] do
2049+
MultVectorRight(mat[i], scalar);
2050+
od;
2051+
end );
2052+
20202053
#############################################################################
20212054
##
20222055
#M MultMatrixLeft( <mat>, <mult> )
@@ -2045,6 +2078,15 @@ InstallEarlyMethod( MultMatrixLeft,
20452078
fi;
20462079
end );
20472080

2081+
InstallMethod( MultMatrixLeft, "for a mutable IsRowListMatrix and a scalar",
2082+
[ IsRowListMatrix and IsMutable, IsScalar ],
2083+
function( mat, scalar )
2084+
local i;
2085+
for i in [1..NrRows(mat)] do
2086+
MultVectorLeft(mat[i], scalar);
2087+
od;
2088+
end );
2089+
20482090
############################################################################
20492091
## Fallback method for DeterminantMatrix
20502092

lib/matobj2.gd

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2062,8 +2062,11 @@ DeclareOperationKernel( "SwapMatrixColumns", [ IsMatrixOrMatrixObj and IsMutable
20622062
## <Returns>nothing</Returns>
20632063
##
20642064
## <Description>
2065-
## Computes the calculation <M>M + c \cdot N</M> in-place, storing the result in <A>M</A>.
2065+
## Computes the calculation <M>M + N \cdot c</M> in-place, storing the result in <A>M</A>.
20662066
## If the optional argument <A>c</A> is omitted, then <A>N</A> is added directly.
2067+
## The matrices must have the same dimensions, otherwise the result is undefined.
2068+
## Specialized methods may be defined only when <A>M</A> and <A>N</A> have the same
2069+
## representation.
20672070
## If both of the matrices are lists-of-lists, then the operation is delegated
20682071
## row by row to <Ref Oper="AddRowVector"/>.
20692072
## <Example><![CDATA[

lib/meatauto.gi

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,12 @@ local n, weights, mat, vec, ReduceRow, t,
132132
if lead > n then
133133
return rhs;
134134
fi;
135+
lhs := ShallowCopy(lhs);
135136
for i in [1..Length(weights)] do
136137
if weights[i] = lead then
137138
z := lhs[lead];
138-
lhs := lhs - z * mat[i]; rhs := rhs - z * vec[i];
139+
AddVector(lhs, mat[i], -z); # lhs is a vector
140+
rhs := rhs - z * vec[i]; # rhs is a scalar
139141
lead := PositionNonZero(lhs, lead);
140142
if lead > n then
141143
return rhs;
@@ -217,10 +219,10 @@ local m, n, zero, i, c, j, factor;
217219
for i in [1..m] do
218220
c := eqns.weights[i];
219221
for j in [1..i-1] do
220-
if eqns.mat[j][c] <> zero then
222+
factor := eqns.mat[j,c];
223+
if factor <> zero then
221224
Info(InfoMtxHom,6,"solveEqns: kill mat[",j,",",c,"]");
222-
factor := eqns.mat[j][c];
223-
eqns.mat[j] := eqns.mat[j] - factor*eqns.mat[i];
225+
AddVector(eqns.mat[j], eqns.mat[i], -factor);
224226
eqns.vec[j] := eqns.vec[j] - factor*eqns.vec[i];
225227
fi;
226228
od;
@@ -306,13 +308,13 @@ local n, coeffs, x, zero, z, i;
306308
coeffs:=[];
307309
x:=v;
308310
else
309-
x:=v;
311+
x:=ShallowCopy(v);
310312
zero:=x[1]*0;
311313
coeffs:=ListWithIdenticalEntries(n, zero);
312314
for i in [1..n] do
313315
z:=x[ech[i]];
314316
if z <> zero then
315-
x:=x - z * base[i];
317+
AddVector(x, base[i], -z);
316318
coeffs[i]:=z;
317319
fi;
318320
od;
@@ -552,13 +554,13 @@ end);
552554
# If a linearly dependent set of elements is supplied, this
553555
# routine will trim it down to a basis.
554556
BindGlobal("SMTX_EcheloniseMats",function (gens, F)
555-
local n, m, zero, ech, k, i, j, l;
557+
local n, m, zero, ech, k, i, j, l, entry;
556558

557559
if Length(gens) = 0 then
558560
return [ [], [] ];
559561
fi;
560562
# copy the list to avoid destroying the original list
561-
gens:=ShallowCopy(gens);
563+
gens:=List(gens, MutableCopyMatrix);
562564

563565
n:=NrRows(gens[1]);
564566
m:=NrCols(gens[1]);
@@ -581,12 +583,15 @@ local n, m, zero, ech, k, i, j, l;
581583
Add(ech, [i,j]);
582584

583585
# First normalise the [i,j] position to 1
584-
gens[k]:=gens[k] / gens[k][i,j];
586+
entry := gens[k][i,j];
587+
if not IsOne(entry) then
588+
MultMatrix(gens[k], 1/entry);
589+
fi;
585590

586591
# Now zero position [i,j] in all further generators
587592
for l in [k+1..Length(gens)] do
588593
if (gens[l][i,j] <> zero) then
589-
gens[l]:=gens[l] - gens[k] * gens[l][i,j];
594+
AddMatrix(gens[l], gens[k], -gens[l][i,j]);
590595
fi;
591596
od;
592597
k:=k + 1;
@@ -617,7 +622,7 @@ end);
617622
# The code is heavily commented, and I appreciate suggestions on how to
618623
# improve it (particularly bits of code).
619624
BindGlobal("SpinHom",function (V, W)
620-
local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0,
625+
local nv, nw, F, zero, minusone, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0,
621626
M, x, pos, z, echm, t, v, echv, a, u, e, start, oldlen, ag, m, uu, ret,
622627
c, s1, X, mat, uuc, uic, newhoms, hom, Uhom, imv0, imv0c, image, i, j, l;
623628

@@ -635,6 +640,7 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0,
635640
TestModulesFitTogether(V,W);
636641
F:=V.field;
637642
zero:=Zero(F);
643+
minusone:=-One(F);
638644

639645
zeroW:=ListWithIdenticalEntries(nw,zero);
640646
zeroW:=ImmutableVector(F,zeroW);
@@ -744,27 +750,26 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0,
744750
# create new element <x>, with its definition as the
745751
# difference between <v0^m> and <uu> in <U>.
746752
x:=v[i] * gV[j];
747-
m:=ag;
753+
m:=MutableCopyMat(ag);
748754
ConvertToMatrixRep(m, F);
749755
uu:=u[i] * gV[j];
750756

751757
ret:=EchResidueCoeffs(U, echu, x,3);
752758
x:=ret.residue;
753-
uu:=uu - ret.projection;
754-
759+
AddVector(uu, ret.projection, minusone);
755760
# reduce modulo the new semi-ech basis elements in <v>,
756761
# storing the coefficients in <c>
757762
#
758763
c:=ListWithIdenticalEntries(Length(v),zero);
759764
for l in [1..Length(v)] do
760765
z:=x[echv[l]];
761766
if z <> zero then
762-
x:=x - z * v[l];
767+
AddVector(x, v[l], -z);
763768
if Length(m) > 0 then
764-
m:=m - z * a[l];
769+
AddMatrix(m, a[l], -z);
765770
fi;
766771
c[l]:=c[l] + z;
767-
uu:=uu - z * u[l];
772+
AddVector(uu, u[l], -z);
768773
fi;
769774
od;
770775
c:=ImmutableVector(F,c);
@@ -797,14 +802,14 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0,
797802
for l in [1..Length(v)] do
798803
if c[l] <> zero then
799804
if Length(X) > 0 then
800-
X:=X + c[l] * a[l];
805+
AddMatrix(X, a[l], c[l]);
801806
fi;
802-
uu:=uu + c[l] * u[l];
807+
AddVector(uu, u[l], c[l]);
803808
fi;
804809
od;
805810

806811
if Length(X) > 0 then
807-
X:=X - ag;
812+
AddMatrix(X, ag, minusone);
808813
fi;
809814

810815
mat:=[];
@@ -814,6 +819,7 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0,
814819
Add(mat, uuc * homs[l] - uic * homs[l] * gW[j]);
815820
od;
816821
Append(mat, X);
822+
ConvertToMatrixRep(mat);
817823
SMTX_AddEqns(e, TransposedMat(mat), zeroW);
818824
fi;
819825
od;
@@ -848,26 +854,26 @@ local nv, nw, F, zero, zeroW, gV, gW, k, U, echu, r, homs, s, work, ans, v0,
848854
ConvertToMatrixRep(Uhom, F);
849855
for l in [1..s] do
850856
if ans[i][l] <> zero then
851-
Uhom:=Uhom + ans[i][l] * homs[l];
857+
AddMatrix(Uhom, homs[l], ans[i][l]);
852858
fi;
853859
od;
854860
for l in [1..r] do
855861
Add(hom, Uhom[l]);
856862
od;
857863
fi;
858864

859-
imv0:=zeroW * zero;
865+
imv0:=ZeroMutable(zeroW);
860866
for l in [1..t] do
861867
if ans[i][s+l] <> zero then
862-
imv0:=imv0 + ans[i][s+l] * M[l];
868+
AddVector(imv0, M[l], ans[i][s+l]);
863869
fi;
864870
od;
865871
imv0c:=EchResidueCoeffs(M, echm, imv0,1);
866872
for l in [1..Length(v)] do
867873
if Length(imv0c)=0 then image:=[];
868874
else image:=imv0c * a[l];fi;
869875
if r > 0 then
870-
image:=image + EchResidueCoeffs(U, echu, u[l],1) * Uhom;
876+
AddVector(image, EchResidueCoeffs(U, echu, u[l],1) * Uhom);
871877
fi;
872878
Add(hom, image);
873879
od;
@@ -984,18 +990,21 @@ local proveIndecomposability, addnilpotent, n, F, zero, basis, enddim,
984990
local i, r, c, k, done, l;
985991
# NB: <remain> and <nildim> and <cnt> are not local
986992

993+
a := MutableCopyMatrix(a);
987994
for i in [1..nildim] do
988-
r:=echelon[nilech[i]][1]; c:=echelon[nilech[i]][2];
995+
r:=echelon[nilech[i]][1];
996+
c:=echelon[nilech[i]][2];
989997
if a[r,c] <> zero then
990-
a:=a - a[r,c] * nilbase[i] / nilbase[i][r,c];
998+
AddMatrix(a, nilbase[i], -a[r,c] / nilbase[i][r,c]);
991999
fi;
9921000
od;
9931001

9941002
# find which echelon index to remove due to this new element
9951003
k:=1; done:=false;
9961004
while not done and k <= Length(remain) do
9971005
l:=remain[k];
998-
r:=echelon[l][1]; c:=echelon[l][2];
1006+
r:=echelon[l][1];
1007+
c:=echelon[l][2];
9991008
if a[r,c] <> zero then
10001009
done:=true;
10011010
else
@@ -1377,12 +1386,12 @@ SMTX.IsomorphismModules:=SMTX_IsomorphismModules;
13771386
# running down diagonals below the main diagonal:
13781387
# [2,1], [3,2], [4,3], ..., [3,1], [4,2], ..., [n-1,1], [n, 2], [n,1]
13791388
BindGlobal("SMTX_EcheloniseNilpotentMatAlg",function (matalg, F)
1380-
local zero, n, base, ech, k, diff, i, j, found, l;
1389+
local zero, n, base, ech, k, diff, i, j, found, l, entry;
13811390

13821391
zero:=Zero(F);
13831392
n := NrCols(matalg[1]);
13841393

1385-
base := ShallowCopy(matalg);
1394+
base := List(matalg, MutableCopyMatrix);
13861395
ech := [];
13871396
k := 1;
13881397

@@ -1409,12 +1418,15 @@ local zero, n, base, ech, k, diff, i, j, found, l;
14091418
Add(ech, [i,j]);
14101419

14111420
# First normalise the [i,j] position to 1
1412-
base[k] := base[k] / base[k][i,j];
1421+
entry := base[k][i,j];
1422+
if not IsOne(entry) then
1423+
MultMatrix(base[k], 1/entry);
1424+
fi;
14131425

14141426
# Now zero position [i,j] in all other basis elements
14151427
for l in [1..Length(base)] do
14161428
if (l <> k) and (base[l][i,j] <> zero) then
1417-
base[l] := base[l] - base[k] * base[l][i,j];
1429+
AddMatrix(base[l], base[k], -base[l][i,j]);
14181430
fi;
14191431
od;
14201432
k := k + 1;

tst/testinstall/meataxe.tst

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#@local G,M,M2,M3,M4,M5,M6,V,bf,bo,cf,homs,m,mat,qf,randM,res,sf,subs,mats,Q,orig,S
1+
#@local G,M,M2,M3,M4,M5,M6,V,bf,bo,cf,homs,m,mat,qf,randM,res,sf,subs,mats,Q,orig,S,dim,F,i
22
gap> START_TEST("meataxe.tst");
33

44
#
@@ -71,16 +71,12 @@ Error, generators are different lengths
7171
#
7272
#
7373
#
74+
gap> G:=SymmetricGroup(3);;
75+
gap> M:=PermutationGModule(G,GF(2));;
7476
gap> M2:=TensorProductGModule(M,M);
7577
rec( IsOverFiniteField := true, dimension := 9, field := GF(2),
7678
generators := [ <an immutable 9x9 matrix over GF2>,
7779
<an immutable 9x9 matrix over GF2> ], isMTXModule := true )
78-
gap> M6:=DirectSumGModule(M,M);
79-
rec( IsOverFiniteField := true, dimension := 6, field := GF(2),
80-
generators := [ <an immutable 6x6 matrix over GF2>,
81-
<an immutable 6x6 matrix over GF2> ], isMTXModule := true )
82-
gap> M6.generators[1] = DirectSumMat(M.generators[1], M.generators[1]);
83-
true
8480
gap> IdGroup(MTX.ModuleAutomorphisms(M2));
8581
[ 1344, 11301 ]
8682
gap> cf:=MTX.CompositionFactors(M2);;
@@ -91,6 +87,29 @@ gap> List(Filtered(cf, x -> x.dimension=2), MTX.InvariantQuadraticForm);
9187
[ <an immutable 2x2 matrix over GF2>, <an immutable 2x2 matrix over GF2>,
9288
<an immutable 2x2 matrix over GF2> ]
9389

90+
#
91+
#
92+
#
93+
gap> M6:=DirectSumGModule(M,M);
94+
rec( IsOverFiniteField := true, dimension := 6, field := GF(2),
95+
generators := [ <an immutable 6x6 matrix over GF2>,
96+
<an immutable 6x6 matrix over GF2> ], isMTXModule := true )
97+
gap> M6.generators[1] = DirectSumMat(M.generators[1], M.generators[1]);
98+
true
99+
100+
#
101+
#
102+
#
103+
gap> dim:=10;; F:=GF(25);;
104+
gap> G:=Sp(dim,F);;
105+
gap> M:=NaturalGModule(G);;
106+
gap> for i in [1..3] do
107+
> M:=DirectSumGModule(M, NaturalGModule(G^RandomInvertibleMat(dim, F)));
108+
> od;
109+
gap> res:=MTX.Indecomposition(M);;
110+
gap> Length(res);
111+
4
112+
94113
#
95114
#
96115
#

0 commit comments

Comments
 (0)