{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Using Cython\n", "\n", "We show how to use Cython to accelerate the computation of a cost function and how to avoid some pitfalls.\n", "\n", "If you do not care specifically about [Cython](https://cython.org) and just want to make your code faster, prefer [Numba](https://numba.pydata.org) (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](https://pybind11.readthedocs.io/en/stable/) is the ideal choice. Cython does not fully support the C++ language, it was designed for C.\n", "\n", "With that disclaimer out of the way, let's see how to use iminuit with a Cython-compiled function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# setup of the notebook\n", "%load_ext Cython\n", "from iminuit import Minuit, describe\n", "import numpy as np\n", "import traceback" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following cell is Cython code and will be compiled to machine code behind the scenes." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%cython\n", "\n", "def cython_func(double x, double y, double z):\n", " return (x - 1.) ** 2 + (y - 2.) ** 2 + (z - 3.) ** 2 + 1." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Unfortunately, if we try to pass starting values to Minuit via keywords, we get a failure." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "try:\n", " m = Minuit(cython_func, x=1, y=2, z=3)\n", "except:\n", " traceback.print_exc()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What happened? `Minuit` uses the `describe` tool which uses introspection to read the function signature, but this failed here. Without that, Minuit does not know how many parameters this function accepts and their names.\n", "\n", "Python built-in functions (like `min`) normally do not have a function signature. Functions from cython and swig also do not have one.\n", "\n", "There are a few ways to fix this.\n", "\n", "- One can pass parameter names explicitly to Minuit, then it works.\n", "- One can use positional arguments.\n", "- One can tell Cython to embed a signature." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m = Minuit(cython_func, name=(\"x\", \"y\", \"z\"), x=0, y=0, z=0)\n", "m.errordef = Minuit.LEAST_SQUARES\n", "m.migrad()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, one can use positional arguments without specifying parameter names." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m = Minuit(cython_func, 0, 0, 0)\n", "m.errordef = Minuit.LEAST_SQUARES\n", "m.migrad()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A nicer solution is to ask Cython to add the missing function signature. This can be achieved with the `embedsignature(true)` decorator." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%cython\n", "cimport cython\n", "\n", "@cython.embedsignature(True) # generate a signature that iminuit can extract\n", "def cython_f(double x, double y, double z):\n", " return (x - 1.) ** 2 + (y - 2.) ** 2 + (z - 3.) ** 2 + 1." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now it works." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m = Minuit(cython_f, x=0, y=0, z=0)\n", "m.errordef = Minuit.LEAST_SQUARES\n", "m.migrad()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.8.13 ('venv': venv)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.8" }, "vscode": { "interpreter": { "hash": "bdbf20ff2e92a3ae3002db8b02bd1dd1b287e934c884beb29a73dced9dbd0fa3" } } }, "nbformat": 4, "nbformat_minor": 4 }