-
Notifications
You must be signed in to change notification settings - Fork 160
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
Help Random methods to use RandomSource #810
Conversation
Wouldn't the following fallback method do the trick?
For the few cases where the double call of (BTW: |
Sorry, I should have explained why this is necessary. The problem isn't performance, it's method selection. If I could change every However, I convert I considered extending dispatch to allow it to choose between the one and two argument versions of Once every installed |
So... couldn't we then add a method like Frank suggested, but with rank Of course that would only work if all packages actually provide both 1 and 2 arg versions of |
Hmm... I just checked, and actually virtually no packages provides So, since we have to prod almost all package authors anyway, I wonder whether it really help to have This also has the advantage that package authors don't need to add a dependency on GAP >= 4.x.y, where 4.x.y is the version which introduced Regardless of whether we merge the PR or not, I think we will have to invest some effort (and careful explain things) if we want package authors to change their packages. |
I'd be happy to take this PR away, and just suggest we work our way through packages and the library, converting 1 arg The main thing I want is 2-arg |
Ok, if the goal is to have versions of all methods for Random with a random source argument then I don't see how this proposed function would help. Most, if not all, methods delegate to Random for lists or two integers. The main work will be that the code of these methods must be changed such that the internal Random calls use the given random source (and not that another two lines for the one argument version are needed - which could also be done with a fallback method as mentioned above). I don't see why this change could not be made by an by. (There will be only few cases where several methods are applicable.) |
I discussed this with @ChrisJefferson some time ago, and while initially sceptical, I now think something along this vein could be benficial. I'll try to explain. First off, this is based on the assumption that it is desirable for us to adapt as many as possible (ideally, all) If one agrees with this, then now the question is how to get there. Right now, virtually all Random (etc.) methods don't take a random source. The first step then should be to change the library to provide methods taking a random source for all our Random (etc.) methods. This will then later on enable package authors to change their Random methods (which often invoke Random methods from the GAP library, thus need to be able to pass random sources to those). Now, as Frank correctly points out, this can right already be done by modifying the existing Random method to take (and use) a random source (which is most of the work required), and then add a second method with the old signature (i.e. not taking a random source) which passes While doing this is indeed relatively easy, there are two caveats:
If we introduce an In order to make this generic, I think After day X, |
Another minor thing: Perhaps |
What is the status of this PR? |
ece1454
to
41dda21
Compare
I've now adjusted this so that the new method, Hopefully this can now get merged, at which point I'll start translating other methods. I haven't done |
Current coverage is 50.55% (diff: 59.63%)@@ master #810 diff @@
==========================================
Files 424 426 +2
Lines 223042 223146 +104
Methods 3430 3430
Messages 0 0
Branches 0 0
==========================================
+ Hits 112594 112804 +210
+ Misses 110448 110342 -106
Partials 0 0
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work, thanks!
@@ -85,6 +85,7 @@ For declaring that a filter is implied by other filters there is | |||
|
|||
<#Include Label="InstallMethod"> | |||
<#Include Label="InstallOtherMethod"> | |||
<#Include Label="InstallMethodWithGlobalRandomGen"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't that mean the function will appear in the manual right after InstallMethod
and InstallOtherMethod
? Do we want that? There are some arguments for it, I guess, but it would also make sense to move this near the documentation for random sources... Alas, see also issue #1057
@@ -69,9 +69,84 @@ DeclareCategory( "IsRandomSource", IsComponentObjectRep ); | |||
## </ManSection> | |||
## <#/GAPDoc> | |||
## | |||
DeclareOperation( "Random", [IsRandomSource, IsList] ); | |||
DeclareOperation( "Random", [IsRandomSource, IsListOrCollection] ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks plausible; does it fix any actual problem? If so, perhaps this should be documented in the PR text and/or covered by a test case? (Or perhaps it already is covered by a test case?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is covered. This just lines up two-argument random with one argument random, which was already DeclareOperation( "Random", [ IsListOrCollection ] );
. It's needed to take random elements from lists which aren't collection.
## Arg="opr,info[,famp],args-filts[,val],method"/> | ||
## | ||
## <Description> | ||
## A helper function which works the same as <Ref Func="InstallMethod"/>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't work quite the "same", does it? Perhaps "which takes the same arguments as" ?
Also, change the comma at the end to a period, or else rephrase the next line (at the very least, make it start lowercase).
|
||
# 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess StartsWith
is not available here?
Hmm... looking at lib/read*.g
, it seems we used to read it later, but it was moved to read1.g
. Testing this, the only reason for that seems to be that matobj2.gd
references random sources... So we can fix this (and you can start using things like BindGlobal
and StartsWith
here) quite easily. This patch does it for me:
diff --git a/lib/read1.g b/lib/read1.g
index 185f74763..3843fdbfd 100644
--- a/lib/read1.g
+++ b/lib/read1.g
@@ -67,8 +67,6 @@ ReadLib( "info.gi" );
ReadLib( "assert.gi" );
ReadLib( "global.gi" );
-ReadLib( "random.gd" );
-
ReadLib( "options.gd" );
ReadLib( "options.gi" );
diff --git a/lib/read3.g b/lib/read3.g
index 51a34f289..40f2730c3 100644
--- a/lib/read3.g
+++ b/lib/read3.g
@@ -82,9 +82,6 @@ ReadLib( "unknown.gd" );
ReadLib( "word.gd" );
ReadLib( "wordass.gd" );
-ReadLib( "matobj2.gd" );
-ReadLib( "matobjplist.gd" );
-
# files dealing with rewriting systems
ReadLib( "rws.gd" );
ReadLib( "rwspcclt.gd" );
@@ -174,9 +171,13 @@ ReadLib( "integer.gi" ); # needed for CoefficientsQadic
ReadLib( "list.gi" ); # was too early
ReadLib( "set.gi" );
ReadLib( "wpobj.gi" );
-## ReadLib( "random.gd" );
-## ReadLib( "random.gi" );
-## ReadLib( "random.g" );
+
+# random sources
+ReadLib( "random.gd" );
+ReadLib( "random.gi" );
+
+ReadLib( "matobj2.gd" );
+ReadLib( "matobjplist.gd" );
# files dealing with nice monomorphism
# grpnice uses some family predicates, so fampred.g must be known
@@ -249,6 +250,3 @@ ReadLib("gasman.gd");
# files dealing with function calling
ReadLib("function.gd");
-
-# random sources
-ReadLib("random.gi");
if intlist1 <> intlist2 then | ||
Print("Random read from local gen effected global gen: ", collection); | ||
fi; | ||
end;; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please end the file with a newline.
intlist2 := List([1..1000], x -> Random([1..10])); | ||
|
||
if intlist1 <> intlist2 then | ||
Print("Random read from local gen effected global gen: ", collection); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
effected -> affected
59dd506
to
8faab9f
Compare
@fingolfin : I have fixed all comments, except:
|
8faab9f
to
9de50f5
Compare
@ChrisJefferson Thanks! I'll take another look |
Note: travis will fails due to the broken log2int on master. So I stopped the build for this PR for now. You can either rebase it on master just before the bad build, or wait till the fix gets in and rebase it again... of course, then the 32bit build will still be broken... Hrmpf |
## <Description> | ||
## This function is designed to simplify adding new overloads for | ||
## <Ref Oper="Random"/> and <Ref Oper="PseudoRandom"/> to GAP which can | ||
## be called both with, and without, a random soure. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: soure -> source
## Arg="opr,info[,famp],args-filts[,val],method"/> | ||
## | ||
## <Description> | ||
## This function is designed to simplify adding new overloads for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps overloads -> methods? Overload is more a C++ term, unusual for GAP.
DeclareOperation( "Random", [IsRandomSource, IsInt, IsInt] ); | ||
|
||
############################################################################## | ||
## | ||
## <#GAPDoc Label="InstallMethodWithGlobalRandomGen"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand that name. What is a "GlobalRandomGen"? Perhaps this refers to the fact that an alternate method using a global random source is installed? Then it should perhaps be InstallMethodWithGlobalRandomSource
?
Or perhaps just InstallMethodWithRandomSource
(indicating it can be used to install any method whose first argument is a random source).
I don't want to bikeshed, but I really don't understand the current name.
## is compulsory and must begin 'for a random source and'. | ||
## <P/> | ||
## This function calls <Ref Func="InstallMethod"/> twice. Firstly | ||
## with it's arguments unchanged, and secondly with the first argument |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's -> its
## be IsRandomSource, and the <A>info</A> argument | ||
## is compulsory and must begin 'for a random source and'. | ||
## <P/> | ||
## This function calls <Ref Func="InstallMethod"/> twice. Firstly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Firstly" sounds quite formal to me. Indeed, see also http://dictionary.cambridge.org/grammar/british-grammar/first-firstly-or-at-first
Perhaps just "first" ?
## This function calls <Ref Func="InstallMethod"/> twice. Firstly | ||
## with it's arguments unchanged, and secondly with the first argument | ||
## removed, instead always passing in the value | ||
## <Ref Var="GlobalRandomSource"/>. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hrm... that only "almost" explains what's going on. I think we should either give a high-level description, or a full explanation, or perhaps both. How about this:
"This function then installs two methods: first it calls InstallMethod with unchanged arguments. Then it calls InstallMethod a second time to install anothr method which lacks the initial random source argument; this additional method simply invokes the original method, with GlobalRandomSource added as first argument."
argscopy[2] := info; | ||
|
||
func := argscopy[Length(argscopy)]; | ||
argscopy[Length(argscopy)] := x -> func(GlobalMersenneTwister,x); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh, so this actually only works if the mtehod takes exactly one argument in addition to the random source. But there are some Random
methods which take 1+2 = 3 argument.
If the user tries to use InstallMethodWithGlobalRandomGen
to set one of those up, the mistake will not be immediately visible -- only if you try to use Random
without a source. So I would suggest we check the number of arguments. In addition, we could also verify that NumberArgumentsFunction(func)
and Length(args[filterpos])
coincide.
Even nicer would of course be if we could support arbitrary numbers of arguments :-). But I am not going to hold this PR hostage over this :-).
33db306
to
d05f087
Compare
Changes made -- also added support for |
d05f087
to
c2c478d
Compare
@frankluebeck do you still haveobjections to this PR in its current form? Otherwise, we will merge it soon... and I suggest that at the same time we create an issue to remind us to convert more code to use this (I have not checked whether there are more Random methods in the library whoch might benefit from this, but in packages those exist for sure... though there we likely will want to wait till 4.9 has been released... |
There are lots of methods in the library that can use this. As a brief search: AdditiveCoset, DoubleCoset, RightCoset, hashtable, AlgebraicExtension, ConjugacyClasses, finite prime fields, pseudorandom groups with product replacement, and I've only got about 1/2 way through the library :) |
The idea behind this patch is that we want (long term) for all implementations of
Random
to take an optionalRandomSource
.Given an implementation of
Random
which takes aRandomSource
, it's easy to wrap it and make a version which doesn't take a random source. This is whatInstallRandomMethod
does.I show an example of using this on
Integers
. If this is happily accepted, then hopefully I (or other people!) will convert allInstallMethod
forRandom
to useInstallRandomMethod
. This will allow users to control random numbers better, and avoid code duplication.