{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Cython Tutorial\n",
    "\n",
    "This is a topical tutorial. If you are new to iminuit, you should go through the basic tutorial first. \n",
    "\n",
    "If you do not already know Cython and you just want to make your code faster, try **numba** or **jax** to accelerate your cost function (see the automatic differentiation tutorial for more details). These are easier to use and more powerful, and you don't have to learn the awkward Cython dialect. iminuit also works with PyPy3.5 or later, by the way.\n",
    "\n",
    "Apart from showing how to use Cython functions with iminuit, this short tutorial focusses on workarounds that are needed when iminuit's introspection cannot detect the parameter names automatically."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# setup of the notebook\n",
    "%load_ext Cython\n",
    "from iminuit import Minuit, describe\n",
    "from iminuit.util import make_func_code\n",
    "import numpy as np\n",
    "import traceback"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Most of the computation time is spend in the cost function when you run iminuit. Cython is (an old-fashioned) way to accelerate it. We will only give a very brief glimps on how to write Cython code, please search the web for a proper Cython tutorial. The following cell is Cython code and will be compiled to machine code behind the scenes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "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 pass this to iminuit, we get a failure."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Traceback (most recent call last):\n",
      "  File \"<ipython-input-3-faebe1f5e16a>\", line 2, in <module>\n",
      "    m = Minuit(cython_func, pedantic=False)\n",
      "  File \"src/iminuit/_libiminuit.pyx\", line 587, in iminuit._libiminuit.Minuit.__init__\n",
      "  File \"/Users/hdembinski/Extern/iminuit/src/iminuit/util.py\", line 404, in describe\n",
      "    raise TypeError(\"Unable to obtain function signature\")\n",
      "TypeError: Unable to obtain function signature\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    m = Minuit(cython_func, pedantic=False)\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",
    "As a simple fix, you can pass the parameter names to Minuit, then it works."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table>\n",
       "<tr>\n",
       "<td colspan=\"2\" title=\"Minimum value of function\">\n",
       "FCN = 1\n",
       "</td>\n",
       "<td align=\"center\" colspan=\"3\" title=\"No. of calls in last algorithm and total number of calls\">\n",
       "Ncalls = 36 (36 total)\n",
       "</td>\n",
       "</tr>\n",
       "<tr>\n",
       "<td colspan=\"2\" title=\"Estimated distance to minimum and target threshold\">\n",
       "EDM = 2.26e-19 (Goal: 0.0002)\n",
       "</td>\n",
       "<td align=\"center\" colspan=\"3\" title=\"Increase in FCN which corresponds to 1 standard deviation\">\n",
       "up = 1.0\n",
       "</td>\n",
       "</tr>\n",
       "<tr>\n",
       "<td align=\"center\" title=\"Validity of the migrad call\">\n",
       "Valid Min.\n",
       "</td>\n",
       "<td align=\"center\" title=\"Validity of parameters\">\n",
       "Valid Param.\n",
       "</td>\n",
       "<td align=\"center\" title=\"Is EDM above goal EDM?\">\n",
       "Above EDM\n",
       "</td>\n",
       "<td align=\"center\" colspan=\"2\" title=\"Did last migrad call reach max call limit?\">\n",
       "Reached call limit\n",
       "</td>\n",
       "</tr>\n",
       "<tr>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "True\n",
       "</td>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "True\n",
       "</td>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "False\n",
       "</td>\n",
       "<td align=\"center\" colspan=\"2\" style=\"background-color:#92CCA6;\">\n",
       "False\n",
       "</td>\n",
       "</tr>\n",
       "<tr>\n",
       "<td align=\"center\" title=\"Did Hesse fail?\">\n",
       "Hesse failed\n",
       "</td>\n",
       "<td align=\"center\" title=\"Has covariance matrix\">\n",
       "Has cov.\n",
       "</td>\n",
       "<td align=\"center\" title=\"Is covariance matrix accurate?\">\n",
       "Accurate\n",
       "</td>\n",
       "<td align=\"center\" title=\"Is covariance matrix positive definite?\">\n",
       "Pos. def.\n",
       "</td>\n",
       "<td align=\"center\" title=\"Was positive definiteness enforced by Minuit?\">\n",
       "Forced\n",
       "</td>\n",
       "</tr>\n",
       "<tr>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "False\n",
       "</td>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "True\n",
       "</td>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "True\n",
       "</td>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "True\n",
       "</td>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "False\n",
       "</td>\n",
       "</tr>\n",
       "</table>\n",
       "<table>\n",
       "<tr style=\"background-color:#F4F4F4;\">\n",
       "<td/>\n",
       "<th title=\"Variable name\">\n",
       "Name\n",
       "</th>\n",
       "<th title=\"Value of parameter\">\n",
       "Value\n",
       "</th>\n",
       "<th title=\"Hesse error\">\n",
       "Hesse Error\n",
       "</th>\n",
       "<th title=\"Minos lower error\">\n",
       "Minos Error-\n",
       "</th>\n",
       "<th title=\"Minos upper error\">\n",
       "Minos Error+\n",
       "</th>\n",
       "<th title=\"Lower limit of the parameter\">\n",
       "Limit-\n",
       "</th>\n",
       "<th title=\"Upper limit of the parameter\">\n",
       "Limit+\n",
       "</th>\n",
       "<th title=\"Is the parameter fixed in the fit\">\n",
       "Fixed\n",
       "</th>\n",
       "</tr>\n",
       "<tr style=\"background-color:#FFFFFF;\">\n",
       "<td>\n",
       "0\n",
       "</td>\n",
       "<td>\n",
       "x\n",
       "</td>\n",
       "<td>\n",
       "1\n",
       "</td>\n",
       "<td>\n",
       "1\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "</tr>\n",
       "<tr style=\"background-color:#F4F4F4;\">\n",
       "<td>\n",
       "1\n",
       "</td>\n",
       "<td>\n",
       "y\n",
       "</td>\n",
       "<td>\n",
       "2\n",
       "</td>\n",
       "<td>\n",
       "1\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "</tr>\n",
       "<tr style=\"background-color:#FFFFFF;\">\n",
       "<td>\n",
       "2\n",
       "</td>\n",
       "<td>\n",
       "z\n",
       "</td>\n",
       "<td>\n",
       "3\n",
       "</td>\n",
       "<td>\n",
       "1\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "</tr>\n",
       "</table>\n"
      ],
      "text/plain": [
       "------------------------------------------------------------------\n",
       "| FCN = 1                       |      Ncalls=36 (36 total)      |\n",
       "| EDM = 2.26e-19 (Goal: 0.0002) |            up = 1.0            |\n",
       "------------------------------------------------------------------\n",
       "|  Valid Min.   | Valid Param.  | Above EDM | Reached call limit |\n",
       "------------------------------------------------------------------\n",
       "|     True      |     True      |   False   |       False        |\n",
       "------------------------------------------------------------------\n",
       "| Hesse failed  |   Has cov.    | Accurate  | Pos. def. | Forced |\n",
       "------------------------------------------------------------------\n",
       "|     False     |     True      |   True    |   True    | False  |\n",
       "------------------------------------------------------------------\n",
       "------------------------------------------------------------------------------------------\n",
       "|   | Name |   Value   | Hesse Err | Minos Err- | Minos Err+ | Limit-  | Limit+  | Fixed |\n",
       "------------------------------------------------------------------------------------------\n",
       "| 0 | x    |     1     |     1     |            |            |         |         |       |\n",
       "| 1 | y    |     2     |     1     |            |            |         |         |       |\n",
       "| 2 | z    |     3     |     1     |            |            |         |         |       |\n",
       "------------------------------------------------------------------------------------------"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m = Minuit(cython_func, name=(\"x\", \"y\", \"z\"), pedantic=False)\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": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%cython\n",
    "cimport cython\n",
    "\n",
    "@cython.embedsignature(True)  # generate a signature that iminuit can extact\n",
    "def cython_f(double x, double y, double z):\n",
    "    return (x - 1.) ** 2 + (y - 2.) ** 2 + (z - 3.) ** 2 + 1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table>\n",
       "<tr>\n",
       "<td colspan=\"2\" title=\"Minimum value of function\">\n",
       "FCN = 1\n",
       "</td>\n",
       "<td align=\"center\" colspan=\"3\" title=\"No. of calls in last algorithm and total number of calls\">\n",
       "Ncalls = 36 (36 total)\n",
       "</td>\n",
       "</tr>\n",
       "<tr>\n",
       "<td colspan=\"2\" title=\"Estimated distance to minimum and target threshold\">\n",
       "EDM = 2.26e-19 (Goal: 0.0002)\n",
       "</td>\n",
       "<td align=\"center\" colspan=\"3\" title=\"Increase in FCN which corresponds to 1 standard deviation\">\n",
       "up = 1.0\n",
       "</td>\n",
       "</tr>\n",
       "<tr>\n",
       "<td align=\"center\" title=\"Validity of the migrad call\">\n",
       "Valid Min.\n",
       "</td>\n",
       "<td align=\"center\" title=\"Validity of parameters\">\n",
       "Valid Param.\n",
       "</td>\n",
       "<td align=\"center\" title=\"Is EDM above goal EDM?\">\n",
       "Above EDM\n",
       "</td>\n",
       "<td align=\"center\" colspan=\"2\" title=\"Did last migrad call reach max call limit?\">\n",
       "Reached call limit\n",
       "</td>\n",
       "</tr>\n",
       "<tr>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "True\n",
       "</td>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "True\n",
       "</td>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "False\n",
       "</td>\n",
       "<td align=\"center\" colspan=\"2\" style=\"background-color:#92CCA6;\">\n",
       "False\n",
       "</td>\n",
       "</tr>\n",
       "<tr>\n",
       "<td align=\"center\" title=\"Did Hesse fail?\">\n",
       "Hesse failed\n",
       "</td>\n",
       "<td align=\"center\" title=\"Has covariance matrix\">\n",
       "Has cov.\n",
       "</td>\n",
       "<td align=\"center\" title=\"Is covariance matrix accurate?\">\n",
       "Accurate\n",
       "</td>\n",
       "<td align=\"center\" title=\"Is covariance matrix positive definite?\">\n",
       "Pos. def.\n",
       "</td>\n",
       "<td align=\"center\" title=\"Was positive definiteness enforced by Minuit?\">\n",
       "Forced\n",
       "</td>\n",
       "</tr>\n",
       "<tr>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "False\n",
       "</td>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "True\n",
       "</td>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "True\n",
       "</td>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "True\n",
       "</td>\n",
       "<td align=\"center\" style=\"background-color:#92CCA6;\">\n",
       "False\n",
       "</td>\n",
       "</tr>\n",
       "</table>\n",
       "<table>\n",
       "<tr style=\"background-color:#F4F4F4;\">\n",
       "<td/>\n",
       "<th title=\"Variable name\">\n",
       "Name\n",
       "</th>\n",
       "<th title=\"Value of parameter\">\n",
       "Value\n",
       "</th>\n",
       "<th title=\"Hesse error\">\n",
       "Hesse Error\n",
       "</th>\n",
       "<th title=\"Minos lower error\">\n",
       "Minos Error-\n",
       "</th>\n",
       "<th title=\"Minos upper error\">\n",
       "Minos Error+\n",
       "</th>\n",
       "<th title=\"Lower limit of the parameter\">\n",
       "Limit-\n",
       "</th>\n",
       "<th title=\"Upper limit of the parameter\">\n",
       "Limit+\n",
       "</th>\n",
       "<th title=\"Is the parameter fixed in the fit\">\n",
       "Fixed\n",
       "</th>\n",
       "</tr>\n",
       "<tr style=\"background-color:#FFFFFF;\">\n",
       "<td>\n",
       "0\n",
       "</td>\n",
       "<td>\n",
       "x\n",
       "</td>\n",
       "<td>\n",
       "1\n",
       "</td>\n",
       "<td>\n",
       "1\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "</tr>\n",
       "<tr style=\"background-color:#F4F4F4;\">\n",
       "<td>\n",
       "1\n",
       "</td>\n",
       "<td>\n",
       "y\n",
       "</td>\n",
       "<td>\n",
       "2\n",
       "</td>\n",
       "<td>\n",
       "1\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "</tr>\n",
       "<tr style=\"background-color:#FFFFFF;\">\n",
       "<td>\n",
       "2\n",
       "</td>\n",
       "<td>\n",
       "z\n",
       "</td>\n",
       "<td>\n",
       "3\n",
       "</td>\n",
       "<td>\n",
       "1\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "<td>\n",
       "\n",
       "</td>\n",
       "</tr>\n",
       "</table>\n"
      ],
      "text/plain": [
       "------------------------------------------------------------------\n",
       "| FCN = 1                       |      Ncalls=36 (36 total)      |\n",
       "| EDM = 2.26e-19 (Goal: 0.0002) |            up = 1.0            |\n",
       "------------------------------------------------------------------\n",
       "|  Valid Min.   | Valid Param.  | Above EDM | Reached call limit |\n",
       "------------------------------------------------------------------\n",
       "|     True      |     True      |   False   |       False        |\n",
       "------------------------------------------------------------------\n",
       "| Hesse failed  |   Has cov.    | Accurate  | Pos. def. | Forced |\n",
       "------------------------------------------------------------------\n",
       "|     False     |     True      |   True    |   True    | False  |\n",
       "------------------------------------------------------------------\n",
       "------------------------------------------------------------------------------------------\n",
       "|   | Name |   Value   | Hesse Err | Minos Err- | Minos Err+ | Limit-  | Limit+  | Fixed |\n",
       "------------------------------------------------------------------------------------------\n",
       "| 0 | x    |     1     |     1     |            |            |         |         |       |\n",
       "| 1 | y    |     2     |     1     |            |            |         |         |       |\n",
       "| 2 | z    |     3     |     1     |            |            |         |         |       |\n",
       "------------------------------------------------------------------------------------------"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m = Minuit(cython_f, pedantic=False, errordef=1)\n",
    "m.migrad()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now it works without forcing parameter names."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.7.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
