Different number of for loops

20 views (last 30 days)
Vasilis Chasiotis
Vasilis Chasiotis on 30 Sep 2020
Edited: Vasilis Chasiotis on 30 Sep 2020
I want my input to be a number at least 9 or 10, say n, and I need a code to create n number of for loops. I need to change the number of loops, because I have many cases with different number of n variables.
Each loop starts from 0 but ends to a different number. In order to keep a solution, I have an if statement.
For example, for n=4 loops,
n = 4;
for x1 = 0:9
for x2 = 0:5
for x3 = 0:5
for x4 = 0:5
if x1+x2+x3+x4==10
....
end
end
end
end
end
For n=10 loops,
n = 10;
for x1 = 0:9
for x2 = 0:5
for x3 = 0:5
for x4 = 0:5
for x5 = 0:5
for x6 = 0:5
for x7 = 0:4
for x8 = 0:4
for x9 = 0:5
for x10 = 0:9
if x1+x2+x3+x4+x5+x6+x7+x8+x9+x10==32
.....
end
end
end
end
end
end
end
end
end
end
end
How I can create this code, using an index vector and one loop, or recursive function?
I have read:
  1. https://www.mathworks.com/matlabcentral/answers/345551-function-with-varying-number-of-for-loops
  2. https://www.mathworks.com/matlabcentral/answers/333926-recursive-function-for-replacing-multiple-for-loops
but I did not achieve my goal.
Thank you in advance!

Answers (2)

KSSV
KSSV on 30 Sep 2020
x1 = 0:9 ;
x2 = 0:5 ;
x3 = 0:5 ;
x4 = 0:5 ;
[x1,x2,x3,x4] = ndgrid(x1,x2,x3,x4) ;
thesum = x1+x2+x3+x4 ;
idx = thesum == 10 ;
iwant = [x1(idx) x2(idx) x3(idx) x4(idx)] ;
Now iwant has the values which obeys your condition. You can use them.
Wont this logic work?
  8 Comments
KSSV
KSSV on 30 Sep 2020
I tried for n = 4...ndgrid taking less time.
Show us the code whcih you have tried.
Vasilis Chasiotis
Vasilis Chasiotis on 30 Sep 2020
For n=4 ndgrid is faster, but not for n=10.
n = 10;
for x1 = 0:9
for x2 = 0:5
for x3 = 0:5
for x4 = 0:5
for x5 = 0:5
for x6 = 0:5
for x7 = 0:4
for x8 = 0:4
for x9 = 0:5
for x10 = 0:9
if x1+x2+x3+x4+x5+x6+x7+x8+x9+x10==32
.....
end
end
end
end
end
end
end
end
end
end
end
The above nested for loops are faster than the corresponding ndgrid.

Sign in to comment.


Walter Roberson
Walter Roberson on 30 Sep 2020
See https://www.mathworks.com/matlabcentral/answers/357969-using-recursive-function-to-calculate-all-possible-peptide-combinations#answer_282766 for what I refer to as the "odometer" pattern (thanks to Chris Torek for the naming suggestion.)
I show there how to use a single for loop to implement incrementing through any number of levels where each level has a finite list of permitted values. The general pattern does not require that the different levels are the same datatype (it is just that the code can be made more compact and use less memory if they are all the same datatype.)
This will not be faster than nested for loops.
There is no general pattern that is faster than nested for loops, because in general it is not always possible to vectorize the work to be done for each combination.
The example you post shows a test for a fixed sum. If the fixed sum is the only acceptable case, then starting around x6 instead of
for x6 = 0:5
for x7 = 0:4
you could
left5 = 32 - (x1+x2+x3+x4+x5);
for x6 = 0: min(5, left5);
left6 = left5 - x6;
for x7 = 0:min(4, left6)
That is, you already have enough information to be able to prune some of the possibilities.
But also consider that asking for the sum of a list of non-negative integer numbers to add up to a particular number, is called a "partition problem", and there are techniques for generating the list of matching values. See for example https://www.mathworks.com/matlabcentral/fileexchange/12009-partitions-of-an-integer
  2 Comments
Vasilis Chasiotis
Vasilis Chasiotis on 30 Sep 2020
Thank you very much for your answer. I will check "odometer".
Obviously, I can do what you said about left5=..., but I am trying to avoid nested for loops.
About partition - already exisitng codes in MATLAB for partitions use positive integer number, but I have non-negative numbers, since I need 0 as well.
Vasilis Chasiotis
Vasilis Chasiotis on 30 Sep 2020
Edited: Vasilis Chasiotis on 30 Sep 2020
Actually, the ''odometer" pattern works perfectly. I made all the necessary changes, converting the code, in order to achieve my goal.
In the following code, we create all possible cases with values 0:5 in 4 places, keeping those for which their sum is equal to 13.
Only the case with 0's in all places does not constructed. However, it is useless, since we are looking for cases whose sum is positive.
This code is a conversion of "odometer" pattern from Walter Roberson as an answer in:
***Many thanks to Walter Roberson for letting me know about his code refered as the "odometer" pattern.
num_diff_vals = [5 5 5 5]; %the maximum value for each place
%the minimum value for each place is 0
num_places = length(num_diff_vals); %the number of places
odo = zeros(1, num_places);
k=0; %to stop the while loop
D={};
d=0;
while k~=1
for i = num_places : -1 : 1
odo(i) = odo(i) + 1;
if odo(i) == num_diff_vals(i)+1
odo(i) = 0;
else
break;
end
end
if sum(odo)==13 %for the cases we want to keep
d=d+1;
D{d}=odo;
end
if all(odo==num_diff_vals) %the last possible case, so we set k=1 to stop the while loop
k=1;
end
end

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!