[a137] seed.

Discuss the future of the AutoHotkey language
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

[a137] seed.

21 Jun 2021, 09:36

Remove RandomSeed() since seeding is no longer possible.
Seeding is very important for reproducability and predictability in certain situations.
Replace MT19937 with RtlGenRandom.
msdn wrote:The RtlGenRandom function is available for use in the operating systems specified in the Requirements section. It may be altered or unavailable in subsequent versions. Instead, use the CryptGenRandom function.
CryptGenRandom maybe can be seeded for such purposes.

I wish you all a great summer, cheers :beer:
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: [a137] seed.

21 Jun 2021, 12:34

yeah, this seems like a regression. now ur forced to roll ur own solution, if u need a seedable generator. and if u needed a MT specifically, then tough luck i guess, i dont think there even exist equivalent dllcallable WINAPI functions for that(since its implemented in the STL)

i dont know how it came to be that the MT had to be ditched. if there were problems with the original implementation, it could have been replaced with a couple lines of STL.
in fact, even if u did want MT gone, bittwiddly code like this...

Code: Select all

	auto &n = *(unsigned int *)(item_curr + 1); // i.e. the randoms are in the odd fields, the pointers in the even.
				GenRandom(&n, sizeof(n));
				n >>= 1;
				// For the above:
				// The random numbers given to SortRandom() must be within INT_MAX of each other, otherwise
				// integer overflow would cause the difference between two items to flip signs depending
				// on how far apart the numbers are, which would mean for some cases where A < B and B < C,
				// it's possible that C > A.  Without n >>= 1, the problem can be proven via the following
				// script, which shows a sharply biased distribution:
				//count := 0
				//Loop total := 10000
				//{
				//	var := Sort("1`n2`n3`n4`n5`n", "Random")
				//	if SubStr(var, 1, 1) = 5
				//		count += 1
				//}
				//MsgBox Round(count / total * 100, 2) "%"
...
	// The first part below produces a 53-bit integer, and from that a value between
		// 0.0 (inclusive) and 1.0 (exclusive) with the maximum precision for a double.
		_f_return((((rand >> 11) / 9007199254740992.0) * (target_max - target_min)) + target_min);
...
	// Do NOT use floating-point to generate random integers because of cases like
		// min=0 and max=1: we want an even distribution of 1's and 0's in that case, not
		// something skewed that might result due to rounding/truncation issues caused by
		// the float method used above.
		// Furthermore, the simple modulo approach is biased when the target range does not
		// divide cleanly into rand.  Suppose that rand ranges from 0..7, and the target range
		// is 0..2.  By using modulo, rand is effectively divided into sets {0..2, 3..5, 6..7}
		// and each value in the set is mapped to the target range 0..2.  Because the last set
		// maps to 0..1, 0 and 1 have greater chance of appearing than 2.  However, since rand
		// is 64-bit, this isn't actually a problem for small ranges such as 1..100 due to the
		// vanishingly small chance of rand falling within the defective set.
		UINT64 u_max = (UINT64)(target_max - target_min);
		if (u_max < UINT64_MAX)
		{
			// What we actually want is (UINT64_MAX + 1) % (u_max + 1), but without overflow.
			UINT64 error_margin = UINT64_MAX % (u_max + 1);
			if (error_margin != u_max) // i.e. ((error_margin + 1) % (u_max + 1)) != 0.
			{
				++error_margin;
				// error_margin is now the remainder after dividing (UINT64_MAX+1) by (u_max+1).
				// This is also the size of the incomplete number set which must be excluded to
				// ensure even distribution of random numbers.  For simplicity we just take the
				// number set starting at 0, since use of modulo below will auto-correct.
				// For example, with a target range of 1..100, the error_margin should be 16,
				// which gives a mere 16 in 2**64 chance that a second iteration will be needed.
				while (rand < error_margin)
					// To ensure even distribution, keep trying until outside the error margin.
					GenRandom(&rand, sizeof(rand));
			}
			rand %= (u_max + 1);
		}
		_f_return((INT64)(rand + (UINT64)target_min));
...ought to be replaced with STL code regardless.
if it took however many years to figure out something was wrong with the Random implementation, who's to say this one, this time, is correct? im not saying it isnt, but im not an expert on that topic, i cant audit this code.
if it was based on the STL, ud at least have the assurance that it was implemented by a team of people(that supposedly know wtf theyre meant to be doing), its got widespread usage, so if something was eventually found to be wrong, all ud have to do is recompile to get the fixes - no extra maintenance burden to urself. also other people would be able to understand more easily what the code does(if u care about that kinda thing)

