numexpr 2.10.2__tar.gz → 2.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- numexpr-2.12.0/ADDFUNCS.rst +222 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/ANNOUNCE.rst +12 -11
- {numexpr-2.10.2 → numexpr-2.12.0}/AUTHORS.txt +1 -1
- numexpr-2.12.0/LICENSES/cpuinfo.txt +31 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/PKG-INFO +26 -6
- {numexpr-2.10.2 → numexpr-2.12.0}/README.rst +18 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/RELEASE_NOTES.rst +32 -1
- numexpr-2.12.0/VERSION +1 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/bench/boolean_timing.py +2 -0
- numexpr-2.12.0/bench/free_threading.py +171 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/bench/issue-36.py +6 -3
- {numexpr-2.10.2 → numexpr-2.12.0}/bench/issue-47.py +1 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/bench/large_array_vs_numpy.py +4 -2
- {numexpr-2.10.2 → numexpr-2.12.0}/bench/multidim.py +4 -3
- {numexpr-2.10.2 → numexpr-2.12.0}/bench/poly.py +3 -1
- {numexpr-2.10.2 → numexpr-2.12.0}/bench/timing.py +4 -1
- {numexpr-2.10.2 → numexpr-2.12.0}/bench/unaligned-simple.py +3 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/bench/varying-expr.py +3 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/bench/vml_timing.py +3 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/bench/vml_timing2.py +4 -1
- {numexpr-2.10.2 → numexpr-2.12.0}/bench/vml_timing3.py +3 -1
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/__init__.py +10 -10
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/cpuinfo.py +5 -3
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/expressions.py +9 -2
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/functions.hpp +28 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/interp_body.cpp +22 -4
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/interpreter.cpp +66 -11
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/interpreter.hpp +13 -1
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/module.cpp +12 -3
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/module.hpp +2 -2
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/msvc_function_stubs.hpp +27 -3
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/necompiler.py +82 -75
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/numexpr_config.hpp +12 -1
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/numexpr_object.cpp +0 -1
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/opcodes.hpp +39 -26
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/tests/__init__.py +1 -1
- numexpr-2.12.0/numexpr/tests/conftest.py +17 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/tests/test_numexpr.py +172 -128
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/utils.py +13 -11
- numexpr-2.12.0/numexpr/version.py +5 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/win32/stdint.h +6 -6
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr.egg-info/PKG-INFO +26 -6
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr.egg-info/SOURCES.txt +4 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/pyproject.toml +20 -6
- {numexpr-2.10.2 → numexpr-2.12.0}/setup.py +6 -5
- numexpr-2.10.2/VERSION +0 -1
- numexpr-2.10.2/numexpr/version.py +0 -5
- {numexpr-2.10.2 → numexpr-2.12.0}/LICENSE.txt +0 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/MANIFEST.in +0 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/complex_functions.hpp +0 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/missing_posix_functions.hpp +0 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/numexpr_object.hpp +0 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/str-two-way.hpp +0 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/win32/pthread.c +0 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr/win32/pthread.h +0 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr.egg-info/dependency_links.txt +0 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr.egg-info/requires.txt +0 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/numexpr.egg-info/top_level.txt +0 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/requirements.txt +0 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/setup.cfg +0 -0
- {numexpr-2.10.2 → numexpr-2.12.0}/site.cfg.example +0 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
Functions and Function signatures
|
|
2
|
+
=================================
|
|
3
|
+
|
|
4
|
+
Adding functions
|
|
5
|
+
----------------
|
|
6
|
+
|
|
7
|
+
In order to add new functions to ``numexpr``, currently it is necessary to edit several files. Consider adding a function
|
|
8
|
+
``out_type myfunc(arg_type)``.
|
|
9
|
+
|
|
10
|
+
* ``numexpr/expressions.py``
|
|
11
|
+
Add ``'myfunc': func(numpy.myfunc, out_dtype),`` to the dict of functions, ``functions = {...``. If the return type of the function is ``bool``, add
|
|
12
|
+
the function to the list ``if opcode in ("isnan", "isfinite"):`` in the ``__init__`` function of the ``FuncNode`` class.
|
|
13
|
+
In the future it might be nice to refactor this function since it sets the output type based on the type of the inputs in general.
|
|
14
|
+
|
|
15
|
+
* ``numexpr/necompiler.py``
|
|
16
|
+
Add ``"myfunc"`` to the list of functions:
|
|
17
|
+
|
|
18
|
+
.. code-block:: python3
|
|
19
|
+
|
|
20
|
+
"floor",
|
|
21
|
+
"isnan",
|
|
22
|
+
"isfinite",
|
|
23
|
+
"myfunc"
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
* ``numexpr/functions.hpp``
|
|
27
|
+
Find the correct function signature ``FUNC_OA`` where ``O`` is the return type, and ``A`` the argument type(s). For example, if the function
|
|
28
|
+
is ``double myfunc(double)``, one should edit within the ``FUNC_DD`` clause. If you cannot find your function signature you will have to add it,
|
|
29
|
+
following the template of the other functions.
|
|
30
|
+
Most likely, you will want to add support for several function signatures (e.g. double -> bool and float -> bool) and so you will have to add the
|
|
31
|
+
function in two clauses. If your function has a float input, you will see that there are 5 arguments in the
|
|
32
|
+
``FUNC_OA`` macro, and you will have to add ``myfunc2`` here is order to compile on MSVC machines (i.e. Windows, see following).
|
|
33
|
+
Example:
|
|
34
|
+
|
|
35
|
+
.. code-block:: cpp
|
|
36
|
+
:emphasize-lines: 6, 20
|
|
37
|
+
|
|
38
|
+
#ifndef FUNC_DD
|
|
39
|
+
#define ELIDE_FUNC_DD
|
|
40
|
+
#define FUNC_DD(...)
|
|
41
|
+
#endif
|
|
42
|
+
...
|
|
43
|
+
FUNC_DD(FUNC_MYFUNC_DD, "myfunc_dd", myfunc, vdMyfunc)
|
|
44
|
+
FUNC_DD(FUNC_DD_LAST, NULL, NULL, NULL)
|
|
45
|
+
#ifdef ELIDE_FUNC_DD
|
|
46
|
+
#undef ELIDE_FUNC_DD
|
|
47
|
+
#undef FUNC_DD
|
|
48
|
+
#endif
|
|
49
|
+
|
|
50
|
+
...
|
|
51
|
+
|
|
52
|
+
#ifndef FUNC_FF
|
|
53
|
+
#define ELIDE_FUNC_FF
|
|
54
|
+
#define FUNC_FF(...)
|
|
55
|
+
#endif
|
|
56
|
+
...
|
|
57
|
+
FUNC_FF(FUNC_MYFUNC_FF, "myfunc_ff", myfuncf, myfuncf2, vfMyfunc)
|
|
58
|
+
FUNC_FF(FUNC_FF_LAST, NULL, NULL, NULL, NULL)
|
|
59
|
+
#ifdef ELIDE_FUNC_FF
|
|
60
|
+
#undef ELIDE_FUNC_FF
|
|
61
|
+
#undef FUNC_FF
|
|
62
|
+
#endif
|
|
63
|
+
|
|
64
|
+
* ``numexpr/msvc_function_stubs.hpp``
|
|
65
|
+
In order to support float arguments, due to oddities of MSVC, you have to provide explicit support for your function in this file.
|
|
66
|
+
Add ``#define myfuncf(x) ((float)floor((double)(x)))`` (if your function is float -> float) to the ``#if`` clause at the top of the file
|
|
67
|
+
which is for old versions of MSVC which did not have support for single precision fucntions. Then in the body, add an inline function
|
|
68
|
+
|
|
69
|
+
.. code-block:: cpp
|
|
70
|
+
|
|
71
|
+
inline float myfuncf2(float x) {
|
|
72
|
+
return myfuncf(x);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
This is the function that appears as the ``f_win32`` parameter in ``functions.hpp``.
|
|
76
|
+
|
|
77
|
+
* ``numexpr/tests/test_numexpr.py``
|
|
78
|
+
Don't forget to add a test for your function!
|
|
79
|
+
|
|
80
|
+
Adding function signatures
|
|
81
|
+
--------------------------
|
|
82
|
+
It may so happen that you cannot find your desired function signature in ``functions.hpp``. This means you will have to add it yourself!
|
|
83
|
+
This involves editing a few more files. In addition, there may be certain bespoke changes, specific to the function signature
|
|
84
|
+
that you may have to make (see Notes, below)
|
|
85
|
+
|
|
86
|
+
* ``numexpr/functions.hpp``
|
|
87
|
+
Firstly, add clause(s) for your function signature. For example, if the function signature is ``bool(double)`` and ``bool(float)``, add
|
|
88
|
+
``FUNC_BD`` and ``FUNC_BF`` clauses (in the latter case you will need the macro to take 5 arguments for MSVC-compatibility.)
|
|
89
|
+
|
|
90
|
+
.. code-block:: cpp
|
|
91
|
+
|
|
92
|
+
#ifndef FUNC_BD
|
|
93
|
+
#define ELIDE_FUNC_BD
|
|
94
|
+
#define FUNC_BD(...)
|
|
95
|
+
#endif
|
|
96
|
+
...
|
|
97
|
+
FUNC_BD(FUNC_BD_LAST, NULL, NULL, NULL)
|
|
98
|
+
#ifdef ELIDE_FUNC_BD
|
|
99
|
+
#undef ELIDE_FUNC_BD
|
|
100
|
+
#undef FUNC_BD
|
|
101
|
+
#endif
|
|
102
|
+
|
|
103
|
+
#ifndef FUNC_BF
|
|
104
|
+
#define ELIDE_FUNC_BF
|
|
105
|
+
#define FUNC_BF(...)
|
|
106
|
+
#endif
|
|
107
|
+
...
|
|
108
|
+
FUNC_BF(FUNC_BF_LAST, NULL, NULL, NULL, NULL)
|
|
109
|
+
#ifdef ELIDE_FUNC_BF
|
|
110
|
+
#undef ELIDE_FUNC_BF
|
|
111
|
+
#undef FUNC_BF
|
|
112
|
+
#endif
|
|
113
|
+
|
|
114
|
+
The ultimate source of the functions in the macro ``FUNC_BF(...)`` are the headers included in ``numexpr/interpreter.cpp`` (in particular
|
|
115
|
+
``numexpr/numexpr_config.hpp``, which can be used to overwrite ``<math.h>`` functions), so the functions should be available from there.
|
|
116
|
+
|
|
117
|
+
* ``numexpr/interp_body.cpp``
|
|
118
|
+
Add case support for OPCODES associated to your new function signatures via e.g. ``case OP_FUNC_BFN`` and ``case OP_FUNC_BDN``, following
|
|
119
|
+
the framework suggested by the other functions:
|
|
120
|
+
|
|
121
|
+
.. code-block:: cpp
|
|
122
|
+
|
|
123
|
+
case OP_FUNC_BFN:
|
|
124
|
+
#ifdef USE_VML
|
|
125
|
+
VEC_ARG1_VML(functions_bf_vml[arg2](BLOCK_SIZE,
|
|
126
|
+
(float*)x1, (bool*)dest));
|
|
127
|
+
#else
|
|
128
|
+
VEC_ARG1(b_dest = functions_bf[arg2](f1));
|
|
129
|
+
#endif
|
|
130
|
+
|
|
131
|
+
Note that it is important that the out variable matches the output type of the function (i.e. ``b_dest`` for bool, ``f_dest`` for float etc.)
|
|
132
|
+
|
|
133
|
+
* ``numexpr/interpreter.hpp``
|
|
134
|
+
Add clauses to read the ``functions.hpp`` macros correctly
|
|
135
|
+
|
|
136
|
+
.. code-block:: cpp
|
|
137
|
+
|
|
138
|
+
enum FuncBFCodes {
|
|
139
|
+
#define FUNC_BF(fop, ...) fop,
|
|
140
|
+
#include "functions.hpp"
|
|
141
|
+
#undef FUNC_BF
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
* ``numexpr/interpreter.cpp``
|
|
145
|
+
Add clauses to generate the FUNC_CODES from the ``functions.hpp`` header, making sure to include clauses for ``_WIN32`` and
|
|
146
|
+
``VML`` as necessary accoridng to the framework suggested by the other functions.
|
|
147
|
+
|
|
148
|
+
.. code-block:: cpp
|
|
149
|
+
|
|
150
|
+
typedef bool (*FuncBFPtr)(float);
|
|
151
|
+
#ifdef _WIN32
|
|
152
|
+
FuncBFPtr functions_bf[] = {
|
|
153
|
+
#define FUNC_BF(fop, s, f, f_win32, ...) f_win32,
|
|
154
|
+
#include "functions.hpp"
|
|
155
|
+
#undef FUNC_BF
|
|
156
|
+
};
|
|
157
|
+
#else
|
|
158
|
+
FuncBFPtr functions_bf[] = {
|
|
159
|
+
#define FUNC_BF(fop, s, f, ...) f,
|
|
160
|
+
#include "functions.hpp"
|
|
161
|
+
#undef FUNC_BF
|
|
162
|
+
};
|
|
163
|
+
#endif
|
|
164
|
+
|
|
165
|
+
#ifdef USE_VML
|
|
166
|
+
typedef void (*FuncBFPtr_vml)(MKL_INT, const float*, bool*);
|
|
167
|
+
FuncBFPtr_vml functions_bf_vml[] = {
|
|
168
|
+
#define FUNC_BF(fop, s, f, f_win32, f_vml) f_vml,
|
|
169
|
+
#include "functions.hpp"
|
|
170
|
+
#undef FUNC_BF
|
|
171
|
+
};
|
|
172
|
+
#endif
|
|
173
|
+
|
|
174
|
+
Add case handling to the ``check_program`` function
|
|
175
|
+
|
|
176
|
+
.. code-block:: cpp
|
|
177
|
+
|
|
178
|
+
else if (op == OP_FUNC_BDN) {
|
|
179
|
+
if (arg < 0 || arg >= FUNC_BD_LAST) {
|
|
180
|
+
PyErr_Format(PyExc_RuntimeError, "invalid program: funccode out of range (%i) at %i", arg, argloc);
|
|
181
|
+
return -1;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else if (op == OP_FUNC_BFN) {
|
|
185
|
+
if (arg < 0 || arg >= FUNC_BF_LAST) {
|
|
186
|
+
PyErr_Format(PyExc_RuntimeError, "invalid program: funccode out of range (%i) at %i", arg, argloc);
|
|
187
|
+
return -1;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
* ``numexpr/module.cpp``
|
|
192
|
+
Add code here to define the ``FUNC_OA`` macros you require
|
|
193
|
+
|
|
194
|
+
.. code-block:: cpp
|
|
195
|
+
|
|
196
|
+
#define FUNC_BF(name, sname, ...) add_func(name, sname);
|
|
197
|
+
#define FUNC_BD(name, sname, ...) add_func(name, sname);
|
|
198
|
+
...
|
|
199
|
+
#include "functions.hpp"
|
|
200
|
+
...
|
|
201
|
+
#undef FUNC_BD
|
|
202
|
+
#undef FUNC_BF
|
|
203
|
+
|
|
204
|
+
* ``numexpr/opcodes.hpp``
|
|
205
|
+
Finally, add the ``OP_FUNC_BDN`` etc. codes here. It is necessary for the OPCODES in the file to be in (ascending order) with
|
|
206
|
+
``NOOP`` as 0 and ``OP_LAST`` as the largest number. Secondly, all reduction OPCODES must appear last. Hence, after adding your
|
|
207
|
+
function signatures (just before the reduction OPCODES) it is necessary to increment all succeeding OPCODES.
|
|
208
|
+
|
|
209
|
+
.. code-block:: cpp
|
|
210
|
+
|
|
211
|
+
OPCODE(106, OP_FUNC_BDN, "func_bdn", Tb, Td, Tn, T0)
|
|
212
|
+
OPCODE(107, OP_FUNC_BFN, "func_bfn", Tb, Tf, Tn, T0)
|
|
213
|
+
|
|
214
|
+
Notes
|
|
215
|
+
-----
|
|
216
|
+
In many cases this process will not be very smooth since one relies on the internal C/C++ standard functions (which can be fussy, to varying degrees on different platforms). Some common gotchas are then:
|
|
217
|
+
|
|
218
|
+
* OPCODES are currently only supported up to 255 - if it becomes necessary to increment further, one will have to change the ``latin_1`` encoding used in ``quadrupleToString`` in ``necompiler.py``. In addition, since the OPCDE table is assumed to be of type ``unsigned char`` the ``get_return_sig`` function in ``numexpr/interpreter.cpp`` may have to be changed (possibly other changes too).
|
|
219
|
+
|
|
220
|
+
* Depending on the new function signature (above all if the out type is different to the input types), one may have to edit the ``__init__`` function in the ``FuncNode`` class in ``expressions.py``.
|
|
221
|
+
|
|
222
|
+
* Depending on MSVC support, namespace clashes, casting problems, it may be necessary to make various changes to ``numexpr/numexpr_config.hpp`` and ``numexpr/msvc_function_stubs.hpp``. For example, in PR #523, non-clashing wrappers were introduced for ``isnan`` and ``isfinite`` since the float versions ``isnanf, isfinitef`` were inconsistently defined (and output ints) - depending on how strict the platform interpreter is, the implicit cast from int to bool was acceptable or not for example. In addition, the base functions were in different namespaces or had different names across platforms.
|
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
=========================
|
|
2
|
-
Announcing NumExpr 2.
|
|
2
|
+
Announcing NumExpr 2.12.0
|
|
3
3
|
=========================
|
|
4
4
|
|
|
5
5
|
Hi everyone,
|
|
6
6
|
|
|
7
|
-
NumExpr 2.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
NumExpr 2.12.0 comes with new isnan/isfinite/isinf functions.
|
|
8
|
+
Most importantly, we have added instructions for adding new functions
|
|
9
|
+
to the virtual machine. See ADDFUNCS.rst for more details. Thanks to
|
|
10
|
+
Luke Shaw for these contributions.
|
|
11
11
|
|
|
12
12
|
Project documentation is available at:
|
|
13
13
|
|
|
14
14
|
http://numexpr.readthedocs.io/
|
|
15
15
|
|
|
16
|
-
Changes from 2.
|
|
16
|
+
Changes from 2.11.0 to 2.12.0
|
|
17
17
|
-----------------------------
|
|
18
18
|
|
|
19
|
-
*
|
|
20
|
-
cores. See #479 and #490. Thanks to @avalentino.
|
|
19
|
+
* Added isnan/isfinite/isinf functions. Thanks to Luke Shaw.
|
|
21
20
|
|
|
22
|
-
*
|
|
23
|
-
|
|
21
|
+
* New instructions for adding new functions to the virtual machine.
|
|
22
|
+
They are available at ADDFUNCS.rst. Thanks to Luke Shaw.
|
|
24
23
|
|
|
25
|
-
*
|
|
24
|
+
* We are distributing binary wheels for Python 3.14 and 3.14t now.
|
|
25
|
+
|
|
26
|
+
* We are distributing musllinux wheels too! Thanks to Clément Robert.
|
|
26
27
|
|
|
27
28
|
What's Numexpr?
|
|
28
29
|
---------------
|
|
@@ -23,7 +23,7 @@ Google Inc. contributed bug fixes.
|
|
|
23
23
|
|
|
24
24
|
David Cox improved readability of the Readme.
|
|
25
25
|
|
|
26
|
-
Robert A. McLeod contributed bug fixes and ported the documentation to
|
|
26
|
+
Robert A. McLeod contributed bug fixes and ported the documentation to
|
|
27
27
|
numexpr.readthedocs.io. He has served as the maintainer of the package
|
|
28
28
|
since 2016 to 2023.
|
|
29
29
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Copyright statement for `cpuinfo` module.
|
|
2
|
+
|
|
3
|
+
Copyright 2002 Pearu Peterson all rights reserved,
|
|
4
|
+
Pearu Peterson <pearu@cens.ioc.ee>
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
* Redistributions of source code must retain the above copyright
|
|
10
|
+
notice, this list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
* Redistributions in binary form must reproduce the above
|
|
13
|
+
copyright notice, this list of conditions and the following
|
|
14
|
+
disclaimer in the documentation and/or other materials provided
|
|
15
|
+
with the distribution.
|
|
16
|
+
|
|
17
|
+
* Neither the name of Pearu Peterson nor the names of its
|
|
18
|
+
contributors may be used to endorse or promote products derived
|
|
19
|
+
from this software without specific prior written permission.
|
|
20
|
+
|
|
21
|
+
HIS SOFTWARE IS PROVIDED BY PEARU PETERSON ''AS IS'' AND ANY EXPRESS
|
|
22
|
+
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
23
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
24
|
+
DISCLAIMED. IN NO EVENT SHALL PEARU PETERSON BE LIABLE FOR ANY DIRECT,
|
|
25
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
26
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
27
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
28
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
29
|
+
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
30
|
+
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
31
|
+
POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: numexpr
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.12.0
|
|
4
4
|
Summary: Fast numerical expression evaluator for NumPy
|
|
5
5
|
Author-email: "David M. Cooke, Francesc Alted, and others" <blosc@blosc.org>
|
|
6
6
|
Maintainer-email: Blosc Development Team <blosc@blosc.org>
|
|
7
|
+
License-Expression: MIT
|
|
7
8
|
Project-URL: homepage, https://github.com/pydata/numexpr
|
|
8
9
|
Project-URL: documentation, https://numexpr.readthedocs.io
|
|
9
10
|
Project-URL: repository, https://github.com/pydata/numexpr
|
|
@@ -11,21 +12,22 @@ Classifier: Development Status :: 6 - Mature
|
|
|
11
12
|
Classifier: Intended Audience :: Developers
|
|
12
13
|
Classifier: Intended Audience :: Information Technology
|
|
13
14
|
Classifier: Intended Audience :: Science/Research
|
|
14
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
15
15
|
Classifier: Programming Language :: Python
|
|
16
16
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
17
|
Classifier: Operating System :: Microsoft :: Windows
|
|
18
18
|
Classifier: Operating System :: Unix
|
|
19
19
|
Classifier: Programming Language :: Python :: 3
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
-
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Requires-Python: >=3.10
|
|
25
26
|
Description-Content-Type: text/x-rst
|
|
26
27
|
License-File: LICENSE.txt
|
|
27
|
-
License-File:
|
|
28
|
+
License-File: LICENSES/cpuinfo.txt
|
|
28
29
|
Requires-Dist: numpy>=1.23.0
|
|
30
|
+
Dynamic: license-file
|
|
29
31
|
|
|
30
32
|
======================================================
|
|
31
33
|
NumExpr: Fast numerical expression evaluator for NumPy
|
|
@@ -188,6 +190,24 @@ Usage
|
|
|
188
190
|
array([ True, False, False], dtype=bool)
|
|
189
191
|
|
|
190
192
|
|
|
193
|
+
Free-threading support
|
|
194
|
+
----------------------
|
|
195
|
+
Starting on CPython 3.13 onwards there is a new distribution that disables the
|
|
196
|
+
Global Interpreter Lock (GIL) altogether, thus increasing the performance yields
|
|
197
|
+
under multi-threaded conditions on a single interpreter, as opposed to having to use
|
|
198
|
+
multiprocessing.
|
|
199
|
+
|
|
200
|
+
Whilst numexpr has been demonstrated to work under free-threaded
|
|
201
|
+
CPython, considerations need to be taken when using numexpr native parallel
|
|
202
|
+
implementation vs using Python threads directly in order to prevent oversubscription,
|
|
203
|
+
we recommend either using the main CPython interpreter thread to spawn multiple C threads
|
|
204
|
+
using the parallel numexpr API, or spawning multiple CPython threads that do not use
|
|
205
|
+
the parallel API.
|
|
206
|
+
|
|
207
|
+
For more information about free-threaded CPython, we recommend visiting the following
|
|
208
|
+
`community Wiki <https://py-free-threading.github.io/>`
|
|
209
|
+
|
|
210
|
+
|
|
191
211
|
Documentation
|
|
192
212
|
-------------
|
|
193
213
|
|
|
@@ -159,6 +159,24 @@ Usage
|
|
|
159
159
|
array([ True, False, False], dtype=bool)
|
|
160
160
|
|
|
161
161
|
|
|
162
|
+
Free-threading support
|
|
163
|
+
----------------------
|
|
164
|
+
Starting on CPython 3.13 onwards there is a new distribution that disables the
|
|
165
|
+
Global Interpreter Lock (GIL) altogether, thus increasing the performance yields
|
|
166
|
+
under multi-threaded conditions on a single interpreter, as opposed to having to use
|
|
167
|
+
multiprocessing.
|
|
168
|
+
|
|
169
|
+
Whilst numexpr has been demonstrated to work under free-threaded
|
|
170
|
+
CPython, considerations need to be taken when using numexpr native parallel
|
|
171
|
+
implementation vs using Python threads directly in order to prevent oversubscription,
|
|
172
|
+
we recommend either using the main CPython interpreter thread to spawn multiple C threads
|
|
173
|
+
using the parallel numexpr API, or spawning multiple CPython threads that do not use
|
|
174
|
+
the parallel API.
|
|
175
|
+
|
|
176
|
+
For more information about free-threaded CPython, we recommend visiting the following
|
|
177
|
+
`community Wiki <https://py-free-threading.github.io/>`
|
|
178
|
+
|
|
179
|
+
|
|
162
180
|
Documentation
|
|
163
181
|
-------------
|
|
164
182
|
|
|
@@ -1,7 +1,38 @@
|
|
|
1
1
|
=====================================
|
|
2
|
-
Release notes for NumExpr 2.
|
|
2
|
+
Release notes for NumExpr 2.12 series
|
|
3
3
|
=====================================
|
|
4
4
|
|
|
5
|
+
Changes from 2.11.0 to 2.12.0
|
|
6
|
+
-----------------------------
|
|
7
|
+
|
|
8
|
+
* Added isnan/isfinite/isinf functions. Thanks to Luke Shaw.
|
|
9
|
+
|
|
10
|
+
* New instructions for adding new functions to the virtual machine.
|
|
11
|
+
They are available at ADDFUNCS.rst. Thanks to Luke Shaw.
|
|
12
|
+
|
|
13
|
+
* We are distributing binary wheels for Python 3.14 and 3.14t now.
|
|
14
|
+
|
|
15
|
+
* We are distributing musllinux wheels too! Thanks to Clément Robert.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
Changes from 2.10.2 to 2.11.0
|
|
19
|
+
-----------------------------
|
|
20
|
+
|
|
21
|
+
* Initial support for free-threaded Python 3.13t has been added.
|
|
22
|
+
This is still experimental, so please report any issues you find.
|
|
23
|
+
For more info, see discussions PRs #504, #505 and #508.
|
|
24
|
+
Thanks to @andfoy, @rgommers and @FrancescAlted for the work.
|
|
25
|
+
|
|
26
|
+
* Fix imaginary evaluation in the form of `1.1e1j`. This was
|
|
27
|
+
previously not supported and would raise an error. Thanks to @27rabbitlt
|
|
28
|
+
for the fix.
|
|
29
|
+
|
|
30
|
+
* The test suite has been modernized to use `pytest` instead of `unittest`.
|
|
31
|
+
This should make it easier to run the tests and contribute to the project.
|
|
32
|
+
|
|
33
|
+
* Python 3.10 is now the minimum supported version.
|
|
34
|
+
|
|
35
|
+
|
|
5
36
|
Changes from 2.10.1 to 2.10.2
|
|
6
37
|
-----------------------------
|
|
7
38
|
|
numexpr-2.12.0/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.12.0
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#################################################################################
|
|
2
|
+
# To compare the performance of numexpr when free-threading CPython is used.
|
|
3
|
+
#
|
|
4
|
+
# This example makes use of Python threads, as opposed to C native ones
|
|
5
|
+
# in order to highlight the improvement introduced by free-threading CPython,
|
|
6
|
+
# which now disables the GIL altogether.
|
|
7
|
+
#################################################################################
|
|
8
|
+
"""
|
|
9
|
+
Results with GIL-enabled CPython:
|
|
10
|
+
|
|
11
|
+
Benchmarking Expression 1:
|
|
12
|
+
NumPy time (threaded over 32 chunks with 16 threads): 1.173090 seconds
|
|
13
|
+
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 0.951071 seconds
|
|
14
|
+
numexpr speedup: 1.23x
|
|
15
|
+
----------------------------------------
|
|
16
|
+
Benchmarking Expression 2:
|
|
17
|
+
NumPy time (threaded over 32 chunks with 16 threads): 10.410874 seconds
|
|
18
|
+
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 8.248753 seconds
|
|
19
|
+
numexpr speedup: 1.26x
|
|
20
|
+
----------------------------------------
|
|
21
|
+
Benchmarking Expression 3:
|
|
22
|
+
NumPy time (threaded over 32 chunks with 16 threads): 9.605909 seconds
|
|
23
|
+
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 11.087108 seconds
|
|
24
|
+
numexpr speedup: 0.87x
|
|
25
|
+
----------------------------------------
|
|
26
|
+
Benchmarking Expression 4:
|
|
27
|
+
NumPy time (threaded over 32 chunks with 16 threads): 3.836962 seconds
|
|
28
|
+
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 18.054531 seconds
|
|
29
|
+
numexpr speedup: 0.21x
|
|
30
|
+
----------------------------------------
|
|
31
|
+
|
|
32
|
+
Results with free-threading CPython:
|
|
33
|
+
|
|
34
|
+
Benchmarking Expression 1:
|
|
35
|
+
NumPy time (threaded over 32 chunks with 16 threads): 3.415349 seconds
|
|
36
|
+
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 2.618876 seconds
|
|
37
|
+
numexpr speedup: 1.30x
|
|
38
|
+
----------------------------------------
|
|
39
|
+
Benchmarking Expression 2:
|
|
40
|
+
NumPy time (threaded over 32 chunks with 16 threads): 19.005238 seconds
|
|
41
|
+
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 12.611407 seconds
|
|
42
|
+
numexpr speedup: 1.51x
|
|
43
|
+
----------------------------------------
|
|
44
|
+
Benchmarking Expression 3:
|
|
45
|
+
NumPy time (threaded over 32 chunks with 16 threads): 20.555149 seconds
|
|
46
|
+
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 17.690749 seconds
|
|
47
|
+
numexpr speedup: 1.16x
|
|
48
|
+
----------------------------------------
|
|
49
|
+
Benchmarking Expression 4:
|
|
50
|
+
NumPy time (threaded over 32 chunks with 16 threads): 38.338372 seconds
|
|
51
|
+
numexpr time (threaded with re_evaluate over 32 chunks with 16 threads): 35.074684 seconds
|
|
52
|
+
numexpr speedup: 1.09x
|
|
53
|
+
----------------------------------------
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
import os
|
|
57
|
+
|
|
58
|
+
os.environ["NUMEXPR_NUM_THREADS"] = "2"
|
|
59
|
+
import threading
|
|
60
|
+
import timeit
|
|
61
|
+
|
|
62
|
+
import numpy as np
|
|
63
|
+
|
|
64
|
+
import numexpr as ne
|
|
65
|
+
|
|
66
|
+
array_size = 10**8
|
|
67
|
+
num_runs = 10
|
|
68
|
+
num_chunks = 32 # Number of chunks
|
|
69
|
+
num_threads = 16 # Number of threads constrained by how many chunks memory can hold
|
|
70
|
+
|
|
71
|
+
a = np.random.rand(array_size).reshape(10**4, -1)
|
|
72
|
+
b = np.random.rand(array_size).reshape(10**4, -1)
|
|
73
|
+
c = np.random.rand(array_size).reshape(10**4, -1)
|
|
74
|
+
|
|
75
|
+
chunk_size = array_size // num_chunks
|
|
76
|
+
|
|
77
|
+
expressions_numpy = [
|
|
78
|
+
lambda a, b, c: a + b * c,
|
|
79
|
+
lambda a, b, c: a**2 + b**2 - 2 * a * b * np.cos(c),
|
|
80
|
+
lambda a, b, c: np.sin(a) + np.log(b) * np.sqrt(c),
|
|
81
|
+
lambda a, b, c: np.exp(a) + np.tan(b) - np.sinh(c),
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
expressions_numexpr = [
|
|
85
|
+
"a + b * c",
|
|
86
|
+
"a**2 + b**2 - 2 * a * b * cos(c)",
|
|
87
|
+
"sin(a) + log(b) * sqrt(c)",
|
|
88
|
+
"exp(a) + tan(b) - sinh(c)",
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def benchmark_numpy_chunk(func, a, b, c, results, indices):
|
|
93
|
+
for index in indices:
|
|
94
|
+
start = index * chunk_size
|
|
95
|
+
end = (index + 1) * chunk_size
|
|
96
|
+
time_taken = timeit.timeit(
|
|
97
|
+
lambda: func(a[start:end], b[start:end], c[start:end]), number=num_runs
|
|
98
|
+
)
|
|
99
|
+
results.append(time_taken)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def benchmark_numexpr_re_evaluate(expr, a, b, c, results, indices):
|
|
103
|
+
for index in indices:
|
|
104
|
+
start = index * chunk_size
|
|
105
|
+
end = (index + 1) * chunk_size
|
|
106
|
+
# if index == 0:
|
|
107
|
+
# Evaluate the first chunk with evaluate
|
|
108
|
+
time_taken = timeit.timeit(
|
|
109
|
+
lambda: ne.evaluate(
|
|
110
|
+
expr,
|
|
111
|
+
local_dict={
|
|
112
|
+
"a": a[start:end],
|
|
113
|
+
"b": b[start:end],
|
|
114
|
+
"c": c[start:end],
|
|
115
|
+
},
|
|
116
|
+
),
|
|
117
|
+
number=num_runs,
|
|
118
|
+
)
|
|
119
|
+
results.append(time_taken)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def run_benchmark_threaded():
|
|
123
|
+
chunk_indices = list(range(num_chunks))
|
|
124
|
+
|
|
125
|
+
for i in range(len(expressions_numpy)):
|
|
126
|
+
print(f"Benchmarking Expression {i+1}:")
|
|
127
|
+
|
|
128
|
+
results_numpy = []
|
|
129
|
+
results_numexpr = []
|
|
130
|
+
|
|
131
|
+
threads_numpy = []
|
|
132
|
+
for j in range(num_threads):
|
|
133
|
+
indices = chunk_indices[j::num_threads] # Distribute chunks across threads
|
|
134
|
+
thread = threading.Thread(
|
|
135
|
+
target=benchmark_numpy_chunk,
|
|
136
|
+
args=(expressions_numpy[i], a, b, c, results_numpy, indices),
|
|
137
|
+
)
|
|
138
|
+
threads_numpy.append(thread)
|
|
139
|
+
thread.start()
|
|
140
|
+
|
|
141
|
+
for thread in threads_numpy:
|
|
142
|
+
thread.join()
|
|
143
|
+
|
|
144
|
+
numpy_time = sum(results_numpy)
|
|
145
|
+
print(
|
|
146
|
+
f"NumPy time (threaded over {num_chunks} chunks with {num_threads} threads): {numpy_time:.6f} seconds"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
threads_numexpr = []
|
|
150
|
+
for j in range(num_threads):
|
|
151
|
+
indices = chunk_indices[j::num_threads] # Distribute chunks across threads
|
|
152
|
+
thread = threading.Thread(
|
|
153
|
+
target=benchmark_numexpr_re_evaluate,
|
|
154
|
+
args=(expressions_numexpr[i], a, b, c, results_numexpr, indices),
|
|
155
|
+
)
|
|
156
|
+
threads_numexpr.append(thread)
|
|
157
|
+
thread.start()
|
|
158
|
+
|
|
159
|
+
for thread in threads_numexpr:
|
|
160
|
+
thread.join()
|
|
161
|
+
|
|
162
|
+
numexpr_time = sum(results_numexpr)
|
|
163
|
+
print(
|
|
164
|
+
f"numexpr time (threaded with re_evaluate over {num_chunks} chunks with {num_threads} threads): {numexpr_time:.6f} seconds"
|
|
165
|
+
)
|
|
166
|
+
print(f"numexpr speedup: {numpy_time / numexpr_time:.2f}x")
|
|
167
|
+
print("-" * 40)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
if __name__ == "__main__":
|
|
171
|
+
run_benchmark_threaded()
|
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
# performs better than the serial code. See issue #36 for details.
|
|
3
3
|
|
|
4
4
|
from __future__ import print_function
|
|
5
|
+
|
|
6
|
+
from time import time
|
|
7
|
+
|
|
5
8
|
import numpy as np
|
|
6
|
-
import numexpr as ne
|
|
7
9
|
from numpy.testing import assert_array_equal
|
|
8
|
-
|
|
10
|
+
|
|
11
|
+
import numexpr as ne
|
|
12
|
+
|
|
9
13
|
|
|
10
14
|
def bench(N):
|
|
11
15
|
print("*** array length:", N)
|
|
@@ -31,4 +35,3 @@ if __name__ == "__main__":
|
|
|
31
35
|
ne.set_num_threads(2)
|
|
32
36
|
for N in range(10, 20):
|
|
33
37
|
bench(2**N)
|
|
34
|
-
|
|
@@ -31,10 +31,12 @@ numexpr speedup: 2.38x
|
|
|
31
31
|
import os
|
|
32
32
|
|
|
33
33
|
os.environ["NUMEXPR_NUM_THREADS"] = "16"
|
|
34
|
+
import threading
|
|
35
|
+
import timeit
|
|
36
|
+
|
|
34
37
|
import numpy as np
|
|
38
|
+
|
|
35
39
|
import numexpr as ne
|
|
36
|
-
import timeit
|
|
37
|
-
import threading
|
|
38
40
|
|
|
39
41
|
array_size = 10**8
|
|
40
42
|
num_runs = 10
|