Using Cython
We show how to use Cython to accelerate the computation of a cost function and how to avoid some pitfalls.
Disclaimer: If you do not care specifically about Cython and just want to make your code faster, prefer Numba (see the corresponding Numba tutorial for more details), or try to run iminuit in the PyPy interpreter. Numba is more powerful and easier to use, and you don’t have to learn the awkward Cython dialect. Cython is a good choice when you have to call into C code from Python, but it is not a good choice to call into C++ code, for this pybind11 is the ideal choice. Cython does not fully support the C++ language, it was designed for C.
With that out of the way, let’s see how to use iminuit with a Cython-compiled function.
[ ]:
# setup of the notebook
%load_ext Cython
from iminuit import Minuit
The following cell is Cython code and will be compiled to machine code behind the scenes.
[ ]:
%%cython
def cython_func(double x, double y, double z):
return (x - 1.) ** 2 + (y - 2.) ** 2 + (z - 3.) ** 2 + 1.
Minuit can work with this compiled function like it was a native Python function.
[ ]:
m = Minuit(cython_func, 1, 1, 1)
m.migrad()
Migrad | |
---|---|
FCN = 1 | Nfcn = 36 |
EDM = 2.38e-18 (Goal: 0.0002) | |
Valid Minimum | Below EDM threshold (goal x 10) |
No parameters at limit | Below call limit |
Hesse ok | Covariance accurate |
Name | Value | Hesse Error | Minos Error- | Minos Error+ | Limit- | Limit+ | Fixed | |
---|---|---|---|---|---|---|---|---|
0 | x | 1 | 1 | |||||
1 | y | 2 | 1 | |||||
2 | z | 3 | 1 |
x | y | z | |
---|---|---|---|
x | 1 | 0 | 0 |
y | 0 | 1 | 0 |
z | 0 | 0 | 1 |
In the past, Cython would not create a proper signature for the function by default, which iminuit uses need to get the parameter names. This was improved at some point.
If you encouter a function without a signature, you can tell Minuit explicitly about the names of the parameters with the keyword name
. This can also be used to override the automatic detection and use other names.
[ ]:
m = Minuit(cython_func, 1, 1, 1, name=("a", "b", "c"))
m.migrad()
Migrad | |
---|---|
FCN = 1 | Nfcn = 36 |
EDM = 9.78e-20 (Goal: 0.0002) | |
Valid Minimum | Below EDM threshold (goal x 10) |
No parameters at limit | Below call limit |
Hesse ok | Covariance accurate |
Name | Value | Hesse Error | Minos Error- | Minos Error+ | Limit- | Limit+ | Fixed | |
---|---|---|---|---|---|---|---|---|
0 | a | 1 | 1 | |||||
1 | b | 2 | 1 | |||||
2 | c | 3 | 1 |
a | b | c | |
---|---|---|---|
a | 1 | 0 | 0 |
b | 0 | 1 | 0 |
c | 0 | 0 | 1 |