if u wanted a cryptographically secure generator, that should have better been a brand new built-in function instead, SecureRandom() or some such. but even if that turned out not to be the case, it would have been fine - cryptographically secure generators u could implement in-script via DllCall no problem
Aetzbarr
Posts: 25
Joined: 20 Jun 2020, 06:18

Re: [a137] seed.

22 Jun 2021, 05:56

I also think a seedable PRNG is useful. It should work like this - if you don't call RandomSeed() or call RandomSeed() without parameters, Random() calls RtlGetRandom; if you call RandomSeed(n), it seeds Mersenne Twister (or another PRNG) with n, and from now on Random() uses that PRNG to get 64 bits (for example by calling Mersenne Twister twice), until you call RandomSeed() without parameters. In other words by default Random() returns truly cryptographic random numbers as in a137, but by seeding the user can opt in to get a reproducible deterministic sequence.
lexikos
Posts: 9556
Joined: 30 Sep 2013, 04:07
Contact:

Re: [a137] seed.

25 Jun 2021, 04:06

I was aware that RandomSeed() makes the results deterministic. The option to supply a seed was first suggested by Laszlo for this purpose:
Laszlo wrote: What could be really useful is an option to seed the random number generator with a user supplied value. This would make scripts deterministic, useful for tests. If no explicit seeding was performed, the standard timer seed is to be used.
Source: More secure random numbers - Scripts and Functions - AutoHotkey Community
Chris wrote: Great suggestion. I will do this.
Source: More secure random numbers - Scripts and Functions - AutoHotkey Community
And yet, the documentation never mentioned making the results deterministic, only improving the "quality/security" of the random numbers. But if the user chooses the seed poorly, the quality/security of the random numbers only suffers. Here's an example:

Code: Select all

Random,,%A_TickCount%
Why did this user choose to reseed, and with this value? The upper bits of the tick count do not change very often. The most significant bit is 0 for the first 24.8 days that the computer is running, the next bit 12.4 days, and so on. If the script runs at system startup and the system usually takes around the same amount of time to start, the seed will be pretty similar each time. As for the default seed ...
the low-order 32-bits traverses its full 32-bit range every 7.2 minutes, which seems to make using it as a seed superior to GetTickCount for most purposes
Source: Chris, script.cpp
Without RandomSeed(), no one will waste their time reading about it or considering using it, or sabotage their own efforts by choosing the seed poorly.

As for reproducing sequences of pseudo-random numbers, the only instance of actual use I've come across was a proof of concept for a gaming application. The OP didn't share details, and the topic was about an inherent issue with this capability: it relies on shared global state. An incorrect sequence is generated if the RNG is unexpectedly invoked part way through the sequence, whether due to thread interruption, a call to a function that independently uses Random or Sort Random, or some hypothetical future feature that utilizes RNG.

The suggested solutions were:
Helgef wrote:
12 Jul 2017, 06:00
If you want the same sequences, just precalculate them,
... or use C#.

It would also be reasonably trivial to compile a C++ dll exposing some of the RNG functionality of STL, in which case different parts of the script can have different RNG state, or even separate algorithms.

Helgef wrote:The RtlGenRandom function is [deprecated]
I am well aware. I researched the choice of API and related topics for several hours, and came to the conclusion that 1) RtlGenRandom is not likely to actually be removed, 2) the recommended APIs are not likely to offer any benefit, and 3) if it ever is removed, it will be easy to replace or supplement with another API (or perhaps a single rdrand CPU instruction, as older CPUs are less likely to run future versions of Windows).
CryptGenRandom maybe can be seeded for such purposes.
No, not for reproducibility (making the results deterministic).
To form the seed for the random number generator, a calling application supplies bits it might have—for instance, mouse or keyboard timing input—that are then combined with both the stored seed and various system data and user data [...] This result is used to seed the pseudorandom number generator (PRNG).
Source: CryptGenRandom function (wincrypt.h) - Win32 apps | Microsoft Docs

