Random permutation of integers from 1 to n without repetition but for large n
5 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
Hi,
I want to use a for loop but iterate through the loop indices in a random order. So I want to have a random permutation of integers 1 to n without repetition. I saw that this can be achieved by simply using the randperm function and something like this would be exactly what I would want:
for i = randperm(n)
%some code
end
However my problem is that my n might be very large, so that using the randperm function becomes infeasible because generating the whole array of length n would exceed the memory limit. So my question would be if you can achieve the same functionality but without generating the whole array. Instead maybe have a function which only generates one integer at a time or some subpart which is small enough to store while making sure that you never generate the same number twice in a later call to the function.
Alternatively formulated: draw a random number from a pool of integers from 1 to n but each time you draw something remove it from the pool of possible integers you can draw.
Thank you for your help!
6 comentarios
Bruno Luong
el 13 de Feb. de 2023
@dpb "it may well turn out to be that there's not enough time to wait for those N calculations to be completed, anyways..."
Why? Looping on n=8e9 is totally feasible, whereas storing such permutation vector of this size is not possible for 99% of PC outthere.
Respuestas (2)
John D'Errico
el 11 de Feb. de 2023
Editada: John D'Errico
el 11 de Feb. de 2023
Almost always, when I see someone wanting to solve a problem in this way, it means they are trying to use brute force, thus a brute force exploration of a huge search space, when an optimization tool would be a better choice. And yes, brute force is a reasonable choice for small problems. It is just faster to solve some problems that way than writing better code.
HOWEVER, IF you cannot possibly find a way to solve this problem without the use of brute force, hey its your life, while you sit there waiting for your code to terminate. You can choose how to spend the time. You might get a big book to read while you wait though. Remember, that If your code needs to generate trillions of permutations, you will be there waiting for a long time. Whatever floats your boat. I would be seriously looking to reformulate the problem, were it me.
If you still cannot do so, then one idea might be to use a function that returns the next permutation, given the previous permutation from a vector. That would not be too difficult to write. In fact, it already exists on the FEX, so I would not write it myself anyway. (And the code seems reasonably well written.)
For example:
V = 1:3;
V = nextperm(V)
V =
1 3 2
V = nextperm(V)
V =
2 1 3
V = nextperm(V)
V =
2 3 1
V = nextperm(V)
V =
3 1 2
V = nextperm(V)
V =
3 2 1
V = nextperm(V)
V =
1 2 3
Be carefiul, in that nextperm seems to happily wrap around. So when you have called it factorial(n) times, you need to stop.
17 comentarios
Bruno Luong
el 14 de Feb. de 2023
Editada: Bruno Luong
el 15 de Feb. de 2023
"But I cant do that because n is to large to store the whole array generated by randperm(n)."
But we did not tell you to do that, we tell you to generate
iarray = randperm(n,niter);
where niter is reasonably in both of computation time and memory, something about 1e9 for many computers.
It can be generated on mine with niter = 1e9, it take few minutes though with a peak memory above 32 Gb during the array is being geneated, and become 8 Gb + other stuffs when the array is being used.

To keep track of of what has been processes before it would slow down considerably (the complexity become n^2) + whatever you want to do with i. So this is a bad strategy and I doubt you can go up to 1e9 iterations. The randperm function uses perhaps one of the variants of Fisher Yates algoritm and according to this wiki page it is optimum in space and time (both is O(n)). So you won't be able to do it better or make the memory requirement going away, beside use smaller type such as uint32 class.
If that value niter is too small to suit for your need, then do Matt tell you : buy a bigger computer.
Image Analyst
el 12 de Feb. de 2023
You ask "looking for a way to avoid storing the whole 1:n! but instead draw only some subset at a time"
Well, randperm allows you to specify some number of elements to be in your subnet. For example for n=5, and n!=120:
n = 5;
subset = randperm(factorial(n), 6) % Retrieve 6 numbers
2 comentarios
Bruno Luong
el 13 de Feb. de 2023
Why everybody speaks about factorial here? OP wants just to iterate on ONE random permutation where n is large, for example n is world population , ~ 8e9.
Image Analyst
el 13 de Feb. de 2023
Editada: Image Analyst
el 13 de Feb. de 2023
@Bruno Luong the original poster said "I just want to have one permutation of one large vector 1:n, for any large n, just by chance in my case n=N!" So I was just going by what he said. To mach his terminology I guess I should have done.
N = 9; % Whatever....
n = factorial(N);
subset = randperm(n, 6) % Retrieve 6 numbers
Ver también
Categorías
Más información sobre Loops and Conditional Statements en Help Center y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!