Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Add seed(InputRange) overload to MersenneTwisterEngine #627

Merged
merged 1 commit into from

3 participants

@jpf91

Adds a new seed overload as discussed here: http://forum.dlang.org/thread/jr0luj$1ctj$1@digitalmars.com

@klickverbot
Collaborator

Maybe add the number of elements required to the error message and documentation?

@klickverbot
Collaborator

Also, you might want to add a note to the single integer overload, describing its limitations.

@jpf91

The the number of elements required is not fixed. It's 624 for Mt19937 but it seems it can be any value for MersenneTwisterEngine. But I added a basic description to the docs.

std/random.d
@@ -559,8 +559,11 @@ Parameter for the generator.
/**
Seeds a MersenneTwisterEngine object.
+ Note:
+ This seed function gives 2^32 starting points. To allow the RNG to be started in any one of its
+ 2^19,937 internal states use the seed overload taking an InputRange.
@klickverbot Collaborator

2^19937 (-1) is only the period for Mt19937, not for MersenneTwisterEngine in general, right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jpf91

Yes, you're right. Removed the 2^19937 note.

std/random.d
@@ -587,6 +590,37 @@ Parameter for the generator.
}
/**
+ Seeds a MersenneTwisterEngine object using an InputRange.
+
+ Throws:
+ $(D Exception) if the InputRange didn't provide enough elements to seed the generator.
+ The number of elements required is the 'n' template parameter of the MersenneTwisterEngine struct.
+
+ Examples:
+ ----------------
+ Mt19937 gen;
+ gen.seed(map!((a) => unpredictableSeed)(repeat(0)));
+ ----------------
+ */
+ void seed(T)(T range) if(isInputRange!T && is(Unqual!(ElementType!T) == UIntType))
+ {
+ int j;
@jmdavis Collaborator
jmdavis added a note

j is used for indexing mt and comparing against n (which is a size_t), so it should be size_t, not int.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
std/random.d
((13 lines not shown))
+ gen.seed(map!((a) => unpredictableSeed)(repeat(0)));
+ ----------------
+ */
+ void seed(T)(T range) if(isInputRange!T && is(Unqual!(ElementType!T) == UIntType))
+ {
+ int j;
+ for(j = 0; j < n && !range.empty; ++j, range.popFront())
+ {
+ mt[j] = range.front;
+ }
+
+ mti = n;
+ if(range.empty && j < n)
+ {
+ throw new Exception("MersenneTwisterEngine.seed: Input range didn't provide enough"
+ " elements: Need " ~ to!string(n) ~ " elements.");
@jmdavis Collaborator
jmdavis added a note

This should use format. It's cleaner and shorter that way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
std/random.d
@@ -698,6 +732,23 @@ unittest
unittest
{
+ Mt19937 gen;
+
+ bool thrown = false;
+ try
+ gen.seed(map!((a) => unpredictableSeed)(repeat(0, 623)));
+ catch(Exception)
+ thrown = true;
+
+ assert(thrown);
@jmdavis Collaborator
jmdavis added a note

Please use assertThrown.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jpf91

@jmdavis OK, implemented your suggested changes. rndGen is also using the new seed overload now. However, I had to slightly change isSeedable as well. Without that change, it's not possible to use isSeedable for the new seed overload.

@jpf91

Yes I should probably do that. Although adding the guarantee about Rng.front was wrong in the first place, but I didn't know that RNGs could be seeded with other types (I implemented isSeedable).

@jpf91

map doesn't work in CTFE yet. I think we can just leave that as is, as long as rndGen uses the new seed method and we document the problems with the old seed overload.

@jmdavis
Collaborator

If there's really no relation between the type of front and the type that's used to seed the range, then there should be no check for whether the type of front and the seed type are the same. I objected, because it was checking that, and you changed it so that it wasn't. Now, it's half-and-half. In one case it checks, and the other doesn't, which seems a bit off to me. So, if you're sure that there's not really any relation between front and the seed type (and the more I think about it, the more it seems like there wouldn't be), then isSeedable shouldn't be checking the type of front at all.

@jpf91

OK, I removed the check again. It doesn't really make sense and user code should always check isRandomRNG(Type, frontType) and isSeedable(SeedType).

@jmdavis jmdavis merged commit d6ffd58 into D-Programming-Language:master
@jmdavis
Collaborator

Merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 17, 2012
  1. @jpf91
This page is out of date. Refresh to see the latest.
Showing with 59 additions and 9 deletions.
  1. +59 −9 std/random.d
View
68 std/random.d
@@ -61,6 +61,7 @@ module std.random;
import std.algorithm, std.c.time, std.conv, std.exception,
std.math, std.numeric, std.range, std.traits,
core.thread, core.time;
+import std.string : format;
version(unittest) import std.typetuple;
@@ -149,21 +150,21 @@ template isUniformRNG(Rng)
/**
* Test if Rng is seedable. The overload
- * taking a ElementType also makes sure that the Rng generates
+ * taking a SeedType also makes sure that the Rng can be seeded with SeedType.
+ * If SeedType is not an InputRange, additionally checks that the Rng generates
* values of that type.
- *
* A seedable random-number generator has the following additional features:
* $(UL
* $(LI it has a 'seed(ElementType)' function)
* )
*/
-template isSeedable(Rng, ElementType)
+template isSeedable(Rng, SeedType)
{
- enum bool isSeedable = isUniformRNG!(Rng, ElementType) &&
+ enum bool isSeedable = isUniformRNG!(Rng) &&
is(typeof(
{
- Rng r = void; // can define a Rng object
- r.seed(ElementType.init); // can seed a Rng
+ Rng r = void; // can define a Rng object
+ r.seed(SeedType.init); // can seed a Rng
}));
}
@@ -173,7 +174,7 @@ template isSeedable(Rng)
enum bool isSeedable = isUniformRNG!Rng &&
is(typeof(
{
- Rng r = void; // can define a Rng object
+ Rng r = void; // can define a Rng object
r.seed(typeof(r.front).init); // can seed a Rng
}));
}
@@ -559,8 +560,11 @@ Parameter for the generator.
/**
Seeds a MersenneTwisterEngine object.
+ Note:
+ This seed function gives 2^32 starting points. To allow the RNG to be started in any one of its
+ internal states use the seed overload taking an InputRange.
*/
- void seed(UIntType value = defaultSeed)
+ void seed()(UIntType value = defaultSeed)
{
static if (w == UIntType.sizeof * 8)
{
@@ -587,6 +591,37 @@ Parameter for the generator.
}
/**
+ Seeds a MersenneTwisterEngine object using an InputRange.
+
+ Throws:
+ $(D Exception) if the InputRange didn't provide enough elements to seed the generator.
+ The number of elements required is the 'n' template parameter of the MersenneTwisterEngine struct.
+
+ Examples:
+ ----------------
+ Mt19937 gen;
+ gen.seed(map!((a) => unpredictableSeed)(repeat(0)));
+ ----------------
+ */
+ void seed(T)(T range) if(isInputRange!T && is(Unqual!(ElementType!T) == UIntType))
+ {
+ size_t j;
+ for(j = 0; j < n && !range.empty; ++j, range.popFront())
+ {
+ mt[j] = range.front;
+ }
+
+ mti = n;
+ if(range.empty && j < n)
+ {
+ throw new Exception(format("MersenneTwisterEngine.seed: Input range didn't provide enough"
+ " elements: Need %s elemnets.", n));
+ }
+
+ popFront();
+ }
+
+/**
Advances the generator.
*/
void popFront()
@@ -691,6 +726,7 @@ unittest
assert(isUniformRNG!(Mt19937, uint));
assert(isSeedable!Mt19937);
assert(isSeedable!(Mt19937, uint));
+ assert(isSeedable!(Mt19937, typeof(map!((a) => unpredictableSeed)(repeat(0)))));
Mt19937 gen;
popFrontN(gen, 9999);
assert(gen.front == 4123659995);
@@ -698,6 +734,17 @@ unittest
unittest
{
+ Mt19937 gen;
+
+ assertThrown(gen.seed(map!((a) => unpredictableSeed)(repeat(0, 623))));
+
+ gen.seed(map!((a) => unpredictableSeed)(repeat(0, 624)));
+ //infinite Range
+ gen.seed(map!((a) => unpredictableSeed)(repeat(0)));
+}
+
+unittest
+{
uint a, b;
{
Mt19937 gen;
@@ -1029,7 +1076,10 @@ and initialized to an unpredictable value for each thread.
static bool initialized;
if (!initialized)
{
- result = Random(unpredictableSeed);
+ static if(isSeedable!(Random, typeof(map!((a) => unpredictableSeed)(repeat(0)))))
+ result.seed(map!((a) => unpredictableSeed)(repeat(0)));
+ else
+ result = Random(unpredictableSeed);
initialized = true;
}
return result;
Something went wrong with that request. Please try again.