Aetzbarr wrote:
22 Jun 2021, 05:56
It should work like this
I had already considered this and do not think it would be wise. For assurance that the random numbers will be of cryptographic quality, script libraries would need to call RandomSeed() without parameters and prevent any thread interruption. It would be more reliable to use DllCall.
lexikos
Posts: 9556
Joined: 30 Sep 2013, 04:07
Contact:

Re: [a137] seed.

25 Jun 2021, 04:12

swagfag wrote:
21 Jun 2021, 12:34
now ur forced to roll ur own solution, if u need a seedable generator.
I have no problem with this whatsoever.
and if u needed a MT specifically, then tough luck i guess,
Actually, jeeswg already translated it to ahk. Also, the STL includes an MT implementation, so it would be trivial for someone to compile a DLL for use with AutoHotkey.
it could have been replaced with a couple lines of STL.
You don't just use a couple lines of STL. All of the relevant code has to be included in the binary. A straight-forward implementation using std::mt19937_64 with std::uniform_real_distribution<double> for floating-point numbers, std::uniform_int_distribution<__int64> for integers and std::uniform_int_distribution<int> for Sort Random currently increases code size by around 7.5 KB. These template classes are designed to take an arbitrary number of bits from each RNG call and produce an integer or floating-point number of an arbitrary size, so they are not optimal.

For comparison, replacing mt19937ar-cok.cpp with RtlGenRandom "refunded" about 200 bytes, some of which I then "spent" improving Random, and replacing RtlGenRandom with mt19937ar-cok.cpp now (calling genrand_int32 twice for 64-bit values) would cost about 600 bytes.

bittwiddly code like this ... ought to be replaced with STL code regardless.
Because it's bittwiddly? :roll:
also other people would be able to understand more easily what the code does
That's doubtful.

Consider a simplified Random() that takes exactly two floating-point parameters;

Code: Select all

std::mt19937_64 g_rng; // g_rng.seed() is called on startup.

BIF_DECL(BIF_Random)
{
	double nmin = ParamIndexToDouble(0), nmax = ParamIndexToDouble(1);
	_f_return(std::uniform_real_distribution<double>(nmin, nmax)(g_rng));
	//or
	//std::uniform_real_distribution<double> distribution(nmin, nmax);
	//_f_return(distribution(g_rng));
}
What does this tell you about what the code does, that wouldn't be more clearly written in the documentation? If you want to know how the number is calculated (without running it in a debugger), you must drill into multiple template definitions, follow inheritance, operator/method calls and macro definitions, and be able to both interpret what you're seeing and put it all together. By comparison, the current implementation edited down to its core parts (for floating-point) is simple (the comments were included):

Code: Select all

BIF_DECL(BIF_Random)
{
	double nmin = ParamIndexToDouble(0), nmax = ParamIndexToDouble(1);
	UINT64 rand = 0;
	GenRandom(&rand, sizeof(rand));
	// The first part below produces a 53-bit integer, and from that a value between
	// 0.0 (inclusive) and 1.0 (exclusive) with the maximum precision for a double.
	_f_return((((rand >> 11) / 9007199254740992.0) * (target_max - target_min)) + target_min);
}
The integer part is more complicated, but not as complicated as the Microsoft STL implementation.
Aetzbarr
Posts: 25
Joined: 20 Jun 2020, 06:18

Re: [a137] seed.

25 Jun 2021, 06:17

Also, writing our own PRNG is easier now that we have the new >>> and >>>= operators.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: [a137] seed.

27 Jun 2021, 13:22

lexikos wrote:
25 Jun 2021, 04:06
And yet, the documentation never mentioned making the results deterministic, only improving the "quality/security" of the random numbers.
isnt that already implied by the concept of a pseudo-random number generator?
As for reproducing sequences of pseudo-random numbers, the only instance of actual use I've come across was a proof of concept for a gaming application.
ive combed through my scripts for reseeding usages and ive used it once in an abandoned flappy bird clone, once in a monte carlo experiment i was trying out and 3 times just for debugging purposes(but not in production) as i was writing the script. obviously this code isnt uploaded anywhere(publicly accessible, at least that im aware), so u wouldnt have been able to come across it. we dont know how many other similar instances exist but ill grant u this much, reseeding probably isnt that popular a feature
The OP didn't share details, and the topic was about an inherent issue with this capability: it relies on shared global state.
seems to me he simply needed 3 separate instances of the PRNG engine(seeded with a particular number. perhaps the same number, perhaps a different one, doesnt matter). i imagine something equivalent to:

