Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Add seed(InputRange) overload to MersenneTwisterEngine #627

Merged
merged 1 commit into from almost 2 years ago

3 participants

Johannes Pfau David Nadlinger Jonathan M Davis
Johannes Pfau
jpf91 commented June 12, 2012

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

David Nadlinger
Collaborator

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

David Nadlinger
Collaborator

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

Johannes Pfau
jpf91 commented June 12, 2012

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.
559 559
 
560 560
 /**
561 561
    Seeds a MersenneTwisterEngine object.
  562
+   Note:
  563
+   This seed function gives 2^32 starting points. To allow the RNG to be started in any one of its
  564
+   2^19,937 internal states use the seed overload taking an InputRange.
1
David Nadlinger Collaborator
klickverbot added a note June 12, 2012

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
Johannes Pfau
jpf91 commented June 13, 2012

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

std/random.d
... ...
@@ -587,6 +590,37 @@ Parameter for the generator.
587 590
     }
588 591
 
589 592
 /**
  593
+   Seeds a MersenneTwisterEngine object using an InputRange.
  594
+
  595
+   Throws:
  596
+   $(D Exception) if the InputRange didn't provide enough elements to seed the generator.
  597
+   The number of elements required is the 'n' template parameter of the MersenneTwisterEngine struct.
  598
+   
  599
+   Examples:
  600
+   ----------------
  601
+   Mt19937 gen;
  602
+   gen.seed(map!((a) => unpredictableSeed)(repeat(0)));
  603
+   ----------------
  604
+ */
  605
+    void seed(T)(T range) if(isInputRange!T && is(Unqual!(ElementType!T) == UIntType))
  606
+    {
  607
+        int j;
1
Jonathan M Davis Collaborator
jmdavis added a note June 17, 2012

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))
  602
+   gen.seed(map!((a) => unpredictableSeed)(repeat(0)));
  603
+   ----------------
  604
+ */
  605
+    void seed(T)(T range) if(isInputRange!T && is(Unqual!(ElementType!T) == UIntType))
  606
