www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Not-so-unpredictable seed?

reply Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
Can anyone explain to me why, when I compile & run this code, the two samples 
seeded with the unpredictableSeed always come out with the same starting value?

//////////////////////////////////////////////////////////////
import std.random, std.range, std.stdio;

void main()
{
	auto s = randomSample(iota(0, 100), 5);

	foreach(uint i; s)
		writeln(i);

	writeln();

	auto s2 = randomSample(iota(0, 100), 5);

	foreach(uint i; s2)
		writeln(i);

	writeln();

	auto urng3 = Random(unpredictableSeed);
	auto s3 = randomSample(iota(0, 100), 5, urng3);

	foreach(uint i; s3)
		writeln(i);

	writeln();

	auto urng4 = Random(unpredictableSeed);
	auto s4 = randomSample(iota(0, 100), 5, urng4);

	foreach(uint i; s4)
		writeln(i);
}
//////////////////////////////////////////////////////////////

In fact it's not just the unpredictable seed -- no matter what seed I pass, so 
long as an RNG is passed to the randomSample function, the first entry is
always 
the same.

Note that this is Phobos' randomSample, not my tweaked implementation.

Anyone got any ideas?
Apr 17 2012
next sibling parent reply "jerro" <a a.com> writes:
On Wednesday, 18 April 2012 at 03:47:31 UTC, Joseph Rushton
Wakeling wrote:
 Can anyone explain to me why, when I compile & run this code, 
 the two samples seeded with the unpredictableSeed always come 
 out with the same starting value?

 //////////////////////////////////////////////////////////////
 import std.random, std.range, std.stdio;

 void main()
 {
 	auto s = randomSample(iota(0, 100), 5);

 	foreach(uint i; s)
 		writeln(i);

 	writeln();

 	auto s2 = randomSample(iota(0, 100), 5);

 	foreach(uint i; s2)
 		writeln(i);

 	writeln();

 	auto urng3 = Random(unpredictableSeed);
 	auto s3 = randomSample(iota(0, 100), 5, urng3);

 	foreach(uint i; s3)
 		writeln(i);

 	writeln();

 	auto urng4 = Random(unpredictableSeed);
 	auto s4 = randomSample(iota(0, 100), 5, urng4);

 	foreach(uint i; s4)
 		writeln(i);
 }
 //////////////////////////////////////////////////////////////

 In fact it's not just the unpredictable seed -- no matter what 
 seed I pass, so long as an RNG is passed to the randomSample 
 function, the first entry is always the same.

 Note that this is Phobos' randomSample, not my tweaked 
 implementation.

 Anyone got any ideas?