Code: Select all

std::mt19937_64 engine1;
std::mt19937_64 engine2;
std::mt19937_64 engine3;
this wouldnt have been possible with the old MT implementation, since there only ever was one instantiated engine, so what he wanted(using ahk builtin code) was impossible from the outset
Without RandomSeed(), no one will waste their time reading about it or considering using it, or sabotage their own efforts by choosing the seed poorly.
fair enough
The suggested solutions were:
  • If you want the same sequences, just precalculate them,
  • ... or use C#.
ok, yeah the latter would work, i suppose
It would also be reasonably trivial to compile a C++ dll exposing some of the RNG functionality of STL, in which case different parts of the script can have different RNG state, or even separate algorithms.
as would this, the only downside being u now got to haul a DLL around
lexikos wrote:
25 Jun 2021, 04:12
Actually, jeeswg already translated it to ahk.
ive looked for it but wasnt able to find anything(and its not like i can ask him for it, for obvious reasons....), so i ported the v1 random to v2, so it can be used like the guy in the proof of concept for a gaming application thread wanted to, ie to have multiple seedable generators:

Code: Select all

#Requires AutoHotkey v2.0-a137-f6f65742

Engine1 := RandomAHKv1(0)
Engine2 := RandomAHKv1(0)

str1 := ''
str2 := ''

Loop 5
{
	str1 .= Engine1.Random() ','
	str2 .= Engine2.Random() ','
}

MsgBox str1 '`n' str2

class RandomAHKv1 {
	; check v1.1.33.09 source/docs for implementation details,
	; requirements, permitted values, guarantees, etc..
	__New(ui32Seed := unset) {
		if !IsSet(ui32Seed)
			ui32Seed := A_TickCount

		try
			this.Seed(ui32Seed)
		catch as Err
			throw %Type(Err)%(Err.Message, -1, Err.Extra)
	}

	Random(min := 0, max := 0x7FFFFFFF) {
		if (min > max)
			throw ValueError(A_ThisFunc ' failed. Min exceeds Max.', -1, min " > " max)

		if (IsFloat(min) || IsFloat(max)) ; either is float
			return (this.MT.genrand_real1() * (max - min)) + min
		else
			return Mod(this.MT.genrand_int32(), max - min + 1) + min
	}

	Seed(ui32Seed) {
		if (!IsInteger(ui32Seed) || (ui32Seed < 0 || ui32Seed > 0xFFFFFFFF))
			throw ValueError(A_ThisFunc ' failed due to invalid seed. A 32-bit unsigned int was expected.', -1, ui32Seed)

		this.MT := MT19937(ui32Seed)
	}
}

/*
   C++ functions for MT19937, with initialization improved 2002/2/10.
   Coded by Takuji Nishimura and Makoto Matsumoto.
   This is a faster version by taking Shawn Cokus's optimization,
   Matthe Bellew's simplification, Isaku Wada's real version.

   Before using, initialize the state by using init_genrand(seed)
   or init_by_array(init_key, key_length).

   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:

     1. Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.

     2. Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.

     3. The names of its contributors may not be used to endorse or promote
        products derived from this software without specific prior written
        permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


   Any feedback is very welcome.
   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
   email: [email protected]
*/
class MT19937 extends Array {
	left := 0
	next := 0

	; zero-based array
	__Item[i] {
		get => super[i + 1]
		set => super[i + 1] := value
	}

	; // initializes state[N] with a seed
	; void init_genrand(unsigned long s)
	; {
	;     int j;
	;
	;     state[0]= s & 0xffffffffUL;
	;     for (j=1; j<N; j++) {
	;         /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
	;          * In the previous versions, MSBs of the seed affect
	;          * only MSBs of the array state[].
	;          * 2002/01/09 modified by Makoto Matsumoto             */
	;         state[j] = (1812433253UL * (state[j-1] ^ (state[j-1] >> 30)) + j);
	;         state[j] &= 0xffffffffUL;  // for >32 bit machines
	;     }
	;     left = 1;
	; 	  initf = 1;
	; }
	__New(ui32Seed) {
		static N := 624 ; Period parameters
		this.Length := N

		this[0] := ui32Seed & 0xffffffff

		; for (j=1; j<N; j++)
		j := 1
		while (j < N)
		{
			this[j] := (1812433253 * (this[j - 1] ^ (this[j - 1] >> 30)) + j)
			this[j] &= 0xffffffff
			j++
		}

		this.left := 1
	}