+    {
  607
+        int j;
  608
+        for(j = 0; j < n && !range.empty; ++j, range.popFront())
  609
+        {
  610
+            mt[j] = range.front;
  611
+        }
  612
+
  613
+        mti = n;
  614
+        if(range.empty && j < n)
  615
+        {
  616
+            throw new Exception("MersenneTwisterEngine.seed: Input range didn't provide enough"
  617
+                " elements: Need " ~ to!string(n) ~ " elements.");
1
Jonathan M Davis Collaborator
jmdavis added a note June 17, 2012

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
698 732
 
699 733
 unittest
700 734
 {
  735
+    Mt19937 gen;
  736
+
  737
+    bool thrown = false;
  738
+    try
  739
+        gen.seed(map!((a) => unpredictableSeed)(repeat(0, 623)));
  740
+    catch(Exception)
  741
+        thrown = true;
  742
+
  743
+    assert(thrown);
1
Jonathan M Davis Collaborator
jmdavis added a note June 17, 2012

Please use assertThrown.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Johannes Pfau
jpf91 commented June 17, 2012

@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.

Johannes Pfau
jpf91 commented June 17, 2012

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).

Johannes Pfau
jpf91 commented June 17, 2012

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.

Jonathan M Davis
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.

Johannes Pfau
jpf91 commented June 17, 2012

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

Jonathan M Davis jmdavis merged commit d6ffd58 into from June 17, 2012
Jonathan M Davis jmdavis closed this June 17, 2012
Jonathan M Davis
Collaborator

Merged.

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

Showing 1 unique commit by 1 author.

Jun 17, 2012
Johannes Pfau Add seed(InputRange) overload to MersenneTwisterEngine c0be641
This page is out of date. Refresh to see the latest.

Showing 1 changed file with 59 additions and 9 deletions. Show diff stats Hide diff stats

  1. 68  std/random.d
68  std/random.d
@@ -61,6 +61,7 @@ module std.random;
61 61
 import std.algorithm, std.c.time, std.conv, std.exception,
62 62
        std.math, std.numeric, std.range, std.traits,
63 63
        core.thread, core.time;
  64
+import std.string : format;
64 65
 
65 66
 version(unittest) import std.typetuple;
66 67
 
@@ -149,21 +150,21 @@ template isUniformRNG(Rng)
149 150
 
150 151
 /**
151 152
  * Test if Rng is seedable. The overload
152  
- * taking a ElementType also makes sure that the Rng generates
  153
+ * taking a SeedType also makes sure that the Rng can be seeded with SeedType.
  154
+ * If SeedType is not an InputRange, additionally checks that the Rng generates
153 155
  * values of that type.
154  
- *
155 156
  * A seedable random-number generator has the following additional features:
156 157
  * $(UL
157 158
  *   $(LI it has a 'seed(ElementType)' function)
158 159
  * )
159 160
  */
160  
-template isSeedable(Rng, ElementType)
  161
+template isSeedable(Rng, SeedType)
161 162
 {
162  
-    enum bool isSeedable = isUniformRNG!(Rng, ElementType) &&
  163
+    enum bool isSeedable = isUniformRNG!(Rng) &&
163 164
         is(typeof(
164 165
         {
165  
-            Rng r = void;                 // can define a Rng object
166  
-            r.seed(ElementType.init);     // can seed a Rng
  166
+            Rng r = void;              // can define a Rng object
  167
+            r.seed(SeedType.init);     // can seed a Rng
167 168
         }));
168 169
 }
169 170
 
@@ -173,7 +174,7 @@ template isSeedable(Rng)
173 174
     enum bool isSeedable = isUniformRNG!Rng &&
174 175
         is(typeof(
175 176
         {
176  
-            Rng r = void;                       // can define a Rng object
  177
+            Rng r = void;                     // can define a Rng object
177 178
             r.seed(typeof(r.front).init);     // can seed a Rng
178 179
         }));
179 180
 }
@@ -559,8 +560,11 @@ Parameter for the generator.
559 560
 
560 561
 /**
561 562
    Seeds a MersenneTwisterEngine object.
  563
+   Note:
  564
+   This seed function gives 2^32 starting points. To allow the RNG to be started in any one of its
  565
+   internal states use the seed overload taking an InputRange.
562 566
 */
563  
-    void seed(UIntType value = defaultSeed)
  567
+    void seed()(UIntType value = defaultSeed)
564 568
     {
565 569
         static if (w == UIntType.sizeof * 8)
566 570
         {
@@ -587,6 +591,37 @@ Parameter for the generator.
587 591
     }
588 592
 
589 593
 /**
  594
+   Seeds a MersenneTwisterEngine object using an InputRange.
  595
+
  596
+   Throws:
  597
+   $(D Exception) if the InputRange didn't provide enough elements to seed the generator.
  598
+   The number of elements required is the 'n' template parameter of the MersenneTwisterEngine struct.
  599
+   
  600
+   Examples:
  601
+   ----------------
  602
+   Mt19937 gen;
  603
+   gen.seed(map!((a) => unpredictableSeed)(repeat(0)));
  604
+   ----------------
  605
+ */
  606
+    void seed(T)(T range) if(isInputRange!T && is(Unqual!(ElementType!T) == UIntType))
  607
+    {
  608
+        size_t j;
  609
+        for(j = 0; j < n && !range.empty; ++j, range.popFront())
  610
+        {
  611
+            mt[j] = range.front;
  612
+        }
  613
+
  614
+        mti = n;
  615
+        if(range.empty && j < n)
  616
+        {
  617
+            throw new Exception(format("MersenneTwisterEngine.seed: Input range didn't provide enough"
  618
+                " elements: Need %s elemnets.", n));
  619
+        }
  620
+
  621
+        popFront();
  622
+    }
  623
+
  624
+/**
590 625
    Advances the generator.
591 626
 */
592 627
     void popFront()
@@ -691,6 +726,7 @@ unittest
691 726
     assert(isUniformRNG!(Mt19937, uint));
692 727
     assert(isSeedable!Mt19937);
693 728
     assert(isSeedable!(Mt19937, uint));
  729
+    assert(isSeedable!(Mt19937, typeof(map!((a) => unpredictableSeed)(repeat(0)))));
694 730
     Mt19937 gen;
695 731
     popFrontN(gen, 9999);
696 732
     assert(gen.front == 4123659995);
@@ -698,6 +734,17 @@ unittest
698 734
 
699 735
 unittest
700 736
 {
  737
+    Mt19937 gen;
  738
+
  739
+    assertThrown(gen.seed(map!((a) => unpredictableSeed)(repeat(0, 623))));
  740
+
  741
+    gen.seed(map!((a) => unpredictableSeed)(repeat(0, 624)));
  742
+    //infinite Range
  743
+    gen.seed(map!((a) => unpredictableSeed)(repeat(0)));
  744
+}
  745
+
  746
+unittest
  747
+{
701 748
     uint a, b;
702 749
     {
703 750
         Mt19937 gen;
@@ -1029,7 +1076,10 @@ and initialized to an unpredictable value for each thread.
1029 1076
     static bool initialized;
1030 1077
     if (!initialized)
1031 1078
     {
1032  
-        result = Random(unpredictableSeed);
  1079
+        static if(isSeedable!(Random, typeof(map!((a) => unpredictableSeed)(repeat(0)))))
  1080
+            result.seed(map!((a) => unpredictableSeed)(repeat(0)));
  1081
+        else
  1082
+            result = Random(unpredictableSeed);
1033 1083
         initialized = true;
1034 1084
     }
1035 1085
     return result;
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.