1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
|
#############################################################################
##
## This file is part of GAP, a system for computational discrete algebra.
## This file's authors include Frank Lübeck, Max Neunhöffer.
##
## Copyright of GAP belongs to its developers, whose names are too numerous
## to list here. Please refer to the COPYRIGHT file for details.
##
## SPDX-License-Identifier: GPL-2.0-or-later
##
## This file declares variables for random sources.
##
#############################################################################
##
#C IsRandomSource( <rs> )
##
## <#GAPDoc Label="IsRandomSource">
## <ManSection>
## <Filt Name="IsRandomSource" Arg='obj' Type='Category'/>
##
## <Description>
## This is the category of random source objects.
## The <E>user interface</E> for these objects consists of the following
## functions.
## <P/>
## <Ref Oper="RandomSource"/> creates a new random source <A>rs</A>, say.
## <P/>
## <C>Random( <A>rs</A>, <A>list</A> )</C> yields a random element of the
## list <A>list</A>, and
## <C>Random( <A>rs</A>, <A>low</A>, <A>high</A> )</C> yields a random
## integer between <A>low</A> and <A>high</A> (inclusive),
## see <Ref Oper="Random" Label="for random source and list"/>.
## <P/>
## If <A>rs</A> supports resetting (see <Ref Oper="State"/>) then
## <C>State( <A>rs</A> )</C> yields a copy <A>state</A>, say,
## of the current state of <A>rs</A> such that
## <C>Reset( <A>rs</A>, <A>state</A> )</C> resets <A>rs</A> to the given
## state.
## <P/>
## One idea behind providing several independent (pseudo) random sources is
## to make algorithms which use some sort of random choices deterministic.
## They can use their own new random source created with a fixed seed and
## so do exactly the same in different calls.
## <P/>
## Random source objects lie in the family <C>RandomSourcesFamily</C>.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
BIND_GLOBAL( "RandomSourcesFamily", NewFamily( "RandomSourcesFamily" ) );
DeclareCategory( "IsRandomSource", IsComponentObjectRep );
#############################################################################
##
#O Random( <rs>, <list> ) . . . for random source and a dense, nonempty list
#O Random( <rs>, <low>, <high> ) . . . . for random source and two integers
##
## <#GAPDoc Label="Random">
## <ManSection>
## <Oper Name="Random" Arg='rs, list' Label="for random source and list"/>
## <Oper Name="Random" Arg='rs, coll'
## Label="for random source and collection"/>
## <Oper Name="Random" Arg='rs, low, high'
## Label="for random source and two integers"/>
##
## <Description>
## This operation returns a random element from the dense, nonempty list
## <A>list</A> or the nonempty collection <A>coll</A>,
## or an integer in the range from the given (possibly large) integers
## <A>low</A> to <A>high</A>, respectively.
## <P/>
## The choice should only depend on the random source <A>rs</A> and have no
## effect on other random sources.
## <P/>
## It is not defined what happens if <A>list</A> or <A>coll</A> is empty,
## <A>list</A> is not dense, or <A>low</A> is larger than <A>high</A>.
## <Example>
## gap> mysource := RandomSource(IsMersenneTwister, 42);;
## gap> Random(mysource, 1, 10^60);
## 999331861769949319194941485000557997842686717712198687315183
## </Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
# We keep the declaration for non-dense lists
# in order not to break existing code.
DeclareOperation( "Random", [IsRandomSource, IsListOrCollection] );
DeclareOperation( "Random", [IsRandomSource, IsInt, IsInt] );
#############################################################################
##
#O State( <rs> ) . . . . . . . . . . . . . . . . . . state of random source
#O Reset( <rs>[, <seed>] ) . . . . . . . . . . . . . reset a random source
##
## <#GAPDoc Label="State">
## <ManSection Label="State and Reset for Random Sources">
## <Heading>State and Reset for Random Sources</Heading>
## <Oper Name="State" Arg='rs'/>
## <Oper Name="Reset" Arg='rs[, seed]'/>
##
## <Description>
## These are the basic operations for random sources (see
## <Ref Filt="IsRandomSource"/>).
## <P/>
## <Ref Oper="State"/> returns a data structure which admits recovering
## the state of the random source such that a sequence of random calls
## using this random source can be reproduced.
## If a random source cannot be reset (say, it uses truly random physical
## data) then <Ref Oper="State"/> returns <K>fail</K>.
## <P/>
## <C>Reset( <A>rs</A>, <A>seed</A> )</C> resets the random source <A>rs</A>
## to a state described by <A>seed</A>, if the random source can be reset;
## otherwise it does nothing.
## Here <A>seed</A> can be an output of <Ref Oper="State"/> and then
## <A>rs</A> gets reset to that state.
## For historical reasons, random sources accept integer values as
## <A>seed</A>.
## We recommend that new code should not rely on this; always use the output
## of a prior call to <Ref Oper="State"/> as <A>seed</A>, or omit it.
## Without the <A>seed</A> argument a fixed default seed is used.
## <Ref Oper="Reset"/> returns the state of <A>rs</A> before the call.
## <P/>
## Most methods for <Ref Oper="Random" Label="for a list or collection"/>
## in the &GAP; library that do not take a random source as argument use the
## <Ref Var="GlobalMersenneTwister"/> as random source. It can be reset
## into a known state as in the following example.
## <Example><![CDATA[
## gap> seed := Reset(GlobalMersenneTwister);;
## gap> seed = State(GlobalMersenneTwister);
## true
## gap> List([1..10],i->Random(Integers));
## [ -3, 2, -1, -2, -1, -1, 1, -4, 1, 0 ]
## gap> List([1..10],i->Random(Integers));
## [ -1, -1, -1, 1, -1, 1, -2, -1, -2, 0 ]
## gap> Reset(GlobalMersenneTwister, seed);;
## gap> List([1..10],i->Random(Integers));
## [ -3, 2, -1, -2, -1, -1, 1, -4, 1, 0 ]
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareOperation( "State", [IsRandomSource] );
DeclareOperation( "Reset", [IsRandomSource] );
DeclareOperation( "Reset", [IsRandomSource, IsObject] );
DeclareOperation( "Init", [IsRandomSource, IsObject] );
#############################################################################
##
#C IsMersenneTwister( <rs> )
#C IsGlobalRandomSource( <rs> )
#C IsGAPRandomSource( <rs> )
#V GlobalRandomSource
#V GlobalMersenneTwister
##
## <#GAPDoc Label="IsGlobalRandomSource">
## <ManSection Label="Kinds of Random Sources">
## <Heading>Kinds of Random Sources</Heading>
## <Filt Name="IsMersenneTwister" Arg='rs' Type='Category'/>
## <Filt Name="IsGAPRandomSource" Arg='rs' Type='Category'/>
## <Filt Name="IsGlobalRandomSource" Arg='rs' Type='Category'/>
## <Var Name="GlobalMersenneTwister"/>
## <Var Name="GlobalRandomSource"/>
##
## <Description>
## Currently, the &GAP; library provides three types of random sources,
## distinguished by the three listed categories.
## <P/>
## <Ref Filt="IsMersenneTwister"/> are random sources which use a fast
## random generator of 32 bit numbers, called the Mersenne twister. The
## pseudo random sequence has a period of <M>2^{19937}-1</M> and the
## numbers have a <M>623</M>-dimensional equidistribution. For more details
## and the origin of the code used in the &GAP; kernel, see:
## <URL>http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html</URL>.
## <P/>
## Use the Mersenne twister if possible, in particular for generating many
## large random integers.
## <P/>
## There is also a predefined global random source
## <Ref Var="GlobalMersenneTwister"/> which is used as the default
## random source by those library
## methods for <Ref Oper="Random" Label="for a list or collection"/>
## that do not take a random source as an argument.
## <P/>
## <Ref Filt="IsGAPRandomSource"/> uses the same number generator as
## <Ref Filt="IsGlobalRandomSource"/>, but you can create several of these
## random sources which generate their random numbers independently of
## all other random sources.
## <P/>
## <Ref Filt="IsGlobalRandomSource"/> gives access to the <E>classical</E>
## global random generator which was used by &GAP; in former releases.
## You do not need to construct new random sources of this kind which would
## all use the same global data structure. Just use the existing random
## source <Ref Var="GlobalRandomSource"/>. This uses the additive random number
## generator described in <Cite Key="TACP2"/> (Algorithm A in 3.2.2
## with lag <M>30</M>).
## <P/>
## Other kinds of random sources are implemented by &GAP; packages.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareCategory("IsGlobalRandomSource", IsRandomSource);
DeclareCategory("IsGAPRandomSource", IsRandomSource);
DeclareCategory("IsMersenneTwister", IsRandomSource);
if IsHPCGAP then
MakeThreadLocal( "GlobalRandomSource" );
MakeThreadLocal( "GlobalMersenneTwister" );
else
DeclareGlobalName( "GlobalRandomSource" );
DeclareGlobalName( "GlobalMersenneTwister" );
fi;
#############################################################################
##
#O RandomSource( <cat>[, <seed>] )
##
## <#GAPDoc Label="RandomSource">
## <ManSection>
## <Oper Name="RandomSource" Arg='cat[, seed]'/>
##
## <Description>
## This operation is used to create new random sources. The first argument
## <A>cat</A> is the category describing the type of the random generator,
## for example one of the categories listed in
## Section <Ref Subsect="Kinds of Random Sources"/>.
## <P/>
## An optional <A>seed</A> can be given to specify the initial state.
## For details,
## see Section <Ref Subsect="State and Reset for Random Sources"/>.
## <P/>
## <Example><![CDATA[
## gap> rs1 := RandomSource(IsMersenneTwister);
## <RandomSource in IsMersenneTwister>
## gap> l1 := List([1..10000], i-> Random(rs1, [1..6]));;
## gap> state1 := State(rs1);;
## gap> rs2 := RandomSource(IsMersenneTwister);;
## gap> l2 := List([1..10000], i-> Random(rs2, [1..6]));;
## gap> l1 = l2;
## true
## gap> l3 := List([1..10000], i-> Random(rs1, [1..6]));;
## gap> l1 = l3;
## false
## gap> rs3 := RandomSource(IsMersenneTwister, state1);;
## gap> l4 := List([1..10000], i-> Random(rs3, [1..6]));;
## gap> l3 = l4;
## true
## gap> n := Random(rs1, 1, 2^220);
## 1077726777923092117987668044202944212469136000816111066409337432400
## ]]></Example>
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareOperation( "RandomSource", [IsOperation] );
DeclareOperation( "RandomSource", [IsOperation, IsObject] );
##############################################################################
##
## <#GAPDoc Label="RandomSource_develop">
## <Subsection Label="Implementing new kinds of random sources">
## <Heading>Implementing new kinds of random sources</Heading>
##
## If one wants to implement a new kind of random sources then
## the first step is the declaration of a new category <C>C</C>, say,
## that implies <Ref Filt="IsRandomSource"/>, analogous to the categories
## listed in Section <Ref Subsect="Kinds of Random Sources"/>,
## as follows.
## <P/>
## <C>DeclareCategory( "C", IsRandomSource );</C>.
## <P/>
## Then the following method installations are needed.
## <P/>
## <Index Key="Init"><C>Init</C> (initialize a random source object)</Index>
## <C>InstallMethod( Init, [ C, IsObject ], function( prers, seed )
## ... end );</C>
## <P/>
## Here <C>prers</C> is an empty component object (which has already the
## filter <C>C</C>), and <C>seed</C> is an integer or a state value
## as returned by <Ref Oper="State"/> that describes the initial state of
## the random source.
## The function should fill in the actual data and then return the
## (now initialized) object <C>prers</C>.
## The default used for <C>seed</C> is the integer <C>1</C>.
## A given state value need not be copied by the function.
## <P/>
## <C>InstallMethod( Random, [ C, IsInt, IsInt ], function( rs, low, high )
## ... end );</C>
## <P/>
## Here <C>rs</C> is an already initialized random source object in the
## category <C>C</C>, and the function returns an integer between <C>low</C>
## and <C>high</C> (inclusive).
## It is not defined what happens when <C>low</C> is larger than <C>high</C>.
## <P/>
## <C>InstallMethod( State, [ C ], function( rs ) ... end );</C>
## <P/>
## If <C>rs</C> supports resetting then the function must return an object
## that describes the current state of <C>rs</C>.
## This object must be an independent copy, that is,
## calling <Ref Oper="Random" Label="for random source and list"/>
## for <C>rs</C> must not change the object that was returned by
## <Ref Oper="State"/>;
## otherwise <Ref Func="ReturnFail"/> should be installed.
## <P/>
## <C>InstallMethod( Reset, [ C, IsObject ], function( rs, seed )
## ... end );</C>
## <P/>
## If <C>rs</C> supports resetting then the function must reinitialize
## <C>rs</C> to the integer or <Ref Oper="State"/> value <C>seed</C>
## and must return the <Ref Oper="State"/> value of <C>rs</C> before these
## changes; if resetting is not supported then <Ref Func="ReturnNothing"/>
## should be installed.
## Reset need not copy a given state.
## Note that the generic unary <Ref Oper="Reset"/> method uses the default
## seed <C>1</C>.
## <P/>
## Examples of implementations as described here are given by the
## random sources with defining filter <Ref Filt="IsMersenneTwister"/>
## or <C>IsRealRandomSource</C>.
## (For the latter, see <Ref Meth="RandomSource" BookName="io"/>
## in the &GAP; package <Package>IO</Package>.)
## </Subsection>
## <#/GAPDoc>
##############################################################################
##
## <#GAPDoc Label="InstallMethodWithRandomSource">
## <ManSection>
## <Func Name="InstallMethodWithRandomSource"
## Arg="opr,info[,famp],args-filts[,val],method"/>
## <Func Name="InstallOtherMethodWithRandomSource"
## Arg="opr,info[,famp],args-filts[,val],method"/>
##
## <Description>
## These functions are designed to simplify adding new methods for
## <Ref Oper="Random" Label="for a list or collection"/>,
## <Ref Oper="PseudoRandom"/>,
## and <Ref Oper="Randomize" Label="for a vector object"/> to &GAP;
## which can be called both with, and without, a random source.
## <P/>
## They accept the same arguments as <Ref Func="InstallMethod"/> and
## <Ref Func="InstallOtherMethod"/>, with
## the extra requirement that the first member of <A>args-filts</A> must
## be <Ref Filt="IsRandomSource"/>, and the <A>info</A> argument
## is compulsory and must begin 'for a random source and'.
## <P/>
## This function then installs two methods: first it calls
## <Ref Func="InstallMethod"/> (or <Ref Func="InstallOtherMethod"/>)
## with unchanged arguments.
## Then it calls <Ref Func="InstallMethod"/>
## (or <Ref Func="InstallOtherMethod"/>) a second time to install
## another method which lacks the initial random source argument; this
## additional method simply invokes the original method, with
## <Ref Var="GlobalMersenneTwister"/> added as first argument.
## </Description>
## </ManSection>
## <#/GAPDoc>
##
DeclareGlobalFunction("InstallMethodWithRandomSource");
DeclareGlobalFunction("InstallOtherMethodWithRandomSource");
|