	; static void next_state(void)
	; {
	;     unsigned long *p=state;
	;     int j;
	;
	;     // if init_genrand() has not been called, a default initial seed is used
	;     if (initf==0)
	;         //init_genrand((unsigned long)time(NULL));  // get timer value
	;         init_genrand(GetTickCount()); // Avoiding the c-lib time functions reduces code size for AHK.
	;
	;     left = N;
	;     next = state;
	;
	;     for (j=N-M+1; --j; p++)
	;         *p = p[M] ^ TWIST(p[0], p[1]);
	;
	;     for (j=M; --j; p++)
	;         *p = p[M-N] ^ TWIST(p[0], p[1]);
	;
	;     *p = p[M-N] ^ TWIST(p[0], state[0]);
	; }
	next_state() {
		static N := 624 ; Period parameters
		static M := 397 ; Period parameters

		p := 0
		this.left := N
		this.next := 0

		; for (j=N-M+1; --j; p++)
		j := N - M + 1
		while (--j)
		{
			; *p = p[M] ^ TWIST(p[0], p[1]);
			pM := this[p + M]
			p0 := this[p]
			p1 := this[p + 1]
			this[p] := pM ^ TWIST(p0, p1)
			p++
		}

		; for (j=M; --j; p++)
		j := M
		while (--j)
		{
			; *p = p[M-N] ^ TWIST(p[0], p[1]);
			pMN := this[p + M - N]
			p0 := this[p]
			p1 := this[p + 1]
			this[p] := pMN ^ TWIST(p0, p1)
			p++
		}

		; *p = p[M-N] ^ TWIST(p[0], state[0]);
		pMN := this[p + M - N]
		p0 := this[p]
		this[p] := pMN ^ TWIST(p0, this[0])

		; #define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) )
		MIXBITS(u, v) {
			static UMASK := 0x80000000 ; // most significant w-r bits
			static LMASK := 0x7fffffff ; // least significant r bits
			return (u & UMASK) | (v & LMASK)
		}

		; #define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL))
		TWIST(u, v) {
			static MATRIX_A := 0x9908b0df ; // constant vector a
			return (MIXBITS(u, v) >> 1) ^ ((v & 1) ? MATRIX_A : 0)
		}
	}

	; // generates a random number on [0,0xffffffff]-interval
	; unsigned long genrand_int32(void)
	; {
	;     unsigned long y;
	;
	;     if (--left == 0)
	; 		next_state();
	;     y = *next++;
	;
	;     // Tempering
	;     y ^= (y >> 11);
	;     y ^= (y << 7) & 0x9d2c5680UL;
	;     y ^= (y << 15) & 0xefc60000UL;
	;     y ^= (y >> 18);
	;
	;     return y;
	; }
	genrand_int32() {
		if (--this.left = 0)
			this.next_state()
		y := this[this.next++]

		; // Tempering
		y ^= (y >> 11)
		y ^= (y << 7) & 0x9d2c5680
		y ^= (y << 15) & 0xefc60000
		y ^= (y >> 18)

		return y
	}

	; // generates a random number on [0,1]-real-interval
	; double genrand_real1(void)
	; {
	;     ...
	;     return (double)y * (1.0/4294967295.0);
	;     // divided by 2^32-1
	; }
	genrand_real1() => this.genrand_int32() * (1.0/4294967295.0)
}
imo this hardly addresses anything. now u have to trust me i implemented it correctly(and even i dont trust myself enough to believe that). or in the case of jeeswg's code - him. or in the case of ahk's source - you(and/or whoever wrote it originally back in the day). and if u used the STL - one or more microsoft guys(who i must assume must be at least somewhat knowledgeable about cryptography, why otherwise would they be charged with maintaining the <random> header of the STL??).
now ask urself this, how many people who actually understand this shit have taken the time to audit my code? what about jeeswg's code? ahk's source? the STL? i dont have an answer for these questions, its probably impossible to tell anyways, but i think u see what im getting at...
... increases code size by around 7.5 KB.
... with RtlGenRandom "refunded" about 200 bytes
ok, i mean, in isolation 7500 bytes vs -200 bytes seems huge, but the exe is like 1meg. why does it matter if it ends up being 1meg or 1.007megs?
That's doubtful.
i beg to differ

