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

Several fixes for Random on long lists in 64-bit GAP #781

Merged
merged 3 commits into from
May 10, 2016
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
2 changes: 1 addition & 1 deletion lib/coll.gd
Original file line number Diff line number Diff line change
Expand Up @@ -1694,7 +1694,7 @@ DeclareOperation( "Random", [ IS_INT, IS_INT ] );
## </ManSection>
## <#/GAPDoc>
##
DeclareSynonym( "RandomList", RANDOM_LIST);
DeclareGlobalFunction( "RandomList" );


#############################################################################
Expand Down
11 changes: 7 additions & 4 deletions lib/coll.gi
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,15 @@ InstallMethod( RepresentativeSmallest,
##
## The default function for random selection in a finite collection computes
## an enumerator of <C> and selects a random element of this list using the
## function `RANDOM_LIST', which is a pseudo random number generator.
## function `RandomList', which is a pseudo random number generator.
##
DeclareGlobalVariable( "GlobalMersenneTwister" );
InstallGlobalFunction( RandomList, function(list)
return list[Random(GlobalMersenneTwister, 1, Length(list))];
end );
InstallMethod( Random, "for a (finite) collection",
[ IsCollection and IsFinite ],
C -> RANDOM_LIST( Enumerator( C ) ) );
C -> RandomList( Enumerator( C ) ) );

RedispatchOnCondition(Random,true,[IsCollection],[IsFinite],0);

Expand All @@ -258,8 +262,7 @@ RedispatchOnCondition(Random,true,[IsCollection],[IsFinite],0);
InstallMethod( PseudoRandom,
"for an internal list",
[ IsList and IsInternalRep ], 100,
#T ?
RANDOM_LIST );
RandomList );


#############################################################################
Expand Down
4 changes: 2 additions & 2 deletions lib/list.gi
Original file line number Diff line number Diff line change
Expand Up @@ -457,14 +457,14 @@ InstallOtherMethod(
InstallOtherMethod( Random,
"for a dense small list",
[ IsList and IsDenseList and IsSmallList ],
RANDOM_LIST );
RandomList );

InstallOtherMethod( Random,
"for a dense (small) list",
[ IsList and IsDenseList ],
function( list )
if IsSmallList( list ) then
return RANDOM_LIST( list );
return RandomList( list );
else
TryNextMethod();
fi;
Expand Down
3 changes: 2 additions & 1 deletion lib/random.gd
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ DeclareCategory("IsGAPRandomSource", IsRandomSource);
DeclareCategory("IsMersenneTwister", IsRandomSource);

DeclareGlobalVariable( "GlobalRandomSource" );
DeclareGlobalVariable( "GlobalMersenneTwister" );
# this declaration is in coll.gi because it is needed for RandomList
# DeclareGlobalVariable( "GlobalMersenneTwister" );

#############################################################################
##
Expand Down
29 changes: 19 additions & 10 deletions lib/random.gi
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,11 @@ InstallMethod(Reset, [IsGlobalRandomSource, IsObject], function(rs, seed)
end);

InstallMethod(Random, [IsGlobalRandomSource, IsList], function(rs, l)
return RANDOM_LIST(l);
if Length(l) < 2^28 then
return RANDOM_LIST(l);
else
return l[Random(rs, 1, Length(l))];
fi;
end);

############################################################################
Expand Down Expand Up @@ -137,12 +141,16 @@ end);

InstallMethod(Random, [IsGAPRandomSource, IsList], function(rs, list)
local rx, rn;
# we need to repeat the code of RANDOM_LIST
rx := rs!.R_X;
rn := rs!.R_N mod 55 + 1;
rs!.R_N := rn;
rx[rn] := (rx[rn] + rx[(rn+30) mod 55+1]) mod R_228;
return list[ QUO_INT( rx[rn] * LEN_LIST(list), R_228 ) + 1 ];
if Length(list) < 2^28 then
# we need to repeat the code of RANDOM_LIST
rx := rs!.R_X;
rn := rs!.R_N mod 55 + 1;
rs!.R_N := rn;
rx[rn] := (rx[rn] + rx[(rn+30) mod 55+1]) mod R_228;
return list[ QUO_INT( rx[rn] * LEN_LIST(list), R_228 ) + 1 ];
else
return list[Random(rs, 1, Length(list))];
fi;
end);


