Different number of for loops

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!

Respuestas (2)

KSSV
KSSV el 30 de Sept. de 2020

0 votos

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 comentarios

Vasilis Chasiotis
Vasilis Chasiotis el 30 de Sept. de 2020
Editada: Vasilis Chasiotis el 30 de Sept. de 2020
I have done something like this, but for n=10, that is x1,...,x10, I have to write another code, because I have 10 variables. So, I need a code that can work for each value of n.
Maybe your code could work if the input in ndgrid is an 1 x n cell array, in which each column is an 1 x 9, 1 x 5, 1 x 5, 1 x 5 vector.
KSSV
KSSV el 30 de Sept. de 2020
Read about ndgrid, you need not to define those many variables. It hasan option of having all outputs into a cell.
KSSV
KSSV el 30 de Sept. de 2020
x = [{1:10} {1:10} {1:10}] ;
[I{1:numel(x)}] = ndgrid(x{:}) ;
I
Vasilis Chasiotis
Vasilis Chasiotis el 30 de Sept. de 2020
Editada: Vasilis Chasiotis el 30 de Sept. de 2020
I used ndgrid(x{:}) and it works for sure. But, if for example n=10, then the 10 nested for loops are faster than ndgrid.
Ok, using ndgrid I achieve my goal, since it works for each value of n, but I want a faster way than nested for loops as well.
When n>=10, note that ndgrid creates all possible cases, which means either memory problem or maximum array size preference. But I will keep some cases, because I have an if statement. So, many cases that ndgrid creates, are useless.
KSSV
KSSV el 30 de Sept. de 2020
I think ndgrid would be faster....
Vasilis Chasiotis
Vasilis Chasiotis el 30 de Sept. de 2020
I tried the example I provide in my question for the case n=10. The nested for loops are faster than ndgrid. Also, as I told you there are memory problems with ndgrid.
KSSV
KSSV el 30 de Sept. de 2020
I tried for n = 4...ndgrid taking less time.
Show us the code whcih you have tried.
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.

Iniciar sesión para comentar.

Walter Roberson
Walter Roberson el 30 de Sept. de 2020

0 votos

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 comentarios

Vasilis Chasiotis
Vasilis Chasiotis el 30 de Sept. de 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 el 30 de Sept. de 2020
Editada: Vasilis Chasiotis el 30 de Sept. de 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

Iniciar sesión para comentar.

Categorías

Más información sobre Loops and Conditional Statements en Centro de ayuda y File Exchange.

Preguntada:

el 30 de Sept. de 2020

Editada:

el 30 de Sept. de 2020

Community Treasure Hunt

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

Start Hunting!

Translated by