Question

I am using Base.Cartesian for the first time and have found it to be very powerful. However, it seems to generate code which uses all available indeces, whereas I have a case where I would like to only use a few.

In short

If I am inside @nloops but I only want to use a subset of the indexing variables, is it possible to generate expressions for those indexing variables using scalars corresponding to their subscript indeces?

a,b -> i_{a}, i_{b} where we have i_{1:N}

Long form

Specifically, I have N objects, each which can take on some number of values:

Obj1: m11, m12, m13
Obj2: m21, m22, m23, m24
Obj3: m31, m32

which corresponds to:

i_1 = 1 : 3
i_2 = 1 : 4
i_3 = 1 : 2

I am generating each combination using @nloops:

{m11,m21,m31}{m12,m21,m31}{m13,m21,m31}{m11,m22,m31}{m12,m22,m31}...

I then run through pairwise enumerations for each combination:

comb = {m11,m21,m31} -> pairs = {m11,m21}{m11,m31}{m21,m31}

I would like to use these pairs to index into a matrix. This is where I am getting tripped up, since I need to generate a varying expression only using a subset of the indexing variables.

a,b = pair[1],pair[2]
foo = max(foo, mat[i_{a}, i_{b}]) # need to figure out appropriate syntax here

Here is a cleaned up demonstrative example: (3 is used as N, I'll use @ngenerate later)

@nloops 3 i d->1:lens[d] begin
    foo = 0
    for pair in combinations([1:3],2)
        a, b  = pair[1], pair[2]
        M_ind  = pair2ind(ia,ib)
        mat = M[M_ind]
        foo = max(foo, mat[i_{a}, i_{b}])  # need to figure this out
        if foo==1 # early exit
            break
        end
    end
    # do something with foo...
end

Is it possible to do what I am trying to do? I tried using @eval, but I couldn't get it to compile:

@eval(parse(@sprintf("foo = max(foo, mat[i_%d, i_%d])", a, b)))
Error: a not defined

Thank you.

Was it helpful?

Solution

The problem was solved by avoiding it altogether. A separate version using recursion was used.

N = number of objects
M = array containing number of states

function next_combination!( comb )
    i = findfirst(i->comb[i] < M[i], 1:N)
    @assert(i != 0)
    comb[i] += 1
    comb[1:i-1] = 1
    return comb
end

ncombs = prod(M)
comb = int([0, ones(N-1)])
for ci = 1 : ncombs
    next_combination!(comb)

    foo = 0
    for pair in combinations([1:N],2)
        a, b = pair[1], pair[2]
        col_ind = pair2ind(a,b)
        foo = max(foo, mymat[col_ind][comb[a], comb[b]])
        if foo == 1 # early out
            break
        end
    end

    # do something with foo...
end

Modifying the Existing Method

As DSM pointed out, the following works:

inds = @tuple 3 i
foo = max(foo, mymat[col_ind][inds[a], inds[b]])
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top