Expand Down Expand Up @@ -190,7 +198,7 @@ InstallMethod(Reset, [IsMersenneTwister, IsObject], function(rs, seed)
end);

InstallMethod(Random, [IsMersenneTwister, IsList], function(rs, list)
return RandomListMT(rs!.state, list);
return list[Random(rs, 1, Length(list))];
end);

InstallMethod(Random, [IsMersenneTwister, IsInt, IsInt], function(rs, a, b)
Expand All @@ -215,8 +223,9 @@ InstallValue(GlobalMersenneTwister, RandomSource(IsMersenneTwister, "1"));
# default random method for lists and pairs of integers using the Mersenne
# twister
InstallMethod( Random, "for an internal list",
[ IsList and IsInternalRep ], 100,
function(l) return Random(GlobalMersenneTwister, l); end );
[ IsList and IsInternalRep ], 100, function(l)
return l[Random(GlobalMersenneTwister, 1, Length(l))];
end );

InstallMethod( Random,
"for two integers",
Expand Down
33 changes: 0 additions & 33 deletions src/intfuncs.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,36 +202,6 @@ UInt4 nextrandMT_int32(UInt4* mt)
return y;
}


Obj FuncRandomListMT(Obj self, Obj mtstr, Obj list)
{
Int len, a, lg;
UInt4 *mt;
while ((! IsStringConv(mtstr)) || GET_LEN_STRING(mtstr) < 2500) {
mtstr = ErrorReturnObj(
"<mtstr> must be a string with at least 2500 characters, ",
0L, 0L,
"you can replace <mtstr> via 'return <mtstr>;'" );
}
while (! IS_LIST(list)) {
list = ErrorReturnObj(
"<list> must be a list, not a %s",
(Int)TNAM_OBJ(list), 0L,
"you can replace <list> via 'return <list>;'" );
}
len = LEN_LIST(list);
if (len == 0) return Fail;
mt = (UInt4*) CHARS_STRING(mtstr);
lg = 31 - CLog2Int(len);
for (a = nextrandMT_int32(mt) >> lg;
a >= len;
a = nextrandMT_int32(mt) >> lg
);
return ELM_LIST(list, a+1);
}



