Using PyCall to call iminuit

Hello, I’m working in high energy physics, and there is a package called MINUIT, https://seal.web.cern.ch/seal/snapshot/work-packages/mathlibs/minuit/, that is commonly used in the field for Function Minimization and Error Analysis. It is in cernlib, and both fortran and c++ versions. Wrapping either of them in Julia does not exist yet. But there is a python wrapping of the c++ version, called iminuit, https://iminuit.readthedocs.io/en/latest/. It can be installed by conda install iminuit.

I then tried PyCall to use iminuit inside Julia.

minuit = pyimport(:iminuit)

datax = LinRange(0,10, 10)
σ = 1; μ = 0;
off = σ .*randn(10) .+ μ
line(x, a, b) = a + sin(x) * b
datay = line.(datax, 1, 2) .+ 0.2*off

function χsq(a, b)
    err = 0.01
    sum(@. (datay- line(datax, a, b))^2/err )
end

I then tried to get the best fit to the data datay by minimizing χsq with the following line

minuit.Minuit(χsq, a=5, b=5, error_a = 0.1, error_b = 0.1, errordef = 1)

Then I got an error starting with

PyError ($(Expr(:escape, :(ccall(#= /homepath/.julia/packages/PyCall/ttONZ/src/pyfncall.jl:44 =# @pysym(:PyObject_Call), PyPtr, (PyPtr, PyPtr, PyPtr), o, pyargsptr, kw))))) <class 'TypeError'>
TypeError('Unable to obtain function signature')
  File "iminuit/_libiminuit.pyx", line 475, in iminuit._libiminuit.Minuit.__init__
File "/homepath/anaconda3/lib/python3.7/site-packages/iminuit/util.py", line 350, in describe
    return better_arg_spec(f, verbose)
  File "/homepath/anaconda3/lib/python3.7/site-packages/iminuit/util.py", line 340, in better_arg_spec
    raise TypeError("Unable to obtain function signature")

Any help will be very grateful.
If there is some day a Julia wrapping of the MINUIT package, there would be great!

Thank you in advance

Not too be dismissive, but Julia already has some state of the art told for these problems. Why not use those?

MINUIT has lots of subroutines that are very useful and easy-to-use for the data analysis at least in high energy physics. Just copy one sentence from the manual:

The Minuit processor MINOS was probably the first, and may still be the only, generally available
program to calculate parameter errors taking into account both parameter correlations and non-linearities.
The MINOS error intervals are in general assymmetric, and may be expensive to calculate, especially if there are a lot of free parameters and the problem is very non-linear.

If this lib can be ported to julia, I’m sure there will be many more julia users from this community.

1 Like

This is https://github.com/JuliaPy/PyCall.jl/issues/268

The workaround is to wrap the Julia function in a Python lambda:

pyfun = py"lambda fun: lambda x, y: fun(x,y)"

minuit.Minuit(pyfun(χsq), a=5, b=5, error_a = 0.1, error_b = 0.1, errordef = 1)
1 Like

Thanks a lot! I tested, to make it work, I need to use the same letters for the parameters as those appear in the lambda definition, i.e.,

pyfun = py"lambda fun: lambda a, b: fun(a, b)"

minuit.Minuit(pyfun(χsq), a=5, b=5, error_a = 0.1, error_b = 0.1, errordef = 1)

Then a, b and error_a, error_b can be correctly recognized.