{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "2d17761e",
   "metadata": {},
   "source": [
    "# df038_NumbaDeclare\n",
    "This tutorial illustrates how PyROOT supports declaring C++ callables from\n",
    "Python callables making them, for example, usable with RDataFrame. The feature\n",
    "uses the numba Python package for just-in-time compilation of the Python callable\n",
    "and supports fundamental types and ROOT::RVec thereof.\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "**Author:** Stefan Wunsch  \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:10 PM.</small></i>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "5e790f77",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:10:22.042096Z",
     "iopub.status.busy": "2026-05-19T20:10:22.041927Z",
     "iopub.status.idle": "2026-05-19T20:10:23.106432Z",
     "shell.execute_reply": "2026-05-19T20:10:23.105590Z"
    }
   },
   "outputs": [],
   "source": [
    "import ROOT"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e594791",
   "metadata": {},
   "source": [
    "To mark a Python callable to be used from C++, you have to use the decorator\n",
    "provided by PyROOT passing the C++ types of the input arguments and the return\n",
    "value."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "b306674f",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:10:23.119477Z",
     "iopub.status.busy": "2026-05-19T20:10:23.119322Z",
     "iopub.status.idle": "2026-05-19T20:10:23.918315Z",
     "shell.execute_reply": "2026-05-19T20:10:23.896396Z"
    }
   },
   "outputs": [],
   "source": [
    "@ROOT.Numba.Declare(['float', 'int'], 'float')\n",
    "def pypow(x, y):\n",
    "    return x**y"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7cb91cfc",
   "metadata": {},
   "source": [
    "The Python callable is now available from C++ in the Numba namespace.\n",
    "For example, we can use it from the interpreter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "7eeb7262",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:10:23.930548Z",
     "iopub.status.busy": "2026-05-19T20:10:23.930294Z",
     "iopub.status.idle": "2026-05-19T20:10:24.046099Z",
     "shell.execute_reply": "2026-05-19T20:10:24.045723Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2^3 = 8\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "139983781803136"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ROOT.gInterpreter.ProcessLine('cout << \"2^3 = \" << Numba::pypow(2, 3) << endl;')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "251ab8c6",
   "metadata": {},
   "source": [
    "Or we can use the callable as well within a RDataFrame workflow."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "05b5cb6e",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:10:24.063241Z",
     "iopub.status.busy": "2026-05-19T20:10:24.063096Z",
     "iopub.status.idle": "2026-05-19T20:10:25.707298Z",
     "shell.execute_reply": "2026-05-19T20:10:25.706645Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "pypow([0. 1. 2. 3.], 3) = [ 0.  1.  8. 27.]\n"
     ]
    }
   ],
   "source": [
    "data = ROOT.RDataFrame(4).Define('x', '(float)rdfentry_')\\\n",
    "                         .Define('x_pow3', 'Numba::pypow(x, 3)')\\\n",
    "                         .AsNumpy()\n",
    "\n",
    "print('pypow({}, 3) = {}'.format(data['x'], data['x_pow3']))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e35429fb",
   "metadata": {},
   "source": [
    "ROOT uses the numba Python package to create C++ functions from python ones.\n",
    "We support as input and return types of the callable fundamental types and\n",
    "ROOT::RVec thereof. See the following callable computing the power of the\n",
    "elements in an array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "ce9ffbc0",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:10:25.710687Z",
     "iopub.status.busy": "2026-05-19T20:10:25.710457Z",
     "iopub.status.idle": "2026-05-19T20:10:27.694434Z",
     "shell.execute_reply": "2026-05-19T20:10:27.693228Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "139983781803136"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "pypowarray({ 0, 1, 2, 3 }, 3) =  { 0, 1, 8, 27 }\n"
     ]
    }
   ],
   "source": [
    "@ROOT.Numba.Declare(['RVecF', 'int'], 'RVecF')\n",
    "def pypowarray(x, y):\n",
    "    return x**y\n",
    "\n",
    "ROOT.gInterpreter.ProcessLine('''\n",
    "ROOT::RVecF x = {0, 1, 2, 3};\n",
    "cout << \"pypowarray(\" << x << \", 3) =  \" << Numba::pypowarray(x, 3) << endl;\n",
    "''')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d3bdaf3",
   "metadata": {},
   "source": [
    "and now with RDataFrame"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "182283d1",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:10:27.713161Z",
     "iopub.status.busy": "2026-05-19T20:10:27.712970Z",
     "iopub.status.idle": "2026-05-19T20:10:28.533931Z",
     "shell.execute_reply": "2026-05-19T20:10:28.528650Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sum(pypowarray({ 1, 2, 3 }, 2)) = "
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " 14.0\n"
     ]
    }
   ],
   "source": [
    "s = ROOT.RDataFrame(1).Define('x', 'ROOT::RVecF{1,2,3}')\\\n",
    "                      .Define('x2', 'Numba::pypowarray(x, 2)')\\\n",
    "                      .Sum('x2') # 1 + 4 + 9 == 14\n",
    "print('sum(pypowarray({ 1, 2, 3 }, 2)) = ', s.GetValue())"
   ]
  }
 ],
 "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
}
