From ce91bdf2231a42000fb753b57e90329ad7d9e17b Mon Sep 17 00:00:00 2001 From: N!no Date: Thu, 3 Jun 2021 06:39:06 -0400 Subject: [PATCH 1/7] feat: create numba example --- docs/examples/HistNumbaFill.ipynb | 301 ++++++++++++++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 docs/examples/HistNumbaFill.ipynb diff --git a/docs/examples/HistNumbaFill.ipynb b/docs/examples/HistNumbaFill.ipynb new file mode 100644 index 00000000..fcd7fe9f --- /dev/null +++ b/docs/examples/HistNumbaFill.ipynb @@ -0,0 +1,301 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Hist Design Prototype" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is `fill` method in python loop:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import numba as nb\n", + "from hist import Hist\n", + "from hist.axis import Regular\n", + "\n", + "# assets\n", + "array = np.random.randn(\n", + " 10000,\n", + ")\n", + "h = Hist.new.Reg(100, -3, 3, name=\"x\", label=\"x-axis\").Double()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# python fill\n", + "# h.fill(array)\n", + "# h" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Numba: Hist" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To extend the Numba, we first need to create a Hist type `HistType` for `Hist`, and then teach Numba about our type inference additions:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from numba import types\n", + "from numba.extending import typeof_impl, as_numba_type, type_callable\n", + "\n", + "# create Numba type\n", + "class RegularType(types.Type):\n", + " def __init__(self):\n", + " super().__init__(name=\"Regular\")\n", + "\n", + "\n", + "regular_type = RegularType()\n", + "\n", + "# infer values\n", + "@typeof_impl.register(Regular)\n", + "def typeof_index(val, c):\n", + " return regular_type\n", + "\n", + "\n", + "# infer annotations\n", + "as_numba_type.register(Regular, regular_type)\n", + "\n", + "# infer operations\n", + "@type_callable(Regular)\n", + "def type_regular(context):\n", + " def typer(bins, lo, hi):\n", + " if (\n", + " isinstance(bins, types.Integer)\n", + " and isinstance(lo, types.Float)\n", + " and isinstance(hi, types.Float)\n", + " ):\n", + " return regular_type\n", + "\n", + " return typer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We also need to teach Numba how to actually generate native representation for the new operations:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "from numba.core import cgutils\n", + "from numba.extending import (\n", + " models,\n", + " register_model,\n", + " make_attribute_wrapper,\n", + " overload_attribute,\n", + " lower_builtin,\n", + " box,\n", + " unbox,\n", + " NativeValue,\n", + ")\n", + "\n", + "# define data model\n", + "@register_model(RegularType)\n", + "class RegularModel(models.StructModel):\n", + " def __init__(self, dmm, fe_type):\n", + " members = [\n", + " (\"bins\", types.int32),\n", + " (\"lo\", types.float64),\n", + " (\"hi\", types.float64),\n", + " ]\n", + " models.StructModel.__init__(self, dmm, fe_type, members)\n", + "\n", + "\n", + "# expose attributes, porperties and constructors\n", + "make_attribute_wrapper(RegularType, \"bins\", \"bins\")\n", + "make_attribute_wrapper(RegularType, \"lo\", \"lo\")\n", + "make_attribute_wrapper(RegularType, \"hi\", \"hi\")\n", + "\n", + "\n", + "@overload_attribute(RegularType, \"width\")\n", + "def get_width(reg):\n", + " def getter(reg):\n", + " return (reg.hi - reg.lo) / reg.bins\n", + "\n", + " return getter\n", + "\n", + "\n", + "@lower_builtin(Regular, types.Integer, types.Float, types.Float)\n", + "def impl_reg(context, builder, sig, args):\n", + " typ = sig.return_type\n", + " lo, hi, bins = args\n", + " reg = cgutils.create_struct_proxy(typ)(context, builder)\n", + " reg.lo = lo\n", + " reg.hi = hi\n", + " reg.bins = bins\n", + " return reg._getvalue()\n", + "\n", + "\n", + "# unbox and box\n", + "@unbox(RegularType)\n", + "def unbox_reg(typ, obj, c):\n", + " bins_obj = c.pyapi.object_getattr_string(obj, \"bins\")\n", + " lo_obj = c.pyapi.object_getattr_string(obj, \"lo\")\n", + " hi_obj = c.pyapi.object_getattr_string(obj, \"hi\")\n", + " reg = cgutils.create_struct_proxy(typ)(c.context, c.builder)\n", + " reg.bins = c.pyapi.float_as_double(bins_obj)\n", + " reg.lo = c.pyapi.float_as_double(lo_obj)\n", + " reg.hi = c.pyapi.float_as_double(hi_obj)\n", + " c.pyapi.decref(bins_obj)\n", + " c.pyapi.decref(lo_obj)\n", + " c.pyapi.decref(hi_obj)\n", + " is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred())\n", + " return NativeValue(reg._getvalue(), is_error=is_error)\n", + "\n", + "\n", + "@box(RegularType)\n", + "def box_reg(typ, val, c):\n", + " reg = cgutils.create_struct_proxy(typ)(c.context, c.builder, value=val)\n", + " bins_obj = c.pyapi.float_from_double(reg.bins)\n", + " lo_obj = c.pyapi.float_from_double(reg.lo)\n", + " hi_obj = c.pyapi.float_from_double(reg.hi)\n", + " class_obj = c.pyapi.unserialize(c.pyapi.serialize_object(Regular))\n", + " res = c.pyapi.call_function_objargs(class_obj, (bins_obj, lo_obj, hi_obj))\n", + " c.pyapi.decref(bins_obj)\n", + " c.pyapi.decref(lo_obj)\n", + " c.pyapi.decref(hi_obj)\n", + " c.pyapi.decref(class_obj)\n", + " return res" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + ":1: NumbaWarning: \n", + "Compilation is falling back to object mode WITH looplifting enabled because Function nb_create_reg failed at nopython mode lowering due to: Invalid store of i64 to double in <__main__.RegularModel object at 0x183567040> (trying to write member #1)\n", + "\n", + "File \"\", line 3:\n", + "def nb_create_reg():\n", + " return Regular(50, -5., 5.,)\n", + " ^\n", + "\n", + "During: lowering \"$10call_function.4 = call $2load_global.0($const4.1, $const6.2, $const8.3, func=$2load_global.0, args=[Var($const4.1, :3), Var($const6.2, :3), Var($const8.3, :3)], kws=(), vararg=None)\" at (3)\n", + " @nb.jit\n", + "/Users/ninolau/anaconda3/envs/hist/lib/python3.9/site-packages/numba/core/object_mode_passes.py:151: NumbaWarning: Function \"nb_create_reg\" was compiled in object mode without forceobj=True.\n", + "\n", + "File \"\", line 2:\n", + "@nb.jit\n", + "def nb_create_reg():\n", + "^\n", + "\n", + " warnings.warn(errors.NumbaWarning(warn_msg,\n", + "/Users/ninolau/anaconda3/envs/hist/lib/python3.9/site-packages/numba/core/object_mode_passes.py:161: NumbaDeprecationWarning: \n", + "Fall-back from the nopython compilation path to the object mode compilation path has been detected, this is deprecated behaviour.\n", + "\n", + "For more information visit https://numba.pydata.org/numba-doc/latest/reference/deprecation.html#deprecation-of-object-mode-fall-back-behaviour-when-using-jit\n", + "\n", + "File \"\", line 2:\n", + "@nb.jit\n", + "def nb_create_reg():\n", + "^\n", + "\n", + " warnings.warn(errors.NumbaDeprecationWarning(msg,\n" + ] + }, + { + "data": { + "text/plain": [ + "Regular(50, -5, 5)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@nb.jit\n", + "def nb_create_reg():\n", + " return Regular(\n", + " 50,\n", + " -5.0,\n", + " 5.0,\n", + " )\n", + "\n", + "\n", + "nb_create_reg()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# def nb_hist_property(h):\n", + "# print(h.lo)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# Numba fill\n", + "# nb_fill(h, array)\n", + "# h" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "hist", + "language": "python", + "name": "hist" + }, + "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.9.4" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 00c1d2c745867a4ec045827851d8c5b45012568a Mon Sep 17 00:00:00 2001 From: N!no Date: Tue, 3 Aug 2021 21:29:37 -0400 Subject: [PATCH 2/7] Update HistNumbaFill.ipynb --- docs/examples/HistNumbaFill.ipynb | 199 ++++++++++-------------------- 1 file changed, 63 insertions(+), 136 deletions(-) diff --git a/docs/examples/HistNumbaFill.ipynb b/docs/examples/HistNumbaFill.ipynb index fcd7fe9f..d33f08ed 100644 --- a/docs/examples/HistNumbaFill.ipynb +++ b/docs/examples/HistNumbaFill.ipynb @@ -16,14 +16,14 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import numba as nb\n", "from hist import Hist\n", - "from hist.axis import Regular\n", + "from hist import axis\n", "\n", "# assets\n", "array = np.random.randn(\n", @@ -34,13 +34,24 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# python fill\n", - "# h.fill(array)\n", - "# h" + "h.fill(array)\n", + "h" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import hist\n", + "\n", + "isinstance(h.axes[0], hist.axis.Regular)" ] }, { @@ -59,7 +70,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -67,34 +78,31 @@ "from numba.extending import typeof_impl, as_numba_type, type_callable\n", "\n", "# create Numba type\n", - "class RegularType(types.Type):\n", + "class HistType(types.Type):\n", " def __init__(self):\n", - " super().__init__(name=\"Regular\")\n", + " super().__init__(name=\"Hist\")\n", "\n", "\n", - "regular_type = RegularType()\n", + "hist_type = HistType()\n", "\n", "# infer values\n", - "@typeof_impl.register(Regular)\n", + "@typeof_impl.register(Hist)\n", "def typeof_index(val, c):\n", - " return regular_type\n", + " return hist_type\n", "\n", "\n", "# infer annotations\n", - "as_numba_type.register(Regular, regular_type)\n", + "as_numba_type.register(Hist, hist_type)\n", "\n", "# infer operations\n", - "@type_callable(Regular)\n", - "def type_regular(context):\n", - " def typer(bins, lo, hi):\n", - " if (\n", - " isinstance(bins, types.Integer)\n", - " and isinstance(lo, types.Float)\n", - " and isinstance(hi, types.Float)\n", - " ):\n", - " return regular_type\n", - "\n", - " return typer" + "@type_callable(Hist)\n", + "def type_hist(context):\n", + " def typer(axes):\n", + " for ax in axes:\n", + " # if not (isinstance(ax, types of axis)):\n", + " return typer\n", + "\n", + " return hist_type" ] }, { @@ -106,7 +114,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -123,151 +131,70 @@ ")\n", "\n", "# define data model\n", - "@register_model(RegularType)\n", - "class RegularModel(models.StructModel):\n", + "@register_model(HistType)\n", + "class HistModel(models.StructModel):\n", " def __init__(self, dmm, fe_type):\n", " members = [\n", - " (\"bins\", types.int32),\n", - " (\"lo\", types.float64),\n", - " (\"hi\", types.float64),\n", + " # (\"axes\", types of list of axis),\n", " ]\n", " models.StructModel.__init__(self, dmm, fe_type, members)\n", "\n", "\n", "# expose attributes, porperties and constructors\n", - "make_attribute_wrapper(RegularType, \"bins\", \"bins\")\n", - "make_attribute_wrapper(RegularType, \"lo\", \"lo\")\n", - "make_attribute_wrapper(RegularType, \"hi\", \"hi\")\n", - "\n", - "\n", - "@overload_attribute(RegularType, \"width\")\n", - "def get_width(reg):\n", - " def getter(reg):\n", - " return (reg.hi - reg.lo) / reg.bins\n", - "\n", - " return getter\n", + "make_attribute_wrapper(HistType, \"axes\", \"axes\")\n", "\n", "\n", "@lower_builtin(Regular, types.Integer, types.Float, types.Float)\n", - "def impl_reg(context, builder, sig, args):\n", + "def impl_h(context, builder, sig, args):\n", + " axes = args\n", " typ = sig.return_type\n", - " lo, hi, bins = args\n", - " reg = cgutils.create_struct_proxy(typ)(context, builder)\n", - " reg.lo = lo\n", - " reg.hi = hi\n", - " reg.bins = bins\n", + " h = cgutils.create_struct_proxy(typ)(context, builder)\n", + " h.axes = axes\n", " return reg._getvalue()\n", "\n", "\n", "# unbox and box\n", - "@unbox(RegularType)\n", - "def unbox_reg(typ, obj, c):\n", - " bins_obj = c.pyapi.object_getattr_string(obj, \"bins\")\n", - " lo_obj = c.pyapi.object_getattr_string(obj, \"lo\")\n", - " hi_obj = c.pyapi.object_getattr_string(obj, \"hi\")\n", - " reg = cgutils.create_struct_proxy(typ)(c.context, c.builder)\n", - " reg.bins = c.pyapi.float_as_double(bins_obj)\n", - " reg.lo = c.pyapi.float_as_double(lo_obj)\n", - " reg.hi = c.pyapi.float_as_double(hi_obj)\n", - " c.pyapi.decref(bins_obj)\n", - " c.pyapi.decref(lo_obj)\n", - " c.pyapi.decref(hi_obj)\n", + "@unbox(HistType)\n", + "def unbox_h(typ, obj, c):\n", + " axes_obj = c.pyapi.object_getattr_string(obj, \"axes\")\n", + " h = cgutils.create_struct_proxy(typ)(c.context, c.builder)\n", + " # h.axes = c.pyapi.float_as_double(axes_obj)\n", + " c.pyapi.decref(axes_obj)\n", " is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred())\n", - " return NativeValue(reg._getvalue(), is_error=is_error)\n", + " return NativeValue(h._getvalue(), is_error=is_error)\n", "\n", "\n", - "@box(RegularType)\n", - "def box_reg(typ, val, c):\n", - " reg = cgutils.create_struct_proxy(typ)(c.context, c.builder, value=val)\n", - " bins_obj = c.pyapi.float_from_double(reg.bins)\n", - " lo_obj = c.pyapi.float_from_double(reg.lo)\n", - " hi_obj = c.pyapi.float_from_double(reg.hi)\n", - " class_obj = c.pyapi.unserialize(c.pyapi.serialize_object(Regular))\n", - " res = c.pyapi.call_function_objargs(class_obj, (bins_obj, lo_obj, hi_obj))\n", - " c.pyapi.decref(bins_obj)\n", - " c.pyapi.decref(lo_obj)\n", - " c.pyapi.decref(hi_obj)\n", + "@box(HistType)\n", + "def box_h(typ, val, c):\n", + " h = cgutils.create_struct_proxy(typ)(c.context, c.builder, value=val)\n", + " axes_obj = c.pyapi.float_from_double(h.axes)\n", + " class_obj = c.pyapi.unserialize(c.pyapi.serialize_object(Hist))\n", + " res = c.pyapi.call_function_objargs(class_obj, (axes_obj))\n", + " c.pyapi.decref(axes_obj)\n", " c.pyapi.decref(class_obj)\n", " return res" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - ":1: NumbaWarning: \n", - "Compilation is falling back to object mode WITH looplifting enabled because Function nb_create_reg failed at nopython mode lowering due to: Invalid store of i64 to double in <__main__.RegularModel object at 0x183567040> (trying to write member #1)\n", - "\n", - "File \"\", line 3:\n", - "def nb_create_reg():\n", - " return Regular(50, -5., 5.,)\n", - " ^\n", - "\n", - "During: lowering \"$10call_function.4 = call $2load_global.0($const4.1, $const6.2, $const8.3, func=$2load_global.0, args=[Var($const4.1, :3), Var($const6.2, :3), Var($const8.3, :3)], kws=(), vararg=None)\" at (3)\n", - " @nb.jit\n", - "/Users/ninolau/anaconda3/envs/hist/lib/python3.9/site-packages/numba/core/object_mode_passes.py:151: NumbaWarning: Function \"nb_create_reg\" was compiled in object mode without forceobj=True.\n", - "\n", - "File \"\", line 2:\n", - "@nb.jit\n", - "def nb_create_reg():\n", - "^\n", - "\n", - " warnings.warn(errors.NumbaWarning(warn_msg,\n", - "/Users/ninolau/anaconda3/envs/hist/lib/python3.9/site-packages/numba/core/object_mode_passes.py:161: NumbaDeprecationWarning: \n", - "Fall-back from the nopython compilation path to the object mode compilation path has been detected, this is deprecated behaviour.\n", - "\n", - "For more information visit https://numba.pydata.org/numba-doc/latest/reference/deprecation.html#deprecation-of-object-mode-fall-back-behaviour-when-using-jit\n", - "\n", - "File \"\", line 2:\n", - "@nb.jit\n", - "def nb_create_reg():\n", - "^\n", - "\n", - " warnings.warn(errors.NumbaDeprecationWarning(msg,\n" - ] - }, - { - "data": { - "text/plain": [ - "Regular(50, -5, 5)" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ + "reg_ax = axis.Regular(10, 0, 1)\n", + "\n", + "\n", "@nb.jit\n", - "def nb_create_reg():\n", - " return Regular(\n", - " 50,\n", - " -5.0,\n", - " 5.0,\n", - " )\n", + "def nb_create_Hist():\n", + " Hist(reg_ax)\n", "\n", "\n", - "nb_create_reg()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# def nb_hist_property(h):\n", - "# print(h.lo)" + "nb_create_Hist()" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ From 254c9e996ba2e7f973cd8e7acc73ab093002ffb4 Mon Sep 17 00:00:00 2001 From: N!no Date: Thu, 5 Aug 2021 22:40:36 -0400 Subject: [PATCH 3/7] Update HistNumbaFill.ipynb --- docs/examples/HistNumbaFill.ipynb | 150 +++++++++++++++++++++--------- 1 file changed, 105 insertions(+), 45 deletions(-) diff --git a/docs/examples/HistNumbaFill.ipynb b/docs/examples/HistNumbaFill.ipynb index d33f08ed..ee4ceffe 100644 --- a/docs/examples/HistNumbaFill.ipynb +++ b/docs/examples/HistNumbaFill.ipynb @@ -16,7 +16,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -25,7 +25,6 @@ "from hist import Hist\n", "from hist import axis\n", "\n", - "# assets\n", "array = np.random.randn(\n", " 10000,\n", ")\n", @@ -34,26 +33,53 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + "\n", + "-3\n", + "\n", + "\n", + "3\n", + "\n", + "\n", + "x-axis\n", + "\n", + "\n", + "\n", + "
\n", + "
\n", + "Regular(100, -3, 3, name='x', label='x-axis')
\n", + "
\n", + "Double() Σ=9973.0 (10000.0 with flow)\n", + "\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + "Hist(Regular(100, -3, 3, name='x', label='x-axis'), storage=Double()) # Sum: 9973.0 (10000.0 with flow)" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# python fill\n", "h.fill(array)\n", "h" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import hist\n", - "\n", - "isinstance(h.axes[0], hist.axis.Regular)" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -70,7 +96,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -99,8 +125,10 @@ "def type_hist(context):\n", " def typer(axes):\n", " for ax in axes:\n", - " # if not (isinstance(ax, types of axis)):\n", - " return typer\n", + " if not (\n", + " isinstance(ax, hist.axis.Regular)\n", + " ): # ToDo: Aassumed all are Regular axes\n", + " return typer\n", "\n", " return hist_type" ] @@ -114,7 +142,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -135,31 +163,43 @@ "class HistModel(models.StructModel):\n", " def __init__(self, dmm, fe_type):\n", " members = [\n", - " # (\"axes\", types of list of axis),\n", + " (\"bins\", types.int32),\n", + " (\"lo\", types.float64),\n", + " (\"hi\", types.float64),\n", " ]\n", " models.StructModel.__init__(self, dmm, fe_type, members)\n", "\n", "\n", "# expose attributes, porperties and constructors\n", - "make_attribute_wrapper(HistType, \"axes\", \"axes\")\n", + "make_attribute_wrapper(HistType, \"bins\", \"bins\")\n", + "make_attribute_wrapper(HistType, \"lo\", \"lo\")\n", + "make_attribute_wrapper(HistType, \"hi\", \"hi\")\n", "\n", "\n", - "@lower_builtin(Regular, types.Integer, types.Float, types.Float)\n", + "@lower_builtin(Hist, types.Integer, types.Float, types.Float)\n", "def impl_h(context, builder, sig, args):\n", - " axes = args\n", " typ = sig.return_type\n", + " lo, hi, bins = args\n", " h = cgutils.create_struct_proxy(typ)(context, builder)\n", - " h.axes = axes\n", - " return reg._getvalue()\n", + " h.lo = lo\n", + " h.hi = hi\n", + " h.bins = bins\n", + " return h._getvalue()\n", "\n", "\n", "# unbox and box\n", "@unbox(HistType)\n", "def unbox_h(typ, obj, c):\n", - " axes_obj = c.pyapi.object_getattr_string(obj, \"axes\")\n", + " bins_obj = c.pyapi.object_getattr_string(obj, \"bins\")\n", + " lo_obj = c.pyapi.object_getattr_string(obj, \"lo\")\n", + " hi_obj = c.pyapi.object_getattr_string(obj, \"hi\")\n", " h = cgutils.create_struct_proxy(typ)(c.context, c.builder)\n", - " # h.axes = c.pyapi.float_as_double(axes_obj)\n", - " c.pyapi.decref(axes_obj)\n", + " h.bins = c.pyapi.float_as_double(bins_obj)\n", + " h.lo = c.pyapi.float_as_double(lo_obj)\n", + " h.hi = c.pyapi.float_as_double(hi_obj)\n", + " c.pyapi.decref(bins_obj)\n", + " c.pyapi.decref(lo_obj)\n", + " c.pyapi.decref(hi_obj)\n", " is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred())\n", " return NativeValue(h._getvalue(), is_error=is_error)\n", "\n", @@ -167,29 +207,53 @@ "@box(HistType)\n", "def box_h(typ, val, c):\n", " h = cgutils.create_struct_proxy(typ)(c.context, c.builder, value=val)\n", - " axes_obj = c.pyapi.float_from_double(h.axes)\n", + " bins_obj = c.pyapi.float_from_double(h.bins)\n", + " lo_obj = c.pyapi.float_from_double(h.lo)\n", + " hi_obj = c.pyapi.float_from_double(h.hi)\n", " class_obj = c.pyapi.unserialize(c.pyapi.serialize_object(Hist))\n", - " res = c.pyapi.call_function_objargs(class_obj, (axes_obj))\n", - " c.pyapi.decref(axes_obj)\n", + " res = c.pyapi.call_function_objargs(class_obj, (bins_obj, lo_obj, hi_obj))\n", + " c.pyapi.decref(bins_obj)\n", + " c.pyapi.decref(lo_obj)\n", + " c.pyapi.decref(hi_obj)\n", " c.pyapi.decref(class_obj)\n", " return res" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ - "reg_ax = axis.Regular(10, 0, 1)\n", - "\n", - "\n", - "@nb.jit\n", - "def nb_create_Hist():\n", - " Hist(reg_ax)\n", - "\n", + "@nb.njit\n", + "def nb_fill_hist(h):\n", + " h.fill(np.random.randn(10))" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "ename": "TypingError", + "evalue": "Failed in nopython mode pipeline (step: nopython frontend)\nUnknown attribute 'fill' of type Hist\n\nFile \"\", line 3:\ndef nb_fill_hist(h):\n h.fill(np.random.randn(10))\n ^\n\nDuring: typing of get attribute at (3)\n\nFile \"\", line 3:\ndef nb_fill_hist(h):\n h.fill(np.random.randn(10))\n ^\n", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypingError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mh1\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mHist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mreg_ax\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mnb_fill_hist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mh1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/anaconda3/envs/hist/lib/python3.9/site-packages/numba/core/dispatcher.py\u001b[0m in \u001b[0;36m_compile_for_args\u001b[0;34m(self, *args, **kws)\u001b[0m\n\u001b[1;32m 418\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpatch_message\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 419\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 420\u001b[0;31m \u001b[0merror_rewrite\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'typing'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 421\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mUnsupportedError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 422\u001b[0m \u001b[0;31m# Something unsupported is present in the user code, add help info\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/envs/hist/lib/python3.9/site-packages/numba/core/dispatcher.py\u001b[0m in \u001b[0;36merror_rewrite\u001b[0;34m(e, issue_type)\u001b[0m\n\u001b[1;32m 359\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 360\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 361\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_traceback\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 362\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 363\u001b[0m \u001b[0margtypes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mTypingError\u001b[0m: Failed in nopython mode pipeline (step: nopython frontend)\nUnknown attribute 'fill' of type Hist\n\nFile \"\", line 3:\ndef nb_fill_hist(h):\n h.fill(np.random.randn(10))\n ^\n\nDuring: typing of get attribute at (3)\n\nFile \"\", line 3:\ndef nb_fill_hist(h):\n h.fill(np.random.randn(10))\n ^\n" + ] + } + ], + "source": [ + "reg_ax = axis.Regular(10, -3, 3)\n", + "h1 = Hist(reg_ax)\n", "\n", - "nb_create_Hist()" + "nb_fill_hist(h1)" ] }, { @@ -197,11 +261,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "# Numba fill\n", - "# nb_fill(h, array)\n", - "# h" - ] + "source": [] } ], "metadata": { From 1c251adabde5e54b42d11018e774008a8c632ed9 Mon Sep 17 00:00:00 2001 From: N!no Date: Fri, 6 Aug 2021 23:58:05 -0400 Subject: [PATCH 4/7] more entries to fill --- docs/examples/HistNumbaFill.ipynb | 70 ++++--------------------------- 1 file changed, 9 insertions(+), 61 deletions(-) diff --git a/docs/examples/HistNumbaFill.ipynb b/docs/examples/HistNumbaFill.ipynb index ee4ceffe..db43ebb5 100644 --- a/docs/examples/HistNumbaFill.ipynb +++ b/docs/examples/HistNumbaFill.ipynb @@ -16,7 +16,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -33,47 +33,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - "\n", - "-3\n", - "\n", - "\n", - "3\n", - "\n", - "\n", - "x-axis\n", - "\n", - "\n", - "\n", - "
\n", - "
\n", - "Regular(100, -3, 3, name='x', label='x-axis')
\n", - "
\n", - "Double() Σ=9973.0 (10000.0 with flow)\n", - "\n", - "
\n", - "
\n", - "" - ], - "text/plain": [ - "Hist(Regular(100, -3, 3, name='x', label='x-axis'), storage=Double()) # Sum: 9973.0 (10000.0 with flow)" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# python fill\n", "h.fill(array)\n", @@ -96,7 +58,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -142,7 +104,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -221,34 +183,20 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@nb.njit\n", "def nb_fill_hist(h):\n", - " h.fill(np.random.randn(10))" + " h.fill(np.random.randn(1000))" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "TypingError", - "evalue": "Failed in nopython mode pipeline (step: nopython frontend)\nUnknown attribute 'fill' of type Hist\n\nFile \"\", line 3:\ndef nb_fill_hist(h):\n h.fill(np.random.randn(10))\n ^\n\nDuring: typing of get attribute at (3)\n\nFile \"\", line 3:\ndef nb_fill_hist(h):\n h.fill(np.random.randn(10))\n ^\n", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mTypingError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mh1\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mHist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mreg_ax\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mnb_fill_hist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mh1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m~/anaconda3/envs/hist/lib/python3.9/site-packages/numba/core/dispatcher.py\u001b[0m in \u001b[0;36m_compile_for_args\u001b[0;34m(self, *args, **kws)\u001b[0m\n\u001b[1;32m 418\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpatch_message\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 419\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 420\u001b[0;31m \u001b[0merror_rewrite\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'typing'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 421\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0merrors\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mUnsupportedError\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 422\u001b[0m \u001b[0;31m# Something unsupported is present in the user code, add help info\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m~/anaconda3/envs/hist/lib/python3.9/site-packages/numba/core/dispatcher.py\u001b[0m in \u001b[0;36merror_rewrite\u001b[0;34m(e, issue_type)\u001b[0m\n\u001b[1;32m 359\u001b[0m \u001b[0;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 360\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 361\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwith_traceback\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 362\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 363\u001b[0m \u001b[0margtypes\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mTypingError\u001b[0m: Failed in nopython mode pipeline (step: nopython frontend)\nUnknown attribute 'fill' of type Hist\n\nFile \"\", line 3:\ndef nb_fill_hist(h):\n h.fill(np.random.randn(10))\n ^\n\nDuring: typing of get attribute at (3)\n\nFile \"\", line 3:\ndef nb_fill_hist(h):\n h.fill(np.random.randn(10))\n ^\n" - ] - } - ], + "outputs": [], "source": [ "reg_ax = axis.Regular(10, -3, 3)\n", "h1 = Hist(reg_ax)\n", From 0d315ddb17670bef391065674172217e3cd9ada0 Mon Sep 17 00:00:00 2001 From: N!no Date: Fri, 6 Aug 2021 23:58:37 -0400 Subject: [PATCH 5/7] more entries to fill --- docs/examples/HistNumbaFill.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/examples/HistNumbaFill.ipynb b/docs/examples/HistNumbaFill.ipynb index db43ebb5..f7a1baaf 100644 --- a/docs/examples/HistNumbaFill.ipynb +++ b/docs/examples/HistNumbaFill.ipynb @@ -189,7 +189,7 @@ "source": [ "@nb.njit\n", "def nb_fill_hist(h):\n", - " h.fill(np.random.randn(1000))" + " h.fill(np.random.randn(10000))" ] }, { From d0a9b806ce20d92e93beea3a96b989cfaa1da672 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 24 Sep 2021 14:35:09 -0400 Subject: [PATCH 6/7] fix: working demo --- dev-environment.yml | 1 + docs/examples/HistNumbaFill.ipynb | 205 +++++++++++++++++++++--------- 2 files changed, 144 insertions(+), 62 deletions(-) diff --git a/dev-environment.yml b/dev-environment.yml index 01c89b7b..eea36bce 100644 --- a/dev-environment.yml +++ b/dev-environment.yml @@ -19,5 +19,6 @@ dependencies: - uncertainties >=3 - mplhep>=0.1.27 - histoprint>=2.2.0 + - rich - pip: - -e . diff --git a/docs/examples/HistNumbaFill.ipynb b/docs/examples/HistNumbaFill.ipynb index f7a1baaf..08e5750c 100644 --- a/docs/examples/HistNumbaFill.ipynb +++ b/docs/examples/HistNumbaFill.ipynb @@ -25,23 +25,10 @@ "from hist import Hist\n", "from hist import axis\n", "\n", - "array = np.random.randn(\n", - " 10000,\n", - ")\n", + "array = np.random.randn(10000)\n", "h = Hist.new.Reg(100, -3, 3, name=\"x\", label=\"x-axis\").Double()" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# python fill\n", - "h.fill(array)\n", - "h" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -63,10 +50,12 @@ "outputs": [], "source": [ "from numba import types\n", - "from numba.extending import typeof_impl, as_numba_type, type_callable\n", + "import numba as nb\n", "\n", "# create Numba type\n", "class HistType(types.Type):\n", + " arraytype = nb.types.Array(nb.types.float64, 1, \"C\")\n", + "\n", " def __init__(self):\n", " super().__init__(name=\"Hist\")\n", "\n", @@ -74,25 +63,25 @@ "hist_type = HistType()\n", "\n", "# infer values\n", - "@typeof_impl.register(Hist)\n", + "@nb.extending.typeof_impl.register(Hist)\n", "def typeof_index(val, c):\n", " return hist_type\n", "\n", "\n", "# infer annotations\n", - "as_numba_type.register(Hist, hist_type)\n", + "nb.extending.as_numba_type.register(Hist, hist_type)\n", "\n", "# infer operations\n", - "@type_callable(Hist)\n", + "@nb.extending.type_callable(Hist)\n", "def type_hist(context):\n", " def typer(axes):\n", " for ax in axes:\n", - " if not (\n", - " isinstance(ax, hist.axis.Regular)\n", - " ): # ToDo: Aassumed all are Regular axes\n", - " return typer\n", + " # TODO: Assumed all are Regular axes\n", + " if not (isinstance(ax, hist.axis.Regular)):\n", + " return None\n", + " return HistType\n", "\n", - " return hist_type" + " return typer" ] }, { @@ -108,77 +97,141 @@ "metadata": {}, "outputs": [], "source": [ + "import numba as nb\n", "from numba.core import cgutils\n", "from numba.extending import (\n", " models,\n", - " register_model,\n", - " make_attribute_wrapper,\n", " overload_attribute,\n", " lower_builtin,\n", - " box,\n", - " unbox,\n", " NativeValue,\n", ")\n", "\n", "# define data model\n", - "@register_model(HistType)\n", + "@nb.extending.register_model(HistType)\n", "class HistModel(models.StructModel):\n", " def __init__(self, dmm, fe_type):\n", " members = [\n", - " (\"bins\", types.int32),\n", + " (\"bins\", types.int64),\n", " (\"lo\", types.float64),\n", " (\"hi\", types.float64),\n", + " (\"data\", fe_type.arraytype),\n", " ]\n", - " models.StructModel.__init__(self, dmm, fe_type, members)\n", + " super().__init__(dmm, fe_type, members)\n", "\n", "\n", "# expose attributes, porperties and constructors\n", - "make_attribute_wrapper(HistType, \"bins\", \"bins\")\n", - "make_attribute_wrapper(HistType, \"lo\", \"lo\")\n", - "make_attribute_wrapper(HistType, \"hi\", \"hi\")\n", + "nb.extending.make_attribute_wrapper(HistType, \"bins\", \"bins\")\n", + "nb.extending.make_attribute_wrapper(HistType, \"lo\", \"lo\")\n", + "nb.extending.make_attribute_wrapper(HistType, \"hi\", \"hi\")\n", + "nb.extending.make_attribute_wrapper(HistType, \"data\", \"data\")\n", "\n", "\n", - "@lower_builtin(Hist, types.Integer, types.Float, types.Float)\n", + "@nb.extending.lower_builtin(Hist, types.Integer, types.Float, types.Float, types.Array)\n", "def impl_h(context, builder, sig, args):\n", " typ = sig.return_type\n", - " lo, hi, bins = args\n", + " lo, hi, bins, data = args\n", " h = cgutils.create_struct_proxy(typ)(context, builder)\n", " h.lo = lo\n", " h.hi = hi\n", " h.bins = bins\n", + " h.data = data\n", " return h._getvalue()\n", "\n", "\n", "# unbox and box\n", - "@unbox(HistType)\n", + "@nb.extending.unbox(HistType)\n", "def unbox_h(typ, obj, c):\n", - " bins_obj = c.pyapi.object_getattr_string(obj, \"bins\")\n", - " lo_obj = c.pyapi.object_getattr_string(obj, \"lo\")\n", - " hi_obj = c.pyapi.object_getattr_string(obj, \"hi\")\n", + " # lower = h.axes[0][0][0]\n", + " # upper = h.axes[0][-1][-1]\n", + " # bins = h.axes[0].__len__(self)\n", + " # data = h.values()\n", + "\n", + " start_obj = c.pyapi.long_from_long(c.context.get_constant(nb.long_, 0))\n", + " stop_obj = c.pyapi.long_from_long(c.context.get_constant(nb.long_, -1))\n", + "\n", + " data_obj = c.pyapi.call_method(obj, \"values\")\n", + "\n", + " axis_tuple_obj = c.pyapi.object_getattr_string(obj, \"axes\")\n", + " axis_obj = c.pyapi.tuple_getitem(axis_tuple_obj, 0)\n", + " bins_obj = c.pyapi.call_method(axis_obj, \"__len__\")\n", + "\n", + " lo1_obj = c.pyapi.object_getitem(axis_obj, start_obj)\n", + " hi1_obj = c.pyapi.object_getitem(axis_obj, stop_obj)\n", + "\n", + " lo_obj = c.pyapi.tuple_getitem(lo1_obj, 0)\n", + " hi_obj = c.pyapi.object_getitem(hi1_obj, stop_obj)\n", + "\n", " h = cgutils.create_struct_proxy(typ)(c.context, c.builder)\n", - " h.bins = c.pyapi.float_as_double(bins_obj)\n", + "\n", + " h.bins = c.pyapi.number_as_ssize_t(bins_obj)\n", " h.lo = c.pyapi.float_as_double(lo_obj)\n", " h.hi = c.pyapi.float_as_double(hi_obj)\n", + " h.data = c.pyapi.to_native_value(typ.arraytype, data_obj).value\n", + "\n", " c.pyapi.decref(bins_obj)\n", " c.pyapi.decref(lo_obj)\n", " c.pyapi.decref(hi_obj)\n", + " c.pyapi.decref(data_obj)\n", + "\n", + " c.pyapi.decref(lo1_obj)\n", + " c.pyapi.decref(hi1_obj)\n", + "\n", + " c.pyapi.decref(axis_tuple_obj)\n", + " # c.pyapi.decref(axis_obj) - no deref needed, crashes\n", + "\n", + " c.pyapi.decref(start_obj)\n", + " c.pyapi.decref(stop_obj)\n", + "\n", " is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred())\n", - " return NativeValue(h._getvalue(), is_error=is_error)\n", + " return NativeValue(h._getvalue(), is_error=is_error)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We also need to teach numba about running the fill:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@nb.extending.overload_method(HistType, \"fill\")\n", + "def fill_resolve(hist, val):\n", + " if not isinstance(hist, HistType):\n", + " return None\n", + " if not isinstance(val, nb.types.Float):\n", + " return None\n", "\n", + " def fill(hist, val):\n", + " delta = 1 / ((hist.hi - hist.lo) / hist.bins)\n", + " i = int((val - hist.lo) * delta)\n", "\n", - "@box(HistType)\n", - "def box_h(typ, val, c):\n", - " h = cgutils.create_struct_proxy(typ)(c.context, c.builder, value=val)\n", - " bins_obj = c.pyapi.float_from_double(h.bins)\n", - " lo_obj = c.pyapi.float_from_double(h.lo)\n", - " hi_obj = c.pyapi.float_from_double(h.hi)\n", - " class_obj = c.pyapi.unserialize(c.pyapi.serialize_object(Hist))\n", - " res = c.pyapi.call_function_objargs(class_obj, (bins_obj, lo_obj, hi_obj))\n", - " c.pyapi.decref(bins_obj)\n", - " c.pyapi.decref(lo_obj)\n", - " c.pyapi.decref(hi_obj)\n", - " c.pyapi.decref(class_obj)\n", - " return res" + " if 0 <= i < hist.bins:\n", + " hist.data[i] += 1\n", + "\n", + " return fill" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Timing the Python version:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%timeit\n", + "h_python = h.copy()\n", + "h_python.fill(array)" ] }, { @@ -188,8 +241,16 @@ "outputs": [], "source": [ "@nb.njit\n", - "def nb_fill_hist(h):\n", - " h.fill(np.random.randn(10000))" + "def nb_fill_hist(h, v):\n", + " for v in array:\n", + " h.fill(v)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Timing the Numba version:" ] }, { @@ -198,10 +259,16 @@ "metadata": {}, "outputs": [], "source": [ - "reg_ax = axis.Regular(10, -3, 3)\n", - "h1 = Hist(reg_ax)\n", - "\n", - "nb_fill_hist(h1)" + "%%timeit\n", + "h_numba = h.copy()\n", + "nb_fill_hist(h_numba, array)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Showing the results:" ] }, { @@ -209,7 +276,21 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "h_numba = h.copy()\n", + "nb_fill_hist(h_numba, array)\n", + "h_numba" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "h_python = h.copy()\n", + "h.fill(array)" + ] } ], "metadata": { @@ -228,7 +309,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.4" + "version": "3.9.7" } }, "nbformat": 4, From 6db04d20f2f9c5ac6c3319509b8778fdd7e0126a Mon Sep 17 00:00:00 2001 From: fabriceMUKARAGE Date: Tue, 13 Jun 2023 10:05:32 +0200 Subject: [PATCH 7/7] stale: Adding a function to integrate axes I am facing the error: "AttributeError: 'ConstructProxy' object has no attribute 'fill'" FAILED tests/test_general.py::test_integrate - AttributeError: 'ConstructProxy' object has no attribute 'fill'. I think I am missing small hint to run the code successful. And I am wondering if I put the function in right location of basehist or which right way to fix the issue I am facing. --- src/hist/basehist.py | 7 +++++++ tests/test_general.py | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/hist/basehist.py b/src/hist/basehist.py index 40725c65..93d0129f 100644 --- a/src/hist/basehist.py +++ b/src/hist/basehist.py @@ -500,6 +500,13 @@ def plot_pie( import hist.plot return hist.plot.plot_pie(self, ax=ax, **kwargs) + + def integrate(self, name: int | str, i_or_list: Loc | list[str | int] | None = None, j: Loc | None = None) -> Self: + if isinstance(i_or_list, list): + return self[{name: i_or_list}][{name: slice(0, len(i_or_list), sum)}] + + return self[{name: slice(i_or_list, j, sum)}] + def stack(self, axis: int | str) -> hist.stack.Stack: """ diff --git a/tests/test_general.py b/tests/test_general.py index ae351224..226da3b3 100644 --- a/tests/test_general.py +++ b/tests/test_general.py @@ -925,3 +925,17 @@ def test_quick_construct_direct(): assert tuple(h.sort(0, key=lambda x: -x).axes[0]) == (4, 2, 1) assert tuple(h.sort(1).axes[1]) == ("AB", "BC", "BCC") assert tuple(h.sort(1, reverse=True).axes[1]) == ("BCC", "BC", "AB") + + +def test_integrate(): + h = ( + hist.new.IntCat([4, 1, 2], name="x") + .StrCat(["AB", "BCC", "BC"], name="y") + .Int(1, 10) # To provide the start and stop values as arguments to the Int() constructor + ) + h.fill(4, "AB", 1) + h.fill(4, "BCC", 2) + h.fill(4, "BC", 4) + h.fill(4, "X", 8) + h1 = h.integrate("y", ["AB", "BC"]) + assert h1[{ "x": 4 }] == 5 \ No newline at end of file