Code: Select all

_f_return(std::uniform_real_distribution<double>(nmin, nmax)(g_rng));
...
// The first part below produces a 53-bit integer, and from that a value between
// 0.0 (inclusive) and 1.0 (exclusive) with the maximum precision for a double.
_f_return((((rand >> 11) / 9007199254740992.0) * (target_max - target_min)) + target_min);
What does this tell you about what the code does, that wouldn't be more clearly written in the documentation?
considering im no expert at this as previously mentioned, in either case i wont be able to interpret what im seeing, and yet the first one tells me i should have great deal of confidence(for reasons already discussed) im getting a number back evenly distributed along the interval [a,b)
the other one tells me i should take at face value the code does what the comment says it does
lexikos
Posts: 9556
Joined: 30 Sep 2013, 04:07
Contact:

Re: [a137] seed.

28 Jun 2021, 06:27

swagfag, what is your purpose?

You already know what the code does, because you're looking at the implementation of the Random function, which has clearly documented input/output. To say that you would "understand" the code better if it was delegating its implementation to some other function, the implementation of which you are going to completely ignore because you trust Microsoft's developers and documentation, is pointless. Perhaps you should give up AutoHotkey and use C++ directly.

I think your confidence in Microsoft is misplaced. For instance, there is an open issue on GitHub wherein two problems with the Microsoft implementation of uniform_real_distribution<float> are described and the author indicates that the "canonical" method - which is the one I used - has neither problem.

Aside from STL and .NET, there are also implementations in other scripting languages, such as JavaScript, which doesn't appear to have a seedable PRNG built-in. These might be easier to translate, although personally I think you exaggerate the difficulty of translating mt19937ar-cok.cpp. You may already know that it isn't cryptographically secure; if you're not sure about your translation, just test it against the properties you need (such as uniformity and reproducibility).

Some other script interpreters are 5-10MB. Is this what I should aim for with AutoHotkey? If I don't care about 7.5KB for one change of dubious benefit, what about each and every change that comes after it?

isnt that already implied by the concept of a pseudo-random number generator?
Who do you expect to implicitly understand that? The same user who needs this explanation?
This function returns a pseudo-randomly generated number, which is a number that simulates a true random number but is really a number based on a complicated formula to make determination/guessing of the next number extremely difficult.
Source: Random - Syntax & Usage | AutoHotkey v2
Or this one?
Reseeding can improve the quality/security of generated random numbers
Source: Random - Syntax & Usage | AutoHotkey
As I already pointed out, the Windows RNG combines any supplied seed with other seeds. Seeding in that case is only to increase entropy, which would be in line with the apparent documented purpose of Random,,NewSeed (above). How do you know that Random,,NewSeed won't do the same?


I have yet to see even a single example that satisfactorily demonstrates the usefulness of reseeding at all, let alone to the extent that would justify it as a built-in feature despite its limitations. Perhaps there are some in private or proprietary scripts, but I expect there are also scripts using Random,,NewSeed to little or detrimental effect, more scripts that use it for reproducing sequences but have issues due to thread interruption, alternative solutions by authors who didn't know they could use it that way, and vastly more scripts that never needed it.
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: [a137] seed.

29 Jun 2021, 07:53

