2017-06-22 47 views
2

我試圖用JuMP解決一個非線性問題,其中變量的數量由用戶決定 - 也就是說,在編譯時不知道。Julia + JuMP:函數參數的可變數量

要做到這一點,@NLobjective行看起來是這樣的:

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

其中,舉例來說,如果n=3,編譯器解釋爲等同於行:

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

的問題是, @eval只能在全局範圍內工作,並且包含在函數中時會引發錯誤。

我的問題是:我怎麼能做到這一點相同的功能 - 讓@NLobjective調用myfx[1],...,x[n]參數個數可變 - 一個函數的局部,而不是知名的,在編譯範圍之內?

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