numba-utils 0.1.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.
- numba_utils-0.1.0/LICENSE +21 -0
- numba_utils-0.1.0/PKG-INFO +191 -0
- numba_utils-0.1.0/README.md +152 -0
- numba_utils-0.1.0/numba_utils/__init__.py +137 -0
- numba_utils-0.1.0/numba_utils/_config.py +92 -0
- numba_utils-0.1.0/numba_utils/algorithms/__init__.py +26 -0
- numba_utils-0.1.0/numba_utils/algorithms/_select.py +123 -0
- numba_utils-0.1.0/numba_utils/algorithms/_sort.py +166 -0
- numba_utils-0.1.0/numba_utils/algorithms/_topk.py +87 -0
- numba_utils-0.1.0/numba_utils/arrays/__init__.py +21 -0
- numba_utils-0.1.0/numba_utils/arrays/_hist.py +56 -0
- numba_utils-0.1.0/numba_utils/arrays/_rolling.py +50 -0
- numba_utils-0.1.0/numba_utils/arrays/_search.py +64 -0
- numba_utils-0.1.0/numba_utils/arrays/_transform.py +89 -0
- numba_utils-0.1.0/numba_utils/arrays/_unique.py +34 -0
- numba_utils-0.1.0/numba_utils/collections/__init__.py +28 -0
- numba_utils-0.1.0/numba_utils/collections/_bitset.py +57 -0
- numba_utils-0.1.0/numba_utils/collections/_heap.py +72 -0
- numba_utils-0.1.0/numba_utils/collections/_sparse.py +105 -0
- numba_utils-0.1.0/numba_utils/collections/_stack_queue.py +123 -0
- numba_utils-0.1.0/numba_utils/collections/_typed.py +58 -0
- numba_utils-0.1.0/numba_utils/decorators/__init__.py +19 -0
- numba_utils-0.1.0/numba_utils/decorators/_wrappers.py +118 -0
- numba_utils-0.1.0/numba_utils/diagnostics/__init__.py +13 -0
- numba_utils-0.1.0/numba_utils/diagnostics/_inspect.py +190 -0
- numba_utils-0.1.0/numba_utils/parallel/__init__.py +31 -0
- numba_utils-0.1.0/numba_utils/parallel/_histogram.py +59 -0
- numba_utils-0.1.0/numba_utils/parallel/_reduce.py +86 -0
- numba_utils-0.1.0/numba_utils/parallel/_scan.py +65 -0
- numba_utils-0.1.0/numba_utils/parallel/_topk.py +86 -0
- numba_utils-0.1.0/numba_utils/profiling/__init__.py +21 -0
- numba_utils-0.1.0/numba_utils/profiling/_compare.py +118 -0
- numba_utils-0.1.0/numba_utils/profiling/_timer.py +144 -0
- numba_utils-0.1.0/numba_utils/random/__init__.py +27 -0
- numba_utils-0.1.0/numba_utils/random/_rng.py +59 -0
- numba_utils-0.1.0/numba_utils/random/_sampling.py +142 -0
- numba_utils-0.1.0/numba_utils/testing/__init__.py +24 -0
- numba_utils-0.1.0/numba_utils/testing/_asserts.py +93 -0
- numba_utils-0.1.0/numba_utils/testing/_generators.py +63 -0
- numba_utils-0.1.0/numba_utils.egg-info/PKG-INFO +191 -0
- numba_utils-0.1.0/numba_utils.egg-info/SOURCES.txt +54 -0
- numba_utils-0.1.0/numba_utils.egg-info/dependency_links.txt +1 -0
- numba_utils-0.1.0/numba_utils.egg-info/requires.txt +10 -0
- numba_utils-0.1.0/numba_utils.egg-info/top_level.txt +1 -0
- numba_utils-0.1.0/pyproject.toml +69 -0
- numba_utils-0.1.0/setup.cfg +4 -0
- numba_utils-0.1.0/tests/test_algorithms.py +206 -0
- numba_utils-0.1.0/tests/test_arrays.py +187 -0
- numba_utils-0.1.0/tests/test_collections.py +285 -0
- numba_utils-0.1.0/tests/test_config.py +75 -0
- numba_utils-0.1.0/tests/test_decorators.py +125 -0
- numba_utils-0.1.0/tests/test_diagnostics.py +100 -0
- numba_utils-0.1.0/tests/test_parallel.py +138 -0
- numba_utils-0.1.0/tests/test_profiling.py +156 -0
- numba_utils-0.1.0/tests/test_random.py +174 -0
- numba_utils-0.1.0/tests/test_testing.py +118 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nicolás Seijas
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: numba-utils
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Battle-tested building blocks for production Numba workloads.
|
|
5
|
+
Author-email: Nicolás Seijas <nicoseijas@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/nicoseijas/numba-utils
|
|
8
|
+
Project-URL: Repository, https://github.com/nicoseijas/numba-utils
|
|
9
|
+
Project-URL: Documentation, https://nicoseijas.github.io/numba-utils/
|
|
10
|
+
Project-URL: Changelog, https://github.com/nicoseijas/numba-utils/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: Issues, https://github.com/nicoseijas/numba-utils/issues
|
|
12
|
+
Keywords: numba,njit,jit,high-performance,numerical-computing,hpc,parallel,benchmarking,data-structures
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
26
|
+
Classifier: Typing :: Typed
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: numba
|
|
31
|
+
Requires-Dist: numpy
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: pytest; extra == "dev"
|
|
34
|
+
Requires-Dist: build; extra == "dev"
|
|
35
|
+
Requires-Dist: twine; extra == "dev"
|
|
36
|
+
Provides-Extra: docs
|
|
37
|
+
Requires-Dist: mkdocs-material>=9.5; extra == "docs"
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
|
|
40
|
+
# numba-utils
|
|
41
|
+
|
|
42
|
+
**Battle-tested building blocks for production
|
|
43
|
+
[Numba](https://numba.pydata.org/) workloads.** Built for production
|
|
44
|
+
numerical software with Numba.
|
|
45
|
+
|
|
46
|
+
✓ Zero dependencies beyond NumPy + Numba · ✓ Callable inside
|
|
47
|
+
`@njit` · ✓ Honest benchmarks · ✓ Diagnostics
|
|
48
|
+
· ✓ CI · ✓ MIT
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
Numba
|
|
52
|
+
▲
|
|
53
|
+
│
|
|
54
|
+
numba-utils
|
|
55
|
+
┌───────────────┼───────────────┐
|
|
56
|
+
Arrays Collections Parallel
|
|
57
|
+
Algorithms Random Profiling
|
|
58
|
+
Decorators Testing Diagnostics
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from numba import njit
|
|
63
|
+
from numba_utils import topk
|
|
64
|
+
|
|
65
|
+
@njit
|
|
66
|
+
def winners(scores):
|
|
67
|
+
return topk(scores, 10) # O(n), no full sort — runs in nopython mode
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from numba import njit
|
|
72
|
+
from numba_utils import PriorityQueue, SparseSet
|
|
73
|
+
|
|
74
|
+
@njit
|
|
75
|
+
def simulate(n_events):
|
|
76
|
+
events = PriorityQueue(n_events) # constructed in nopython mode
|
|
77
|
+
active = SparseSet(100_000) # O(1) add/discard/contains/clear
|
|
78
|
+
...
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from numba_utils import compare
|
|
83
|
+
|
|
84
|
+
compare(numpy_impl, njit_impl, args=(values,))
|
|
85
|
+
# 31x on a fused kernel — JIT compilation excluded automatically
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
And the part that almost no library ships — diagnostics for compiled
|
|
89
|
+
code:
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
>>> from numba_utils import diagnostics
|
|
93
|
+
>>> diagnostics.check(fn)
|
|
94
|
+
⚠ cache=True may crash when loaded across processes (farms, network FS)
|
|
95
|
+
→ NUMBA_UTILS_CACHE=0 or configure(cache=False)
|
|
96
|
+
⚠ fastmath=True relaxes IEEE 754 — not for exact/reproducible results
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Why this exists
|
|
100
|
+
|
|
101
|
+
After enough numerical projects — long-running Monte Carlo engines,
|
|
102
|
+
solvers, simulation farms — you realize you've rewritten the same binary
|
|
103
|
+
search, the same typed collections, the same sampling algorithms and the
|
|
104
|
+
same benchmarking helpers again. And debugged the same Numba production
|
|
105
|
+
surprises again.
|
|
106
|
+
|
|
107
|
+
numba-utils ships more than code. It ships the production knowledge
|
|
108
|
+
that usually stays trapped inside numerical projects — as kernels with
|
|
109
|
+
the pitfalls engineered around, as diagnostics, and as
|
|
110
|
+
[documentation](https://github.com/nicoseijas/numba-utils/tree/main/docs).
|
|
111
|
+
It does not compete with Numba: it builds on top of it.
|
|
112
|
+
|
|
113
|
+
## Why not...
|
|
114
|
+
|
|
115
|
+
- **heapq / `collections`?** They can't be called from nopython mode.
|
|
116
|
+
The containers here are jitclasses usable inside `@njit`.
|
|
117
|
+
- **NumPy?** Many helpers are built to run *inside* compiled kernels,
|
|
118
|
+
where NumPy calls can't reach. Where NumPy is faster (bandwidth-bound
|
|
119
|
+
sweeps, its SIMD sort),
|
|
120
|
+
[BENCHMARKS.md](https://github.com/nicoseijas/numba-utils/blob/main/BENCHMARKS.md)
|
|
121
|
+
says so.
|
|
122
|
+
- **SciPy?** A heavy dependency that isn't njit-callable; this stays at
|
|
123
|
+
NumPy + Numba and works in the compiled path.
|
|
124
|
+
- **Numba itself?** Numba is a compiler. numba-utils is a standard
|
|
125
|
+
library on top of it.
|
|
126
|
+
|
|
127
|
+
## Design principles
|
|
128
|
+
|
|
129
|
+
1. **Performance First** — nothing ships without a benchmarked justification.
|
|
130
|
+
2. **No Hidden Magic** — thin, readable layers over Numba; nothing rewrites your code.
|
|
131
|
+
3. **Numba Compatible** — everything callable from your own `@njit` code, no hacks.
|
|
132
|
+
4. **Minimal APIs** — `topk(arr, 10)`, not twenty keyword parameters.
|
|
133
|
+
5. **Benchmark Honesty** — losses are published next to the wins.
|
|
134
|
+
|
|
135
|
+
The identity behind these:
|
|
136
|
+
[docs/philosophy.md](https://github.com/nicoseijas/numba-utils/blob/main/docs/philosophy.md).
|
|
137
|
+
|
|
138
|
+
## Modules
|
|
139
|
+
|
|
140
|
+
**Core** — decorators, arrays, algorithms ·
|
|
141
|
+
**Performance** — parallel (complete operations, not prange wrappers),
|
|
142
|
+
profiling (JIT excluded by default), diagnostics ·
|
|
143
|
+
**Data structures** — collections, random ·
|
|
144
|
+
**Developer tools** — testing, config
|
|
145
|
+
|
|
146
|
+
Full API:
|
|
147
|
+
[docs/modules.md](https://github.com/nicoseijas/numba-utils/blob/main/docs/modules.md)
|
|
148
|
+
· Runnable code:
|
|
149
|
+
[examples/](https://github.com/nicoseijas/numba-utils/tree/main/examples)
|
|
150
|
+
|
|
151
|
+
## Benchmark honesty
|
|
152
|
+
|
|
153
|
+
Every algorithm states whether it is **faster**, **similar but more
|
|
154
|
+
ergonomic**, or **slower but solving a problem unavailable elsewhere**.
|
|
155
|
+
[BENCHMARKS.md](https://github.com/nicoseijas/numba-utils/blob/main/BENCHMARKS.md)
|
|
156
|
+
contains losing rows on purpose: they tell you when NOT to use a
|
|
157
|
+
function. Backed in-repo by reproducible
|
|
158
|
+
[benchmarks/](https://github.com/nicoseijas/numba-utils/tree/main/benchmarks),
|
|
159
|
+
200+ reference-validated tests
|
|
160
|
+
([why there's no coverage badge](https://github.com/nicoseijas/numba-utils/blob/main/docs/testing.md)),
|
|
161
|
+
and CI running all of it. Trade-off records:
|
|
162
|
+
[docs/design/](https://github.com/nicoseijas/numba-utils/tree/main/docs/design).
|
|
163
|
+
|
|
164
|
+
## Used in
|
|
165
|
+
|
|
166
|
+
Patterns extracted from real workloads: Monte Carlo equity engines,
|
|
167
|
+
game-theory solvers (CFR), quantitative research, scientific
|
|
168
|
+
simulations, optimization loops.
|
|
169
|
+
|
|
170
|
+
## Status
|
|
171
|
+
|
|
172
|
+
Phase 1 (see
|
|
173
|
+
[ROADMAP.md](https://github.com/nicoseijas/numba-utils/blob/main/ROADMAP.md)):
|
|
174
|
+
|
|
175
|
+
- [x] decorators, profiling, diagnostics, config
|
|
176
|
+
- [x] arrays, algorithms, random, collections
|
|
177
|
+
- [x] parallel patterns, testing helpers
|
|
178
|
+
- [ ] dtype-generic collections, `stable_argsort`, `lexsort`
|
|
179
|
+
- [ ] PyPI release
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
python -m venv .venv
|
|
185
|
+
.venv/Scripts/pip install -e .[dev]
|
|
186
|
+
.venv/Scripts/python -m pytest
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Contributions follow
|
|
190
|
+
[GUIDELINES.md](https://github.com/nicoseijas/numba-utils/blob/main/GUIDELINES.md)
|
|
191
|
+
— benchmarks are mandatory, honesty is policy.
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# numba-utils
|
|
2
|
+
|
|
3
|
+
**Battle-tested building blocks for production
|
|
4
|
+
[Numba](https://numba.pydata.org/) workloads.** Built for production
|
|
5
|
+
numerical software with Numba.
|
|
6
|
+
|
|
7
|
+
✓ Zero dependencies beyond NumPy + Numba · ✓ Callable inside
|
|
8
|
+
`@njit` · ✓ Honest benchmarks · ✓ Diagnostics
|
|
9
|
+
· ✓ CI · ✓ MIT
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Numba
|
|
13
|
+
▲
|
|
14
|
+
│
|
|
15
|
+
numba-utils
|
|
16
|
+
┌───────────────┼───────────────┐
|
|
17
|
+
Arrays Collections Parallel
|
|
18
|
+
Algorithms Random Profiling
|
|
19
|
+
Decorators Testing Diagnostics
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from numba import njit
|
|
24
|
+
from numba_utils import topk
|
|
25
|
+
|
|
26
|
+
@njit
|
|
27
|
+
def winners(scores):
|
|
28
|
+
return topk(scores, 10) # O(n), no full sort — runs in nopython mode
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from numba import njit
|
|
33
|
+
from numba_utils import PriorityQueue, SparseSet
|
|
34
|
+
|
|
35
|
+
@njit
|
|
36
|
+
def simulate(n_events):
|
|
37
|
+
events = PriorityQueue(n_events) # constructed in nopython mode
|
|
38
|
+
active = SparseSet(100_000) # O(1) add/discard/contains/clear
|
|
39
|
+
...
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from numba_utils import compare
|
|
44
|
+
|
|
45
|
+
compare(numpy_impl, njit_impl, args=(values,))
|
|
46
|
+
# 31x on a fused kernel — JIT compilation excluded automatically
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
And the part that almost no library ships — diagnostics for compiled
|
|
50
|
+
code:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
>>> from numba_utils import diagnostics
|
|
54
|
+
>>> diagnostics.check(fn)
|
|
55
|
+
⚠ cache=True may crash when loaded across processes (farms, network FS)
|
|
56
|
+
→ NUMBA_UTILS_CACHE=0 or configure(cache=False)
|
|
57
|
+
⚠ fastmath=True relaxes IEEE 754 — not for exact/reproducible results
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Why this exists
|
|
61
|
+
|
|
62
|
+
After enough numerical projects — long-running Monte Carlo engines,
|
|
63
|
+
solvers, simulation farms — you realize you've rewritten the same binary
|
|
64
|
+
search, the same typed collections, the same sampling algorithms and the
|
|
65
|
+
same benchmarking helpers again. And debugged the same Numba production
|
|
66
|
+
surprises again.
|
|
67
|
+
|
|
68
|
+
numba-utils ships more than code. It ships the production knowledge
|
|
69
|
+
that usually stays trapped inside numerical projects — as kernels with
|
|
70
|
+
the pitfalls engineered around, as diagnostics, and as
|
|
71
|
+
[documentation](https://github.com/nicoseijas/numba-utils/tree/main/docs).
|
|
72
|
+
It does not compete with Numba: it builds on top of it.
|
|
73
|
+
|
|
74
|
+
## Why not...
|
|
75
|
+
|
|
76
|
+
- **heapq / `collections`?** They can't be called from nopython mode.
|
|
77
|
+
The containers here are jitclasses usable inside `@njit`.
|
|
78
|
+
- **NumPy?** Many helpers are built to run *inside* compiled kernels,
|
|
79
|
+
where NumPy calls can't reach. Where NumPy is faster (bandwidth-bound
|
|
80
|
+
sweeps, its SIMD sort),
|
|
81
|
+
[BENCHMARKS.md](https://github.com/nicoseijas/numba-utils/blob/main/BENCHMARKS.md)
|
|
82
|
+
says so.
|
|
83
|
+
- **SciPy?** A heavy dependency that isn't njit-callable; this stays at
|
|
84
|
+
NumPy + Numba and works in the compiled path.
|
|
85
|
+
- **Numba itself?** Numba is a compiler. numba-utils is a standard
|
|
86
|
+
library on top of it.
|
|
87
|
+
|
|
88
|
+
## Design principles
|
|
89
|
+
|
|
90
|
+
1. **Performance First** — nothing ships without a benchmarked justification.
|
|
91
|
+
2. **No Hidden Magic** — thin, readable layers over Numba; nothing rewrites your code.
|
|
92
|
+
3. **Numba Compatible** — everything callable from your own `@njit` code, no hacks.
|
|
93
|
+
4. **Minimal APIs** — `topk(arr, 10)`, not twenty keyword parameters.
|
|
94
|
+
5. **Benchmark Honesty** — losses are published next to the wins.
|
|
95
|
+
|
|
96
|
+
The identity behind these:
|
|
97
|
+
[docs/philosophy.md](https://github.com/nicoseijas/numba-utils/blob/main/docs/philosophy.md).
|
|
98
|
+
|
|
99
|
+
## Modules
|
|
100
|
+
|
|
101
|
+
**Core** — decorators, arrays, algorithms ·
|
|
102
|
+
**Performance** — parallel (complete operations, not prange wrappers),
|
|
103
|
+
profiling (JIT excluded by default), diagnostics ·
|
|
104
|
+
**Data structures** — collections, random ·
|
|
105
|
+
**Developer tools** — testing, config
|
|
106
|
+
|
|
107
|
+
Full API:
|
|
108
|
+
[docs/modules.md](https://github.com/nicoseijas/numba-utils/blob/main/docs/modules.md)
|
|
109
|
+
· Runnable code:
|
|
110
|
+
[examples/](https://github.com/nicoseijas/numba-utils/tree/main/examples)
|
|
111
|
+
|
|
112
|
+
## Benchmark honesty
|
|
113
|
+
|
|
114
|
+
Every algorithm states whether it is **faster**, **similar but more
|
|
115
|
+
ergonomic**, or **slower but solving a problem unavailable elsewhere**.
|
|
116
|
+
[BENCHMARKS.md](https://github.com/nicoseijas/numba-utils/blob/main/BENCHMARKS.md)
|
|
117
|
+
contains losing rows on purpose: they tell you when NOT to use a
|
|
118
|
+
function. Backed in-repo by reproducible
|
|
119
|
+
[benchmarks/](https://github.com/nicoseijas/numba-utils/tree/main/benchmarks),
|
|
120
|
+
200+ reference-validated tests
|
|
121
|
+
([why there's no coverage badge](https://github.com/nicoseijas/numba-utils/blob/main/docs/testing.md)),
|
|
122
|
+
and CI running all of it. Trade-off records:
|
|
123
|
+
[docs/design/](https://github.com/nicoseijas/numba-utils/tree/main/docs/design).
|
|
124
|
+
|
|
125
|
+
## Used in
|
|
126
|
+
|
|
127
|
+
Patterns extracted from real workloads: Monte Carlo equity engines,
|
|
128
|
+
game-theory solvers (CFR), quantitative research, scientific
|
|
129
|
+
simulations, optimization loops.
|
|
130
|
+
|
|
131
|
+
## Status
|
|
132
|
+
|
|
133
|
+
Phase 1 (see
|
|
134
|
+
[ROADMAP.md](https://github.com/nicoseijas/numba-utils/blob/main/ROADMAP.md)):
|
|
135
|
+
|
|
136
|
+
- [x] decorators, profiling, diagnostics, config
|
|
137
|
+
- [x] arrays, algorithms, random, collections
|
|
138
|
+
- [x] parallel patterns, testing helpers
|
|
139
|
+
- [ ] dtype-generic collections, `stable_argsort`, `lexsort`
|
|
140
|
+
- [ ] PyPI release
|
|
141
|
+
|
|
142
|
+
## Development
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
python -m venv .venv
|
|
146
|
+
.venv/Scripts/pip install -e .[dev]
|
|
147
|
+
.venv/Scripts/python -m pytest
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Contributions follow
|
|
151
|
+
[GUIDELINES.md](https://github.com/nicoseijas/numba-utils/blob/main/GUIDELINES.md)
|
|
152
|
+
— benchmarks are mandatory, honesty is policy.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""numba-utils: high-performance building blocks for Numba."""
|
|
2
|
+
|
|
3
|
+
from numba_utils import diagnostics, testing
|
|
4
|
+
from numba_utils._config import config, configure
|
|
5
|
+
from numba_utils.algorithms import (
|
|
6
|
+
argmax2,
|
|
7
|
+
counting_sort,
|
|
8
|
+
fast_argpartition,
|
|
9
|
+
insertion_sort,
|
|
10
|
+
nth_element,
|
|
11
|
+
partial_sort,
|
|
12
|
+
quickselect,
|
|
13
|
+
radix_sort,
|
|
14
|
+
topk,
|
|
15
|
+
)
|
|
16
|
+
from numba_utils.arrays import (
|
|
17
|
+
bincount,
|
|
18
|
+
binary_search,
|
|
19
|
+
cumulative_sum,
|
|
20
|
+
fast_clip,
|
|
21
|
+
histogram,
|
|
22
|
+
lower_bound,
|
|
23
|
+
normalize,
|
|
24
|
+
rolling_mean,
|
|
25
|
+
rolling_sum,
|
|
26
|
+
unique_sorted,
|
|
27
|
+
upper_bound,
|
|
28
|
+
)
|
|
29
|
+
from numba_utils.collections import (
|
|
30
|
+
BitSet,
|
|
31
|
+
FixedQueue,
|
|
32
|
+
ObjectPool,
|
|
33
|
+
PriorityQueue,
|
|
34
|
+
RingBuffer,
|
|
35
|
+
SparseSet,
|
|
36
|
+
Stack,
|
|
37
|
+
counter,
|
|
38
|
+
typed_defaultdict,
|
|
39
|
+
)
|
|
40
|
+
from numba_utils.decorators import (
|
|
41
|
+
boundscheck,
|
|
42
|
+
cached_njit,
|
|
43
|
+
njit_fast,
|
|
44
|
+
njit_parallel,
|
|
45
|
+
)
|
|
46
|
+
from numba_utils.parallel import (
|
|
47
|
+
parallel_histogram,
|
|
48
|
+
parallel_prefix_sum,
|
|
49
|
+
parallel_reduce,
|
|
50
|
+
parallel_sum,
|
|
51
|
+
parallel_topk,
|
|
52
|
+
)
|
|
53
|
+
from numba_utils.profiling import (
|
|
54
|
+
BenchmarkResult,
|
|
55
|
+
ComparisonResult,
|
|
56
|
+
TimingStats,
|
|
57
|
+
benchmark,
|
|
58
|
+
compare,
|
|
59
|
+
compile_stats,
|
|
60
|
+
compile_time,
|
|
61
|
+
warmup,
|
|
62
|
+
)
|
|
63
|
+
from numba_utils.random import (
|
|
64
|
+
alias_draw,
|
|
65
|
+
alias_sample,
|
|
66
|
+
alias_setup,
|
|
67
|
+
choice,
|
|
68
|
+
permutation,
|
|
69
|
+
reservoir_sampling,
|
|
70
|
+
seed,
|
|
71
|
+
shuffle,
|
|
72
|
+
weighted_sampling,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
__version__ = "0.1.0"
|
|
76
|
+
|
|
77
|
+
__all__ = [
|
|
78
|
+
"BenchmarkResult",
|
|
79
|
+
"BitSet",
|
|
80
|
+
"ComparisonResult",
|
|
81
|
+
"FixedQueue",
|
|
82
|
+
"ObjectPool",
|
|
83
|
+
"PriorityQueue",
|
|
84
|
+
"RingBuffer",
|
|
85
|
+
"SparseSet",
|
|
86
|
+
"Stack",
|
|
87
|
+
"TimingStats",
|
|
88
|
+
"alias_draw",
|
|
89
|
+
"alias_sample",
|
|
90
|
+
"alias_setup",
|
|
91
|
+
"argmax2",
|
|
92
|
+
"benchmark",
|
|
93
|
+
"bincount",
|
|
94
|
+
"binary_search",
|
|
95
|
+
"boundscheck",
|
|
96
|
+
"cached_njit",
|
|
97
|
+
"choice",
|
|
98
|
+
"compare",
|
|
99
|
+
"compile_stats",
|
|
100
|
+
"compile_time",
|
|
101
|
+
"config",
|
|
102
|
+
"configure",
|
|
103
|
+
"counter",
|
|
104
|
+
"counting_sort",
|
|
105
|
+
"cumulative_sum",
|
|
106
|
+
"diagnostics",
|
|
107
|
+
"fast_argpartition",
|
|
108
|
+
"fast_clip",
|
|
109
|
+
"histogram",
|
|
110
|
+
"insertion_sort",
|
|
111
|
+
"lower_bound",
|
|
112
|
+
"njit_fast",
|
|
113
|
+
"njit_parallel",
|
|
114
|
+
"normalize",
|
|
115
|
+
"nth_element",
|
|
116
|
+
"parallel_histogram",
|
|
117
|
+
"parallel_prefix_sum",
|
|
118
|
+
"parallel_reduce",
|
|
119
|
+
"parallel_sum",
|
|
120
|
+
"parallel_topk",
|
|
121
|
+
"partial_sort",
|
|
122
|
+
"permutation",
|
|
123
|
+
"quickselect",
|
|
124
|
+
"radix_sort",
|
|
125
|
+
"reservoir_sampling",
|
|
126
|
+
"rolling_mean",
|
|
127
|
+
"rolling_sum",
|
|
128
|
+
"seed",
|
|
129
|
+
"shuffle",
|
|
130
|
+
"testing",
|
|
131
|
+
"topk",
|
|
132
|
+
"typed_defaultdict",
|
|
133
|
+
"unique_sorted",
|
|
134
|
+
"upper_bound",
|
|
135
|
+
"warmup",
|
|
136
|
+
"weighted_sampling",
|
|
137
|
+
]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Global configuration: code-level overrides with environment fallbacks.
|
|
2
|
+
|
|
3
|
+
Two levels, resolved per option at decoration time:
|
|
4
|
+
|
|
5
|
+
1. Code: ``configure(cache=False)`` or ``config.cache = False``.
|
|
6
|
+
2. Environment: ``NUMBA_UTILS_CACHE=0`` (checked only when the code level
|
|
7
|
+
is unset).
|
|
8
|
+
|
|
9
|
+
A set option (``True``/``False``) is a GLOBAL override: it wins over
|
|
10
|
+
decorator defaults and per-call keyword arguments alike. That is the
|
|
11
|
+
point — overrides exist for environment-level policy, like disabling the
|
|
12
|
+
on-disk cache on machines where it is unsafe (see docs/numba-cache.md).
|
|
13
|
+
``None`` means "no override": decorator defaults and per-call arguments
|
|
14
|
+
apply unchanged.
|
|
15
|
+
|
|
16
|
+
Overrides affect only functions decorated AFTER the change — configure
|
|
17
|
+
before defining your jitted functions.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import os
|
|
23
|
+
|
|
24
|
+
_TRUTHY = frozenset({"1", "true", "yes", "on"})
|
|
25
|
+
_FALSY = frozenset({"0", "false", "no", "off"})
|
|
26
|
+
|
|
27
|
+
OPTION_ENV_VARS = {
|
|
28
|
+
"cache": "NUMBA_UTILS_CACHE",
|
|
29
|
+
"fastmath": "NUMBA_UTILS_FASTMATH",
|
|
30
|
+
"parallel": "NUMBA_UTILS_PARALLEL",
|
|
31
|
+
"nogil": "NUMBA_UTILS_NOGIL",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class GlobalConfig:
|
|
36
|
+
"""Tri-state global overrides for every numba-utils decorator.
|
|
37
|
+
|
|
38
|
+
Attributes ``cache``, ``fastmath``, ``parallel``, ``nogil`` are each
|
|
39
|
+
``None`` (no override), ``True`` or ``False`` (forced globally).
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
__slots__ = ("cache", "fastmath", "parallel", "nogil")
|
|
43
|
+
|
|
44
|
+
def __init__(self) -> None:
|
|
45
|
+
self.reset()
|
|
46
|
+
|
|
47
|
+
def reset(self) -> None:
|
|
48
|
+
"""Clear all code-level overrides. Environment fallbacks remain."""
|
|
49
|
+
for name in OPTION_ENV_VARS:
|
|
50
|
+
setattr(self, name, None)
|
|
51
|
+
|
|
52
|
+
def resolve(self, name: str) -> bool | None:
|
|
53
|
+
"""Effective override for ``name``: code level, else environment,
|
|
54
|
+
else ``None``. Unrecognized environment values count as unset."""
|
|
55
|
+
value = getattr(self, name)
|
|
56
|
+
if value is not None:
|
|
57
|
+
return bool(value)
|
|
58
|
+
raw = os.environ.get(OPTION_ENV_VARS[name], "").strip().lower()
|
|
59
|
+
if raw in _TRUTHY:
|
|
60
|
+
return True
|
|
61
|
+
if raw in _FALSY:
|
|
62
|
+
return False
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
config = GlobalConfig()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def configure(**options: bool | None) -> None:
|
|
70
|
+
"""Set global decorator overrides in code.
|
|
71
|
+
|
|
72
|
+
::
|
|
73
|
+
|
|
74
|
+
import numba_utils as nu
|
|
75
|
+
nu.configure(cache=False, fastmath=True)
|
|
76
|
+
|
|
77
|
+
Valid options: ``cache``, ``fastmath``, ``parallel``, ``nogil``.
|
|
78
|
+
Pass ``None`` to clear a single override; ``config.reset()`` clears
|
|
79
|
+
all. Raises ``ValueError`` on unknown names (fail fast, no typos
|
|
80
|
+
silently ignored).
|
|
81
|
+
"""
|
|
82
|
+
for name, value in options.items():
|
|
83
|
+
if name not in OPTION_ENV_VARS:
|
|
84
|
+
valid = ", ".join(sorted(OPTION_ENV_VARS))
|
|
85
|
+
raise ValueError(
|
|
86
|
+
f"configure: unknown option {name!r}; valid options: {valid}"
|
|
87
|
+
)
|
|
88
|
+
if value is not None and not isinstance(value, bool):
|
|
89
|
+
raise ValueError(
|
|
90
|
+
f"configure: option {name!r} must be True, False or None"
|
|
91
|
+
)
|
|
92
|
+
setattr(config, name, value)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Selection and sorting algorithms specialized for Numba."""
|
|
2
|
+
|
|
3
|
+
from numba_utils.algorithms._select import (
|
|
4
|
+
fast_argpartition,
|
|
5
|
+
nth_element,
|
|
6
|
+
quickselect,
|
|
7
|
+
)
|
|
8
|
+
from numba_utils.algorithms._sort import (
|
|
9
|
+
counting_sort,
|
|
10
|
+
insertion_sort,
|
|
11
|
+
partial_sort,
|
|
12
|
+
radix_sort,
|
|
13
|
+
)
|
|
14
|
+
from numba_utils.algorithms._topk import argmax2, topk
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"argmax2",
|
|
18
|
+
"counting_sort",
|
|
19
|
+
"fast_argpartition",
|
|
20
|
+
"insertion_sort",
|
|
21
|
+
"nth_element",
|
|
22
|
+
"partial_sort",
|
|
23
|
+
"quickselect",
|
|
24
|
+
"radix_sort",
|
|
25
|
+
"topk",
|
|
26
|
+
]
|