The following python code describes exactly what I want to achieve for a sequence of arbitrary size (collection):
import random fixed_seed = 1
The problem with this method is that it requires generating everything first in memory. This can be a problem for large populations.
Note that the potentially big advantage of this method is that you can select any position in the array at any time.
Now - if the problem at hand allows you to set the population size to a power of two (minus 1), a linear feedback shift register can be used to obtain a predictable random sequence. LFSRs are neat and well described in the wikipedia article .
The following is a sample Python code (and I did a bunch of uniqueness tests to make sure that it works as advertised). See the wikipedia article for an explanation of how the code works ( Galois Configuration ).
TAP_MASKS = { #only one needed, but I included 3 to make the code more useful 10: 0x00000240, #taps at 10, 7 16: 0x0000B400, #taps at 16, 14, 13, 11 32: 0xE0000200, #taps at 32, 31, 30, 10 } def MaxLengthLFSR(seed, register_length): "Gets next value from seed in max-length LFSR using Galois configuration." lsb = seed & 1 next_val = seed >> 1 if lsb == 1: mask = TAP_MASKS[register_length] next_val ^= mask return next_val reglen = 16 #number of bits in register population = (2**reglen) - 1 #not used, just showing it fixed_seed = 1 #seed == startval in this case (could randomize in population) sample_count = 5 #demonstration number num_retries = 3 #just enough to show the repeatable behaviour for trynum in xrange(num_retries): next_val = fixed_seed seq = [fixed_seed, ] for x in xrange(sample_count - 1): next_val = MaxLengthLFSR(next_val, reglen) seq.append(next_val) seq = [str(x) for x in seq] print "try %s: %s..." % (trynum + 1, ", ".join(seq)) #Sample output... #try 1: 1, 46080, 23040, 11520, 5760... #try 2: 1, 46080, 23040, 11520, 5760... #try 3: 1, 46080, 23040, 11520, 5760...
This is good because you can have a HUGE population and easily calculate a repeatable sequence of repeating random numbers without using a large chunk of memory.
Disadvantages: a) that it is limited to โshufflingโ size sequences (2 ** N - 1) and b) that you cannot determine what value of a particular position in a random sequence is located at an arbitrary location. You need to know the meaning at a certain point and walk from there.
The latter (b) is mostly approved, as most of the time you will generate the sequence in order, so you just need to remember the last value. The strength of constraint 2 (a) is the kind of deal killer, though ... depending on the application.
How do you achieve non-duplicate results with a maximum LFSR length for an arbitrary sequence length?
As a bonus, it would be nice to have a solution in which you can find out the number in the given position of the sequence without missing the sequence in this position.
Note: if you need a good starting set of LFSR crane locations for LFSRs of maximum length (those that generate the entire set of registers without repeating once), this link is pretty good and has a huge number of tap locations per register size (up to 32 bits, anyway )
Also note that I saw many questions closely related to my question and shuffling / LFSR, but none of them relate to what I need (predictable movement of an arbitrary linear sequence). Or at least as far as I could understand them, anyway.
I recently studied linear congruent generators that seem promising, but I have not been able to get them to work so far. Instead of sitting on the question further, I will ask him and send an answer if I find out and they work.