Julia:在Base.Cartesian中创建特定的索引变量

时间:2014-07-31 16:23:44

标签: metaprogramming julia cartesian

我第一次使用Base.Cartesian并发现它非常强大。但是,它似乎生成了使用所有可用indeces的代码,而我有一个案例,我只想使用一些。

简而言之

如果我在@nloops内,但我只想使用索引变量的子集,是否可以使用与其下标indeces对应的标量为这些索引变量生成表达式?

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

长篇

具体来说,我有N个对象,每个对象可以采用一些值:

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

对应于:

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

我使用@nloops生成每个组合:

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

然后我为每个组合运行成对枚举:

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

我想使用这些对来索引矩阵。这是我被绊倒的地方,因为我需要仅使用索引变量的子集生成变化的表达式。

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

以下是一个清理过的示范示例:(3用作N,我以后再用@ngenerate

@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

有可能做我想做的事吗? 我尝试使用@eval,但我无法编译:

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

谢谢。

1 个答案:

答案 0 :(得分:0)

通过完全避免问题解决了这个问题。使用了使用递归的单独版本。

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

修改现有方法

正如帝斯曼指出的那样,以下工作:

inds = @tuple 3 i
foo = max(foo, mymat[col_ind][inds[a], inds[b]])