Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add isRandomNumberGenerator template #398

Merged
merged 4 commits into from

2 participants

@jpf91

This adds a isRandomNumberGenerator template to std.random, which can be used to detect if a type is a random-number generator.

@andralex

Odd naming convention, use Rng (or RandomNumberGenerator to avoid confusion with Range)

@andralex
Owner

We really need this but the question is whether seed() is enough of a distinguishing factor for RNGs, or we should have every RNG out there expose an explicit trait saying "yes, I am a RNG".

@jpf91

Thinking about this, some Rngs might not even have seed methods, at least those that would be based on /dev/random and /dev/urandom. So we should probably have isRandomNumberGenerator and isSeedable.

What's the best way to implement that 'trait'? A simple enum isRandom = true; as a member of every Rng?

@andralex
Owner

Yah, something like that but with "uniform" or "normal" in the name.

@jpf91

Should RandomSample and RandomCover also have that tag?

@andralex
Owner

I don't think RandomSample and RandomCover would need the tag. We need the isUniform tag to make sure e.g. we generate Gaussians from uniform distributions etc.

@jpf91

ping?

@andralex

Hmmm, this does not have "uniform" in its name, which would lead to confusion. For example, one would expect that a Gaussian random number generator does satisfy isRandomNumberGenerator. Should we call it isUniformRNG or isUniformRandomNumberGenerator or isUniformRandom?

I think isUniformRNG is best, isUniformRandomNumberGenerator is too long. Should the 'RNG' part really be all uppercase this time?

@andralex andralex merged commit d2a605d into from
@schveiguy schveiguy referenced this pull request in schveiguy/phobos
Merged

std.process ready for review? #1

@ghost Unknown referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@ghost Unknown referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@ghost Unknown referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@ghost Unknown referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 19, 2012
  1. @jpf91
Commits on Feb 8, 2012
  1. @jpf91
Commits on Feb 21, 2012
  1. @jpf91

    Merge branch 'master' into isRNG

    jpf91 authored
  2. @jpf91
This page is out of date. Refresh to see the latest.
Showing with 167 additions and 6 deletions.
  1. +167 −6 std/random.d
