Random integers (no permutation)
Show older comments
Let’s say that I have this working example:
lover_bound = 10;
upper_bound = 180;
steps = 10;
NumeroCestelli = 8;
livello = [lover_bound:steps:upper_bound];
L = length(livello);
n_c = ceil((factorial(L+NumeroCestelli-1))/(factorial(NumeroCestelli)*factorial(L-1)));
randIdxs = randi([1,L],n_c,NumeroCestelli);
PianoSperimentale = single(livello(randIdxs));
I need to perform an `n_c x NumeroCestelli` matrix (called `PianoSperimentale`) where each row is unique. It's not allowed any form of permutation. Using randi I can't perform what I'm asking.
[10 20 30 40 50 60 70 80] is equal to [80 70 60 50 40 30 20 10]
`PianoSperimentale` should be a `1081575x8` matrix. In the past I was using the [Combinator](<http://www.mathworks.com/matlabcentral/fileexchange/24325-combinator-combinations-and-permutations)>) function but is very slow for very large matrix.
[PianoSperimentale] = combinator(L,NumeroCestelli,'c','r');
for i=1:L
PianoSperimentale(PianoSperimentale==i)=livello(i);
end
So, there is a way to perform the same matrix that `combinator` do but with `randi` speed?
Answers (2)
Sean de Wolski
on 8 Nov 2013
Use randperm with 'k' option
randperm(10,3)
And for more info:
doc randperm
3 Comments
Sean de Wolski
on 8 Nov 2013
Edited: Sean de Wolski
on 8 Nov 2013
The biggest thing here is preallocation. Simply preallocating R will make this run super fast:
tic
n_c = 1081575;
NumeroCestelli = 8;
L = 180;
R = zeros(n_c,NumeroCestelli);
for k = 1:n_c
R(k,:) = randperm(L, NumeroCestelli);
end
toc
Elapsed time is 3.779653 seconds.
On my relatively wimpy laptop :)
Sean de Wolski
on 8 Nov 2013
Also, you can specify dimension to sort along, e.g.:
sort(magic(3),2)
Rather than double transposing.
Roger Stafford
on 9 Nov 2013
You can use matlab's 'nchoosek' function to generate your desired matrix. It will find all combinations of k=8 things out of n+k-1=25 where n=18 and where no repetitions are allowed. There will be 25!/17!/8! = 1081575 of these. Then these are manipulated so as to find all combinations of k things out of n where repetitions are permitted. Again there will be 1081575 of these.
Here is code that would accomplish that:
v = 10:10:180; % <-- Your livello
n = length(v); % <-- Your L
k = 8; % <-- Your NumeroCestelli
c = nchoosek(1:n+k-1,k)';
N = size(c,2);
q = false(n+k-1,N);
q(c+(n+k-1)*repmat(0:N-1,k,1)) = true;
p = cumsum(~q,1)+1;
r = reshape(v(p(q)),k,[])'; % <-- Your PianoSperimentale
However I doubt that this is any faster than, or even as fast as, Matt Fig's 'combinator' function.
Note: There is a logical flaw in your for-loop code
[PianoSperimentale] = combinator(L,NumeroCestelli,'c','r');
for i=1:L
PianoSperimentale(PianoSperimentale==i)=livello(i);
end
which you presented. With the first value of i = 1, PianoSperimentale will have every element equal to 1 replaced by 10. Unfortunately when you get to i = 10, these same elements will then all be replaced by 100, which I believe is not what you meant to happen.
Categories
Find more on Random Number Generation in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!