# Dynamic "for"

**URL:** https://discourse.julialang.org/t/dynamic-for/58701
**Category:** New to Julia
**Tags:** question
**Created:** [April 6, 2021, 4:28pm UTC](https://discourse.julialang.org/t/dynamic-for/58701 "2021-04-06T16:28:12Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![marllos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marllos/32/205917_2.png) [@marllos](https://discourse.julialang.org/u/marllos)
#### Post date: [April 6, 2021, 4:28pm UTC](https://discourse.julialang.org/t/dynamic-for/58701/1 "2021-04-06T16:28:12Z")

</div>

Hello everyone!  
How do I write the code below using @nloops or other Base.Cartesian elements? I’ve made several attempts. My goal is to generalize to n nested for’s.

```julia
function test()
	for i_1 = 0:1
		for i_2 = 0:1
			for i_3 = 0:1
				n = i_3*2^0 + i_2*2^1 + i_1*2^2
				println(n)
			end
		end
	end
end

```

---

<div class="post-metadata">

### Author: ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)
#### Post date: [April 6, 2021, 5:28pm UTC](https://discourse.julialang.org/t/dynamic-for/58701/2 "2021-04-06T17:28:33Z")

</div>

Something like this? There’s probably a cleaner way than `Iterators.product`, but it works.

```julia
f(i::NTuple{N,T}) where {N,T} = sum(((i, e),) -> i*2^e, zip(i, (N-1):-1:0))

@generated function test(::Val{N}) where {N}
    quote
        idx = collect(Iterators.product(fill(0:1, $N)...))
        Base.Cartesian.@nloops $N i idx begin
            n = f(Base.Cartesian.@nref $N idx i)
            @show n
        end
    end
end

test(N::Int) = test(Val(N))

```

```julia
julia> test(3)
n = 0
n = 4
n = 2
n = 6
n = 1
n = 5
n = 3
n = 7

```

---

<div class="post-metadata">

### Author: ![chris-b1](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chris-b1/32/14165_2.png) [@chris-b1](https://discourse.julialang.org/u/chris-b1)
#### Post date: [April 6, 2021, 5:31pm UTC](https://discourse.julialang.org/t/dynamic-for/58701/3 "2021-04-06T17:31:39Z")

</div>

Here’s a slightly different approach - might not be quite as efficient but no metaprogramming

```julia
function power(tpl::NTuple{N, <: Integer}) where {N}
    ans = 0
    for i in 0:(N-1)
        ans += tpl[i+1] * 2 ^ i
    end
    ans
end

function test2(I::CartesianIndices)
    for i in I
        n = power(Tuple(i))
        println(n)
    end
end

julia> test2(CartesianIndices(ntuple(_ -> 0:1, 3)))
0
1
2
3
4
5
6
7

julia> test2(CartesianIndices(ntuple(_ -> 0:1, 4)))
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

```

---

<div class="post-metadata">

### Author: ![marllos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marllos/32/205917_2.png) [@marllos](https://discourse.julialang.org/u/marllos)
#### Post date: [April 6, 2021, 6:51pm UTC](https://discourse.julialang.org/t/dynamic-for/58701/5 "2021-04-06T18:51:50Z")

</div>

Sorry, I didn’t post the desired result, which is: 0, 1, 2, …, 2^N-1, where N is the number of nested “for”. Right after getting the n, I need to use it in another function, not sure if I can use it out of order. Thanks stillyslalom.

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [April 6, 2021, 7:30pm UTC](https://discourse.julialang.org/t/dynamic-for/58701/7 "2021-04-06T19:30:48Z")

</div>

> [@chris-b1](#):
>
> Here’s a slightly different approach - might not be quite as efficient but no metaprogramming

Actually, your code is faster than @stillyslalom’s `@generated` example, and can be made faster and simpler still. (To benchmark, replace the `println` or `@show` statements with `s += n`, initialized to `s=0`, and return the sum `s`.) `CartesianIndices` are just as fast as `@nloops` if done properly, if somewhat less flexible (they are implemented using `@nloops` internally IIRC).

Consider:

```julia
function test3(v::Val)
    p2 = ntuple(i->2^(i-1), v)
    for idx in CartesianIndices(ntuple(i->0:1, v))
        n = sum(Tuple(idx) .* p2)
        @show n
    end
end

test3(Val(3))

```

Note that `ntuple` with a `Val` argument is completely unrolled and inlined by the compiler, and `sum(Tuple(idx) .* p2)` is also unrolled and inlined since the arguments are tuples with lengths known to the compiler.

---

<div class="post-metadata">

### Author: ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)
#### Post date: [April 6, 2021, 7:47pm UTC](https://discourse.julialang.org/t/dynamic-for/58701/8 "2021-04-06T19:47:18Z")

</div>

> [@stillyslalom](#):
>
> `idx = collect(Iterators.product(fill(0:1, $N)...))`

Yeah, `collect` is a performance-killer here. Hopefully we’ll one day be able to index into an `Iterators.product` without first needing to collect.

---

<div class="post-metadata">

### Author: ![marllos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marllos/32/205917_2.png) [@marllos](https://discourse.julialang.org/u/marllos)
#### Post date: [April 6, 2021, 10:23pm UTC](https://discourse.julialang.org/t/dynamic-for/58701/9 "2021-04-06T22:23:51Z")

</div>

I’m sorry, I misformulated the result. The indices are inverted and I don’t know how to invert them. The order in which the indices i\_1, i\_2, i\_3 appear is important, because it represents the position in a chain of spins. The result needs to be:

```julia
function test()
	for i_1 = 0:1
		for i_2 = 0:1
			for i_3 = 0:1
				n = i_3*2^0 + i_2*2^1 + i_1*2^2
				println("$(i_1)$(i_2)$(i_3) => $n")
			end
		end
	end
end

000 => 0
001 => 1
010 => 2
011 => 3
100 => 4
101 => 5
110 => 6
111 => 7

```

And not

```julia
000 => 0
100 => 1
010 => 2
110 => 3
001 => 4
101 => 5
011 => 6
111 => 7

```

---

<div class="post-metadata">

### Author: ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)
#### Post date: [April 6, 2021, 11:16pm UTC](https://discourse.julialang.org/t/dynamic-for/58701/10 "2021-04-06T23:16:00Z")

</div>

Just reverse the tuples?

```julia
function test3(v::Val{N}) where {N}
    p2 = reverse(ntuple(i->2^(i-1), v))
    for idx in CartesianIndices(ntuple(i->0:1, v))
        n = sum(reverse(Tuple(idx)) .* p2)
    end
end

```

I tested with `N = 5` and found no performance penalty compared to @stevengj’s version.

---

<div class="post-metadata">

### Author: ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)
#### Post date: [April 6, 2021, 11:26pm UTC](https://discourse.julialang.org/t/dynamic-for/58701/11 "2021-04-06T23:26:42Z")

</div>

Would that require a `product` method specialized for arguments with the `HasMethod(getindex)` trait?

---

<div class="post-metadata">

### Author: ![marllos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marllos/32/205917_2.png) [@marllos](https://discourse.julialang.org/u/marllos)
#### Post date: [April 7, 2021, 12:05am UTC](https://discourse.julialang.org/t/dynamic-for/58701/12 "2021-04-07T00:05:44Z")

</div>

Not inverting i\_1, i\_2, i\_3

Correct result:

```julia
function test()
	for i_1 = 0:1
		for i_2 = 0:1
			for i_3 = 0:1
				n = i_3*2^0 + i_2*2^1 + i_1*2^2
				println("$(i_1)$(i_2)$(i_3) => $n")
			end
		end
	end
end

test()

000 => 0
001 => 1
010 => 2
011 => 3
100 => 4
101 => 5
110 => 6
111 => 7

```

Result still with i\_1, i\_2, i\_3 inverted

```julia
function test2(v::Val{N}) where {N}
    p2 = reverse(ntuple(i->2^(i-1), v))
    for idx in CartesianIndices(ntuple(i->0:1, v))
        n = sum(reverse(Tuple(idx)) .* p2)
        println("$(idx) = > $n")
    end
end

test2(Val(3))

CartesianIndex(0, 0, 0) = > 0
CartesianIndex(1, 0, 0) = > 1
CartesianIndex(0, 1, 0) = > 2
CartesianIndex(1, 1, 0) = > 3
CartesianIndex(0, 0, 1) = > 4
CartesianIndex(1, 0, 1) = > 5
CartesianIndex(0, 1, 1) = > 6
CartesianIndex(1, 1, 1) = > 7

```

---

<div class="post-metadata">

### Author: ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)
#### Post date: [April 7, 2021, 1:00am UTC](https://discourse.julialang.org/t/dynamic-for/58701/13 "2021-04-07T01:00:58Z")

</div>

You need to use the reversed indices:

```julia
function test3(v::Val{N}) where {N}
    p2 = reverse(ntuple(i->2^(i-1), v))
    for idx in CartesianIndices(ntuple(i->0:1, v))
        ridx = reverse(Tuple(idx))
        n = sum(ridx .* p2)
        println(ridx[1], ridx[2], ridx[3], " => ", n)
    end
end

```

```julia
000 => 0
001 => 1
010 => 2
011 => 3
100 => 4
101 => 5
110 => 6
111 => 7

```

---

<div class="post-metadata">

### Author: ![marllos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marllos/32/205917_2.png) [@marllos](https://discourse.julialang.org/u/marllos)
#### Post date: [April 7, 2021, 4:30pm UTC](https://discourse.julialang.org/t/dynamic-for/58701/15 "2021-04-07T16:30:35Z")

</div>

------------ \*\*\* ---------------  
Thank you very much stillyslalom. It worked here and in my code. Also, now I have several examples to help me understand Base.Cartesian. Thank you everyone very much.
