1- randomTest := function (collection, method, checkin... )
2- local test1, test2, test3, test4, test5, test6, localgen, checkmethod;
3- if Length(checkin) = 0 then
4- checkmethod := \in ;
5- else
6- checkmethod := checkin[ 1 ] ;
7- fi ;
1+ # Perform a variety of tests on Random Sources and functions which create
2+ # random objects.
3+ #
4+ # This function is used for a variety is different tests:
5+ #
6+ # Test that 'Random(C)' and 'Random(GlobalMersenneTwister, C)' produce
7+ # the same answer.
8+ #
9+ # Test that 'Random(rs,C)' only uses 'rs', and no other source of random
10+ #
11+ # Test Random and RandomList
12+ #
13+ # Where there is a global instance of a random source
14+ # (GlobalMersenneTwister and GlobalRandomSource), they produce the same
15+ # sequence of answers as a new instance of the same random source.
16+
17+ # filter: The type of random source we are testing.
18+ # global_rs: A pre-existing object of type 'filter'.
19+ # randfunc(rs, C): A two argument function which creates random elements of C using
20+ # 'rs' as the source.
21+ # global_randfunc(C): A one argument function which is equivalent to
22+ # {x} -> rand(global_rs, x). This lets us check 'Random(C)' and
23+ # 'Random(GlobalMersenneTwister,C)' produce the same answer when testing
24+ # GlobalMersenneTwister. For other random sources, this can just
25+ # be set to {x} -> rand(global_rs,x).
26+ # collection: The object (usually a collection) to find random members of.
27+ # checkin(e, C): returns if e is in C (usually checkin is '\in').
28+
29+ randomTestInner := function (filter, global_rs, global_randfunc, randfunc, collection, checkin )
30+ local test1, test2, test3, test4, test5, test6, local_rs;
831
932 # We do a single call first, to deal with calling Random causing extra attributes
1033 # of 'collection' to be set, changing the dispatch
11- method (collection);
34+ randfunc (collection);
1235
1336 # Firstly, we will generate a base list
14- Init(GlobalMersenneTwister , 6 );
15- test1 := List([ 1 .. 1000 ] , x -> method (collection));
16- # test2 should = test1
17- Init(GlobalMersenneTwister , 6 );
18- test2 := List([ 1 .. 1000 ] , x -> method (collection));
37+ Init(global_rs , 6 );
38+ test1 := List([ 1 .. 1000 ] , x -> global_randfunc (collection));
39+ # test2 should equal test1
40+ Init(global_rs , 6 );
41+ test2 := List([ 1 .. 1000 ] , x -> global_randfunc (collection));
1942 # test3 should also = test1
20- Init(GlobalMersenneTwister , 6 );
21- test3 := List([ 1 .. 1000 ] , x -> method(GlobalMersenneTwister , collection));
43+ Init(global_rs , 6 );
44+ test3 := List([ 1 .. 1000 ] , x -> randfunc(global_rs , collection));
2245 # test4 should be different (as it came from a different seed)
23- Init(GlobalMersenneTwister , 8 );
24- test4 := List([ 1 .. 1000 ] , x -> method (collection));
46+ Init(global_rs , 8 );
47+ test4 := List([ 1 .. 1000 ] , x -> global_randfunc (collection));
2548 # test5 should be the same as test4, as it is made from seed 8
2649 # test6 should be the same as test1. Also, it checks that making test5
2750 # did not touch the global source at all.
28- Init(GlobalMersenneTwister , 8 );
29- localgen := RandomSource(IsMersenneTwister , 6 );
30- test5 := List([ 1 .. 1000 ] , x -> method(localgen , collection));
31- test6 := List([ 1 .. 1000 ] , x -> method (collection));
32- if ForAny(Concatenation(test1, test2, test3, test4, test5, test6), x -> not (checkmethod (x, collection)) ) then
51+ Init(global_rs , 8 );
52+ local_rs := RandomSource(filter , 6 );
53+ test5 := List([ 1 .. 1000 ] , x -> randfunc(local_rs , collection));
54+ test6 := List([ 1 .. 1000 ] , x -> global_randfunc (collection));
55+ if ForAny(Concatenation(test1, test2, test3, test4, test5, test6), x -> not (checkin (x, collection)) ) then
3356 Print(" Random member outside collection: " , collection," \n " );
3457 fi ;
3558 if test1 <> test2 then
@@ -45,49 +68,81 @@ randomTest := function(collection, method, checkin...)
4568 Print(" Alt gen broken: " , collection, " \n " );
4669 fi ;
4770 if test4 <> test6 then
48- Print(" Random with a passed in seed affected the global generator : " , collection, " \n " );
71+ Print(" Random with a passed in seed affected the global source : " , collection, " \n " );
4972 fi ;
5073end ;;
5174
75+
5276# A special test for collections of size 1
53- randomTestForSizeOneCollection := function (collection, method )
54- local i, val, localgen, intlist1, intlist2;
55- if Size(collection) <> 1 then
56- Print(" randomTestForSizeOneCollection is only for collections of size 1" );
57- return ;
58- fi ;
77+ # Here we can't check different seeds produce different answers
78+ # We do check that the random source is not used, for efficency.
79+ randomTestForSizeOneCollectionInner := function (filter, global_rs, global_randfunc, randfunc, collection, checkin )
80+ local i, val, local_rs, intlist1, intlist2;
5981
6082 val := Representative(collection);
6183
62- Init(GlobalMersenneTwister , 6 );
63- intlist1 := List([ 1 .. 1000 ] , x -> Random ([ 1 .. 10 ] ));
84+ Init(global_rs , 6 );
85+ intlist1 := List([ 1 .. 10 ] , x -> global_randfunc ([ 1 .. 1000 ] ));
6486
65- for i in [ 1 .. 1000 ] do
66- if method (collection) <> val then
87+ for i in [ 1 .. 100 ] do
88+ if global_randfunc (collection) <> val then
6789 Print(" Random returned something outside collection :" , collection, " :" , val);
6890 fi ;
6991 od ;
7092
71- for i in [ 1 .. 1000 ] do
72- if method(GlobalMersenneTwister , collection) <> val then
93+ for i in [ 1 .. 100 ] do
94+ if randfunc(global_rs , collection) <> val then
7395 Print(" Random returned something outside collection :" , collection, " :" , val);
7496 fi ;
7597 od ;
7698
77- localgen := RandomSource(IsMersenneTwister , 6 );
99+ local_rs := RandomSource(filter , 6 );
78100
79- Init(GlobalMersenneTwister , 6 );
80- for i in [ 1 .. 1000 ] do
81- if method(localgen , collection) <> val then
101+ Init(global_rs , 6 );
102+ for i in [ 1 .. 100 ] do
103+ if randfunc(local_rs , collection) <> val then
82104 Print(" Random returned something outside collection :" , collection, " :" , val);
83105 fi ;
84106 od ;
85107
86- # The previous loop should not have affected GlobalMersenneTwister ,
108+ # The previous loop should not have affected global_rs ,
87109 # so this should be the same as intlist1
88- intlist2 := List([ 1 .. 1000 ] , x -> Random ([ 1 .. 10 ] ));
110+ intlist2 := List([ 1 .. 10 ] , x -> global_randfunc ([ 1 .. 1000 ] ));
89111
90112 if intlist1 <> intlist2 then
91113 Print(" Random read from local gen affected global gen: " , collection);
92114 fi ;
93115end ;;
116+
117+
118+ randomTest := function (collection, randfunc, checkin... )
119+ local sizeone, randchecker;
120+ if Length(checkin) = 0 then
121+ checkin := \in ;
122+ else
123+ checkin := checkin[ 1 ] ;
124+ fi ;
125+
126+ # Make a best attempt to find if the collection is size 1.
127+ # There are implementations of random for objects which do not support
128+ # Size or IsTrivial, e.g. PadicExtensionNumberFamily
129+ if IsList(collection) then
130+ sizeone := (Size(collection) = 1 );
131+ elif IsCollection(collection) then
132+ sizeone := IsTrivial(collection);
133+ else
134+ sizeone := false ;
135+ fi ;
136+
137+ if sizeone then
138+ randchecker := randomTestForSizeOneCollectionInner;
139+ else
140+ randchecker := randomTestInner;
141+ fi ;
142+
143+ randchecker(IsMersenneTwister,
144+ GlobalMersenneTwister, x -> randfunc(x), randfunc, collection, checkin);
145+ randchecker(IsGAPRandomSource,
146+ GlobalRandomSource, x -> randfunc(GlobalRandomSource, x), randfunc,
147+ collection, checkin);
148+ end ;
0 commit comments