How to create recursive nested loops that use loop variables inside?

I need to create a nested loop with arbitrary depth. Recursive loops seem to be correct, but I don't know how to use loop variables in a loop. For example, as soon as I specify a depth of 3, it should work like

count = 1 for i=1, Nmax-2 for j=i+1, Nmax-1 for k=j+1,Nmax function(i,j,k,0,0,0,0....) // a function having Nmax arguments count += 1 end end end 

I want to make a subroutine that takes the depth of the loops as an argument.

UPDATE:

I implemented the scheme proposed by Zoltan. I wrote it in python for simplicity.

 count = 0; def f(CurrentDepth, ArgSoFar, MaxDepth, Nmax): global count; if CurrentDepth > MaxDepth: count += 1; print count, ArgSoFar; else: if CurrentDepth == 1: for i in range(1, Nmax + 2 - MaxDepth): NewArgs = ArgSoFar; NewArgs[1-1] = i; f(2, NewArgs, MaxDepth, Nmax); else: for i in range(ArgSoFar[CurrentDepth-1-1] + 1, Nmax + CurrentDepth - MaxDepth +1): NewArgs = ArgSoFar; NewArgs[CurrentDepth-1] = i; f(CurrentDepth + 1, NewArgs, MaxDepth, Nmax); f(1,[0,0,0,0,0],3,5) 

and results

 1 [1, 2, 3, 0, 0] 2 [1, 2, 4, 0, 0] 3 [1, 2, 5, 0, 0] 4 [1, 3, 4, 0, 0] 5 [1, 3, 5, 0, 0] 6 [1, 4, 5, 0, 0] 7 [2, 3, 4, 0, 0] 8 [2, 3, 5, 0, 0] 9 [2, 4, 5, 0, 0] 10 [3, 4, 5, 0, 0] 

There may be a better way to do this, but so far it works well. It is easy to do in fortran. Thank you so much for your help!

+4
source share
4 answers

you can define your function to have a List argument that is initially empty.

 void f(int num,List argumentsSoFar){ // call f() for num+1..Nmax for(i = num+1 ; i < Nmax ; i++){ List newArgs=argumentsSoFar.clone(); newArgs.add(i); f(i,newArgs); } if (num+1==Nmax){ // do the work with your argument list...i think you wanted to arrive here ;) } } 

caveat: the stack must be able to handle Nmax calls to depth functions

+1
source

Here is one way to do what you want. This is pseudo code, I have not written enough to compile and test it, but you should get an image.

Define a function, let's call it fun1 , which takes, among other things, an integer array argument, perhaps like this

 <type> function fun1(indices, other_arguments) integer, dimension(:), intent(in) :: indices ... 

which you can call it that way

 fun1([4,5,6],...) 

and the interpretation of this is that the function is to use the depth of the 3rd level of the loop like this:

 do ix = 1,4 do jx = 1,5 do kx = 1,6 ... 

Of course, you cannot write a loopback socket whose depth is determined at runtime (and not in Fortran), so you would smooth it out in a single loop along the lines

 do ix = 1, product(indices) 

If you want the values โ€‹โ€‹of individual indices within a loop, you will need to decouple the linearized index. Note that all you do is write code to convert array indices from ND to 1-D and vice versa; this is what the compiler does for you when you can specify the rank of the array at compile time. If the inner loops will not work across the entire range of indices, you will need to do something more complex, requiring careful coding, but not difficult.

Depending on what you are actually trying to do, this may or may not be a good or even satisfactory approach. If you are trying to write a function to calculate the value for each element in an array whose rank is unknown when writing the function, then the previous sentence is wrong, in this case you need to write the elemental function. Update your question if you want more information.

+2
source

Another way to achieve what you want is based on High Performance Mark's answer, but can be made more general:

 subroutine nestedLoop(indicesIn) ! Input indices, of arbitrary rank integer,dimension(:),intent(in) :: indicesIn ! Internal indices, here set to length 5 for brevity, but set as many as you'd like integer,dimension(5) :: indices = 0 integer :: i1,i2,i3,i4,i5 indices(1:size(indicesIn)) = indicesIn do i1 = 0,indices(1) do i2 = 0,indices(2) do i3 = 0,indices(3) do i4 = 0,indices(4) do i5 = 0,indices(5) ! Do calculations here: ! myFunc(i1,i2,i3,i4,i5) enddo enddo enddo enddo enddo endsubroutine nestedLoop 

Now you have nested loops explicitly encoded, but these are loops with 1 loop, unless otherwise required. Please note: if you plan to build rank arrays that depend on the depth of the nested loop, you can go to rank 7 or 15 if you have a compiler that supports it (Fortran 2008). Now you can try:

 call nestedLoop([1]) call nestedLoop([2,3]) call nestedLoop([1,2,3,2,1]) 

You can modify this procedure to your liking and desired applicability, add exception handling, etc.

+1
source

From the OOP approach, each cycle can be represented by a โ€œLoopโ€ object - this object will be able to be constructed, while it contains another instance by itself. Then you could theoretically nest them as deep as you need.

Loop1 will execute Loop2 will execute Loop3 .. and beyond.

0
source

Source: https://habr.com/ru/post/1497463/


All Articles