Skip to content

Commit

Permalink
Include random.gd before coll.gi
Browse files Browse the repository at this point in the history
This way, we can move the definition of GlobalMersenneTwister from
coll.gi to random.gd, and will be able to use InstallMethodWithRandomSource
inside of coll.gi
  • Loading branch information
fingolfin authored and ChrisJefferson committed Feb 23, 2018
1 parent e94dfa6 commit 880bf19
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 112 deletions.
5 changes: 0 additions & 5 deletions lib/coll.gi
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,6 @@ InstallMethod( RepresentativeSmallest,
## an enumerator of <C> and selects a random element of this list using the
## function `RandomList', which is a pseudo random number generator.
##
if IsHPCGAP then
MakeThreadLocal( "GlobalMersenneTwister" );
else
DeclareGlobalVariable( "GlobalMersenneTwister" );
fi;
InstallGlobalFunction( RandomList, function(list)
return list[Random(GlobalMersenneTwister, 1, Length(list))];
end );
Expand Down
208 changes: 103 additions & 105 deletions lib/random.gd
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
## </ManSection>
## <#/GAPDoc>
##
BindGlobal( "RandomSourcesFamily", NewFamily( "RandomSourcesFamily" ) );
BIND_GLOBAL( "RandomSourcesFamily", NewFamily( "RandomSourcesFamily" ) );
DeclareCategory( "IsRandomSource", IsComponentObjectRep );

#############################################################################
Expand Down Expand Up @@ -72,106 +72,6 @@ DeclareCategory( "IsRandomSource", IsComponentObjectRep );
DeclareOperation( "Random", [IsRandomSource, IsListOrCollection] );
DeclareOperation( "Random", [IsRandomSource, IsInt, IsInt] );

##############################################################################
##
## <#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"/> and
## <Ref Oper="PseudoRandom"/> 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>
##
(function()
local func;
func := function(installType)
return function(args...)
local str, filterpos, filtercopy, argscopy, i, func, info;

# Check we understand arguments
# Second value must be an info string
if not IsString(args[2]) then
ErrorNoReturn("Second argument must be an info string");
fi;

# Info strings always tend to begin 'for ', and here we want
# to be able to edit it, so we check.
if args[2]{[1..23]} <> "for a random source and" then
ErrorNoReturn("Info string must begin 'for a random source and'");
fi;

# Filters must start with 'IsRandomSource'
for i in [1..Length(args)] do
if IsList(args[i]) and args[i][1] = IsRandomSource then
filterpos := i;
fi;
od;

if not IsBound(filterpos) then
ErrorNoReturn("Must use a list of filters beginning 'IsRandomSource'");
fi;

# Last argument must be the actual method
if not IsFunction(args[Length(args)]) then
ErrorNoReturn("Argument list must end with the method");
fi;

# Install
CallFuncList(installType, args);

# Install random, wrapping random source argument
argscopy := List(args);

# Remove 'IsRandomSource' from the filter list
argscopy[filterpos] := argscopy[filterpos]{[2..Length(argscopy[filterpos])]};

# Correct info string by removing 'a random source and'
info := "for";
APPEND_LIST(info, argscopy[2]{[24..Length(argscopy[2])]});
argscopy[2] := info;

func := argscopy[Length(argscopy)];
if Length(argscopy[filterpos]) = 1 then
argscopy[Length(argscopy)] := x -> func(GlobalMersenneTwister,x);
elif Length(argscopy[filterpos]) = 2 then
argscopy[Length(argscopy)] :=
function(x,y)
return func(GlobalMersenneTwister,x,y);
end;
else
Error("Only 2 or 3 argument methods supported");
fi;

CallFuncList(installType, argscopy);
end;
end;
BIND_GLOBAL("InstallMethodWithRandomSource", func(InstallMethod));
BIND_GLOBAL("InstallOtherMethodWithRandomSource", func(InstallOtherMethod));
end)();

#############################################################################
##
#O State( <rs> ) . . . . . . . . . . . . . . . state of random source
Expand Down Expand Up @@ -290,12 +190,10 @@ DeclareCategory("IsMersenneTwister", IsRandomSource);

if IsHPCGAP then
MakeThreadLocal( "GlobalRandomSource" );
# this declaration is in coll.gi because it is needed for RandomList
# MakeThreadLocal( "GlobalMersenneTwister" );
MakeThreadLocal( "GlobalMersenneTwister" );
else
DeclareGlobalVariable( "GlobalRandomSource" );
# this declaration is in coll.gi because it is needed for RandomList
# DeclareGlobalVariable( "GlobalMersenneTwister" );
DeclareGlobalVariable( "GlobalMersenneTwister" );
fi;

#############################################################################
Expand Down Expand Up @@ -334,6 +232,106 @@ fi;
DeclareOperation( "RandomSource", [IsOperation] );
DeclareOperation( "RandomSource", [IsOperation, IsObject] );

##############################################################################
##
## <#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"/> and
## <Ref Oper="PseudoRandom"/> 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>
##
(function()
local func;
func := function(installType)
return function(args...)
local str, filterpos, filtercopy, argscopy, i, func, info;

# Check we understand arguments
# Second value must be an info string
if not IsString(args[2]) then
ErrorNoReturn("Second argument must be an info string");
fi;

# Info strings always tend to begin 'for ', and here we want
# to be able to edit it, so we check.
if args[2]{[1..23]} <> "for a random source and" then
ErrorNoReturn("Info string must begin 'for a random source and'");
fi;

# Filters must start with 'IsRandomSource'
for i in [1..Length(args)] do
if IsList(args[i]) and args[i][1] = IsRandomSource then
filterpos := i;
fi;
od;

if not IsBound(filterpos) then
ErrorNoReturn("Must use a list of filters beginning 'IsRandomSource'");
fi;

# Last argument must be the actual method
if not IsFunction(args[Length(args)]) then
ErrorNoReturn("Argument list must end with the method");
fi;

# Install
CallFuncList(installType, args);

# Install random, wrapping random source argument
argscopy := List(args);

# Remove 'IsRandomSource' from the filter list
argscopy[filterpos] := argscopy[filterpos]{[2..Length(argscopy[filterpos])]};

# Correct info string by removing 'a random source and'
info := "for";
APPEND_LIST(info, argscopy[2]{[24..Length(argscopy[2])]});
argscopy[2] := info;

func := argscopy[Length(argscopy)];
if Length(argscopy[filterpos]) = 1 then
argscopy[Length(argscopy)] := x -> func(GlobalMersenneTwister,x);
elif Length(argscopy[filterpos]) = 2 then
argscopy[Length(argscopy)] :=
function(x,y)
return func(GlobalMersenneTwister,x,y);
end;
else
Error("Only 2 or 3 argument methods supported");
fi;

CallFuncList(installType, argscopy);
end;
end;
BIND_GLOBAL("InstallMethodWithRandomSource", func(InstallMethod));
BIND_GLOBAL("InstallOtherMethodWithRandomSource", func(InstallOtherMethod));
end)();

#############################################################################
##
#E
4 changes: 2 additions & 2 deletions lib/read1.g
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ ReadLib( "set.gd" );

ReadLib( "record.gd" );

ReadLib( "random.gd" );

ReadLib( "cache.gi" );
ReadLib( "coll.gi" );

Expand Down Expand Up @@ -70,8 +72,6 @@ ReadLib( "info.gi" );
ReadLib( "assert.gi" );
ReadLib( "global.gi" );

ReadLib( "random.gd" );

ReadLib( "options.gd" );
ReadLib( "options.gi" );

Expand Down

0 comments on commit 880bf19

Please sign in to comment.