When you pass in your own random generator, you use this function: auto randomSample(R, Random)(R r, size_t n, Random gen) if (isInputRange!R && hasLength!R && isUniformRNG!Random) { auto ret = RandomSample!(R, Random)(r, n, r.length); ret.gen = gen; return ret; } which calls this constructor: this(R input, size_t howMany, size_t total) { _input = input; _available = total; _toSelect = howMany; enforce(_toSelect <= _available); // we should skip some elements initially so we don't always // start with the first prime(); } According to the comment the call to prime() is necessary so that the result doesn't always start with the same element. But prime() uses the gen member which is only assigned after the constructor completes. So at the time when prime() is called the gen member is in some default state, so the prime() call in the constructor always does the same thing. The fix would be to either modify the constructor to take random generator as a parameter if Random type parameter is not void, or to move the call to prime() out of constructor and into all the randomSample functions. In the ones that have a random generator parameter, the call to prime should come after gen is asigned.
Apr 17 2012
parent reply Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 18/04/12 06:43, jerro wrote:
 According to the comment the call to prime() is necessary
 so that the result doesn't always start with the same element.
 But prime() uses the gen member which is only assigned after the
 constructor completes. So at the time when prime() is called the
 gen member is in some default state, so the prime() call in the
 constructor always does the same thing. The fix would be to
 either modify the constructor to take random generator as a
 parameter if Random type parameter is not void, or to move the
 call to prime() out of constructor and into all the randomSample
 functions. In the ones that have a random generator parameter,
 the call to prime should come after gen is asigned.
Ahhh, clear. I should have worked that out from the code, brain not working right today. :-P It still looks like a serious bug to me, so I've filed a report. http://d.puremagic.com/issues/show_bug.cgi?id=7936
Apr 17 2012
parent "jerro" <a a.com> writes:
On Wednesday, 18 April 2012 at 05:05:20 UTC, Joseph Rushton 
Wakeling wrote:
 On 18/04/12 06:43, jerro wrote:
 According to the comment the call to prime() is necessary
 so that the result doesn't always start with the same element.
 But prime() uses the gen member which is only assigned after 
 the
 constructor completes. So at the time when prime() is called 
 the
 gen member is in some default state, so the prime() call in the
 constructor always does the same thing. The fix would be to
 either modify the constructor to take random generator as a
 parameter if Random type parameter is not void, or to move the
 call to prime() out of constructor and into all the 
 randomSample
 functions. In the ones that have a random generator parameter,
 the call to prime should come after gen is asigned.
Ahhh, clear. I should have worked that out from the code, brain not working right today. :-P It still looks like a serious bug to me, so I've filed a report. http://d.puremagic.com/issues/show_bug.cgi?id=7936
Well, off course it's a bug :D. I opened a pull request: https://github.com/D-Programming-Language/phobos/pull/542
Apr 17 2012
prev sibling parent "jerro" <a a.com> writes:
On Wednesday, 18 April 2012 at 03:47:31 UTC, Joseph Rushton
Wakeling wrote:
 Can anyone explain to me why, when I compile & run this code, 
 the two samples seeded with the unpredictableSeed always come 
 out with the same starting value?

 //////////////////////////////////////////////////////////////
 import std.random, std.range, std.stdio;

 void main()
 {
 	auto s = randomSample(iota(0, 100), 5);

 	foreach(uint i; s)
 		writeln(i);

 	writeln();

 	auto s2 = randomSample(iota(0, 100), 5);

 	foreach(uint i; s2)
 		writeln(i);

 	writeln();

 	auto urng3 = Random(unpredictableSeed);
 	auto s3 = randomSample(iota(0, 100), 5, urng3);

 	foreach(uint i; s3)
 		writeln(i);

 	writeln();

 	auto urng4 = Random(unpredictableSeed);
 	auto s4 = randomSample(iota(0, 100), 5, urng4);

 	foreach(uint i; s4)
 		writeln(i);
 }
 //////////////////////////////////////////////////////////////

 In fact it's not just the unpredictable seed -- no matter what 
 seed I pass, so long as an RNG is passed to the randomSample 
 function, the first entry is always the same.

 Note that this is Phobos' randomSample, not my tweaked 
 implementation.

 Anyone got any ideas?
When you pass in your own random generator, you use this function: auto randomSample(R, Random)(R r, size_t n, Random gen) if (isInputRange!R && hasLength!R && isUniformRNG!Random) { auto ret = RandomSample!(R, Random)(r, n, r.length); ret.gen = gen; return ret; } which calls this constructor: this(R input, size_t howMany, size_t total) { _input = input; _available = total; _toSelect = howMany; enforce(_toSelect <= _available); // we should skip some elements initially so we don't always // start with the first prime(); } According to the comment the call to prime() is necessary so that the result doesn't always start with the same element. But prime() uses the gen member which is only assigned after the constructor completes. At the time when prime() is called the gen member is in some default state, so the prime() call in the constructor always does the same thing. The fix would be to either modify the constructor to take random generator as a parameter if Random type parameter is not void, or to move the call to prime() out of constructor and into all the randomSample functions. In the ones that have a random generator parameter, the call to prime should come after gen is asigned.
Apr 17 2012