numexpr 2.10.1__tar.gz → 2.10.2__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.10.2}/ANNOUNCE.rst +12 -13
- numexpr-2.10.2/PKG-INFO +214 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/RELEASE_NOTES.rst +17 -5
- numexpr-2.10.2/VERSION +1 -0
- numexpr-2.10.2/bench/large_array_vs_numpy.py +152 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/necompiler.py +3 -5
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/tests/test_numexpr.py +73 -1
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/utils.py +81 -0
- numexpr-2.10.2/numexpr/version.py +5 -0
- numexpr-2.10.2/numexpr.egg-info/PKG-INFO +214 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr.egg-info/SOURCES.txt +1 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/pyproject.toml +1 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/setup.py +6 -0
- 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.10.2}/AUTHORS.txt +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/LICENSE.txt +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/MANIFEST.in +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/README.rst +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/bench/boolean_timing.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/bench/issue-36.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/bench/issue-47.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/bench/multidim.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/bench/poly.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/bench/timing.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/bench/unaligned-simple.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/bench/varying-expr.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/bench/vml_timing.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/bench/vml_timing2.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/bench/vml_timing3.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/__init__.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/complex_functions.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/cpuinfo.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/expressions.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/functions.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/interp_body.cpp +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/interpreter.cpp +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/interpreter.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/missing_posix_functions.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/module.cpp +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/module.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/msvc_function_stubs.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/numexpr_config.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/numexpr_object.cpp +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/numexpr_object.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/opcodes.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/str-two-way.hpp +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/tests/__init__.py +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/win32/pthread.c +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/win32/pthread.h +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr/win32/stdint.h +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr.egg-info/dependency_links.txt +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr.egg-info/requires.txt +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/numexpr.egg-info/top_level.txt +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/requirements.txt +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/setup.cfg +0 -0
- {numexpr-2.10.1 → numexpr-2.10.2}/site.cfg.example +0 -0
|
@@ -1,29 +1,28 @@
|
|
|
1
1
|
=========================
|
|
2
|
-
Announcing NumExpr 2.10.
|
|
2
|
+
Announcing NumExpr 2.10.2
|
|
3
3
|
=========================
|
|
4
4
|
|
|
5
5
|
Hi everyone,
|
|
6
6
|
|
|
7
|
-
NumExpr 2.10.
|
|
8
|
-
Also,
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
NumExpr 2.10.2 provides wheels for Python 2.13 for first time.
|
|
8
|
+
Also, there is better support for CPUs that do not have a power
|
|
9
|
+
of 2 number of cores. Finally, numexpr is allowed to run with
|
|
10
|
+
the multithreading package in Python.
|
|
11
11
|
|
|
12
12
|
Project documentation is available at:
|
|
13
13
|
|
|
14
14
|
http://numexpr.readthedocs.io/
|
|
15
15
|
|
|
16
|
-
Changes from 2.
|
|
17
|
-
|
|
16
|
+
Changes from 2.10.1 to 2.10.2
|
|
17
|
+
-----------------------------
|
|
18
18
|
|
|
19
|
-
*
|
|
20
|
-
|
|
21
|
-
Caswell for the work.
|
|
19
|
+
* Better support for CPUs that do not have a power of 2 number of
|
|
20
|
+
cores. See #479 and #490. Thanks to @avalentino.
|
|
22
21
|
|
|
23
|
-
*
|
|
24
|
-
|
|
22
|
+
* Allow numexpr to run with the multithreading package in Python.
|
|
23
|
+
See PR #496. Thanks to @emmaai
|
|
25
24
|
|
|
26
|
-
*
|
|
25
|
+
* Wheels for Python 3.13 are now provided.
|
|
27
26
|
|
|
28
27
|
What's Numexpr?
|
|
29
28
|
---------------
|
numexpr-2.10.2/PKG-INFO
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: numexpr
|
|
3
|
+
Version: 2.10.2
|
|
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
|
+
Project-URL: homepage, https://github.com/pydata/numexpr
|
|
8
|
+
Project-URL: documentation, https://numexpr.readthedocs.io
|
|
9
|
+
Project-URL: repository, https://github.com/pydata/numexpr
|
|
10
|
+
Classifier: Development Status :: 6 - Mature
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Information Technology
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
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.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Requires-Python: >=3.9
|
|
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
|
+
|
|
30
|
+
======================================================
|
|
31
|
+
NumExpr: Fast numerical expression evaluator for NumPy
|
|
32
|
+
======================================================
|
|
33
|
+
|
|
34
|
+
:Author: David M. Cooke, Francesc Alted, and others.
|
|
35
|
+
:Maintainer: Francesc Alted
|
|
36
|
+
:Contact: faltet@gmail.com
|
|
37
|
+
:URL: https://github.com/pydata/numexpr
|
|
38
|
+
:Documentation: http://numexpr.readthedocs.io/en/latest/
|
|
39
|
+
:GitHub Actions: |actions|
|
|
40
|
+
:PyPi: |version|
|
|
41
|
+
:DOI: |doi|
|
|
42
|
+
:readthedocs: |docs|
|
|
43
|
+
|
|
44
|
+
.. |actions| image:: https://github.com/pydata/numexpr/workflows/Build/badge.svg
|
|
45
|
+
:target: https://github.com/pydata/numexpr/actions
|
|
46
|
+
.. |travis| image:: https://travis-ci.org/pydata/numexpr.png?branch=master
|
|
47
|
+
:target: https://travis-ci.org/pydata/numexpr
|
|
48
|
+
.. |docs| image:: https://readthedocs.org/projects/numexpr/badge/?version=latest
|
|
49
|
+
:target: http://numexpr.readthedocs.io/en/latest
|
|
50
|
+
.. |doi| image:: https://zenodo.org/badge/doi/10.5281/zenodo.2483274.svg
|
|
51
|
+
:target: https://doi.org/10.5281/zenodo.2483274
|
|
52
|
+
.. |version| image:: https://img.shields.io/pypi/v/numexpr
|
|
53
|
+
:target: https://pypi.python.org/pypi/numexpr
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
What is NumExpr?
|
|
57
|
+
----------------
|
|
58
|
+
|
|
59
|
+
NumExpr is a fast numerical expression evaluator for NumPy. With it,
|
|
60
|
+
expressions that operate on arrays (like :code:`'3*a+4*b'`) are accelerated
|
|
61
|
+
and use less memory than doing the same calculation in Python.
|
|
62
|
+
|
|
63
|
+
In addition, its multi-threaded capabilities can make use of all your
|
|
64
|
+
cores -- which generally results in substantial performance scaling compared
|
|
65
|
+
to NumPy.
|
|
66
|
+
|
|
67
|
+
Last but not least, numexpr can make use of Intel's VML (Vector Math
|
|
68
|
+
Library, normally integrated in its Math Kernel Library, or MKL).
|
|
69
|
+
This allows further acceleration of transcendent expressions.
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
How NumExpr achieves high performance
|
|
73
|
+
-------------------------------------
|
|
74
|
+
|
|
75
|
+
The main reason why NumExpr achieves better performance than NumPy is
|
|
76
|
+
that it avoids allocating memory for intermediate results. This
|
|
77
|
+
results in better cache utilization and reduces memory access in
|
|
78
|
+
general. Due to this, NumExpr works best with large arrays.
|
|
79
|
+
|
|
80
|
+
NumExpr parses expressions into its own op-codes that are then used by
|
|
81
|
+
an integrated computing virtual machine. The array operands are split
|
|
82
|
+
into small chunks that easily fit in the cache of the CPU and passed
|
|
83
|
+
to the virtual machine. The virtual machine then applies the
|
|
84
|
+
operations on each chunk. It's worth noting that all temporaries and
|
|
85
|
+
constants in the expression are also chunked. Chunks are distributed among
|
|
86
|
+
the available cores of the CPU, resulting in highly parallelized code
|
|
87
|
+
execution.
|
|
88
|
+
|
|
89
|
+
The result is that NumExpr can get the most of your machine computing
|
|
90
|
+
capabilities for array-wise computations. Common speed-ups with regard
|
|
91
|
+
to NumPy are usually between 0.95x (for very simple expressions like
|
|
92
|
+
:code:`'a + 1'`) and 4x (for relatively complex ones like :code:`'a*b-4.1*a > 2.5*b'`),
|
|
93
|
+
although much higher speed-ups can be achieved for some functions and complex
|
|
94
|
+
math operations (up to 15x in some cases).
|
|
95
|
+
|
|
96
|
+
NumExpr performs best on matrices that are too large to fit in L1 CPU cache.
|
|
97
|
+
In order to get a better idea on the different speed-ups that can be achieved
|
|
98
|
+
on your platform, run the provided benchmarks.
|
|
99
|
+
|
|
100
|
+
Installation
|
|
101
|
+
------------
|
|
102
|
+
|
|
103
|
+
From wheels
|
|
104
|
+
^^^^^^^^^^^
|
|
105
|
+
|
|
106
|
+
NumExpr is available for install via `pip` for a wide range of platforms and
|
|
107
|
+
Python versions (which may be browsed at: https://pypi.org/project/numexpr/#files).
|
|
108
|
+
Installation can be performed as::
|
|
109
|
+
|
|
110
|
+
pip install numexpr
|
|
111
|
+
|
|
112
|
+
If you are using the Anaconda or Miniconda distribution of Python you may prefer
|
|
113
|
+
to use the `conda` package manager in this case::
|
|
114
|
+
|
|
115
|
+
conda install numexpr
|
|
116
|
+
|
|
117
|
+
From Source
|
|
118
|
+
^^^^^^^^^^^
|
|
119
|
+
|
|
120
|
+
On most \*nix systems your compilers will already be present. However if you
|
|
121
|
+
are using a virtual environment with a substantially newer version of Python than
|
|
122
|
+
your system Python you may be prompted to install a new version of `gcc` or `clang`.
|
|
123
|
+
|
|
124
|
+
For Windows, you will need to install the Microsoft Visual C++ Build Tools
|
|
125
|
+
(which are free) first. The version depends on which version of Python you have
|
|
126
|
+
installed:
|
|
127
|
+
|
|
128
|
+
https://wiki.python.org/moin/WindowsCompilers
|
|
129
|
+
|
|
130
|
+
For Python 3.6+ simply installing the latest version of MSVC build tools should
|
|
131
|
+
be sufficient. Note that wheels found via pip do not include MKL support. Wheels
|
|
132
|
+
available via `conda` will have MKL, if the MKL backend is used for NumPy.
|
|
133
|
+
|
|
134
|
+
See `requirements.txt` for the required version of NumPy.
|
|
135
|
+
|
|
136
|
+
NumExpr is built in the standard Python way::
|
|
137
|
+
|
|
138
|
+
python setup.py build install
|
|
139
|
+
|
|
140
|
+
You can test `numexpr` with::
|
|
141
|
+
|
|
142
|
+
python -c "import numexpr; numexpr.test()"
|
|
143
|
+
|
|
144
|
+
Do not test NumExpr in the source directory or you will generate import errors.
|
|
145
|
+
|
|
146
|
+
Enable Intel® MKL support
|
|
147
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
148
|
+
|
|
149
|
+
NumExpr includes support for Intel's MKL library. This may provide better
|
|
150
|
+
performance on Intel architectures, mainly when evaluating transcendental
|
|
151
|
+
functions (trigonometrical, exponential, ...).
|
|
152
|
+
|
|
153
|
+
If you have Intel's MKL, copy the `site.cfg.example` that comes with the
|
|
154
|
+
distribution to `site.cfg` and edit the latter file to provide correct paths to
|
|
155
|
+
the MKL libraries in your system. After doing this, you can proceed with the
|
|
156
|
+
usual building instructions listed above.
|
|
157
|
+
|
|
158
|
+
Pay attention to the messages during the building process in order to know
|
|
159
|
+
whether MKL has been detected or not. Finally, you can check the speed-ups on
|
|
160
|
+
your machine by running the `bench/vml_timing.py` script (you can play with
|
|
161
|
+
different parameters to the `set_vml_accuracy_mode()` and `set_vml_num_threads()`
|
|
162
|
+
functions in the script so as to see how it would affect performance).
|
|
163
|
+
|
|
164
|
+
Usage
|
|
165
|
+
-----
|
|
166
|
+
|
|
167
|
+
::
|
|
168
|
+
|
|
169
|
+
>>> import numpy as np
|
|
170
|
+
>>> import numexpr as ne
|
|
171
|
+
|
|
172
|
+
>>> a = np.arange(1e6) # Choose large arrays for better speedups
|
|
173
|
+
>>> b = np.arange(1e6)
|
|
174
|
+
|
|
175
|
+
>>> ne.evaluate("a + 1") # a simple expression
|
|
176
|
+
array([ 1.00000000e+00, 2.00000000e+00, 3.00000000e+00, ...,
|
|
177
|
+
9.99998000e+05, 9.99999000e+05, 1.00000000e+06])
|
|
178
|
+
|
|
179
|
+
>>> ne.evaluate("a * b - 4.1 * a > 2.5 * b") # a more complex one
|
|
180
|
+
array([False, False, False, ..., True, True, True], dtype=bool)
|
|
181
|
+
|
|
182
|
+
>>> ne.evaluate("sin(a) + arcsinh(a/b)") # you can also use functions
|
|
183
|
+
array([ NaN, 1.72284457, 1.79067101, ..., 1.09567006,
|
|
184
|
+
0.17523598, -0.09597844])
|
|
185
|
+
|
|
186
|
+
>>> s = np.array([b'abba', b'abbb', b'abbcdef'])
|
|
187
|
+
>>> ne.evaluate("b'abba' == s") # string arrays are supported too
|
|
188
|
+
array([ True, False, False], dtype=bool)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
Documentation
|
|
192
|
+
-------------
|
|
193
|
+
|
|
194
|
+
Please see the official documentation at `numexpr.readthedocs.io <https://numexpr.readthedocs.io>`_.
|
|
195
|
+
Included is a user guide, benchmark results, and the reference API.
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
Authors
|
|
199
|
+
-------
|
|
200
|
+
|
|
201
|
+
Please see `AUTHORS.txt <https://github.com/pydata/numexpr/blob/master/AUTHORS.txt>`_.
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
License
|
|
205
|
+
-------
|
|
206
|
+
|
|
207
|
+
NumExpr is distributed under the `MIT <http://www.opensource.org/licenses/mit-license.php>`_ license.
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
.. Local Variables:
|
|
211
|
+
.. mode: text
|
|
212
|
+
.. coding: utf-8
|
|
213
|
+
.. fill-column: 70
|
|
214
|
+
.. End:
|
|
@@ -2,21 +2,33 @@
|
|
|
2
2
|
Release notes for NumExpr 2.10 series
|
|
3
3
|
=====================================
|
|
4
4
|
|
|
5
|
+
Changes from 2.10.1 to 2.10.2
|
|
6
|
+
-----------------------------
|
|
7
|
+
|
|
8
|
+
* Better support for CPUs that do not have a power of 2 number of
|
|
9
|
+
cores. See #479 and #490. Thanks to @avalentino.
|
|
10
|
+
|
|
11
|
+
* Allow numexpr to run with the multithreading package in Python.
|
|
12
|
+
See PR #496. Thanks to @emmaai
|
|
13
|
+
|
|
14
|
+
* Wheels for Python 3.13 are now provided.
|
|
15
|
+
|
|
16
|
+
|
|
5
17
|
Changes from 2.10.0 to 2.10.1
|
|
6
18
|
-----------------------------
|
|
7
19
|
|
|
8
|
-
|
|
20
|
+
* The default number of 'safe' threads has been upgraded to 16 (instead of
|
|
9
21
|
previous 8). That means that if your CPU has > 16 cores, the default is
|
|
10
22
|
to use 16. You can always override this with the "NUMEXPR_MAX_THREADS"
|
|
11
23
|
environment variable.
|
|
12
24
|
|
|
13
|
-
|
|
25
|
+
* NumPy 1.23 is now the minimum supported.
|
|
14
26
|
|
|
15
|
-
|
|
27
|
+
* Preliminary support for Python 3.13. Thanks to Karolina Surma.
|
|
16
28
|
|
|
17
|
-
|
|
29
|
+
* Fix tests on nthreads detection (closes: #479). Thanks to @avalentino.
|
|
18
30
|
|
|
19
|
-
|
|
31
|
+
* The build process has been modernized and now uses the `pyproject.toml`
|
|
20
32
|
file for more of the configuration options.
|
|
21
33
|
|
|
22
34
|
|
numexpr-2.10.2/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.10.2
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#################################################################################
|
|
2
|
+
# To mimic the scenario that computation is i/o bound and constrained by memory
|
|
3
|
+
#
|
|
4
|
+
# It's a much simplified version that the chunk is computed in a loop,
|
|
5
|
+
# and expression is evaluated in a sequence, which is not true in reality.
|
|
6
|
+
# Neverthless, numexpr outperforms numpy.
|
|
7
|
+
#################################################################################
|
|
8
|
+
"""
|
|
9
|
+
Benchmarking Expression 1:
|
|
10
|
+
NumPy time (threaded over 32 chunks with 2 threads): 4.612313 seconds
|
|
11
|
+
numexpr time (threaded with re_evaluate over 32 chunks with 2 threads): 0.951172 seconds
|
|
12
|
+
numexpr speedup: 4.85x
|
|
13
|
+
----------------------------------------
|
|
14
|
+
Benchmarking Expression 2:
|
|
15
|
+
NumPy time (threaded over 32 chunks with 2 threads): 23.862752 seconds
|
|
16
|
+
numexpr time (threaded with re_evaluate over 32 chunks with 2 threads): 2.182058 seconds
|
|
17
|
+
numexpr speedup: 10.94x
|
|
18
|
+
----------------------------------------
|
|
19
|
+
Benchmarking Expression 3:
|
|
20
|
+
NumPy time (threaded over 32 chunks with 2 threads): 20.594895 seconds
|
|
21
|
+
numexpr time (threaded with re_evaluate over 32 chunks with 2 threads): 2.927881 seconds
|
|
22
|
+
numexpr speedup: 7.03x
|
|
23
|
+
----------------------------------------
|
|
24
|
+
Benchmarking Expression 4:
|
|
25
|
+
NumPy time (threaded over 32 chunks with 2 threads): 12.834101 seconds
|
|
26
|
+
numexpr time (threaded with re_evaluate over 32 chunks with 2 threads): 5.392480 seconds
|
|
27
|
+
numexpr speedup: 2.38x
|
|
28
|
+
----------------------------------------
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
import os
|
|
32
|
+
|
|
33
|
+
os.environ["NUMEXPR_NUM_THREADS"] = "16"
|
|
34
|
+
import numpy as np
|
|
35
|
+
import numexpr as ne
|
|
36
|
+
import timeit
|
|
37
|
+
import threading
|
|
38
|
+
|
|
39
|
+
array_size = 10**8
|
|
40
|
+
num_runs = 10
|
|
41
|
+
num_chunks = 32 # Number of chunks
|
|
42
|
+
num_threads = 2 # Number of threads constrained by how many chunks memory can hold
|
|
43
|
+
|
|
44
|
+
a = np.random.rand(array_size).reshape(10**4, -1)
|
|
45
|
+
b = np.random.rand(array_size).reshape(10**4, -1)
|
|
46
|
+
c = np.random.rand(array_size).reshape(10**4, -1)
|
|
47
|
+
|
|
48
|
+
chunk_size = array_size // num_chunks
|
|
49
|
+
|
|
50
|
+
expressions_numpy = [
|
|
51
|
+
lambda a, b, c: a + b * c,
|
|
52
|
+
lambda a, b, c: a**2 + b**2 - 2 * a * b * np.cos(c),
|
|
53
|
+
lambda a, b, c: np.sin(a) + np.log(b) * np.sqrt(c),
|
|
54
|
+
lambda a, b, c: np.exp(a) + np.tan(b) - np.sinh(c),
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
expressions_numexpr = [
|
|
58
|
+
"a + b * c",
|
|
59
|
+
"a**2 + b**2 - 2 * a * b * cos(c)",
|
|
60
|
+
"sin(a) + log(b) * sqrt(c)",
|
|
61
|
+
"exp(a) + tan(b) - sinh(c)",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def benchmark_numpy_chunk(func, a, b, c, results, indices):
|
|
66
|
+
for index in indices:
|
|
67
|
+
start = index * chunk_size
|
|
68
|
+
end = (index + 1) * chunk_size
|
|
69
|
+
time_taken = timeit.timeit(
|
|
70
|
+
lambda: func(a[start:end], b[start:end], c[start:end]), number=num_runs
|
|
71
|
+
)
|
|
72
|
+
results.append(time_taken)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def benchmark_numexpr_re_evaluate(expr, a, b, c, results, indices):
|
|
76
|
+
for index in indices:
|
|
77
|
+
start = index * chunk_size
|
|
78
|
+
end = (index + 1) * chunk_size
|
|
79
|
+
if index == 0:
|
|
80
|
+
# Evaluate the first chunk with evaluate
|
|
81
|
+
time_taken = timeit.timeit(
|
|
82
|
+
lambda: ne.evaluate(
|
|
83
|
+
expr,
|
|
84
|
+
local_dict={
|
|
85
|
+
"a": a[start:end],
|
|
86
|
+
"b": b[start:end],
|
|
87
|
+
"c": c[start:end],
|
|
88
|
+
},
|
|
89
|
+
),
|
|
90
|
+
number=num_runs,
|
|
91
|
+
)
|
|
92
|
+
else:
|
|
93
|
+
# Re-evaluate subsequent chunks with re_evaluate
|
|
94
|
+
time_taken = timeit.timeit(
|
|
95
|
+
lambda: ne.re_evaluate(
|
|
96
|
+
local_dict={"a": a[start:end], "b": b[start:end], "c": c[start:end]}
|
|
97
|
+
),
|
|
98
|
+
number=num_runs,
|
|
99
|
+
)
|
|
100
|
+
results.append(time_taken)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def run_benchmark_threaded():
|
|
104
|
+
chunk_indices = list(range(num_chunks))
|
|
105
|
+
|
|
106
|
+
for i in range(len(expressions_numpy)):
|
|
107
|
+
print(f"Benchmarking Expression {i+1}:")
|
|
108
|
+
|
|
109
|
+
results_numpy = []
|
|
110
|
+
results_numexpr = []
|
|
111
|
+
|
|
112
|
+
threads_numpy = []
|
|
113
|
+
for j in range(num_threads):
|
|
114
|
+
indices = chunk_indices[j::num_threads] # Distribute chunks across threads
|
|
115
|
+
thread = threading.Thread(
|
|
116
|
+
target=benchmark_numpy_chunk,
|
|
117
|
+
args=(expressions_numpy[i], a, b, c, results_numpy, indices),
|
|
118
|
+
)
|
|
119
|
+
threads_numpy.append(thread)
|
|
120
|
+
thread.start()
|
|
121
|
+
|
|
122
|
+
for thread in threads_numpy:
|
|
123
|
+
thread.join()
|
|
124
|
+
|
|
125
|
+
numpy_time = sum(results_numpy)
|
|
126
|
+
print(
|
|
127
|
+
f"NumPy time (threaded over {num_chunks} chunks with {num_threads} threads): {numpy_time:.6f} seconds"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
threads_numexpr = []
|
|
131
|
+
for j in range(num_threads):
|
|
132
|
+
indices = chunk_indices[j::num_threads] # Distribute chunks across threads
|
|
133
|
+
thread = threading.Thread(
|
|
134
|
+
target=benchmark_numexpr_re_evaluate,
|
|
135
|
+
args=(expressions_numexpr[i], a, b, c, results_numexpr, indices),
|
|
136
|
+
)
|
|
137
|
+
threads_numexpr.append(thread)
|
|
138
|
+
thread.start()
|
|
139
|
+
|
|
140
|
+
for thread in threads_numexpr:
|
|
141
|
+
thread.join()
|
|
142
|
+
|
|
143
|
+
numexpr_time = sum(results_numexpr)
|
|
144
|
+
print(
|
|
145
|
+
f"numexpr time (threaded with re_evaluate over {num_chunks} chunks with {num_threads} threads): {numexpr_time:.6f} seconds"
|
|
146
|
+
)
|
|
147
|
+
print(f"numexpr speedup: {numpy_time / numexpr_time:.2f}x")
|
|
148
|
+
print("-" * 40)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
if __name__ == "__main__":
|
|
152
|
+
run_benchmark_threaded()
|
|
@@ -19,7 +19,7 @@ import numpy
|
|
|
19
19
|
|
|
20
20
|
is_cpu_amd_intel = False # DEPRECATION WARNING: WILL BE REMOVED IN FUTURE RELEASE
|
|
21
21
|
from numexpr import interpreter, expressions, use_vml
|
|
22
|
-
from numexpr.utils import CacheDict
|
|
22
|
+
from numexpr.utils import CacheDict, ContextDict
|
|
23
23
|
|
|
24
24
|
# Declare a double type that does not exist in Python space
|
|
25
25
|
double = numpy.double
|
|
@@ -776,11 +776,9 @@ def getArguments(names, local_dict=None, global_dict=None, _frame_depth: int=2):
|
|
|
776
776
|
# Dictionaries for caching variable names and compiled expressions
|
|
777
777
|
_names_cache = CacheDict(256)
|
|
778
778
|
_numexpr_cache = CacheDict(256)
|
|
779
|
-
_numexpr_last =
|
|
779
|
+
_numexpr_last = ContextDict()
|
|
780
780
|
evaluate_lock = threading.Lock()
|
|
781
781
|
|
|
782
|
-
# MAYBE: decorate this function to add attributes instead of having the
|
|
783
|
-
# _numexpr_last dictionary?
|
|
784
782
|
def validate(ex: str,
|
|
785
783
|
local_dict: Optional[Dict] = None,
|
|
786
784
|
global_dict: Optional[Dict] = None,
|
|
@@ -887,7 +885,7 @@ def validate(ex: str,
|
|
|
887
885
|
compiled_ex = _numexpr_cache[numexpr_key] = NumExpr(ex, signature, sanitize=sanitize, **context)
|
|
888
886
|
kwargs = {'out': out, 'order': order, 'casting': casting,
|
|
889
887
|
'ex_uses_vml': ex_uses_vml}
|
|
890
|
-
_numexpr_last
|
|
888
|
+
_numexpr_last.set(ex=compiled_ex, argnames=names, kwargs=kwargs)
|
|
891
889
|
except Exception as e:
|
|
892
890
|
return e
|
|
893
891
|
return None
|
|
@@ -1129,7 +1129,7 @@ class test_threading_config(TestCase):
|
|
|
1129
1129
|
"if 'NUMEXPR_MAX_THREADS' in os.environ: os.environ.pop('NUMEXPR_MAX_THREADS')",
|
|
1130
1130
|
"if 'OMP_NUM_THREADS' in os.environ: os.environ.pop('OMP_NUM_THREADS')",
|
|
1131
1131
|
"import numexpr",
|
|
1132
|
-
"assert(numexpr.nthreads <=
|
|
1132
|
+
f"assert(numexpr.nthreads <= {MAX_THREADS})",
|
|
1133
1133
|
"exit(0)"])
|
|
1134
1134
|
subprocess.check_call([sys.executable, '-c', script])
|
|
1135
1135
|
|
|
@@ -1201,6 +1201,7 @@ class test_threading(TestCase):
|
|
|
1201
1201
|
test.join()
|
|
1202
1202
|
|
|
1203
1203
|
def test_multithread(self):
|
|
1204
|
+
|
|
1204
1205
|
import threading
|
|
1205
1206
|
|
|
1206
1207
|
# Running evaluate() from multiple threads shouldn't crash
|
|
@@ -1218,6 +1219,77 @@ class test_threading(TestCase):
|
|
|
1218
1219
|
for t in threads:
|
|
1219
1220
|
t.join()
|
|
1220
1221
|
|
|
1222
|
+
def test_thread_safety(self):
|
|
1223
|
+
"""
|
|
1224
|
+
Expected output
|
|
1225
|
+
|
|
1226
|
+
When not safe (before the pr this test is commited)
|
|
1227
|
+
AssertionError: Thread-0 failed: result does not match expected
|
|
1228
|
+
|
|
1229
|
+
When safe (after the pr this test is commited)
|
|
1230
|
+
Should pass without failure
|
|
1231
|
+
"""
|
|
1232
|
+
import threading
|
|
1233
|
+
import time
|
|
1234
|
+
|
|
1235
|
+
barrier = threading.Barrier(4)
|
|
1236
|
+
|
|
1237
|
+
# Function that each thread will run with different expressions
|
|
1238
|
+
def thread_function(a_value, b_value, expression, expected_result, results, index):
|
|
1239
|
+
validate(expression, local_dict={"a": a_value, "b": b_value})
|
|
1240
|
+
# Wait for all threads to reach this point
|
|
1241
|
+
# such that they all set _numexpr_last
|
|
1242
|
+
barrier.wait()
|
|
1243
|
+
|
|
1244
|
+
# Simulate some work or a context switch delay
|
|
1245
|
+
time.sleep(0.1)
|
|
1246
|
+
|
|
1247
|
+
result = re_evaluate(local_dict={"a": a_value, "b": b_value})
|
|
1248
|
+
results[index] = np.array_equal(result, expected_result)
|
|
1249
|
+
|
|
1250
|
+
def test_thread_safety_with_numexpr():
|
|
1251
|
+
num_threads = 4
|
|
1252
|
+
array_size = 1000000
|
|
1253
|
+
|
|
1254
|
+
expressions = [
|
|
1255
|
+
"a + b",
|
|
1256
|
+
"a - b",
|
|
1257
|
+
"a * b",
|
|
1258
|
+
"a / b"
|
|
1259
|
+
]
|
|
1260
|
+
|
|
1261
|
+
a_value = [np.full(array_size, i + 1) for i in range(num_threads)]
|
|
1262
|
+
b_value = [np.full(array_size, (i + 1) * 2) for i in range(num_threads)]
|
|
1263
|
+
|
|
1264
|
+
expected_results = [
|
|
1265
|
+
a_value[i] + b_value[i] if expr == "a + b" else
|
|
1266
|
+
a_value[i] - b_value[i] if expr == "a - b" else
|
|
1267
|
+
a_value[i] * b_value[i] if expr == "a * b" else
|
|
1268
|
+
a_value[i] / b_value[i] if expr == "a / b" else None
|
|
1269
|
+
for i, expr in enumerate(expressions)
|
|
1270
|
+
]
|
|
1271
|
+
|
|
1272
|
+
results = [None] * num_threads
|
|
1273
|
+
threads = []
|
|
1274
|
+
|
|
1275
|
+
# Create and start threads with different expressions
|
|
1276
|
+
for i in range(num_threads):
|
|
1277
|
+
thread = threading.Thread(
|
|
1278
|
+
target=thread_function,
|
|
1279
|
+
args=(a_value[i], b_value[i], expressions[i], expected_results[i], results, i)
|
|
1280
|
+
)
|
|
1281
|
+
threads.append(thread)
|
|
1282
|
+
thread.start()
|
|
1283
|
+
|
|
1284
|
+
for thread in threads:
|
|
1285
|
+
thread.join()
|
|
1286
|
+
|
|
1287
|
+
for i in range(num_threads):
|
|
1288
|
+
if not results[i]:
|
|
1289
|
+
self.fail(f"Thread-{i} failed: result does not match expected")
|
|
1290
|
+
|
|
1291
|
+
test_thread_safety_with_numexpr()
|
|
1292
|
+
|
|
1221
1293
|
|
|
1222
1294
|
# The worker function for the subprocess (needs to be here because Windows
|
|
1223
1295
|
# has problems pickling nested functions with the multiprocess module :-/)
|
|
@@ -13,6 +13,7 @@ log = logging.getLogger(__name__)
|
|
|
13
13
|
|
|
14
14
|
import os
|
|
15
15
|
import subprocess
|
|
16
|
+
import contextvars
|
|
16
17
|
|
|
17
18
|
from numexpr.interpreter import _set_num_threads, _get_num_threads, MAX_THREADS
|
|
18
19
|
from numexpr import use_vml
|
|
@@ -226,3 +227,83 @@ class CacheDict(dict):
|
|
|
226
227
|
super(CacheDict, self).__delitem__(k)
|
|
227
228
|
super(CacheDict, self).__setitem__(key, value)
|
|
228
229
|
|
|
230
|
+
|
|
231
|
+
class ContextDict:
|
|
232
|
+
"""
|
|
233
|
+
A context aware version dictionary
|
|
234
|
+
"""
|
|
235
|
+
def __init__(self):
|
|
236
|
+
self._context_data = contextvars.ContextVar('context_data', default={})
|
|
237
|
+
|
|
238
|
+
def set(self, key=None, value=None, **kwargs):
|
|
239
|
+
data = self._context_data.get().copy()
|
|
240
|
+
|
|
241
|
+
if key is not None:
|
|
242
|
+
data[key] = value
|
|
243
|
+
|
|
244
|
+
for k, v in kwargs.items():
|
|
245
|
+
data[k] = v
|
|
246
|
+
|
|
247
|
+
self._context_data.set(data)
|
|
248
|
+
|
|
249
|
+
def get(self, key, default=None):
|
|
250
|
+
data = self._context_data.get()
|
|
251
|
+
return data.get(key, default)
|
|
252
|
+
|
|
253
|
+
def delete(self, key):
|
|
254
|
+
data = self._context_data.get().copy()
|
|
255
|
+
if key in data:
|
|
256
|
+
del data[key]
|
|
257
|
+
self._context_data.set(data)
|
|
258
|
+
|
|
259
|
+
def clear(self):
|
|
260
|
+
self._context_data.set({})
|
|
261
|
+
|
|
262
|
+
def all(self):
|
|
263
|
+
return self._context_data.get()
|
|
264
|
+
|
|
265
|
+
def update(self, *args, **kwargs):
|
|
266
|
+
data = self._context_data.get().copy()
|
|
267
|
+
|
|
268
|
+
if args:
|
|
269
|
+
if len(args) > 1:
|
|
270
|
+
raise TypeError(f"update() takes at most 1 positional argument ({len(args)} given)")
|
|
271
|
+
other = args[0]
|
|
272
|
+
if isinstance(other, dict):
|
|
273
|
+
data.update(other)
|
|
274
|
+
else:
|
|
275
|
+
for k, v in other:
|
|
276
|
+
data[k] = v
|
|
277
|
+
|
|
278
|
+
data.update(kwargs)
|
|
279
|
+
self._context_data.set(data)
|
|
280
|
+
|
|
281
|
+
def keys(self):
|
|
282
|
+
return self._context_data.get().keys()
|
|
283
|
+
|
|
284
|
+
def values(self):
|
|
285
|
+
return self._context_data.get().values()
|
|
286
|
+
|
|
287
|
+
def items(self):
|
|
288
|
+
return self._context_data.get().items()
|
|
289
|
+
|
|
290
|
+
def __getitem__(self, key):
|
|
291
|
+
return self.get(key)
|
|
292
|
+
|
|
293
|
+
def __setitem__(self, key, value):
|
|
294
|
+
self.set(key, value)
|
|
295
|
+
|
|
296
|
+
def __delitem__(self, key):
|
|
297
|
+
self.delete(key)
|
|
298
|
+
|
|
299
|
+
def __contains__(self, key):
|
|
300
|
+
return key in self._context_data.get()
|
|
301
|
+
|
|
302
|
+
def __len__(self):
|
|
303
|
+
return len(self._context_data.get())
|
|
304
|
+
|
|
305
|
+
def __iter__(self):
|
|
306
|
+
return iter(self._context_data.get())
|
|
307
|
+
|
|
308
|
+
def __repr__(self):
|
|
309
|
+
return repr(self._context_data.get())
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: numexpr
|
|
3
|
+
Version: 2.10.2
|
|
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
|
+
Project-URL: homepage, https://github.com/pydata/numexpr
|
|
8
|
+
Project-URL: documentation, https://numexpr.readthedocs.io
|
|
9
|
+
Project-URL: repository, https://github.com/pydata/numexpr
|
|
10
|
+
Classifier: Development Status :: 6 - Mature
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Information Technology
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
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.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Requires-Python: >=3.9
|
|
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
|
+
|
|
30
|
+
======================================================
|
|
31
|
+
NumExpr: Fast numerical expression evaluator for NumPy
|
|
32
|
+
======================================================
|
|
33
|
+
|
|
34
|
+
:Author: David M. Cooke, Francesc Alted, and others.
|
|
35
|
+
:Maintainer: Francesc Alted
|
|
36
|
+
:Contact: faltet@gmail.com
|
|
37
|
+
:URL: https://github.com/pydata/numexpr
|
|
38
|
+
:Documentation: http://numexpr.readthedocs.io/en/latest/
|
|
39
|
+
:GitHub Actions: |actions|
|
|
40
|
+
:PyPi: |version|
|
|
41
|
+
:DOI: |doi|
|
|
42
|
+
:readthedocs: |docs|
|
|
43
|
+
|
|
44
|
+
.. |actions| image:: https://github.com/pydata/numexpr/workflows/Build/badge.svg
|
|
45
|
+
:target: https://github.com/pydata/numexpr/actions
|
|
46
|
+
.. |travis| image:: https://travis-ci.org/pydata/numexpr.png?branch=master
|
|
47
|
+
:target: https://travis-ci.org/pydata/numexpr
|
|
48
|
+
.. |docs| image:: https://readthedocs.org/projects/numexpr/badge/?version=latest
|
|
49
|
+
:target: http://numexpr.readthedocs.io/en/latest
|
|
50
|
+
.. |doi| image:: https://zenodo.org/badge/doi/10.5281/zenodo.2483274.svg
|
|
51
|
+
:target: https://doi.org/10.5281/zenodo.2483274
|
|
52
|
+
.. |version| image:: https://img.shields.io/pypi/v/numexpr
|
|
53
|
+
:target: https://pypi.python.org/pypi/numexpr
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
What is NumExpr?
|
|
57
|
+
----------------
|
|
58
|
+
|
|
59
|
+
NumExpr is a fast numerical expression evaluator for NumPy. With it,
|
|
60
|
+
expressions that operate on arrays (like :code:`'3*a+4*b'`) are accelerated
|
|
61
|
+
and use less memory than doing the same calculation in Python.
|
|
62
|
+
|
|
63
|
+
In addition, its multi-threaded capabilities can make use of all your
|
|
64
|
+
cores -- which generally results in substantial performance scaling compared
|
|
65
|
+
to NumPy.
|
|
66
|
+
|
|
67
|
+
Last but not least, numexpr can make use of Intel's VML (Vector Math
|
|
68
|
+
Library, normally integrated in its Math Kernel Library, or MKL).
|
|
69
|
+
This allows further acceleration of transcendent expressions.
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
How NumExpr achieves high performance
|
|
73
|
+
-------------------------------------
|
|
74
|
+
|
|
75
|
+
The main reason why NumExpr achieves better performance than NumPy is
|
|
76
|
+
that it avoids allocating memory for intermediate results. This
|
|
77
|
+
results in better cache utilization and reduces memory access in
|
|
78
|
+
general. Due to this, NumExpr works best with large arrays.
|
|
79
|
+
|
|
80
|
+
NumExpr parses expressions into its own op-codes that are then used by
|
|
81
|
+
an integrated computing virtual machine. The array operands are split
|
|
82
|
+
into small chunks that easily fit in the cache of the CPU and passed
|
|
83
|
+
to the virtual machine. The virtual machine then applies the
|
|
84
|
+
operations on each chunk. It's worth noting that all temporaries and
|
|
85
|
+
constants in the expression are also chunked. Chunks are distributed among
|
|
86
|
+
the available cores of the CPU, resulting in highly parallelized code
|
|
87
|
+
execution.
|
|
88
|
+
|
|
89
|
+
The result is that NumExpr can get the most of your machine computing
|
|
90
|
+
capabilities for array-wise computations. Common speed-ups with regard
|
|
91
|
+
to NumPy are usually between 0.95x (for very simple expressions like
|
|
92
|
+
:code:`'a + 1'`) and 4x (for relatively complex ones like :code:`'a*b-4.1*a > 2.5*b'`),
|
|
93
|
+
although much higher speed-ups can be achieved for some functions and complex
|
|
94
|
+
math operations (up to 15x in some cases).
|
|
95
|
+
|
|
96
|
+
NumExpr performs best on matrices that are too large to fit in L1 CPU cache.
|
|
97
|
+
In order to get a better idea on the different speed-ups that can be achieved
|
|
98
|
+
on your platform, run the provided benchmarks.
|
|
99
|
+
|
|
100
|
+
Installation
|
|
101
|
+
------------
|
|
102
|
+
|
|
103
|
+
From wheels
|
|
104
|
+
^^^^^^^^^^^
|
|
105
|
+
|
|
106
|
+
NumExpr is available for install via `pip` for a wide range of platforms and
|
|
107
|
+
Python versions (which may be browsed at: https://pypi.org/project/numexpr/#files).
|
|
108
|
+
Installation can be performed as::
|
|
109
|
+
|
|
110
|
+
pip install numexpr
|
|
111
|
+
|
|
112
|
+
If you are using the Anaconda or Miniconda distribution of Python you may prefer
|
|
113
|
+
to use the `conda` package manager in this case::
|
|
114
|
+
|
|
115
|
+
conda install numexpr
|
|
116
|
+
|
|
117
|
+
From Source
|
|
118
|
+
^^^^^^^^^^^
|
|
119
|
+
|
|
120
|
+
On most \*nix systems your compilers will already be present. However if you
|
|
121
|
+
are using a virtual environment with a substantially newer version of Python than
|
|
122
|
+
your system Python you may be prompted to install a new version of `gcc` or `clang`.
|
|
123
|
+
|
|
124
|
+
For Windows, you will need to install the Microsoft Visual C++ Build Tools
|
|
125
|
+
(which are free) first. The version depends on which version of Python you have
|
|
126
|
+
installed:
|
|
127
|
+
|
|
128
|
+
https://wiki.python.org/moin/WindowsCompilers
|
|
129
|
+
|
|
130
|
+
For Python 3.6+ simply installing the latest version of MSVC build tools should
|
|
131
|
+
be sufficient. Note that wheels found via pip do not include MKL support. Wheels
|
|
132
|
+
available via `conda` will have MKL, if the MKL backend is used for NumPy.
|
|
133
|
+
|
|
134
|
+
See `requirements.txt` for the required version of NumPy.
|
|
135
|
+
|
|
136
|
+
NumExpr is built in the standard Python way::
|
|
137
|
+
|
|
138
|
+
python setup.py build install
|
|
139
|
+
|
|
140
|
+
You can test `numexpr` with::
|
|
141
|
+
|
|
142
|
+
python -c "import numexpr; numexpr.test()"
|
|
143
|
+
|
|
144
|
+
Do not test NumExpr in the source directory or you will generate import errors.
|
|
145
|
+
|
|
146
|
+
Enable Intel® MKL support
|
|
147
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
148
|
+
|
|
149
|
+
NumExpr includes support for Intel's MKL library. This may provide better
|
|
150
|
+
performance on Intel architectures, mainly when evaluating transcendental
|
|
151
|
+
functions (trigonometrical, exponential, ...).
|
|
152
|
+
|
|
153
|
+
If you have Intel's MKL, copy the `site.cfg.example` that comes with the
|
|
154
|
+
distribution to `site.cfg` and edit the latter file to provide correct paths to
|
|
155
|
+
the MKL libraries in your system. After doing this, you can proceed with the
|
|
156
|
+
usual building instructions listed above.
|
|
157
|
+
|
|
158
|
+
Pay attention to the messages during the building process in order to know
|
|
159
|
+
whether MKL has been detected or not. Finally, you can check the speed-ups on
|
|
160
|
+
your machine by running the `bench/vml_timing.py` script (you can play with
|
|
161
|
+
different parameters to the `set_vml_accuracy_mode()` and `set_vml_num_threads()`
|
|
162
|
+
functions in the script so as to see how it would affect performance).
|
|
163
|
+
|
|
164
|
+
Usage
|
|
165
|
+
-----
|
|
166
|
+
|
|
167
|
+
::
|
|
168
|
+
|
|
169
|
+
>>> import numpy as np
|
|
170
|
+
>>> import numexpr as ne
|
|
171
|
+
|
|
172
|
+
>>> a = np.arange(1e6) # Choose large arrays for better speedups
|
|
173
|
+
>>> b = np.arange(1e6)
|
|
174
|
+
|
|
175
|
+
>>> ne.evaluate("a + 1") # a simple expression
|
|
176
|
+
array([ 1.00000000e+00, 2.00000000e+00, 3.00000000e+00, ...,
|
|
177
|
+
9.99998000e+05, 9.99999000e+05, 1.00000000e+06])
|
|
178
|
+
|
|
179
|
+
>>> ne.evaluate("a * b - 4.1 * a > 2.5 * b") # a more complex one
|
|
180
|
+
array([False, False, False, ..., True, True, True], dtype=bool)
|
|
181
|
+
|
|
182
|
+
>>> ne.evaluate("sin(a) + arcsinh(a/b)") # you can also use functions
|
|
183
|
+
array([ NaN, 1.72284457, 1.79067101, ..., 1.09567006,
|
|
184
|
+
0.17523598, -0.09597844])
|
|
185
|
+
|
|
186
|
+
>>> s = np.array([b'abba', b'abbb', b'abbcdef'])
|
|
187
|
+
>>> ne.evaluate("b'abba' == s") # string arrays are supported too
|
|
188
|
+
array([ True, False, False], dtype=bool)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
Documentation
|
|
192
|
+
-------------
|
|
193
|
+
|
|
194
|
+
Please see the official documentation at `numexpr.readthedocs.io <https://numexpr.readthedocs.io>`_.
|
|
195
|
+
Included is a user guide, benchmark results, and the reference API.
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
Authors
|
|
199
|
+
-------
|
|
200
|
+
|
|
201
|
+
Please see `AUTHORS.txt <https://github.com/pydata/numexpr/blob/master/AUTHORS.txt>`_.
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
License
|
|
205
|
+
-------
|
|
206
|
+
|
|
207
|
+
NumExpr is distributed under the `MIT <http://www.opensource.org/licenses/mit-license.php>`_ license.
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
.. Local Variables:
|
|
211
|
+
.. mode: text
|
|
212
|
+
.. coding: utf-8
|
|
213
|
+
.. fill-column: 70
|
|
214
|
+
.. End:
|
|
@@ -12,6 +12,7 @@ include = ["numexpr"]
|
|
|
12
12
|
[project]
|
|
13
13
|
name = "numexpr"
|
|
14
14
|
description = "Fast numerical expression evaluator for NumPy"
|
|
15
|
+
readme = "README.rst"
|
|
15
16
|
authors = [{name = "David M. Cooke, Francesc Alted, and others", email = "blosc@blosc.org"}]
|
|
16
17
|
maintainers = [{ name = "Blosc Development Team", email = "blosc@blosc.org"}]
|
|
17
18
|
classifiers = [
|
|
@@ -31,6 +31,10 @@ with open('numexpr/version.py', 'w') as fh:
|
|
|
31
31
|
pass
|
|
32
32
|
fh.write("platform_machine = '%s'\n" % platform.machine())
|
|
33
33
|
|
|
34
|
+
# Read the contents of your README file
|
|
35
|
+
with open('README.rst', encoding='utf-8') as f:
|
|
36
|
+
long_description = f.read()
|
|
37
|
+
|
|
34
38
|
lib_dirs = []
|
|
35
39
|
inc_dirs = [np.get_include()]
|
|
36
40
|
libs = [] # Pre-built libraries ONLY, like python36.so
|
|
@@ -101,6 +105,8 @@ def setup_package():
|
|
|
101
105
|
|
|
102
106
|
metadata = dict(
|
|
103
107
|
version=version,
|
|
108
|
+
long_description=long_description,
|
|
109
|
+
long_description_content_type='text/x-rst',
|
|
104
110
|
install_requires=requirements,
|
|
105
111
|
libraries=clibs,
|
|
106
112
|
ext_modules=[
|
numexpr-2.10.1/PKG-INFO
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: numexpr
|
|
3
|
-
Version: 2.10.1
|
|
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
|
-
Project-URL: homepage, https://github.com/pydata/numexpr
|
|
8
|
-
Project-URL: documentation, https://numexpr.readthedocs.io
|
|
9
|
-
Project-URL: repository, https://github.com/pydata/numexpr
|
|
10
|
-
Classifier: Development Status :: 6 - Mature
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: Intended Audience :: Information Technology
|
|
13
|
-
Classifier: Intended Audience :: Science/Research
|
|
14
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
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.9
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
-
Requires-Python: >=3.9
|
|
25
|
-
License-File: LICENSE.txt
|
|
26
|
-
License-File: AUTHORS.txt
|
|
27
|
-
Requires-Dist: numpy>=1.23.0
|
numexpr-2.10.1/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
2.10.1
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: numexpr
|
|
3
|
-
Version: 2.10.1
|
|
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
|
-
Project-URL: homepage, https://github.com/pydata/numexpr
|
|
8
|
-
Project-URL: documentation, https://numexpr.readthedocs.io
|
|
9
|
-
Project-URL: repository, https://github.com/pydata/numexpr
|
|
10
|
-
Classifier: Development Status :: 6 - Mature
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: Intended Audience :: Information Technology
|
|
13
|
-
Classifier: Intended Audience :: Science/Research
|
|
14
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
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.9
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
-
Requires-Python: >=3.9
|
|
25
|
-
License-File: LICENSE.txt
|
|
26
|
-
License-File: AUTHORS.txt
|
|
27
|
-
Requires-Dist: numpy>=1.23.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|