lexikos wrote:
28 Jun 2021, 06:27
swagfag, what is your purpose?
my purpose? was to try and suggest an alternative, (then-presumed, ill get back to that) more robust way of addressing the issue that was supposed to be self-maintainable(ie, microsoft would maintain it), in order to ensure there would be a need to revisit this topic yet again 10 years from now, in case someone does end up unveiling more issues with the current reimplementation. trust me when i say i only mean well
You already know what the code does, because you're looking at the implementation of the Random function, which has clearly documented input/output. To say that you would "understand" the code better if it was delegating its implementation to some other function, the implementation of which you are going to completely ignore because you trust Microsoft's developers and documentation, is pointless.
this isnt just about me in particular. its about anyone who might wanna look at the source. its one thing seeing std::uniform_real_distribution, and a whole nother - bitshift barf. i also explained the reasons for instead wanting to go with the STL in my previous post
Perhaps you should give up AutoHotkey and use C++ directly.
:lol: believe me i wish, im not that hardcore though
I think your confidence in Microsoft is misplaced. For instance, there is an open issue on GitHub wherein two problems with the Microsoft implementation of uniform_real_distribution<float> are described and the author indicates that the "canonical" method - which is the one I used - has neither problem.
well, thats a twist if i ever saw one. honestly wasnt expecting that, although it does appear its an issue with C++ itself. the MS guys have implemented it according to the standard...which happens to be wrong/ambiguous. in that case its pointless to argue any further
in other scripting languages, such as JavaScript, which doesn't appear to have a seedable PRNG built-in....
....I have yet to see even a single example that satisfactorily demonstrates the usefulness of reseeding at all
yes, i agreed, seeding probably wasnt as popular a feature
Some other script interpreters are 5-10MB. Is this what I should aim for with AutoHotkey?
i dont know. what do you want to aim for? personally, i wouldnt care much if it was 5mb or 10mb. i dont write a ton of 10 line scripts and compile them afterwards, but even if i did i wouldnt care about the disk space either way. but i understand there might be people that do, perhaps ure even one of them. i also understand there could be other considerations, eg network costs if people now had to download 10mb interpreters instead. what cant know is how big of an issue that is. how could i?
If I don't care about 7.5KB for one change of dubious benefit, what about each and every change that comes after it?
i mean yeah ok i get, slippery slope and all that. everything's a trade-off. researching correct implementations of random VS code size. u chose the former, thats fine
Who do you expect to implicitly understand that?
a "pseudo-random number generator" is not something unique to autohotkey. u can read up on it and its properties in other places, too(if u dont implicitly understand them)
How do you know that Random,,NewSeed won't do the same?
if it doesnt state its going to also mix in some other random numbers along with the seed i gave it, i have no reason to believe its going to do that.
other than that i guess u could try checking in-script and observing the behavior using different seeds(inconclusive)
the only way to be sure, would be of course to check the source(assuming its available)
lexikos
Posts: 9556
Joined: 30 Sep 2013, 04:07
Contact:

Re: [a137] seed.

29 Jun 2021, 22:11

swagfag wrote:
29 Jun 2021, 07:53
this isnt just about me in particular.
I was mostly speaking generally, not about you. :roll:
a "pseudo-random number generator" is not something unique to autohotkey. u can read up on it and its properties in other places, too(if u dont implicitly understand them)
I think that fails to address my question. You're basically implying that something that no one could intuitively understand without prior knowledge of RNG doesn't need to be documented because they can learn it elsewhere.

Because it's not documented, fewer users would ever use it; and I think of all users, those who realize it is possible because they know about PRNG would be more likely able to find an alternative solution.
if it doesnt state its going to also mix in some other random numbers along with the seed i gave it, i have no reason to believe its going to do that.
It doesn't state that it is not going to, or how the "seed" is used or what it is, or that the results will be the same given the same seed and min/max. If one is familiar with CryptGenRandom, they would have reason to doubt that. If one assumes the purpose is to "improve the quality/security of generated random numbers", one would have reason. If one doesn't know much about the topic, it is very likely that they won't have reason to believe anything not explicitly documented, or to consider the possibility of how else the seed could be used.
the only way to be sure, would be of course to check the source(assuming its available)
The source code of the current implementation is no guarantee for future versions.
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: [a137] seed.

24 Aug 2021, 07:47

Hi all 🌞
As for reproducing sequences of pseudo-random numbers, the only instance of actual use I've come across was a proof of concept for a gaming application.
I'm not asking for multiple streams, although that would be one notch better than one global.

I've used seeding many times. It is good practice for example when benchmarking code which has random components. Code like this is typically not shared. I used seeding publicly once as far as I can remember, :arrow: Pzulze 13: Uamcsblrne!.

I don't see the usefulness of debating the usefulness of seeding for predictability, I take it as a given and if anyone disagrees, that is fine.

Cheers.
User avatar
vvhitevvizard
Posts: 454
Joined: 25 Nov 2018, 10:15
Location: Russia

Re: [a137] seed.

24 Aug 2021, 10:17

I, for one, agree with you. Repeatability of rnd sequences is useful for profiling/optimizing.
User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: [a137] seed.

25 Sep 2021, 05:45

Its a basic feature most languages do have
Recommends AHK Studio

Return to “AutoHotkey Development”

Who is online

Users browsing this forum: No registered users and 35 guests