Passing a Julia function to a Python function

Hi there,

I want to use a GPyOpt Python package for Bayesian Optimization to find the minimum value of a function which is written in Julia. For that end, I try to use the PyCall.jl and to call the function as

function f(arg1::Float64, arg2::Float64)

end

py"“”
domain = [{‘name’: ‘arg1’, ‘type’: ‘continuous’, ‘domain’: (-2.0, 5.0)}, {‘name’: ‘arg2’, ‘type’: ‘continuous’, ‘domain’: (-2.0, 5.0)}]
“”"

And then to call the Python package as:
gpyopt = pyimport(“GPyOpt.methods”)
gpyopt.BayesianOptimization(f, py"domain")

However, this leads to the following error:
ERROR: LoadError: (in a Julia function called from Python)
JULIA: MethodError: no method matching (::var"#f#3644"{Array{Float64,2},Array{Float64,2},Int64,Int64})(::Array{Float64,2})
Closest candidates are:
f(!Matched::Float64, !Matched::Float64) at C:\Users\kpostek\Dropbox\Bi-level optimization\code\Heart dataset\BayesianOpt.jl:155

In general, passing a Julia function as an argument to a Python function seems to be difficult. Do you know any tricks for that? Re-coding the Julia function fully into Python is too much of a hassle…

From the error message it looks like the Python function tries to call the julia function with four arguments, two matrices and two scalars, but you have only defined it for two scalars. Are you certain that you are using the package correctly?

Cf.

julia> using PyCall

julia> so = pyimport("scipy.optimize")
PyObject <module 'scipy.optimize' from '/home/gunnar/.local/lib/python3.8/site-packages/scipy/optimize/__init__.py'>

julia> so.newton(x -> cos(x) - x, 1)
0.7390851332151607

julia> so.newton((x, y) -> cos(x) - x - y, 1)
ERROR: (in a Julia function called from Python)
JULIA: MethodError: no method matching (::var"#3#4")(::Float64)
Closest candidates are:
  (::var"#3#4")(::Any, !Matched::Any) at REPL[4]:1
2 Likes

Thanks! Indeed the way of using the package seems to be our problem. I don’t know how should I define the function/pass it in PyCall so that the whole thing works…

My best suggestion is that you first figure out how to use the package in Python with a radically simplified version of your objective function, then port the simplified function to Julia and get it to work via PyCall, and finally replace the simplified function with the real function. The simplified function can probably be completely trivial as long as it is in the same domain as your real function.

If you get stuck on the step from Python to PyCall, the simplified function should provide a Minimal Working Example that other people can run themselves to find where the problem is.

Thanks a lot, it turned out that the way the input worked already on the Python level was somewhat un-intuitive!