使用从 python 最小化时 Julia 中的函数和 Lambda 表达式

Function and Lambda expression in Julia when using minimize from python

我在 Julia 中有一段代码,我在其中使用了 python 中的最小化函数。在这里,我放了一个简化的例子,它的工作原理是 cose

using PyCall
@pyimport scipy.optimize as so

function fidelity1(x)
    f1 = x[1]*x[1]+3*x[2]*x[2]
    return f1
end

x0 = [1 1]
res = so.minimize(fidelity1,x0)

谁的结果是正确的

Dict{Any,Any} with 10 entries:
  "hess_inv" => [0.5 3.0102e-12; 3.0102e-12 0.166667]
  "fun"      => 2.22049e-16
  "nfev"     => 18
  "status"   => 0
  "message"  => "Optimization terminated successfully."
  "success"  => true
  "x"        => [-7.45039e-9, -7.45073e-9]
  "jac"      => [3.73556e-13, -9.08177e-13]
  "nit"      => 4
  "njev"     => 6

现在,使用 lambda 表达式会非常有用,所以我按以下方式编写代码

using PyCall
@pyimport scipy.optimize as so

fidelity2 = (x1,x2) ->  x1*x1+3*x2*x2

x0 = [1 1]
res = so.minimize(fidelity2,x0)

然而,在这种情况下我得到

(in a Julia function called from Python)
JULIA: MethodError: no method matching (::var"#3#4")(::Array{Float64,1})
Closest candidates are:
  #3(::Any, !Matched::Any) at In[2]:4
Stacktrace:
 [1] #invokelatest#1 at ./essentials.jl:712 [inlined]
 [2] invokelatest(::Any, ::Any) at ./essentials.jl:711
 [3] _pyjlwrap_call(::Function, ::Ptr{PyCall.PyObject_struct}, ::Ptr{PyCall.PyObject_struct}) at /home/candeloro/.julia/packages/PyCall/tqyST/src/callback.jl:28
 [4] pyjlwrap_call(::Ptr{PyCall.PyObject_struct}, ::Ptr{PyCall.PyObject_struct}, ::Ptr{PyCall.PyObject_struct}) at /home/candeloro/.julia/packages/PyCall/tqyST/src/callback.jl:44
 [5] macro expansion at /home/candeloro/.julia/packages/PyCall/tqyST/src/exception.jl:95 [inlined]
 [6] #109 at /home/candeloro/.julia/packages/PyCall/tqyST/src/pyfncall.jl:43 [inlined]
 [7] disable_sigint at ./c.jl:446 [inlined]
 [8] __pycall! at /home/candeloro/.julia/packages/PyCall/tqyST/src/pyfncall.jl:42 [inlined]
 [9] _pycall!(::PyObject, ::PyObject, ::Tuple{var"#3#4",Array{Int64,2}}, ::Int64, ::Ptr{Nothing}) at /home/candeloro/.julia/packages/PyCall/tqyST/src/pyfncall.jl:29
 [10] _pycall!(::PyObject, ::PyObject, ::Tuple{var"#3#4",Array{Int64,2}}, ::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at /home/candeloro/.julia/packages/PyCall/tqyST/src/pyfncall.jl:11
 [11] (::PyObject)(::Function, ::Vararg{Any,N} where N; kwargs::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at /home/candeloro/.julia/packages/PyCall/tqyST/src/pyfncall.jl:86
 [12] (::PyObject)(::Function, ::Vararg{Any,N} where N) at /home/candeloro/.julia/packages/PyCall/tqyST/src/pyfncall.jl:86
 [13] top-level scope at In[2]:7
 [14] eval at ./boot.jl:331 [inlined]
 [15] softscope_include_string(::Module, ::String, ::String) at /home/candeloro/.julia/packages/SoftGlobalScope/u4UzH/src/SoftGlobalScope.jl:217
 [16] execute_request(::ZMQ.Socket, ::IJulia.Msg) at /home/candeloro/.julia/packages/IJulia/IDNmS/src/execute_request.jl:67
 [17] #invokelatest#1 at ./essentials.jl:712 [inlined]
 [18] invokelatest at ./essentials.jl:711 [inlined]
 [19] eventloop(::ZMQ.Socket) at /home/candeloro/.julia/packages/IJulia/IDNmS/src/eventloop.jl:8
 [20] (::IJulia.var"#15#18")() at ./task.jl:358

Stacktrace:
 [1] pyerr_check at /home/candeloro/.julia/packages/PyCall/tqyST/src/exception.jl:62 [inlined]
 [2] pyerr_check at /home/candeloro/.julia/packages/PyCall/tqyST/src/exception.jl:66 [inlined]
 [3] _handle_error(::String) at /home/candeloro/.julia/packages/PyCall/tqyST/src/exception.jl:83
 [4] macro expansion at /home/candeloro/.julia/packages/PyCall/tqyST/src/exception.jl:97 [inlined]
 [5] #109 at /home/candeloro/.julia/packages/PyCall/tqyST/src/pyfncall.jl:43 [inlined]
 [6] disable_sigint at ./c.jl:446 [inlined]
 [7] __pycall! at /home/candeloro/.julia/packages/PyCall/tqyST/src/pyfncall.jl:42 [inlined]
 [8] _pycall!(::PyObject, ::PyObject, ::Tuple{var"#3#4",Array{Int64,2}}, ::Int64, ::Ptr{Nothing}) at /home/candeloro/.julia/packages/PyCall/tqyST/src/pyfncall.jl:29
 [9] _pycall!(::PyObject, ::PyObject, ::Tuple{var"#3#4",Array{Int64,2}}, ::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at /home/candeloro/.julia/packages/PyCall/tqyST/src/pyfncall.jl:11
 [10] (::PyObject)(::Function, ::Vararg{Any,N} where N; kwargs::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}) at /home/candeloro/.julia/packages/PyCall/tqyST/src/pyfncall.jl:86
 [11] (::PyObject)(::Function, ::Vararg{Any,N} where N) at /home/candeloro/.julia/packages/PyCall/tqyST/src/pyfncall.jl:86
 [12] top-level scope at In[2]:7

我不明白为什么第二个代码不起作用

scipy.optimize.minimize 期望 objective 函数(在您的例子中 fidelity2)将大小为 (n,) 的数组作为其第一个参数,该参数保存 n 自变量。在迁移到使用 lambda 表达式的第二种格式时,请注意您还更改了签名:fidelity2 期望自变量在不同的函数参数中而不是在数组中,但那是 not scipy.optimize.minimize 如何运作。

如果您只想使用 lambda 表达式,您可以将 fidelity2 更改为更像您的第一个示例

using PyCall
@pyimport scipy.optimize as so

fidelity2 = x -> x[1]*x[1]+3*x[2]*x[2]

x0 = [1 1]
res = so.minimize(fidelity2, x0)

请注意,您不必为 lambda 表达式命名。您可以在对 minimize 的调用中将其用作匿名函数。这意味着以下内容也有效:

using PyCall
@pyimport scipy.optimize as so

x0 = [1 1]
res = so.minimize(x -> x[1]*x[1]+3*x[2]*x[2], x0)