numexpr 2.10.1__tar.gz → 2.11.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.10.1 → numexpr-2.11.0}/ANNOUNCE.rst +17 -13
- {numexpr-2.10.1 → numexpr-2.11.0}/AUTHORS.txt +1 -1
- numexpr-2.11.0/PKG-INFO +233 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/README.rst +18 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/RELEASE_NOTES.rst +35 -6
- numexpr-2.11.0/VERSION +1 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/bench/boolean_timing.py +2 -0
- numexpr-2.11.0/bench/free_threading.py +171 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/bench/issue-36.py +6 -3
- {numexpr-2.10.1 → numexpr-2.11.0}/bench/issue-47.py +1 -0
- numexpr-2.11.0/bench/large_array_vs_numpy.py +154 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/bench/multidim.py +4 -3
- {numexpr-2.10.1 → numexpr-2.11.0}/bench/poly.py +3 -1
- {numexpr-2.10.1 → numexpr-2.11.0}/bench/timing.py +4 -1
- {numexpr-2.10.1 → numexpr-2.11.0}/bench/unaligned-simple.py +3 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/bench/varying-expr.py +3 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/bench/vml_timing.py +3 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/bench/vml_timing2.py +4 -1
- {numexpr-2.10.1 → numexpr-2.11.0}/bench/vml_timing3.py +3 -1
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/__init__.py +10 -10
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/cpuinfo.py +5 -3
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/expressions.py +3 -2
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/interp_body.cpp +4 -4
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/interpreter.cpp +10 -8
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/interpreter.hpp +1 -1
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/module.cpp +8 -2
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/module.hpp +2 -2
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/necompiler.py +78 -76
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/numexpr_config.hpp +1 -1
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/numexpr_object.cpp +0 -1
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/tests/__init__.py +1 -1
- numexpr-2.11.0/numexpr/tests/conftest.py +16 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/tests/test_numexpr.py +229 -128
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/utils.py +93 -10
- numexpr-2.11.0/numexpr/version.py +5 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/win32/stdint.h +6 -6
- numexpr-2.11.0/numexpr.egg-info/PKG-INFO +233 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr.egg-info/SOURCES.txt +3 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/pyproject.toml +4 -3
- {numexpr-2.10.1 → numexpr-2.11.0}/setup.py +12 -5
- numexpr-2.10.1/PKG-INFO +0 -27
- numexpr-2.10.1/VERSION +0 -1
- numexpr-2.10.1/numexpr/version.py +0 -5
- numexpr-2.10.1/numexpr.egg-info/PKG-INFO +0 -27
- {numexpr-2.10.1 → numexpr-2.11.0}/LICENSE.txt +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/MANIFEST.in +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/complex_functions.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/functions.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/missing_posix_functions.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/msvc_function_stubs.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/numexpr_object.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/opcodes.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/str-two-way.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/win32/pthread.c +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr/win32/pthread.h +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr.egg-info/dependency_links.txt +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr.egg-info/requires.txt +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/numexpr.egg-info/top_level.txt +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/requirements.txt +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/setup.cfg +0 -0
- {numexpr-2.10.1 → numexpr-2.11.0}/site.cfg.example +0 -0
|
@@ -1,29 +1,33 @@
|
|
|
1
1
|
=========================
|
|
2
|
-
Announcing NumExpr 2.
|
|
2
|
+
Announcing NumExpr 2.11.0
|
|
3
3
|
=========================
|
|
4
4
|
|
|
5
5
|
Hi everyone,
|
|
6
6
|
|
|
7
|
-
NumExpr 2.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
thanks to Karolina Surma.
|
|
7
|
+
NumExpr 2.11.0 Initial support for free-threaded Python 3.13t has been added.
|
|
8
|
+
This is still experimental, so please report any issues you find.
|
|
9
|
+
Finally, Python 3.10 is now the minimum supported version.
|
|
11
10
|
|
|
12
11
|
Project documentation is available at:
|
|
13
12
|
|
|
14
13
|
http://numexpr.readthedocs.io/
|
|
15
14
|
|
|
16
|
-
Changes from 2.
|
|
17
|
-
|
|
15
|
+
Changes from 2.10.2 to 2.11.0
|
|
16
|
+
-----------------------------
|
|
18
17
|
|
|
19
|
-
*
|
|
20
|
-
report any issues you find.
|
|
21
|
-
|
|
18
|
+
* Initial support for free-threaded Python 3.13t has been added.
|
|
19
|
+
This is still experimental, so please report any issues you find.
|
|
20
|
+
For more info, see discussions PRs #504, #505 and #508.
|
|
21
|
+
Thanks to @andfoy, @rgommers and @FrancescAlted for the work.
|
|
22
22
|
|
|
23
|
-
*
|
|
24
|
-
|
|
23
|
+
* Fix imaginary evaluation in the form of `1.1e1j`. This was
|
|
24
|
+
previously not supported and would raise an error. Thanks to @27rabbitlt
|
|
25
|
+
for the fix.
|
|
25
26
|
|
|
26
|
-
*
|
|
27
|
+
* The test suite has been modernized to use `pytest` instead of `unittest`.
|
|
28
|
+
This should make it easier to run the tests and contribute to the project.
|
|
29
|
+
|
|
30
|
+
* Python 3.10 is now the minimum supported version.
|
|
27
31
|
|
|
28
32
|
What's Numexpr?
|
|
29
33
|
---------------
|
|
@@ -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
|
|
numexpr-2.11.0/PKG-INFO
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: numexpr
|
|
3
|
+
Version: 2.11.0
|
|
4
|
+
Summary: Fast numerical expression evaluator for NumPy
|
|
5
|
+
Author-email: "David M. Cooke, Francesc Alted, and others" <blosc@blosc.org>
|
|
6
|
+
Maintainer-email: Blosc Development Team <blosc@blosc.org>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: homepage, https://github.com/pydata/numexpr
|
|
9
|
+
Project-URL: documentation, https://numexpr.readthedocs.io
|
|
10
|
+
Project-URL: repository, https://github.com/pydata/numexpr
|
|
11
|
+
Classifier: Development Status :: 6 - Mature
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Information Technology
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
18
|
+
Classifier: Operating System :: Unix
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/x-rst
|
|
26
|
+
License-File: LICENSE.txt
|
|
27
|
+
License-File: AUTHORS.txt
|
|
28
|
+
Requires-Dist: numpy>=1.23.0
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
======================================================
|
|
32
|
+
NumExpr: Fast numerical expression evaluator for NumPy
|
|
33
|
+
======================================================
|
|
34
|
+
|
|
35
|
+
:Author: David M. Cooke, Francesc Alted, and others.
|
|
36
|
+
:Maintainer: Francesc Alted
|
|
37
|
+
:Contact: faltet@gmail.com
|
|
38
|
+
:URL: https://github.com/pydata/numexpr
|
|
39
|
+
:Documentation: http://numexpr.readthedocs.io/en/latest/
|
|
40
|
+
:GitHub Actions: |actions|
|
|
41
|
+
:PyPi: |version|
|
|
42
|
+
:DOI: |doi|
|
|
43
|
+
:readthedocs: |docs|
|
|
44
|
+
|
|
45
|
+
.. |actions| image:: https://github.com/pydata/numexpr/workflows/Build/badge.svg
|
|
46
|
+
:target: https://github.com/pydata/numexpr/actions
|
|
47
|
+
.. |travis| image:: https://travis-ci.org/pydata/numexpr.png?branch=master
|
|
48
|
+
:target: https://travis-ci.org/pydata/numexpr
|
|
49
|
+
.. |docs| image:: https://readthedocs.org/projects/numexpr/badge/?version=latest
|
|
50
|
+
:target: http://numexpr.readthedocs.io/en/latest
|
|
51
|
+
.. |doi| image:: https://zenodo.org/badge/doi/10.5281/zenodo.2483274.svg
|
|
52
|
+
:target: https://doi.org/10.5281/zenodo.2483274
|
|
53
|
+
.. |version| image:: https://img.shields.io/pypi/v/numexpr
|
|
54
|
+
:target: https://pypi.python.org/pypi/numexpr
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
What is NumExpr?
|
|
58
|
+
----------------
|
|
59
|
+
|
|
60
|
+
NumExpr is a fast numerical expression evaluator for NumPy. With it,
|
|
61
|
+
expressions that operate on arrays (like :code:`'3*a+4*b'`) are accelerated
|
|
62
|
+
and use less memory than doing the same calculation in Python.
|
|
63
|
+
|
|
64
|
+
In addition, its multi-threaded capabilities can make use of all your
|
|
65
|
+
cores -- which generally results in substantial performance scaling compared
|
|
66
|
+
to NumPy.
|
|
67
|
+
|
|
68
|
+
Last but not least, numexpr can make use of Intel's VML (Vector Math
|
|
69
|
+
Library, normally integrated in its Math Kernel Library, or MKL).
|
|
70
|
+
This allows further acceleration of transcendent expressions.
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
How NumExpr achieves high performance
|
|
74
|
+
-------------------------------------
|
|
75
|
+
|
|
76
|
+
The main reason why NumExpr achieves better performance than NumPy is
|
|
77
|
+
that it avoids allocating memory for intermediate results. This
|
|
78
|
+
results in better cache utilization and reduces memory access in
|
|
79
|
+
general. Due to this, NumExpr works best with large arrays.
|
|
80
|
+
|
|
81
|
+
NumExpr parses expressions into its own op-codes that are then used by
|
|
82
|
+
an integrated computing virtual machine. The array operands are split
|
|
83
|
+
into small chunks that easily fit in the cache of the CPU and passed
|
|
84
|
+
to the virtual machine. The virtual machine then applies the
|
|
85
|
+
operations on each chunk. It's worth noting that all temporaries and
|
|
86
|
+
constants in the expression are also chunked. Chunks are distributed among
|
|
87
|
+
the available cores of the CPU, resulting in highly parallelized code
|
|
88
|
+
execution.
|
|
89
|
+
|
|
90
|
+
The result is that NumExpr can get the most of your machine computing
|
|
91
|
+
capabilities for array-wise computations. Common speed-ups with regard
|
|
92
|
+
to NumPy are usually between 0.95x (for very simple expressions like
|
|
93
|
+
:code:`'a + 1'`) and 4x (for relatively complex ones like :code:`'a*b-4.1*a > 2.5*b'`),
|
|
94
|
+
although much higher speed-ups can be achieved for some functions and complex
|
|
95
|
+
math operations (up to 15x in some cases).
|
|
96
|
+
|
|
97
|
+
NumExpr performs best on matrices that are too large to fit in L1 CPU cache.
|
|
98
|
+
In order to get a better idea on the different speed-ups that can be achieved
|
|
99
|
+
on your platform, run the provided benchmarks.
|
|
100
|
+
|
|
101
|
+
Installation
|
|
102
|
+
------------
|
|
103
|
+
|
|
104
|
+
From wheels
|
|
105
|
+
^^^^^^^^^^^
|
|
106
|
+
|
|
107
|
+
NumExpr is available for install via `pip` for a wide range of platforms and
|
|
108
|
+
Python versions (which may be browsed at: https://pypi.org/project/numexpr/#files).
|
|
109
|
+
Installation can be performed as::
|
|
110
|
+
|
|
111
|
+
pip install numexpr
|
|
112
|
+
|
|
113
|
+
If you are using the Anaconda or Miniconda distribution of Python you may prefer
|
|
114
|
+
to use the `conda` package manager in this case::
|
|
115
|
+
|
|
116
|
+
conda install numexpr
|
|
117
|
+
|
|
118
|
+
From Source
|
|
119
|
+
^^^^^^^^^^^
|
|
120
|
+
|
|
121
|
+
On most \*nix systems your compilers will already be present. However if you
|
|
122
|
+
are using a virtual environment with a substantially newer version of Python than
|
|
123
|
+
your system Python you may be prompted to install a new version of `gcc` or `clang`.
|
|
124
|
+
|
|
125
|
+
For Windows, you will need to install the Microsoft Visual C++ Build Tools
|
|
126
|
+
(which are free) first. The version depends on which version of Python you have
|
|
127
|
+
installed:
|
|
128
|
+
|
|
129
|
+
https://wiki.python.org/moin/WindowsCompilers
|
|
130
|
+
|
|
131
|
+
For Python 3.6+ simply installing the latest version of MSVC build tools should
|
|
132
|
+
be sufficient. Note that wheels found via pip do not include MKL support. Wheels
|
|
133
|
+
available via `conda` will have MKL, if the MKL backend is used for NumPy.
|
|
134
|
+
|
|
135
|
+
See `requirements.txt` for the required version of NumPy.
|
|
136
|
+
|
|
137
|
+
NumExpr is built in the standard Python way::
|
|
138
|
+
|
|
139
|
+
python setup.py build install
|
|
140
|
+
|
|
141
|
+
You can test `numexpr` with::
|
|
142
|
+
|
|
143
|
+
python -c "import numexpr; numexpr.test()"
|
|
144
|
+
|
|
145
|
+
Do not test NumExpr in the source directory or you will generate import errors.
|
|
146
|
+
|
|
147
|
+
Enable Intel® MKL support
|
|
148
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
149
|
+
|
|
150
|
+
NumExpr includes support for Intel's MKL library. This may provide better
|
|
151
|
+
performance on Intel architectures, mainly when evaluating transcendental
|
|
152
|
+
functions (trigonometrical, exponential, ...).
|
|
153
|
+
|
|
154
|
+
If you have Intel's MKL, copy the `site.cfg.example` that comes with the
|
|
155
|
+
distribution to `site.cfg` and edit the latter file to provide correct paths to
|
|
156
|
+
the MKL libraries in your system. After doing this, you can proceed with the
|
|
157
|
+
usual building instructions listed above.
|
|
158
|
+
|
|
159
|
+
Pay attention to the messages during the building process in order to know
|
|
160
|
+
whether MKL has been detected or not. Finally, you can check the speed-ups on
|
|
161
|
+
your machine by running the `bench/vml_timing.py` script (you can play with
|
|
162
|
+
different parameters to the `set_vml_accuracy_mode()` and `set_vml_num_threads()`
|
|
163
|
+
functions in the script so as to see how it would affect performance).
|
|
164
|
+
|
|
165
|
+
Usage
|
|
166
|
+
-----
|
|
167
|
+
|
|
168
|
+
::
|
|
169
|
+
|
|
170
|
+
>>> import numpy as np
|
|
171
|
+
>>> import numexpr as ne
|
|
172
|
+
|
|
173
|
+
>>> a = np.arange(1e6) # Choose large arrays for better speedups
|
|
174
|
+
>>> b = np.arange(1e6)
|
|
175
|
+
|
|
176
|
+
>>> ne.evaluate("a + 1") # a simple expression
|
|
177
|
+
array([ 1.00000000e+00, 2.00000000e+00, 3.00000000e+00, ...,
|
|
178
|
+
9.99998000e+05, 9.99999000e+05, 1.00000000e+06])
|
|
179
|
+
|
|
180
|
+
>>> ne.evaluate("a * b - 4.1 * a > 2.5 * b") # a more complex one
|
|
181
|
+
array([False, False, False, ..., True, True, True], dtype=bool)
|
|
182
|
+
|
|
183
|
+
>>> ne.evaluate("sin(a) + arcsinh(a/b)") # you can also use functions
|
|
184
|
+
array([ NaN, 1.72284457, 1.79067101, ..., 1.09567006,
|
|
185
|
+
0.17523598, -0.09597844])
|
|
186
|
+
|
|
187
|
+
>>> s = np.array([b'abba', b'abbb', b'abbcdef'])
|
|
188
|
+
>>> ne.evaluate("b'abba' == s") # string arrays are supported too
|
|
189
|
+
array([ True, False, False], dtype=bool)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
Free-threading support
|
|
193
|
+
----------------------
|
|
194
|
+
Starting on CPython 3.13 onwards there is a new distribution that disables the
|
|
195
|
+
Global Interpreter Lock (GIL) altogether, thus increasing the performance yields
|
|
196
|
+
under multi-threaded conditions on a single interpreter, as opposed to having to use
|
|
197
|
+
multiprocessing.
|
|
198
|
+
|
|
199
|
+
Whilst numexpr has been demonstrated to work under free-threaded
|
|
200
|
+
CPython, considerations need to be taken when using numexpr native parallel
|
|
201
|
+
implementation vs using Python threads directly in order to prevent oversubscription,
|
|
202
|
+
we recommend either using the main CPython interpreter thread to spawn multiple C threads
|
|
203
|
+
using the parallel numexpr API, or spawning multiple CPython threads that do not use
|
|
204
|
+
the parallel API.
|
|
205
|
+
|
|
206
|
+
For more information about free-threaded CPython, we recommend visiting the following
|
|
207
|
+
`community Wiki <https://py-free-threading.github.io/>`
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
Documentation
|
|
211
|
+
-------------
|
|
212
|
+
|
|
213
|
+
Please see the official documentation at `numexpr.readthedocs.io <https://numexpr.readthedocs.io>`_.
|
|
214
|
+
Included is a user guide, benchmark results, and the reference API.
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
Authors
|
|
218
|
+
-------
|
|
219
|
+
|
|
220
|
+
Please see `AUTHORS.txt <https://github.com/pydata/numexpr/blob/master/AUTHORS.txt>`_.
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
License
|
|
224
|
+
-------
|
|
225
|
+
|
|
226
|
+
NumExpr is distributed under the `MIT <http://www.opensource.org/licenses/mit-license.php>`_ license.
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
.. Local Variables:
|
|
230
|
+
.. mode: text
|
|
231
|
+
.. coding: utf-8
|
|
232
|
+
.. fill-column: 70
|
|
233
|
+
.. End:
|
|
@@ -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,22 +1,51 @@
|
|
|
1
1
|
=====================================
|
|
2
|
-
Release notes for NumExpr 2.
|
|
2
|
+
Release notes for NumExpr 2.11 series
|
|
3
3
|
=====================================
|
|
4
4
|
|
|
5
|
+
Changes from 2.10.2 to 2.11.0
|
|
6
|
+
-----------------------------
|
|
7
|
+
|
|
8
|
+
* Initial support for free-threaded Python 3.13t has been added.
|
|
9
|
+
This is still experimental, so please report any issues you find.
|
|
10
|
+
For more info, see discussions PRs #504, #505 and #508.
|
|
11
|
+
Thanks to @andfoy, @rgommers and @FrancescAlted for the work.
|
|
12
|
+
|
|
13
|
+
* Fix imaginary evaluation in the form of `1.1e1j`. This was
|
|
14
|
+
previously not supported and would raise an error. Thanks to @27rabbitlt
|
|
15
|
+
for the fix.
|
|
16
|
+
|
|
17
|
+
* The test suite has been modernized to use `pytest` instead of `unittest`.
|
|
18
|
+
This should make it easier to run the tests and contribute to the project.
|
|
19
|
+
|
|
20
|
+
* Python 3.10 is now the minimum supported version.
|
|
21
|
+
|
|
22
|
+
Changes from 2.10.1 to 2.10.2
|
|
23
|
+
-----------------------------
|
|
24
|
+
|
|
25
|
+
* Better support for CPUs that do not have a power of 2 number of
|
|
26
|
+
cores. See #479 and #490. Thanks to @avalentino.
|
|
27
|
+
|
|
28
|
+
* Allow numexpr to run with the multithreading package in Python.
|
|
29
|
+
See PR #496. Thanks to @emmaai
|
|
30
|
+
|
|
31
|
+
* Wheels for Python 3.13 are now provided.
|
|
32
|
+
|
|
33
|
+
|
|
5
34
|
Changes from 2.10.0 to 2.10.1
|
|
6
35
|
-----------------------------
|
|
7
36
|
|
|
8
|
-
|
|
37
|
+
* The default number of 'safe' threads has been upgraded to 16 (instead of
|
|
9
38
|
previous 8). That means that if your CPU has > 16 cores, the default is
|
|
10
39
|
to use 16. You can always override this with the "NUMEXPR_MAX_THREADS"
|
|
11
40
|
environment variable.
|
|
12
41
|
|
|
13
|
-
|
|
42
|
+
* NumPy 1.23 is now the minimum supported.
|
|
14
43
|
|
|
15
|
-
|
|
44
|
+
* Preliminary support for Python 3.13. Thanks to Karolina Surma.
|
|
16
45
|
|
|
17
|
-
|
|
46
|
+
* Fix tests on nthreads detection (closes: #479). Thanks to @avalentino.
|
|
18
47
|
|
|
19
|
-
|
|
48
|
+
* The build process has been modernized and now uses the `pyproject.toml`
|
|
20
49
|
file for more of the configuration options.
|
|
21
50
|
|
|
22
51
|
|
numexpr-2.11.0/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.11.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
|
-
|