View
173 std/random.d
@@ -124,10 +124,141 @@ version (Posix)
}
/**
+ * Test if Rng is a random-number generator. The overload
+ * taking a ElementType also makes sure that the Rng generates
+ * values of that type.
+ *
+ * A random-number generator has at least the following features:
+ * $(UL
+ * $(LI it's an InputRange)
+ * $(LI it has a 'bool isUniformRandom' field readable in CTFE)
+ * )
+ */
+template isUniformRNG(Rng, ElementType)
+{
+ enum bool isUniformRNG = isInputRange!Rng &&
+ is(typeof(Rng.front) == ElementType) &&
+ is(typeof(
+ {
+ static assert(Rng.isUniformRandom); //tag
+ }));
+}
+
+/**
+ * ditto
+ */
+template isUniformRNG(Rng)
+{
+ enum bool isUniformRNG = isInputRange!Rng &&
+ is(typeof(
+ {
+ static assert(Rng.isUniformRandom); //tag
+ }));
+}
+
+/**
+ * Test if Rng is seedable. The overload
+ * taking a ElementType also makes sure 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)
+{
+ enum bool isSeedable = isUniformRNG!(Rng, ElementType) &&
+ is(typeof(
+ {
+ Rng r = void; // can define a Rng object
+ r.seed(ElementType.init); // can seed a Rng
+ }));
+}
+
+///ditto
+template isSeedable(Rng)
+{
+ enum bool isSeedable = isUniformRNG!Rng &&
+ is(typeof(
+ {
+ Rng r = void; // can define a Rng object
+ r.seed(typeof(r.front).init); // can seed a Rng
+ }));
+}
+
+unittest
+{
+ struct NoRng
+ {
+ @property uint front() {return 0;}
+ @property bool empty() {return false;}
+ void popFront() {}
+ }
+ assert(!isUniformRNG!(NoRng, uint));
+ assert(!isUniformRNG!(NoRng));
+ assert(!isSeedable!(NoRng, uint));
+ assert(!isSeedable!(NoRng));
+
+ struct NoRng2
+ {
+ @property uint front() {return 0;}
+ @property bool empty() {return false;}
+ void popFront() {}
+
+ enum isUniformRandom = false;
+ }
+ assert(!isUniformRNG!(NoRng2, uint));
+ assert(!isUniformRNG!(NoRng2));
+ assert(!isSeedable!(NoRng2, uint));
+ assert(!isSeedable!(NoRng2));
+
+ struct NoRng3
+ {
+ @property bool empty() {return false;}
+ void popFront() {}
+
+ enum isUniformRandom = true;
+ }
+ assert(!isUniformRNG!(NoRng3, uint));
+ assert(!isUniformRNG!(NoRng3));
+ assert(!isSeedable!(NoRng3, uint));
+ assert(!isSeedable!(NoRng3));
+
+ struct validRng
+ {
+ @property uint front() {return 0;}
+ @property bool empty() {return false;}
+ void popFront() {}
+
+ enum isUniformRandom = true;
+ }
+ assert(isUniformRNG!(validRng, uint));
+ assert(isUniformRNG!(validRng));
+ assert(!isSeedable!(validRng, uint));
+ assert(!isSeedable!(validRng));
+
+ struct seedRng
+ {
+ @property uint front() {return 0;}
+ @property bool empty() {return false;}
+ void popFront() {}
+ void seed(uint val){}
+ enum isUniformRandom = true;
+ }
+ assert(isUniformRNG!(seedRng, uint));
+ assert(isUniformRNG!(seedRng));
+ assert(isSeedable!(seedRng, uint));
+ assert(isSeedable!(seedRng));
+}
+
+/**
Linear Congruential generator.
*/
struct LinearCongruentialEngine(UIntType, UIntType a, UIntType c, UIntType m)
{
+ ///Mark this as a Rng
+ enum bool isUniformRandom = true;
/// Does this generator have a fixed range? ($(D_PARAM true)).
enum bool hasFixedRange = true;
/// Lowest generated value ($(D 1) if $(D c == 0), $(D 0) otherwise).
@@ -328,7 +459,15 @@ alias LinearCongruentialEngine!(uint, 48271, 0, 2147483647) MinstdRand;
unittest
{
- static assert(isForwardRange!MinstdRand);
+ assert(isForwardRange!MinstdRand);
+ assert(isUniformRNG!MinstdRand);
+ assert(isUniformRNG!MinstdRand0);
+ assert(isUniformRNG!(MinstdRand, uint));
+ assert(isUniformRNG!(MinstdRand0, uint));
+ assert(isSeedable!MinstdRand);
+ assert(isSeedable!MinstdRand0);
+ assert(isSeedable!(MinstdRand, uint));
+ assert(isSeedable!(MinstdRand0, uint));
// The correct numbers are taken from The Database of Integer Sequences
// http://www.research.att.com/~njas/sequences/eisBTfry00128.txt
@@ -381,6 +520,9 @@ struct MersenneTwisterEngine(
UIntType c, size_t l)
{
static assert(UIntType.min == 0);
+
+ ///Mark this as a Rng
+ enum bool isUniformRandom = true;
/**
Parameter for the generator.
*/
@@ -547,6 +689,10 @@ alias MersenneTwisterEngine!(uint, 32, 624, 397, 31, 0x9908b0df, 11, 7,
unittest
{
+ assert(isUniformRNG!Mt19937);
+ assert(isUniformRNG!(Mt19937, uint));
+ assert(isSeedable!Mt19937);
+ assert(isSeedable!(Mt19937, uint));
Mt19937 gen;
popFrontN(gen, 9999);
assert(gen.front == 4123659995);
@@ -591,6 +737,8 @@ struct XorshiftEngine(UIntType, UIntType bits, UIntType a, UIntType b, UIntType
public:
+ ///Mark this as a Rng
+ enum bool isUniformRandom = true;
/// Always $(D false) (random generators are infinite ranges).
enum empty = false;
/// Smallest generated value.
@@ -777,7 +925,11 @@ alias Xorshift128 Xorshift; /// ditto
unittest
{
- static assert(isForwardRange!Xorshift);
+ assert(isForwardRange!Xorshift);
+ assert(isUniformRNG!Xorshift);
+ assert(isUniformRNG!(Xorshift, uint));
+ assert(isSeedable!Xorshift);
+ assert(isSeedable!(Xorshift, uint));
// Result from reference implementation.
auto checking = [
@@ -844,6 +996,14 @@ method being used.
alias Mt19937 Random;
+unittest
+{
+ assert(isUniformRNG!Random);
+ assert(isUniformRNG!(Random, uint));
+ assert(isSeedable!Random);
+ assert(isSeedable!(Random, uint));
+}
+
/**
Global random number generator used by various functions in this
module whenever no generator is specified. It is allocated per-thread
@@ -1204,7 +1364,7 @@ foreach (e; randomCover(a, rnd))
}
----
*/
-struct RandomCover(Range, Random)
+struct RandomCover(Range, Random) if (isUniformRNG!Random)
{
private Range _input;
private Random _rnd;
@@ -1273,6 +1433,7 @@ struct RandomCover(Range, Random)
/// Ditto
RandomCover!(Range, Random) randomCover(Range, Random)(Range r, Random rnd)
+ if(isUniformRNG!Random)
{
return typeof(return)(r, rnd);
}
@@ -1319,6 +1480,7 @@ foreach (e; randomSample(a, 5))
----
*/
struct RandomSample(R, Random = void)
+ if(isUniformRNG!Random || is(Random == void))
{
private size_t _available, _toSelect;
private R _input;
@@ -1444,7 +1606,7 @@ auto randomSample(R)(R r, size_t n) if (hasLength!R)
/// Ditto
auto randomSample(R, Random)(R r, size_t n, size_t total, Random gen)
-if(isInputRange!R && isInputRange!Random)
+if(isInputRange!R && isUniformRNG!Random)
{
auto ret = RandomSample!(R, Random)(r, n, total);
ret.gen = gen;
@@ -1453,7 +1615,7 @@ if(isInputRange!R && isInputRange!Random)
/// Ditto
auto randomSample(R, Random)(R r, size_t n, Random gen)
-if (isInputRange!R && hasLength!R && isInputRange!Random)
+if (isInputRange!R && hasLength!R && isUniformRNG!Random)
{
auto ret = RandomSample!(R, Random)(r, n, r.length);
ret.gen = gen;
@@ -1479,4 +1641,3 @@ unittest
}
assert(i == 5);
}
-
Something went wrong with that request. Please try again.