Skip to content

Commit 0644142

Browse files
authored
Add error checks to ShortestVectors, cleanup (#6273)
1 parent 8ed47ea commit 0644142

File tree

2 files changed

+62
-43
lines changed

2 files changed

+62
-43
lines changed

lib/zlattice.gi

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,21 +1241,24 @@ end );
12411241
##
12421242
#F ShortestVectors( <mat>, <bound> [, \"positive\" ] )
12431243
##
1244-
InstallGlobalFunction( ShortestVectors, function( arg )
1244+
InstallGlobalFunction( ShortestVectors, function( a, m, arg... )
12451245
local
12461246
# variables
1247-
n, checkpositiv, a, llg, nullv, m, c, con, b, v,
1247+
n, positiveOnly, llg, zeroCoeffs, c, continueSearch, b, v, i, j,
12481248
# procedures
1249-
srt, vschr;
1249+
search, emitVector;
12501250

1251-
# search for shortest vectors
1252-
srt := function( d, dam )
1253-
local i, j, x, k, k1, q;
1251+
# Enumerate coefficient vectors recursively in the LLL-reduced basis,
1252+
# starting near the nearest integer to keep the search tree small.
1253+
search := function( d, norm )
1254+
local i, j, x, k, nextnorm, q;
12541255
if d = 0 then
1255-
if v = nullv then
1256-
con := false;
1256+
# Once the zero coefficient vector is reached, the remaining branch
1257+
# would only enumerate the already covered opposite vectors.
1258+
if v = zeroCoeffs then
1259+
continueSearch := false;
12571260
else
1258-
vschr( dam );
1261+
emitVector( norm );
12591262
fi;
12601263
else
12611264
x := 0;
@@ -1267,27 +1270,27 @@ InstallGlobalFunction( ShortestVectors, function( arg )
12671270
i := i - SignInt( x );
12681271
fi;
12691272
k := i + x;
1270-
q := ( m + 1/1000 - dam ) / llg.B[d];
1273+
q := ( m + 1/1000 - norm ) / llg.B[d];
12711274
if k * k < q then
12721275
repeat
12731276
i := i + 1;
12741277
k := k + 1;
12751278
until k * k >= q and k > 0;
12761279
i := i - 1;
12771280
k := k - 1;
1278-
while k * k < q and con do
1281+
while k * k < q and continueSearch do
12791282
v[d] := i;
1280-
k1 := llg.B[d] * k * k + dam;
1281-
srt( d-1, k1 );
1283+
nextnorm := llg.B[d] * k * k + norm;
1284+
search( d-1, nextnorm );
12821285
i := i - 1;
12831286
k := k - 1;
12841287
od;
12851288
fi;
12861289
fi;
12871290
end;
12881291

1289-
# output of vector
1290-
vschr := function( dam )
1292+
# Convert coefficients back to the original basis before storing them.
1293+
emitVector := function( norm )
12911294
local newvec, i, j, w, haspos, hasneg;
12921295
newvec := [];
12931296
haspos := false;
@@ -1304,55 +1307,55 @@ InstallGlobalFunction( ShortestVectors, function( arg )
13041307
fi;
13051308
newvec[i] := w;
13061309
od;
1307-
if checkpositiv then
1310+
if positiveOnly then
13081311
if haspos and hasneg then
13091312
return;
13101313
elif hasneg then
13111314
newvec := -newvec;
13121315
fi;
13131316
fi;
13141317
Add(c.vectors, newvec);
1315-
Add(c.norms, dam);
1318+
Add(c.norms, norm);
13161319
end;
13171320

13181321
# main program
13191322
# check input
1320-
if not IsBound( arg[1] )
1321-
or not IsList( arg[1] ) or not IsList( arg[1][1] ) then
1322-
Error ( "first argument must be Gram matrix\n",
1323+
if not IsMatrixOrMatrixObj( a ) or NrRows( a ) <> NrCols( a ) then
1324+
Error ( "first argument must be a square Gram matrix\n",
13231325
"usage: ShortestVectors( <mat>, <integer> [,<\"positive\">] )" );
1324-
elif not IsBound( arg[2] ) or not IsInt( arg[2] ) then
1325-
Error ( "second argument must be integer\n",
1326+
elif not IsInt( m ) or m < 0 then
1327+
Error ( "second argument must be a nonnegative integer\n",
13261328
"usage: ShortestVectors( <mat>, <integer> [,<\"positive\">] )");
1327-
elif IsBound( arg[3] ) then
1328-
if IsString( arg[3] ) then
1329-
if arg[3] = "positive" then
1330-
checkpositiv := true;
1331-
else
1332-
checkpositiv := false;
1333-
fi;
1329+
elif IsBound( arg[1] ) then
1330+
if arg[1] = "positive" then
1331+
positiveOnly := true;
13341332
else
1335-
Error ( "third argument must be string\n",
1333+
Error ( "third argument, if given, must be \"positive\"\n",
13361334
"usage: ShortestVectors( <mat>, <integer> [,<\"positive\">] )");
13371335
fi;
13381336
else
1339-
checkpositiv := false;
1337+
positiveOnly := false;
13401338
fi;
13411339

1342-
a := arg[1];
1343-
m := arg[2];
1344-
n := Length( a );
1345-
b := List( a, ShallowCopy );
1340+
if not IsSymmetricMatrix(a) then
1341+
Error ( "first argument must be a symmetric Gram matrix\n",
1342+
"usage: ShortestVectors( <mat>, <integer> [,<\"positive\">] )" );
1343+
fi;
1344+
n := NrRows( a );
1345+
b := MutableCopyMatrix( a );
13461346
c := rec( vectors:= [], norms:= [] );
13471347
v := ListWithIdenticalEntries( n, 0 );
1348-
nullv := ListWithIdenticalEntries( n, 0 );
1348+
zeroCoeffs := ListWithIdenticalEntries( n, 0 );
13491349

13501350
llg:= LLLReducedGramMat( b );
1351-
#T here check that the matrix is really regular
1352-
#T (empty relations component)
1351+
if Length( llg.relations ) <> 0 then
1352+
Error ( "first argument must be a regular Gram matrix\n",
1353+
"usage: ShortestVectors( <mat>, <integer> [,<\"positive\">] )" );
1354+
fi;
13531355

1354-
con := true;
1355-
srt( n, 0 );
1356+
# The small offset avoids missing vectors on the exact norm boundary.
1357+
continueSearch := true;
1358+
search( n, 0 );
13561359

13571360
Info( InfoZLattice, 2,
13581361
"ShortestVectors: ", Length( c.vectors ), " vectors found" );
@@ -1703,14 +1706,14 @@ l := deca( l-1 );
17031706
Error( "first argument must be symmetric Gram matrix\n",
17041707
"usage : Orthog... ( < gram-matrix > \n",
17051708
" [, <\"positive\"> ] [, < integer > ] )" );
1706-
elif Length( arg[1] ) <> Length( arg[1][1] ) then
1709+
elif NrRows( arg[1] ) <> NrCols( arg[1] ) then
17071710
Error( "Gram matrix must be quadratic\n",
17081711
"usage : Orthog... ( < gram-matrix >\n",
17091712
" [, <\"positive\"> ] [, < integer > ] )" );
17101713
fi;
17111714
g := List( arg[1], ShallowCopy );
17121715
checkdim := false;
1713-
chpo := "xxx";
1716+
chpo := fail;
17141717
if IsBound( arg[2] ) then
17151718
if IsString( arg[2] ) then
17161719
chpo := arg[2];
@@ -1755,7 +1758,11 @@ l := deca( l-1 );
17551758
invg := Symmatinv( g );
17561759
m := invg.enuminator;
17571760
invg := invg.inverse;
1758-
x := ShortestVectors( invg, m, chpo );
1761+
if chpo = "positive" then
1762+
x := ShortestVectors( invg, m, chpo );
1763+
else
1764+
x := ShortestVectors( invg, m );
1765+
fi;
17591766
t := Length(x.vectors);
17601767
for i in [1..t] do
17611768
x.vectors[i][n+1] := x.norms[i];

tst/testbugfix/2026-02-26-ShortestVectors-positive.tst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,15 @@ gap> Length( sv.vectors );
1313
120
1414
gap> ForAll( sv.vectors, x -> ForAll( x, y -> y >= 0 ) );
1515
true
16+
gap> ShortestVectors( [ [ 2 ] ], 2, "bogus" );
17+
Error, third argument, if given, must be "positive"
18+
usage: ShortestVectors( <mat>, <integer> [,<"positive">] )
19+
gap> ShortestVectors( [ [ 2 ] ], -1 );
20+
Error, second argument must be a nonnegative integer
21+
usage: ShortestVectors( <mat>, <integer> [,<"positive">] )
22+
gap> ShortestVectors( [ [ 1, 2 ], [ 0, 1 ] ], 1 );
23+
Error, first argument must be a symmetric Gram matrix
24+
usage: ShortestVectors( <mat>, <integer> [,<"positive">] )
25+
gap> ShortestVectors( [ [ 0 ] ], 1 );
26+
Error, first argument must be a regular Gram matrix
27+
usage: ShortestVectors( <mat>, <integer> [,<"positive">] )

0 commit comments

Comments
 (0)