flopscope 0.2.0__py3-none-any.whl
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.
- benchmarks/__init__.py +1 -0
- benchmarks/__main__.py +6 -0
- benchmarks/_baseline.py +171 -0
- benchmarks/_bitwise.py +231 -0
- benchmarks/_complex.py +176 -0
- benchmarks/_contractions.py +291 -0
- benchmarks/_fft.py +198 -0
- benchmarks/_impl_urls.py +139 -0
- benchmarks/_linalg.py +197 -0
- benchmarks/_linalg_delegates.py +407 -0
- benchmarks/_metadata.py +141 -0
- benchmarks/_misc.py +653 -0
- benchmarks/_perf.py +321 -0
- benchmarks/_perm_group_calibration.py +175 -0
- benchmarks/_pointwise.py +372 -0
- benchmarks/_polynomial.py +193 -0
- benchmarks/_random.py +209 -0
- benchmarks/_reductions.py +136 -0
- benchmarks/_sorting.py +289 -0
- benchmarks/_stats.py +137 -0
- benchmarks/_window.py +92 -0
- benchmarks/accumulation/__init__.py +0 -0
- benchmarks/accumulation/bench_cost_compute.py +138 -0
- benchmarks/dashboard.py +312 -0
- benchmarks/runner.py +636 -0
- flopscope/__init__.py +273 -0
- flopscope/_accumulation/__init__.py +13 -0
- flopscope/_accumulation/_bipartite.py +121 -0
- flopscope/_accumulation/_burnside.py +51 -0
- flopscope/_accumulation/_cache.py +146 -0
- flopscope/_accumulation/_components.py +153 -0
- flopscope/_accumulation/_cost.py +1414 -0
- flopscope/_accumulation/_cost_descriptions.py +63 -0
- flopscope/_accumulation/_detection.py +318 -0
- flopscope/_accumulation/_ladder.py +191 -0
- flopscope/_accumulation/_output_orbit.py +104 -0
- flopscope/_accumulation/_partition.py +290 -0
- flopscope/_accumulation/_path_info.py +211 -0
- flopscope/_accumulation/_public.py +169 -0
- flopscope/_accumulation/_reduction.py +310 -0
- flopscope/_accumulation/_regimes.py +303 -0
- flopscope/_accumulation/_shape.py +33 -0
- flopscope/_accumulation/_wreath.py +209 -0
- flopscope/_budget.py +1027 -0
- flopscope/_config.py +118 -0
- flopscope/_counting_ops.py +451 -0
- flopscope/_display.py +478 -0
- flopscope/_docstrings.py +59 -0
- flopscope/_dtypes.py +20 -0
- flopscope/_einsum.py +717 -0
- flopscope/_errstate.py +25 -0
- flopscope/_flops.py +282 -0
- flopscope/_free_ops.py +2654 -0
- flopscope/_ndarray.py +1126 -0
- flopscope/_opt_einsum/LICENSE +21 -0
- flopscope/_opt_einsum/NOTICE +59 -0
- flopscope/_opt_einsum/__init__.py +209 -0
- flopscope/_opt_einsum/_contract.py +1478 -0
- flopscope/_opt_einsum/_helpers.py +164 -0
- flopscope/_opt_einsum/_hsluv.py +273 -0
- flopscope/_opt_einsum/_path_random.py +462 -0
- flopscope/_opt_einsum/_paths.py +1653 -0
- flopscope/_opt_einsum/_subgraph_symmetry.py +544 -0
- flopscope/_opt_einsum/_symmetry.py +140 -0
- flopscope/_opt_einsum/_typing.py +37 -0
- flopscope/_perm_group.py +717 -0
- flopscope/_pointwise.py +2522 -0
- flopscope/_polynomial.py +278 -0
- flopscope/_registry.py +3216 -0
- flopscope/_sorting_ops.py +571 -0
- flopscope/_symmetric.py +812 -0
- flopscope/_symmetry_transport.py +510 -0
- flopscope/_symmetry_utils.py +669 -0
- flopscope/_type_info.py +12 -0
- flopscope/_unwrap.py +70 -0
- flopscope/_validation.py +83 -0
- flopscope/_version_check.py +46 -0
- flopscope/_weights.py +195 -0
- flopscope/_window.py +177 -0
- flopscope/accounting.py +565 -0
- flopscope/data/default_weights.json +462 -0
- flopscope/data/weights.csv +509 -0
- flopscope/errors.py +197 -0
- flopscope/numpy/__init__.py +878 -0
- flopscope/numpy/fft/__init__.py +55 -0
- flopscope/numpy/fft/_free.py +51 -0
- flopscope/numpy/fft/_transforms.py +695 -0
- flopscope/numpy/linalg/__init__.py +105 -0
- flopscope/numpy/linalg/_aliases.py +126 -0
- flopscope/numpy/linalg/_compound.py +161 -0
- flopscope/numpy/linalg/_decompositions.py +353 -0
- flopscope/numpy/linalg/_properties.py +533 -0
- flopscope/numpy/linalg/_solvers.py +444 -0
- flopscope/numpy/linalg/_svd.py +122 -0
- flopscope/numpy/random/__init__.py +684 -0
- flopscope/numpy/random/_cost_formulas.py +115 -0
- flopscope/numpy/random/_counted_classes.py +241 -0
- flopscope/numpy/testing/__init__.py +13 -0
- flopscope/numpy/typing/__init__.py +30 -0
- flopscope/py.typed +0 -0
- flopscope/stats/__init__.py +84 -0
- flopscope/stats/_base.py +77 -0
- flopscope/stats/_cauchy.py +146 -0
- flopscope/stats/_erf.py +190 -0
- flopscope/stats/_expon.py +146 -0
- flopscope/stats/_laplace.py +150 -0
- flopscope/stats/_logistic.py +148 -0
- flopscope/stats/_lognorm.py +160 -0
- flopscope/stats/_ndtri.py +133 -0
- flopscope/stats/_norm.py +149 -0
- flopscope/stats/_truncnorm.py +186 -0
- flopscope/stats/_uniform.py +141 -0
- flopscope-0.2.0.dist-info/METADATA +23 -0
- flopscope-0.2.0.dist-info/RECORD +115 -0
- flopscope-0.2.0.dist-info/WHEEL +4 -0
flopscope/_polynomial.py
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"""Counted polynomial operations for flopscope."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import inspect as _inspect
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import numpy as _np
|
|
9
|
+
from numpy.typing import ArrayLike
|
|
10
|
+
|
|
11
|
+
from flopscope._budget import _call_numpy, _counted_wrapper
|
|
12
|
+
from flopscope._docstrings import attach_docstring
|
|
13
|
+
from flopscope._ndarray import FlopscopeArray, _to_base_ndarray
|
|
14
|
+
from flopscope._validation import require_budget
|
|
15
|
+
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
# Cost functions
|
|
18
|
+
# ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def polyval_cost(deg: int, m: int) -> int:
|
|
22
|
+
"""Cost for polyval: Horner's method under FMA=2 textbook convention.
|
|
23
|
+
|
|
24
|
+
Per coefficient: 1 multiply + 1 add (FMA=2). m output cells, deg coefficients.
|
|
25
|
+
Returns 2 * m * deg FLOPs.
|
|
26
|
+
"""
|
|
27
|
+
return max(2 * m * deg, 1)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def polyadd_cost(n1: int, n2: int) -> int:
|
|
31
|
+
"""Cost for polyadd: max(n1, n2) FLOPs."""
|
|
32
|
+
return max(n1, n2, 1)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def polysub_cost(n1: int, n2: int) -> int:
|
|
36
|
+
"""Cost for polysub: max(n1, n2) FLOPs."""
|
|
37
|
+
return max(n1, n2, 1)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def polyder_cost(n: int) -> int:
|
|
41
|
+
"""Cost for polyder: n FLOPs (n = len of coeffs)."""
|
|
42
|
+
return max(n, 1)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def polyint_cost(n: int) -> int:
|
|
46
|
+
"""Cost for polyint: n FLOPs (n = len of coeffs)."""
|
|
47
|
+
return max(n, 1)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def polymul_cost(n1: int, n2: int) -> int:
|
|
51
|
+
"""Cost for polymul: n1 * n2 FLOPs."""
|
|
52
|
+
return max(n1 * n2, 1)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def polydiv_cost(n1: int, n2: int) -> int:
|
|
56
|
+
"""Cost for polydiv: n1 * n2 FLOPs."""
|
|
57
|
+
return max(n1 * n2, 1)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def polyfit_cost(m: int, deg: int) -> int:
|
|
61
|
+
"""Cost for polyfit: 2 * m * (deg+1)^2 FLOPs."""
|
|
62
|
+
return max(2 * m * (deg + 1) ** 2, 1)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def poly_cost(n: int) -> int:
|
|
66
|
+
"""Cost for poly: $n^2$ FLOPs."""
|
|
67
|
+
return max(n * n, 1)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def roots_cost(n: int) -> int:
|
|
71
|
+
"""Cost for roots: $n^3$ FLOPs (companion matrix eigendecomposition, simplified)."""
|
|
72
|
+
return max(n**3, 1)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# ---------------------------------------------------------------------------
|
|
76
|
+
# Wrapped operations
|
|
77
|
+
# ---------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@_counted_wrapper
|
|
81
|
+
def polyval(p: ArrayLike, x: ArrayLike) -> FlopscopeArray:
|
|
82
|
+
"""Evaluate a polynomial at given points. Wraps ``numpy.polyval``.
|
|
83
|
+
|
|
84
|
+
Both ``p`` and ``x`` are converted to plain ``np.ndarray`` (via
|
|
85
|
+
``_to_base_ndarray`` after ``np.asarray``) before being passed to
|
|
86
|
+
``_np.polyval``, because numpy's polyval implementation internally calls
|
|
87
|
+
``np.zeros_like(x)`` and other ops that do not handle
|
|
88
|
+
``FlopscopeArray`` subclasses (they are not in the
|
|
89
|
+
``__array_function__`` allowlist).
|
|
90
|
+
"""
|
|
91
|
+
budget = require_budget()
|
|
92
|
+
p_arr = _to_base_ndarray(_np.asarray(p))
|
|
93
|
+
x_arr = _to_base_ndarray(_np.asarray(x))
|
|
94
|
+
deg = len(p_arr) - 1
|
|
95
|
+
m = x_arr.size
|
|
96
|
+
cost = polyval_cost(deg, m)
|
|
97
|
+
with budget.deduct(
|
|
98
|
+
"polyval", flop_cost=cost, subscripts=None, shapes=(p_arr.shape, x_arr.shape)
|
|
99
|
+
):
|
|
100
|
+
result = _call_numpy(_np.polyval, p_arr, x_arr)
|
|
101
|
+
return result # type: ignore[return-value]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
attach_docstring(
|
|
105
|
+
polyval, _np.polyval, "counted_custom", "m * deg FLOPs (Horner's method, FMA=1)"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@_counted_wrapper
|
|
110
|
+
def polyadd(a1: ArrayLike, a2: ArrayLike) -> FlopscopeArray:
|
|
111
|
+
"""Add two polynomials. Wraps ``numpy.polyadd``."""
|
|
112
|
+
budget = require_budget()
|
|
113
|
+
a1 = _np.asarray(a1)
|
|
114
|
+
a2 = _np.asarray(a2)
|
|
115
|
+
n1 = len(a1)
|
|
116
|
+
n2 = len(a2)
|
|
117
|
+
cost = polyadd_cost(n1, n2)
|
|
118
|
+
with budget.deduct(
|
|
119
|
+
"polyadd", flop_cost=cost, subscripts=None, shapes=(a1.shape, a2.shape)
|
|
120
|
+
):
|
|
121
|
+
result = _call_numpy(_np.polyadd, a1, a2)
|
|
122
|
+
return result # type: ignore[return-value]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
attach_docstring(polyadd, _np.polyadd, "counted_custom", "max(n1, n2) FLOPs")
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@_counted_wrapper
|
|
129
|
+
def polysub(a1: ArrayLike, a2: ArrayLike) -> FlopscopeArray:
|
|
130
|
+
"""Subtract two polynomials. Wraps ``numpy.polysub``."""
|
|
131
|
+
budget = require_budget()
|
|
132
|
+
a1 = _np.asarray(a1)
|
|
133
|
+
a2 = _np.asarray(a2)
|
|
134
|
+
n1 = len(a1)
|
|
135
|
+
n2 = len(a2)
|
|
136
|
+
cost = polysub_cost(n1, n2)
|
|
137
|
+
with budget.deduct(
|
|
138
|
+
"polysub", flop_cost=cost, subscripts=None, shapes=(a1.shape, a2.shape)
|
|
139
|
+
):
|
|
140
|
+
result = _call_numpy(_np.polysub, a1, a2)
|
|
141
|
+
return result # type: ignore[return-value]
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
attach_docstring(polysub, _np.polysub, "counted_custom", "max(n1, n2) FLOPs")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@_counted_wrapper
|
|
148
|
+
def polyder(p: ArrayLike, m: int = 1) -> FlopscopeArray:
|
|
149
|
+
"""Differentiate a polynomial. Wraps ``numpy.polyder``."""
|
|
150
|
+
budget = require_budget()
|
|
151
|
+
p = _np.asarray(p)
|
|
152
|
+
n = len(p)
|
|
153
|
+
cost = polyder_cost(n)
|
|
154
|
+
with budget.deduct("polyder", flop_cost=cost, subscripts=None, shapes=(p.shape,)):
|
|
155
|
+
result = _call_numpy(_np.polyder, p, m=m)
|
|
156
|
+
return result # type: ignore[return-value]
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
attach_docstring(polyder, _np.polyder, "counted_custom", "n FLOPs (n = len(coeffs))")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@_counted_wrapper
|
|
163
|
+
def polyint(p: ArrayLike, m: int = 1, k: ArrayLike | None = None) -> FlopscopeArray:
|
|
164
|
+
"""Integrate a polynomial. Wraps ``numpy.polyint``."""
|
|
165
|
+
budget = require_budget()
|
|
166
|
+
p = _np.asarray(p)
|
|
167
|
+
n = len(p)
|
|
168
|
+
cost = polyint_cost(n)
|
|
169
|
+
with budget.deduct("polyint", flop_cost=cost, subscripts=None, shapes=(p.shape,)):
|
|
170
|
+
if k is None:
|
|
171
|
+
result = _call_numpy(_np.polyint, p, m=m)
|
|
172
|
+
else:
|
|
173
|
+
result = _call_numpy(_np.polyint, p, m=m, k=k) # type: ignore[arg-type]
|
|
174
|
+
return result # type: ignore[return-value]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
attach_docstring(polyint, _np.polyint, "counted_custom", "n FLOPs (n = len(coeffs))")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@_counted_wrapper
|
|
181
|
+
def polymul(a1: ArrayLike, a2: ArrayLike) -> FlopscopeArray:
|
|
182
|
+
"""Multiply polynomials. Wraps ``numpy.polymul``."""
|
|
183
|
+
budget = require_budget()
|
|
184
|
+
a1 = _np.asarray(a1)
|
|
185
|
+
a2 = _np.asarray(a2)
|
|
186
|
+
n1 = len(a1)
|
|
187
|
+
n2 = len(a2)
|
|
188
|
+
cost = polymul_cost(n1, n2)
|
|
189
|
+
with budget.deduct(
|
|
190
|
+
"polymul", flop_cost=cost, subscripts=None, shapes=(a1.shape, a2.shape)
|
|
191
|
+
):
|
|
192
|
+
result = _call_numpy(_np.polymul, a1, a2)
|
|
193
|
+
return result # type: ignore[return-value]
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
attach_docstring(polymul, _np.polymul, "counted_custom", "n1 * n2 FLOPs")
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@_counted_wrapper
|
|
200
|
+
def polydiv(u: ArrayLike, v: ArrayLike) -> tuple[FlopscopeArray, FlopscopeArray]:
|
|
201
|
+
"""Divide one polynomial by another. Wraps ``numpy.polydiv``."""
|
|
202
|
+
budget = require_budget()
|
|
203
|
+
u = _np.atleast_1d(_np.asarray(u))
|
|
204
|
+
v = _np.atleast_1d(_np.asarray(v))
|
|
205
|
+
n1 = len(u)
|
|
206
|
+
n2 = len(v)
|
|
207
|
+
cost = polydiv_cost(n1, n2)
|
|
208
|
+
with budget.deduct(
|
|
209
|
+
"polydiv", flop_cost=cost, subscripts=None, shapes=(u.shape, v.shape)
|
|
210
|
+
):
|
|
211
|
+
result = _call_numpy(_np.polydiv, u, v)
|
|
212
|
+
return result # type: ignore[return-value]
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
attach_docstring(polydiv, _np.polydiv, "counted_custom", "n1 * n2 FLOPs")
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@_counted_wrapper
|
|
219
|
+
def polyfit(
|
|
220
|
+
x: ArrayLike,
|
|
221
|
+
y: ArrayLike,
|
|
222
|
+
deg: int,
|
|
223
|
+
**kwargs: Any,
|
|
224
|
+
) -> FlopscopeArray:
|
|
225
|
+
"""Least-squares polynomial fit. Wraps ``numpy.polyfit``."""
|
|
226
|
+
budget = require_budget()
|
|
227
|
+
x = _np.asarray(x)
|
|
228
|
+
m = len(x)
|
|
229
|
+
cost = polyfit_cost(m, deg)
|
|
230
|
+
with budget.deduct("polyfit", flop_cost=cost, subscripts=None, shapes=(x.shape,)):
|
|
231
|
+
result = _call_numpy(_np.polyfit, x, y, deg, **kwargs) # type: ignore[arg-type]
|
|
232
|
+
return result # type: ignore[return-value]
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
attach_docstring(polyfit, _np.polyfit, "counted_custom", "2 * m * (deg+1)^2 FLOPs")
|
|
236
|
+
polyfit.__signature__ = _inspect.signature(_np.polyfit) # type: ignore[attr-defined]
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@_counted_wrapper
|
|
240
|
+
def poly(seq_of_zeros: ArrayLike) -> FlopscopeArray:
|
|
241
|
+
"""Return polynomial coefficients from roots. Wraps ``numpy.poly``."""
|
|
242
|
+
budget = require_budget()
|
|
243
|
+
seq = _np.asarray(seq_of_zeros)
|
|
244
|
+
# If 2D (square matrix), n = shape[0]; if 1D, n = len(seq)
|
|
245
|
+
if seq.ndim == 2:
|
|
246
|
+
n = seq.shape[0]
|
|
247
|
+
else:
|
|
248
|
+
n = len(seq)
|
|
249
|
+
cost = poly_cost(n)
|
|
250
|
+
with budget.deduct("poly", flop_cost=cost, subscripts=None, shapes=(seq.shape,)):
|
|
251
|
+
result = _call_numpy(_np.poly, seq_of_zeros)
|
|
252
|
+
return result # type: ignore[return-value]
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
attach_docstring(poly, _np.poly, "counted_custom", "n^2 FLOPs")
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
@_counted_wrapper
|
|
259
|
+
def roots(p: ArrayLike) -> FlopscopeArray:
|
|
260
|
+
"""Return the roots of a polynomial with given coefficients. Wraps ``numpy.roots``."""
|
|
261
|
+
budget = require_budget()
|
|
262
|
+
p = _np.asarray(p)
|
|
263
|
+
n = len(p) - 1 # degree = number of roots
|
|
264
|
+
cost = roots_cost(n)
|
|
265
|
+
with budget.deduct("roots", flop_cost=cost, subscripts=None, shapes=(p.shape,)):
|
|
266
|
+
result = _call_numpy(_np.roots, p)
|
|
267
|
+
return result # type: ignore[return-value]
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
attach_docstring(
|
|
271
|
+
roots, _np.roots, "counted_custom", "n^3 FLOPs (companion matrix eig, simplified)"
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
import sys as _sys # noqa: E402
|
|
275
|
+
|
|
276
|
+
from flopscope._ndarray import wrap_module_returns as _wrap_module_returns # noqa: E402
|
|
277
|
+
|
|
278
|
+
_wrap_module_returns(_sys.modules[__name__])
|