2017-06-22 13 views
2

変数数がユーザによって決定される非線形問題、すなわちコンパイル時には分からない問題を解決するためにJuMPを使用しようとしています。これを実現するためにJulia + JuMP:関数への可変引数数

@NLobjective行は次のようになります。

n=3場合、たとえば、コンパイラは同じような行を解釈し、
@eval @JuMP.NLobjective(m, Min, $(Expr(:call, :myf, [Expr(:ref, :x, i) for i=1:n]...))) 

@JuMP.NLobjective(m, Min, myf(x[1], x[2], x[3])) 

問題があることです@evalはグローバルスコープ内でのみ機能し、関数に含まれるとエラーがスローされます。

私の質問は:は、どのように私はこれと同じ機能を実現することができます - 関数の局所的な、知られていない-でコンパイル範囲内 - @NLobjectivex[1],...,x[n]引数の数が可変でmyfを呼び出すようになって?

def testme(n) 
    myf(a...) = sum(collect(a).^2) 

    m = JuMP.Model(solver=Ipopt.IpoptSolver()) 

    JuMP.register(m, :myf, n, myf, autodiff=true) 
    @JuMP.variable(m, x[1:n] >= 0.5) 

    @eval @JuMP.NLobjective(m, Min, $(Expr(:call, :myf, [Expr(:ref, :x, i) for i=1:n]...))) 
    JuMP.solve(m) 
end 

testme(3) 

ありがとうございます!

+1

これは 'JuMP'には役立ちませんが、あなたが本当に動けなくなる場合は、' NLopt'はないことにする引数の数が可能になりますコンパイル時に知られており、APIは比較的簡単です。 –

+0

ありがとう!私はそれを調べます。 –

答えて

3

http://jump.readthedocs.io/en/latest/nlp.html#raw-expression-inputで説明したように、目的関数をマクロなしで与えることができます。関連する表現:

JuMP.setNLobjective(m, :Min, Expr(:call, :myf, [x[i] for i=1:n]...)) 

@eval基づくものよりもさらに簡単で、機能で動作します。

using JuMP, Ipopt 

function testme(n) 
    myf(a...) = sum(collect(a).^2) 

    m = JuMP.Model(solver=Ipopt.IpoptSolver()) 

    JuMP.register(m, :myf, n, myf, autodiff=true) 
    @JuMP.variable(m, x[1:n] >= 0.5) 

    JuMP.setNLobjective(m, :Min, Expr(:call, :myf, [x[i] for i=1:n]...)) 
    JuMP.solve(m) 
    return [getvalue(x[i]) for i=1:n] 
end 

testme(3) 

、それが返されます:コードがある

julia> testme(3) 

: 

EXIT: Optimal Solution Found. 
3-element Array{Float64,1}: 
0.5 
0.5 
0.5 
+2

それは素敵なトリックです、自分でそれを考えたこともありませんでした。これを読んでいる人には、高次元の入力関数で 'autodiff = true'を使うことには注意が必要です。現在の実装では、入力ディメンションが増加するとうまく調整されない順方向モードADが使用されます。 – mlubin

+0

@mlubin 'autodiff'の代替手段は何ですか? –

+0

[ReverseDiff.jl](https://github.com/JuliaDiff/ReverseDiff.jl)は、JuMPにグラデーション機能を提供するために使用できる、良い逆モード実装です。 – mlubin

関連する問題