/****************************************************************************
**
*F FuncHASHKEY_BAG(<self>,<obj>,<seed>,<offset>,<maxlen>)
Expand Down Expand Up @@ -755,9 +725,6 @@ static StructGVarFunc GVarFuncs [] = {
{ "InitRandomMT", 1, "initstr",
FuncInitRandomMT, "src/integer.c:InitRandomMT" },

{ "RandomListMT", 2, "mtstr, list",
FuncRandomListMT, "src/integer.c:RandomListMT" },

{ "INT_STRING", 1, "string",
FuncINT_STRING, "src/integer.c:INT_STRING" },

Expand Down
74 changes: 74 additions & 0 deletions tst/test32bit/randlist.tst
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#############################################################################
##
#W randlist.tst GAP library Frank Lübeck
##
##
#Y Copyright (C) 2016, The GAP Group
##
gap> START_TEST("randlist.tst");
gap> l := [1..2^(8*GAPInfo.BytesPerVariable-4)-1];
[ 1 .. 268435455 ]
gap> Reset(GlobalMersenneTwister, 1);;
gap> List([1..10], i-> Random(1, 2^70));
[ 389420078096435786116, 1135477438879460122740, 425191437180319830675,
1083900231106243887320, 600872374094649387692, 39438917363375403157,
860639563472417594821, 1064153947161477828981, 140455377727366448871,
198677943275448576238 ]
gap> List([1..10], i-> Random(l));
[ 13155435, 3131483, 21560873, 174688373, 142786538, 140745645, 25528157,
45625016, 214994737, 84644 ]
gap> List([1..10], i-> Random(1,10^(3*i)));
[ 721, 46797, 22238206, 187185663184, 734387696875236, 101821667962893342,
669052909362560486368, 769723171201061857635320,
874658974599856967310222061, 397063360144420204491778152435 ]
gap> Reset(GlobalRandomSource, 1);;
gap> List([1..10], i-> Random(GlobalRandomSource, 1, 2^70));
[ 1128431629504922105781, 1101744982711025966526, 975266616221323178376,
678285771456235093359, 337368903834409162500, 1067481644129172537859,
666712591436546208470, 471773889319658808870, 27293053954741592585,
894173925476383505759 ]
gap> List([1..10], i-> Random(GlobalRandomSource, l));
[ 40228334, 111587641, 262452744, 44854923, 39845682, 206581571, 92903376,
231314873, 66408590, 258714463 ]
gap> List([1..10], i-> Random(GlobalRandomSource, l)) mod 2^28;
[ 184978940, 159620597, 123129748, 68026743, 233471294, 232591449, 24005304,
5708683, 167299138, 197744113 ]
gap> List([1..10], i-> Random(GlobalRandomSource, 1,10^(3*i)));
[ 602, 615764, 985971579, 527993069062, 970982477709403, 915182928712255106,
52224684171237700022, 63091858766485771208964, 391269615753496331510430301,
929557928485066381724613674190 ]
gap> rs := RandomSource(IsMersenneTwister, 1);
<RandomSource in IsMersenneTwister>
gap> List([1..10], i-> Random(rs, 1, 2^70));
[ 389420078096435786116, 1135477438879460122740, 425191437180319830675,
1083900231106243887320, 600872374094649387692, 39438917363375403157,
860639563472417594821, 1064153947161477828981, 140455377727366448871,
198677943275448576238 ]
gap> List([1..10], i-> Random(rs, l));
[ 13155435, 3131483, 21560873, 174688373, 142786538, 140745645, 25528157,
45625016, 214994737, 84644 ]
gap> List([1..10], i-> Random(rs, 1,10^(3*i)));
[ 721, 46797, 22238206, 187185663184, 734387696875236, 101821667962893342,
669052909362560486368, 769723171201061857635320,
874658974599856967310222061, 397063360144420204491778152435 ]
gap> rs := RandomSource(IsGAPRandomSource, 1);
<RandomSource in IsGAPRandomSource>
gap> List([1..10], i-> Random(rs, 1, 2^70));
[ 1128431629504922105781, 1101744982711025966526, 975266616221323178376,
678285771456235093359, 337368903834409162500, 1067481644129172537859,
666712591436546208470, 471773889319658808870, 27293053954741592585,
894173925476383505759 ]
gap> List([1..10], i-> Random(rs, l));
[ 40228334, 111587641, 262452744, 44854923, 39845682, 206581571, 92903376,
231314873, 66408590, 258714463 ]
gap> List([1..10], i-> Random(rs, l)) mod 2^28;
[ 184978940, 159620597, 123129748, 68026743, 233471294, 232591449, 24005304,
5708683, 167299138, 197744113 ]
gap> List([1..10], i-> Random(rs, 1,10^(3*i)));
[ 602, 615764, 985971579, 527993069062, 970982477709403, 915182928712255106,
52224684171237700022, 63091858766485771208964, 391269615753496331510430301,
929557928485066381724613674190 ]
gap> STOP_TEST( "randlist.tst", 640000);
#############################################################################
##
#E
80 changes: 80 additions & 0 deletions tst/test64bit/randlist.tst
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#############################################################################
##
#W randlist.tst GAP library Frank Lübeck
##
##
#Y Copyright (C) 2016, The GAP Group
##
gap> START_TEST("randlist.tst");
gap> l := [1..2^(8*GAPInfo.BytesPerVariable-4)-1];
[ 1 .. 1152921504606846975 ]
gap> Reset(GlobalMersenneTwister, 1);;
gap> List([1..10], i-> Random(1, 2^70));
[ 389420078096435786116, 1135477438879460122740, 425191437180319830675,
1083900231106243887320, 600872374094649387692, 39438917363375403157,
860639563472417594821, 1064153947161477828981, 140455377727366448871,
198677943275448576238 ]
gap> List([1..10], i-> Random(l));
[ 13449613059603563, 750280845826784809, 604497940593164266,
195957948672214877, 363541010878257, 252402567376707281, 370012941179900926,
417909953390052908, 963123934602894316, 270776873282813509 ]
gap> List([1..10], i-> Random(1,10^(3*i)));
[ 200, 711160, 554290144, 155776019526, 905142534515704, 885417939216212735,
932340683886669498401, 455800814114634556722688,
791206551199537424739336406, 382559260149794825284857428764 ]
gap> Reset(GlobalRandomSource, 1);;
gap> List([1..10], i-> Random(GlobalRandomSource, 1, 2^70));
[ 1128431629504922105781, 1101744982711025966526, 975266616221323178376,
678285771456235093359, 337368903834409162500, 1067481644129172537859,
666712591436546208470, 471773889319658808870, 27293053954741592585,
894173925476383505759 ]
gap> List([1..10], i-> Random(GlobalRandomSource, l));
[ 172731053183754005, 399538608969287265, 528332786381188118,
719153818282315693, 341000865208262150, 994286057174428461,
975057260589483054, 343216463929586102, 60169085279927990,
236724101465774021 ]
gap> List([1..10], i-> Random(GlobalRandomSource, l)) mod 2^28;
[ 82408175, 222596625, 2843657, 140496253, 243545930, 128569490, 62441909,
102134268, 47094864, 154341103 ]
gap> List([1..10], i-> Random(GlobalRandomSource, 1,10^(3*i)));
[ 871, 264536, 392436441, 73737636655, 456525824458936, 890212987711716841,
234476903267325497175, 596997600529202583174722,
290628328961307271818818898, 17261260615457929009978390979 ]
gap> rs := RandomSource(IsMersenneTwister, 1);
<RandomSource in IsMersenneTwister>
gap> List([1..10], i-> Random(rs, 1, 2^70));
[ 389420078096435786116, 1135477438879460122740, 425191437180319830675,
1083900231106243887320, 600872374094649387692, 39438917363375403157,
860639563472417594821, 1064153947161477828981, 140455377727366448871,
198677943275448576238 ]
gap> List([1..10], i-> Random(rs, l));
[ 13449613059603563, 750280845826784809, 604497940593164266,
195957948672214877, 363541010878257, 252402567376707281, 370012941179900926,
417909953390052908, 963123934602894316, 270776873282813509 ]
gap> List([1..10], i-> Random(rs, 1,10^(3*i)));
[ 200, 711160, 554290144, 155776019526, 905142534515704, 885417939216212735,
932340683886669498401, 455800814114634556722688,
791206551199537424739336406, 382559260149794825284857428764 ]
gap> rs := RandomSource(IsGAPRandomSource, 1);
<RandomSource in IsGAPRandomSource>
gap> List([1..10], i-> Random(rs, 1, 2^70));
[ 1128431629504922105781, 1101744982711025966526, 975266616221323178376,
678285771456235093359, 337368903834409162500, 1067481644129172537859,
666712591436546208470, 471773889319658808870, 27293053954741592585,
894173925476383505759 ]
gap> List([1..10], i-> Random(rs, l));
[ 172731053183754005, 399538608969287265, 528332786381188118,
719153818282315693, 341000865208262150, 994286057174428461,
975057260589483054, 343216463929586102, 60169085279927990,
236724101465774021 ]
gap> List([1..10], i-> Random(rs, l)) mod 2^28;
[ 82408175, 222596625, 2843657, 140496253, 243545930, 128569490, 62441909,
102134268, 47094864, 154341103 ]
gap> List([1..10], i-> Random(rs, 1,10^(3*i)));
[ 871, 264536, 392436441, 73737636655, 456525824458936, 890212987711716841,
234476903267325497175, 596997600529202583174722,
290628328961307271818818898, 17261260615457929009978390979 ]
gap> STOP_TEST( "randlist.tst", 640000);
#############################################################################
##
#E
4 changes: 3 additions & 1 deletion tst/teststandard.g
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ Print( "You should start GAP4 using `gap -A -x 80 -r -m 100m -o 1g'.\n",

TestDirectory( [
Filename( DirectoriesLibrary( "tst" ), "teststandard" ),
Filename( DirectoriesLibrary( "tst" ), "testinstall" )],
Filename( DirectoriesLibrary( "tst" ), "testinstall" ),
Filename( DirectoriesLibrary( "tst" ),
Concatenation("test", String(8*GAPInfo.BytesPerVariable), "bit"))],
rec(exitGAP := true) );

# Should never get here
Expand Down