{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "67aba2b5",
   "metadata": {},
   "source": [
    "# exampleFunction\n",
    "Example of using Python functions as inputs to numerical algorithms\n",
    "using the ROOT Functor class. \n",
    "\n",
    "\n",
    "\n",
    "\n",
    "**Author:** Lorenzo Moneta  \n",
    "<i><small>This notebook tutorial was automatically generated with <a href= \"https://github.com/root-project/root/blob/master/documentation/doxygen/converttonotebook.py\">ROOTBOOK-izer</a> from the macro found in the ROOT repository  on Tuesday, May 19, 2026 at 08:24 PM.</small></i>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "26842f22",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:24:23.534803Z",
     "iopub.status.busy": "2026-05-19T20:24:23.534685Z",
     "iopub.status.idle": "2026-05-19T20:24:24.573906Z",
     "shell.execute_reply": "2026-05-19T20:24:24.573366Z"
    }
   },
   "outputs": [],
   "source": [
    "import array\n",
    "\n",
    "import ROOT\n",
    "\n",
    "try:\n",
    "    import numpy as np\n",
    "except Exception as e:\n",
    "    print(\"Failed to import numpy:\", e)\n",
    "    exit()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e2a2cf7",
   "metadata": {},
   "source": [
    " example 1D function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "6f4cace6",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:24:24.576004Z",
     "iopub.status.busy": "2026-05-19T20:24:24.575809Z",
     "iopub.status.idle": "2026-05-19T20:24:24.943385Z",
     "shell.execute_reply": "2026-05-19T20:24:24.942645Z"
    }
   },
   "outputs": [],
   "source": [
    "def f(x):\n",
    "   return x*x -1\n",
    "\n",
    "func = ROOT.Math.Functor1D(f)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7fd8b1d4",
   "metadata": {},
   "source": [
    "xample of using the integral"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "b48c5c56",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:24:24.948649Z",
     "iopub.status.busy": "2026-05-19T20:24:24.948486Z",
     "iopub.status.idle": "2026-05-19T20:24:25.103642Z",
     "shell.execute_reply": "2026-05-19T20:24:25.102943Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Use Functor1D for wrapping one-dimensional function and compute integral of f(x) = x^2-1\n",
      "integral-1D value =  5.999999999999999\n"
     ]
    }
   ],
   "source": [
    "print(\"Use Functor1D for wrapping one-dimensional function and compute integral of f(x) = x^2-1\")\n",
    "\n",
    "ig = ROOT.Math.Integrator()\n",
    "ig.SetFunction(func)\n",
    "\n",
    "value = ig.Integral(0, 3)\n",
    "print(\"integral-1D value = \", value)\n",
    "expValue = 6\n",
    "if (not ROOT.TMath.AreEqualRel(value, expValue, 1.E-15)) :\n",
    "   print(\"Error computing integral - computed value - different than expected, diff = \", value - expValue)\n",
    "   "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44446759",
   "metadata": {},
   "source": [
    "example multi-dim function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d595aa6a",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:24:25.105346Z",
     "iopub.status.busy": "2026-05-19T20:24:25.105213Z",
     "iopub.status.idle": "2026-05-19T20:24:25.272468Z",
     "shell.execute_reply": "2026-05-19T20:24:25.271840Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "Use Functor for wrapping a multi-dimensional function, the Rosenbrock Function r(x,y) and find its minimum\n"
     ]
    }
   ],
   "source": [
    "print(\"\\n\\nUse Functor for wrapping a multi-dimensional function, the Rosenbrock Function r(x,y) and find its minimum\")\n",
    "\n",
    "def RosenbrockFunction(xx):\n",
    "  x = xx[0]\n",
    "  y = xx[1]\n",
    "  tmp1 = y-x*x\n",
    "  tmp2 = 1-x\n",
    "  return 100*tmp1*tmp1+tmp2*tmp2\n",
    "\n",
    "\n",
    "func2D = ROOT.Math.Functor(RosenbrockFunction,2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1d26cde1",
   "metadata": {},
   "source": [
    "# minimize multi-dim function using fitter class"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "fe56c501",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:24:25.280485Z",
     "iopub.status.busy": "2026-05-19T20:24:25.280350Z",
     "iopub.status.idle": "2026-05-19T20:24:25.402254Z",
     "shell.execute_reply": "2026-05-19T20:24:25.401405Z"
    }
   },
   "outputs": [],
   "source": [
    "fitter = ROOT.Fit.Fitter()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e439abd1",
   "metadata": {},
   "source": [
    "se a numpy array to pass initial parameter array "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "a161f526",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:24:25.409352Z",
     "iopub.status.busy": "2026-05-19T20:24:25.409213Z",
     "iopub.status.idle": "2026-05-19T20:24:25.583727Z",
     "shell.execute_reply": "2026-05-19T20:24:25.583314Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "****************************************\n",
      "Minimizer is Minuit2 / Migrad\n",
      "MinFCN                    =    1.687e-08\n",
      "NDf                       =            0\n",
      "Edm                       =  1.68896e-08\n",
      "NCalls                    =          146\n",
      "Par_0                     =     0.999952   +/-   1.00372     \n",
      "Par_1                     =     0.999892   +/-   2.00986     \n"
     ]
    }
   ],
   "source": [
    "initialParams = np.array([0.,0.], dtype='d')\n",
    "fitter.FitFCN(func2D, initialParams)\n",
    "fitter.Result().Print(ROOT.std.cout)\n",
    "if (not ROOT.TMath.AreEqualRel(fitter.Result().Parameter(0), 1, 1.E-3) or not ROOT.TMath.AreEqualRel(fitter.Result().Parameter(1), 1, 1.E-3)) :\n",
    "   print(\"Error minimizing Rosenbrock function \")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "357f1104",
   "metadata": {},
   "source": [
    " example 1d grad function\n",
    " derivative of f(x)= x**2-1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "ab89040b",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:24:25.595542Z",
     "iopub.status.busy": "2026-05-19T20:24:25.595400Z",
     "iopub.status.idle": "2026-05-19T20:24:25.699118Z",
     "shell.execute_reply": "2026-05-19T20:24:25.698429Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "Use GradFunctor1D for making a function object implementing f(x) and f'(x)\n"
     ]
    }
   ],
   "source": [
    "print(\"\\n\\nUse GradFunctor1D for making a function object implementing f(x) and f'(x)\")\n",
    "\n",
    "def g(x): return 2 * x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cf4fe39e",
   "metadata": {},
   "source": [
    "GSL_Newton is part of ROOT's MathMore library, which is not always active.\n",
    "Let's therefore run this in a try block:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "1ae85d72",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:24:25.700678Z",
     "iopub.status.busy": "2026-05-19T20:24:25.700529Z",
     "iopub.status.idle": "2026-05-19T20:24:25.961130Z",
     "shell.execute_reply": "2026-05-19T20:24:25.960345Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found root value x0 : f(x0) = 0  :   1.0\n",
      "\n",
      "\n",
      "Use GradFunctor for making a function object implementing f(x,y) and df(x,y)/dx and df(x,y)/dy\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    gradFunc = ROOT.Math.GradFunctor1D(f, g)\n",
    "    rf = ROOT.Math.RootFinder(ROOT.Math.RootFinder.kGSL_NEWTON)\n",
    "    rf.SetFunction(gradFunc, 3)\n",
    "    rf.Solve()\n",
    "    value = rf.Root()\n",
    "    print(\"Found root value x0 : f(x0) = 0  :  \", value)\n",
    "    if value != 1:\n",
    "        print(\"Error finding a ROOT of function f(x)=x^2-1\")\n",
    "except Exception as e:\n",
    "    print(e)\n",
    "\n",
    "\n",
    "print(\"\\n\\nUse GradFunctor for making a function object implementing f(x,y) and df(x,y)/dx and df(x,y)/dy\")\n",
    "\n",
    "def RosenbrockDerivatives(xx, icoord):\n",
    "  x = xx[0]\n",
    "  y = xx[1]\n",
    "  #derivative w.r.t x \n",
    "  if (icoord == 0) :\n",
    "    return 2*(200*x*x*x-200*x*y+x-1)\n",
    "  else : \n",
    "    return 200 * (y - x * x)\n",
    "    \n",
    "gradFunc2d = ROOT.Math.GradFunctor(RosenbrockFunction, RosenbrockDerivatives, 2)\n",
    "\n",
    "fitter = ROOT.Fit.Fitter()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "087bb3a5",
   "metadata": {},
   "source": [
    "ere we use a python array to pass initial parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "0a0ef6e1",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:24:25.970454Z",
     "iopub.status.busy": "2026-05-19T20:24:25.970310Z",
     "iopub.status.idle": "2026-05-19T20:24:26.144479Z",
     "shell.execute_reply": "2026-05-19T20:24:26.144092Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "****************************************\n",
      "Minimizer is Minuit2 / Migrad\n",
      "MinFCN                    =  2.72222e-08\n",
      "NDf                       =            0\n",
      "Edm                       =  2.72448e-08\n",
      "NCalls                    =           76\n",
      "Par_0                     =     0.999954   +/-   1.00444     \n",
      "Par_1                     =     0.999892   +/-   2.01131     \n"
     ]
    }
   ],
   "source": [
    "initialParams = array.array('d',[0.,0.])\n",
    "fitter.FitFCN(gradFunc2d, initialParams)\n",
    "fitter.Result().Print(ROOT.std.cout)\n",
    "if (not ROOT.TMath.AreEqualRel(fitter.Result().Parameter(0), 1, 1.E-3) or not ROOT.TMath.AreEqualRel(fitter.Result().Parameter(1), 1, 1.E-3)) :\n",
    "   print(\"Error minimizing Rosenbrock function \")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e84ff4af",
   "metadata": {},
   "source": [
    "Draw all canvases "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "14fb3a9d",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:24:26.148183Z",
     "iopub.status.busy": "2026-05-19T20:24:26.148062Z",
     "iopub.status.idle": "2026-05-19T20:24:26.255877Z",
     "shell.execute_reply": "2026-05-19T20:24:26.255173Z"
    }
   },
   "outputs": [],
   "source": [
    "from ROOT import gROOT \n",
    "gROOT.GetListOfCanvases().Draw()"
   ]
  }
 ],
 "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.12.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
