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
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""Logistic distribution for :mod:`flopscope.stats`."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as _np
|
|
6
|
+
|
|
7
|
+
from flopscope.stats._base import ContinuousDistribution
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LogisticDistribution(ContinuousDistribution):
|
|
11
|
+
"""Logistic continuous random variable.
|
|
12
|
+
|
|
13
|
+
This object mirrors ``scipy.stats.logistic``.
|
|
14
|
+
|
|
15
|
+
Methods
|
|
16
|
+
-------
|
|
17
|
+
pdf(x, loc=0, scale=1)
|
|
18
|
+
Evaluate the probability density function.
|
|
19
|
+
cdf(x, loc=0, scale=1)
|
|
20
|
+
Evaluate the cumulative distribution function.
|
|
21
|
+
ppf(q, loc=0, scale=1)
|
|
22
|
+
Evaluate the percent-point function.
|
|
23
|
+
|
|
24
|
+
Notes
|
|
25
|
+
-----
|
|
26
|
+
``loc`` is the center of the distribution and ``scale`` controls the
|
|
27
|
+
spread. The CDF is the sigmoid function and the PPF is the logit
|
|
28
|
+
function. Each public method deducts ``1 * numel(input)`` FLOPs from the
|
|
29
|
+
active budget.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self):
|
|
33
|
+
super().__init__("logistic")
|
|
34
|
+
|
|
35
|
+
def pdf(self, x, loc=0, scale=1):
|
|
36
|
+
"""Evaluate the probability density function.
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
x : array_like
|
|
41
|
+
Points at which to evaluate the density.
|
|
42
|
+
loc : float, optional
|
|
43
|
+
Location parameter of the distribution. Defaults to ``0``.
|
|
44
|
+
scale : float, optional
|
|
45
|
+
Scale parameter of the distribution. Defaults to ``1``.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
FlopscopeArray
|
|
50
|
+
Probability density evaluated elementwise at ``x``.
|
|
51
|
+
|
|
52
|
+
Notes
|
|
53
|
+
-----
|
|
54
|
+
Equivalent to ``scipy.stats.logistic.pdf(x, loc, scale)``.
|
|
55
|
+
FLOP cost: ``1 * numel(x)``.
|
|
56
|
+
|
|
57
|
+
Examples
|
|
58
|
+
--------
|
|
59
|
+
>>> import numpy as np
|
|
60
|
+
>>> import flopscope as flops
|
|
61
|
+
>>> x = np.array([-1.0, 0.0, 1.0])
|
|
62
|
+
>>> np.round(flops.stats.logistic.pdf(x), 3)
|
|
63
|
+
array([0.197, 0.25 , 0.197])
|
|
64
|
+
"""
|
|
65
|
+
return self._deduct_and_call("pdf", 1, x, loc=loc, scale=scale)
|
|
66
|
+
|
|
67
|
+
def cdf(self, x, loc=0, scale=1):
|
|
68
|
+
"""Evaluate the cumulative distribution function.
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
x : array_like
|
|
73
|
+
Points at which to evaluate the cumulative probability.
|
|
74
|
+
loc : float, optional
|
|
75
|
+
Location parameter of the distribution. Defaults to ``0``.
|
|
76
|
+
scale : float, optional
|
|
77
|
+
Scale parameter of the distribution. Defaults to ``1``.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
FlopscopeArray
|
|
82
|
+
Cumulative probability evaluated elementwise at ``x``.
|
|
83
|
+
|
|
84
|
+
Notes
|
|
85
|
+
-----
|
|
86
|
+
Equivalent to ``scipy.stats.logistic.cdf(x, loc, scale)``.
|
|
87
|
+
FLOP cost: ``1 * numel(x)``.
|
|
88
|
+
|
|
89
|
+
Examples
|
|
90
|
+
--------
|
|
91
|
+
>>> import numpy as np
|
|
92
|
+
>>> import flopscope as flops
|
|
93
|
+
>>> x = np.array([-1.0, 0.0, 1.0])
|
|
94
|
+
>>> np.round(flops.stats.logistic.cdf(x), 3)
|
|
95
|
+
array([0.269, 0.5 , 0.731])
|
|
96
|
+
"""
|
|
97
|
+
return self._deduct_and_call("cdf", 1, x, loc=loc, scale=scale)
|
|
98
|
+
|
|
99
|
+
def ppf(self, q, loc=0, scale=1):
|
|
100
|
+
"""Evaluate the percent-point function.
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
q : array_like
|
|
105
|
+
Probabilities in ``[0, 1]``.
|
|
106
|
+
loc : float, optional
|
|
107
|
+
Location parameter of the distribution. Defaults to ``0``.
|
|
108
|
+
scale : float, optional
|
|
109
|
+
Scale parameter of the distribution. Defaults to ``1``.
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
FlopscopeArray
|
|
114
|
+
Quantiles corresponding to ``q``.
|
|
115
|
+
|
|
116
|
+
Notes
|
|
117
|
+
-----
|
|
118
|
+
Equivalent to ``scipy.stats.logistic.ppf(q, loc, scale)``.
|
|
119
|
+
FLOP cost: ``1 * numel(q)``.
|
|
120
|
+
|
|
121
|
+
Examples
|
|
122
|
+
--------
|
|
123
|
+
>>> import numpy as np
|
|
124
|
+
>>> import flopscope as flops
|
|
125
|
+
>>> q = np.array([0.25, 0.5, 0.75])
|
|
126
|
+
>>> np.round(flops.stats.logistic.ppf(q), 3)
|
|
127
|
+
array([-1.099, 0. , 1.099])
|
|
128
|
+
"""
|
|
129
|
+
return self._deduct_and_call("ppf", 1, q, loc=loc, scale=scale)
|
|
130
|
+
|
|
131
|
+
def _compute_pdf(self, x, loc=0, scale=1):
|
|
132
|
+
z = (x - loc) / scale
|
|
133
|
+
ez = _np.exp(-z)
|
|
134
|
+
return ez / (scale * (1.0 + ez) ** 2)
|
|
135
|
+
|
|
136
|
+
def _compute_cdf(self, x, loc=0, scale=1):
|
|
137
|
+
z = (x - loc) / scale
|
|
138
|
+
return 1.0 / (1.0 + _np.exp(-z))
|
|
139
|
+
|
|
140
|
+
def _compute_ppf(self, q, loc=0, scale=1):
|
|
141
|
+
result = loc + scale * _np.log(q / (1.0 - q))
|
|
142
|
+
result = _np.where((q > 0) & (q < 1), result, _np.nan)
|
|
143
|
+
result = _np.where(q == 0, -_np.inf, result)
|
|
144
|
+
result = _np.where(q == 1, _np.inf, result)
|
|
145
|
+
return result
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
logistic = LogisticDistribution()
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Log-normal distribution for :mod:`flopscope.stats`."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as _np
|
|
6
|
+
|
|
7
|
+
from flopscope.stats._base import ContinuousDistribution
|
|
8
|
+
from flopscope.stats._erf import _erf
|
|
9
|
+
from flopscope.stats._ndtri import _ndtri
|
|
10
|
+
|
|
11
|
+
_SQRT2 = _np.sqrt(2.0)
|
|
12
|
+
_INV_SQRT_2PI = 1.0 / _np.sqrt(2.0 * _np.pi)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class LognormDistribution(ContinuousDistribution):
|
|
16
|
+
"""Log-normal continuous random variable.
|
|
17
|
+
|
|
18
|
+
This object mirrors ``scipy.stats.lognorm``.
|
|
19
|
+
|
|
20
|
+
Methods
|
|
21
|
+
-------
|
|
22
|
+
pdf(x, s, loc=0, scale=1)
|
|
23
|
+
Evaluate the probability density function.
|
|
24
|
+
cdf(x, s, loc=0, scale=1)
|
|
25
|
+
Evaluate the cumulative distribution function.
|
|
26
|
+
ppf(q, s, loc=0, scale=1)
|
|
27
|
+
Evaluate the percent-point function.
|
|
28
|
+
|
|
29
|
+
Notes
|
|
30
|
+
-----
|
|
31
|
+
``s`` is the shape parameter: the standard deviation of the underlying
|
|
32
|
+
normal distribution. It is the first positional argument, ahead of
|
|
33
|
+
``loc`` and ``scale``, matching SciPy's ``lognorm`` signature. Each
|
|
34
|
+
public method deducts ``1 * numel(input)`` FLOPs from the active budget.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self):
|
|
38
|
+
super().__init__("lognorm")
|
|
39
|
+
|
|
40
|
+
def pdf(self, x, s, loc=0, scale=1):
|
|
41
|
+
"""Evaluate the probability density function.
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
x : array_like
|
|
46
|
+
Points at which to evaluate the density.
|
|
47
|
+
s : float
|
|
48
|
+
Shape parameter of the distribution.
|
|
49
|
+
loc : float, optional
|
|
50
|
+
Location parameter. Defaults to ``0``.
|
|
51
|
+
scale : float, optional
|
|
52
|
+
Scale parameter. Defaults to ``1``.
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
FlopscopeArray
|
|
57
|
+
Probability density evaluated elementwise at ``x``.
|
|
58
|
+
|
|
59
|
+
Notes
|
|
60
|
+
-----
|
|
61
|
+
Equivalent to ``scipy.stats.lognorm.pdf(x, s, loc, scale)``.
|
|
62
|
+
FLOP cost: ``1 * numel(x)``.
|
|
63
|
+
|
|
64
|
+
Examples
|
|
65
|
+
--------
|
|
66
|
+
>>> import numpy as np
|
|
67
|
+
>>> import flopscope as flops
|
|
68
|
+
>>> x = np.array([0.5, 1.0, 2.0])
|
|
69
|
+
>>> np.round(flops.stats.lognorm.pdf(x, s=0.5), 3)
|
|
70
|
+
array([0.61 , 0.798, 0.153])
|
|
71
|
+
"""
|
|
72
|
+
return self._deduct_and_call("pdf", 1, x, s, loc=loc, scale=scale)
|
|
73
|
+
|
|
74
|
+
def cdf(self, x, s, loc=0, scale=1):
|
|
75
|
+
"""Evaluate the cumulative distribution function.
|
|
76
|
+
|
|
77
|
+
Parameters
|
|
78
|
+
----------
|
|
79
|
+
x : array_like
|
|
80
|
+
Points at which to evaluate the cumulative probability.
|
|
81
|
+
s : float
|
|
82
|
+
Shape parameter of the distribution.
|
|
83
|
+
loc : float, optional
|
|
84
|
+
Location parameter. Defaults to ``0``.
|
|
85
|
+
scale : float, optional
|
|
86
|
+
Scale parameter. Defaults to ``1``.
|
|
87
|
+
|
|
88
|
+
Returns
|
|
89
|
+
-------
|
|
90
|
+
FlopscopeArray
|
|
91
|
+
Cumulative probability evaluated elementwise at ``x``.
|
|
92
|
+
|
|
93
|
+
Notes
|
|
94
|
+
-----
|
|
95
|
+
Equivalent to ``scipy.stats.lognorm.cdf(x, s, loc, scale)``.
|
|
96
|
+
FLOP cost: ``1 * numel(x)``.
|
|
97
|
+
|
|
98
|
+
Examples
|
|
99
|
+
--------
|
|
100
|
+
>>> import numpy as np
|
|
101
|
+
>>> import flopscope as flops
|
|
102
|
+
>>> x = np.array([0.5, 1.0, 2.0])
|
|
103
|
+
>>> np.round(flops.stats.lognorm.cdf(x, s=0.5), 3)
|
|
104
|
+
array([0.083, 0.5 , 0.917])
|
|
105
|
+
"""
|
|
106
|
+
return self._deduct_and_call("cdf", 1, x, s, loc=loc, scale=scale)
|
|
107
|
+
|
|
108
|
+
def ppf(self, q, s, loc=0, scale=1):
|
|
109
|
+
"""Evaluate the percent-point function.
|
|
110
|
+
|
|
111
|
+
Parameters
|
|
112
|
+
----------
|
|
113
|
+
q : array_like
|
|
114
|
+
Probabilities in ``[0, 1]``.
|
|
115
|
+
s : float
|
|
116
|
+
Shape parameter of the distribution.
|
|
117
|
+
loc : float, optional
|
|
118
|
+
Location parameter. Defaults to ``0``.
|
|
119
|
+
scale : float, optional
|
|
120
|
+
Scale parameter. Defaults to ``1``.
|
|
121
|
+
|
|
122
|
+
Returns
|
|
123
|
+
-------
|
|
124
|
+
FlopscopeArray
|
|
125
|
+
Quantiles corresponding to ``q``.
|
|
126
|
+
|
|
127
|
+
Notes
|
|
128
|
+
-----
|
|
129
|
+
Equivalent to ``scipy.stats.lognorm.ppf(q, s, loc, scale)``.
|
|
130
|
+
FLOP cost: ``1 * numel(q)``.
|
|
131
|
+
|
|
132
|
+
Examples
|
|
133
|
+
--------
|
|
134
|
+
>>> import numpy as np
|
|
135
|
+
>>> import flopscope as flops
|
|
136
|
+
>>> q = np.array([0.25, 0.5, 0.75])
|
|
137
|
+
>>> np.round(flops.stats.lognorm.ppf(q, s=0.5), 3)
|
|
138
|
+
array([0.714, 1. , 1.401])
|
|
139
|
+
"""
|
|
140
|
+
return self._deduct_and_call("ppf", 1, q, s, loc=loc, scale=scale)
|
|
141
|
+
|
|
142
|
+
def _compute_pdf(self, x, s, loc=0, scale=1):
|
|
143
|
+
y = (x - loc) / scale
|
|
144
|
+
safe_y = _np.where(y > 0, y, 1.0) # avoid log(0)
|
|
145
|
+
lny = _np.log(safe_y)
|
|
146
|
+
result = _INV_SQRT_2PI / (s * safe_y * scale) * _np.exp(-0.5 * (lny / s) ** 2)
|
|
147
|
+
return _np.where(y > 0, result, 0.0)
|
|
148
|
+
|
|
149
|
+
def _compute_cdf(self, x, s, loc=0, scale=1):
|
|
150
|
+
y = (x - loc) / scale
|
|
151
|
+
safe_y = _np.where(y > 0, y, 1.0)
|
|
152
|
+
z = _np.log(safe_y) / (s * _SQRT2)
|
|
153
|
+
result = 0.5 * (1.0 + _erf(z))
|
|
154
|
+
return _np.where(y > 0, result, 0.0)
|
|
155
|
+
|
|
156
|
+
def _compute_ppf(self, q, s, loc=0, scale=1):
|
|
157
|
+
return loc + scale * _np.exp(s * _ndtri(q))
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
lognorm = LognormDistribution()
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""Inverse standard normal CDF (ndtri) via Acklam's algorithm + Newton refinement.
|
|
2
|
+
|
|
3
|
+
Accuracy: ~1e-12 against scipy.special.ndtri.
|
|
4
|
+
|
|
5
|
+
References
|
|
6
|
+
----------
|
|
7
|
+
.. [1] Peter J. Acklam, "An algorithm for computing the inverse normal
|
|
8
|
+
cumulative distribution function," 2004.
|
|
9
|
+
https://web.archive.org/web/20151030215612/http://home.online.no/~pjacklam/notes/invnorm/
|
|
10
|
+
(Rational approximation coefficients; algorithm made freely available by the author.)
|
|
11
|
+
|
|
12
|
+
.. [2] StackedBoxes, "Acklam's Normal Quantile Function," 2017.
|
|
13
|
+
https://stackedboxes.org/2017/05/01/acklams-normal-quantile-function/
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
from flopscope.stats._erf import _erf
|
|
21
|
+
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
# Acklam coefficients
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
_A = (
|
|
27
|
+
-3.969683028665376e01,
|
|
28
|
+
2.209460984245205e02,
|
|
29
|
+
-2.759285104469687e02,
|
|
30
|
+
1.383577518672690e02,
|
|
31
|
+
-3.066479806614716e01,
|
|
32
|
+
2.506628277459239e00,
|
|
33
|
+
)
|
|
34
|
+
_B = (
|
|
35
|
+
-5.447609879822406e01,
|
|
36
|
+
1.615858368580409e02,
|
|
37
|
+
-1.556989798598866e02,
|
|
38
|
+
6.680131188771972e01,
|
|
39
|
+
-1.328068155288572e01,
|
|
40
|
+
)
|
|
41
|
+
_C = (
|
|
42
|
+
-7.784894002430293e-03,
|
|
43
|
+
-3.223964580411365e-01,
|
|
44
|
+
-2.400758277161838e00,
|
|
45
|
+
-2.549732539343734e00,
|
|
46
|
+
4.374664141464968e00,
|
|
47
|
+
2.938163982698783e00,
|
|
48
|
+
)
|
|
49
|
+
_D = (
|
|
50
|
+
7.784695709041462e-03,
|
|
51
|
+
3.224671290700398e-01,
|
|
52
|
+
2.445134137142996e00,
|
|
53
|
+
3.754408661907416e00,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
_P_LOW = 0.02425
|
|
57
|
+
_P_HIGH = 1.0 - _P_LOW
|
|
58
|
+
|
|
59
|
+
_SQRT2 = np.sqrt(2.0)
|
|
60
|
+
_INV_SQRT_2PI = 1.0 / np.sqrt(2.0 * np.pi)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _norm_pdf_internal(x):
|
|
64
|
+
"""Standard normal PDF (internal helper, no budget deduction)."""
|
|
65
|
+
return _INV_SQRT_2PI * np.exp(-0.5 * x * x)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _norm_cdf_internal(x):
|
|
69
|
+
"""Standard normal CDF (internal helper, no budget deduction)."""
|
|
70
|
+
return 0.5 * (1.0 + _erf(x / _SQRT2))
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _ndtri(p):
|
|
74
|
+
"""Inverse standard normal CDF.
|
|
75
|
+
|
|
76
|
+
Maps probability *p* in (0, 1) to the quantile *x* such that
|
|
77
|
+
Phi(x) = p, where Phi is the standard normal CDF.
|
|
78
|
+
|
|
79
|
+
Uses Acklam's rational approximation [1]_ with one Newton-Raphson
|
|
80
|
+
refinement step for ~1e-12 accuracy.
|
|
81
|
+
|
|
82
|
+
Edge cases: p=0 -> -inf, p=1 -> +inf, p<0 or p>1 -> nan.
|
|
83
|
+
"""
|
|
84
|
+
p = np.asarray(p, dtype=np.float64)
|
|
85
|
+
scalar = p.ndim == 0
|
|
86
|
+
p = np.atleast_1d(p)
|
|
87
|
+
|
|
88
|
+
out = np.empty_like(p)
|
|
89
|
+
|
|
90
|
+
# Edge cases
|
|
91
|
+
out[p == 0.0] = -np.inf
|
|
92
|
+
out[p == 1.0] = np.inf
|
|
93
|
+
out[(p < 0.0) | (p > 1.0)] = np.nan
|
|
94
|
+
|
|
95
|
+
# Lower region: 0 < p < P_LOW
|
|
96
|
+
m_low = (p > 0.0) & (p < _P_LOW)
|
|
97
|
+
if np.any(m_low):
|
|
98
|
+
q = np.sqrt(-2.0 * np.log(p[m_low]))
|
|
99
|
+
num = ((((_C[0] * q + _C[1]) * q + _C[2]) * q + _C[3]) * q + _C[4]) * q + _C[5]
|
|
100
|
+
den = (((_D[0] * q + _D[1]) * q + _D[2]) * q + _D[3]) * q + 1.0
|
|
101
|
+
out[m_low] = num / den
|
|
102
|
+
|
|
103
|
+
# Central region: P_LOW <= p <= P_HIGH
|
|
104
|
+
m_mid = (p >= _P_LOW) & (p <= _P_HIGH)
|
|
105
|
+
if np.any(m_mid):
|
|
106
|
+
q = p[m_mid] - 0.5
|
|
107
|
+
r = q * q
|
|
108
|
+
num = ((((_A[0] * r + _A[1]) * r + _A[2]) * r + _A[3]) * r + _A[4]) * r + _A[5]
|
|
109
|
+
den = ((((_B[0] * r + _B[1]) * r + _B[2]) * r + _B[3]) * r + _B[4]) * r + 1.0
|
|
110
|
+
out[m_mid] = q * num / den
|
|
111
|
+
|
|
112
|
+
# Upper region: P_HIGH < p < 1
|
|
113
|
+
m_high = (p > _P_HIGH) & (p < 1.0)
|
|
114
|
+
if np.any(m_high):
|
|
115
|
+
q = np.sqrt(-2.0 * np.log(1.0 - p[m_high]))
|
|
116
|
+
num = ((((_C[0] * q + _C[1]) * q + _C[2]) * q + _C[3]) * q + _C[4]) * q + _C[5]
|
|
117
|
+
den = (((_D[0] * q + _D[1]) * q + _D[2]) * q + _D[3]) * q + 1.0
|
|
118
|
+
out[m_high] = -(num / den)
|
|
119
|
+
|
|
120
|
+
# Newton refinement (one step) for the interior
|
|
121
|
+
m_interior = (p > 0.0) & (p < 1.0)
|
|
122
|
+
if np.any(m_interior):
|
|
123
|
+
x0 = out[m_interior]
|
|
124
|
+
phi = _norm_cdf_internal(x0)
|
|
125
|
+
pdf = _norm_pdf_internal(x0)
|
|
126
|
+
# Avoid division by zero in pdf
|
|
127
|
+
safe = pdf > 1e-300
|
|
128
|
+
correction = np.where(safe, (phi - p[m_interior]) / pdf, 0.0)
|
|
129
|
+
out[m_interior] = x0 - correction
|
|
130
|
+
|
|
131
|
+
if scalar:
|
|
132
|
+
return float(out[0])
|
|
133
|
+
return out
|
flopscope/stats/_norm.py
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""Normal distribution for :mod:`flopscope.stats`."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from flopscope.stats._base import ContinuousDistribution
|
|
8
|
+
from flopscope.stats._erf import _erf
|
|
9
|
+
from flopscope.stats._ndtri import _ndtri
|
|
10
|
+
|
|
11
|
+
_SQRT2 = np.sqrt(2.0)
|
|
12
|
+
_INV_SQRT_2PI = 1.0 / np.sqrt(2.0 * np.pi)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class NormDistribution(ContinuousDistribution):
|
|
16
|
+
"""Normal (Gaussian) continuous random variable.
|
|
17
|
+
|
|
18
|
+
This object mirrors ``scipy.stats.norm`` and uses the standard
|
|
19
|
+
``loc``/``scale`` parameterization.
|
|
20
|
+
|
|
21
|
+
Methods
|
|
22
|
+
-------
|
|
23
|
+
pdf(x, loc=0, scale=1)
|
|
24
|
+
Evaluate the probability density function.
|
|
25
|
+
cdf(x, loc=0, scale=1)
|
|
26
|
+
Evaluate the cumulative distribution function.
|
|
27
|
+
ppf(q, loc=0, scale=1)
|
|
28
|
+
Evaluate the percent-point function.
|
|
29
|
+
|
|
30
|
+
Notes
|
|
31
|
+
-----
|
|
32
|
+
``loc`` is the mean and ``scale`` is the standard deviation. Each public
|
|
33
|
+
method deducts ``1 * numel(input)`` FLOPs from the active budget.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self):
|
|
37
|
+
super().__init__("norm")
|
|
38
|
+
|
|
39
|
+
def pdf(self, x, loc=0, scale=1):
|
|
40
|
+
"""Evaluate the probability density function.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
x : array_like
|
|
45
|
+
Points at which to evaluate the density.
|
|
46
|
+
loc : float, optional
|
|
47
|
+
Mean of the distribution. Defaults to ``0``.
|
|
48
|
+
scale : float, optional
|
|
49
|
+
Standard deviation of the distribution. Defaults to ``1``.
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
FlopscopeArray
|
|
54
|
+
Probability density evaluated elementwise at ``x``.
|
|
55
|
+
|
|
56
|
+
Notes
|
|
57
|
+
-----
|
|
58
|
+
Equivalent to ``scipy.stats.norm.pdf(x, loc, scale)``.
|
|
59
|
+
FLOP cost: ``1 * numel(x)``.
|
|
60
|
+
|
|
61
|
+
Examples
|
|
62
|
+
--------
|
|
63
|
+
>>> import numpy as np
|
|
64
|
+
>>> import flopscope as flops
|
|
65
|
+
>>> x = np.array([-1.0, 0.0, 1.0])
|
|
66
|
+
>>> np.round(flops.stats.norm.pdf(x), 3)
|
|
67
|
+
array([0.242, 0.399, 0.242])
|
|
68
|
+
"""
|
|
69
|
+
return self._deduct_and_call("pdf", 1, x, loc=loc, scale=scale)
|
|
70
|
+
|
|
71
|
+
def cdf(self, x, loc=0, scale=1):
|
|
72
|
+
"""Evaluate the cumulative distribution function.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
x : array_like
|
|
77
|
+
Points at which to evaluate the cumulative probability.
|
|
78
|
+
loc : float, optional
|
|
79
|
+
Mean of the distribution. Defaults to ``0``.
|
|
80
|
+
scale : float, optional
|
|
81
|
+
Standard deviation of the distribution. Defaults to ``1``.
|
|
82
|
+
|
|
83
|
+
Returns
|
|
84
|
+
-------
|
|
85
|
+
FlopscopeArray
|
|
86
|
+
Cumulative probability evaluated elementwise at ``x``.
|
|
87
|
+
|
|
88
|
+
Notes
|
|
89
|
+
-----
|
|
90
|
+
Equivalent to ``scipy.stats.norm.cdf(x, loc, scale)``.
|
|
91
|
+
FLOP cost: ``1 * numel(x)``.
|
|
92
|
+
|
|
93
|
+
Examples
|
|
94
|
+
--------
|
|
95
|
+
>>> import numpy as np
|
|
96
|
+
>>> import flopscope as flops
|
|
97
|
+
>>> x = np.array([-1.0, 0.0, 1.0])
|
|
98
|
+
>>> np.round(flops.stats.norm.cdf(x), 3)
|
|
99
|
+
array([0.159, 0.5 , 0.841])
|
|
100
|
+
"""
|
|
101
|
+
return self._deduct_and_call("cdf", 1, x, loc=loc, scale=scale)
|
|
102
|
+
|
|
103
|
+
def ppf(self, q, loc=0, scale=1):
|
|
104
|
+
"""Evaluate the percent-point function.
|
|
105
|
+
|
|
106
|
+
Parameters
|
|
107
|
+
----------
|
|
108
|
+
q : array_like
|
|
109
|
+
Probabilities in ``[0, 1]``.
|
|
110
|
+
loc : float, optional
|
|
111
|
+
Mean of the distribution. Defaults to ``0``.
|
|
112
|
+
scale : float, optional
|
|
113
|
+
Standard deviation of the distribution. Defaults to ``1``.
|
|
114
|
+
|
|
115
|
+
Returns
|
|
116
|
+
-------
|
|
117
|
+
FlopscopeArray
|
|
118
|
+
Quantiles corresponding to ``q``.
|
|
119
|
+
|
|
120
|
+
Notes
|
|
121
|
+
-----
|
|
122
|
+
Equivalent to ``scipy.stats.norm.ppf(q, loc, scale)``.
|
|
123
|
+
FLOP cost: ``1 * numel(q)``.
|
|
124
|
+
|
|
125
|
+
Examples
|
|
126
|
+
--------
|
|
127
|
+
>>> import numpy as np
|
|
128
|
+
>>> import flopscope as flops
|
|
129
|
+
>>> q = np.array([0.25, 0.5, 0.75])
|
|
130
|
+
>>> np.round(flops.stats.norm.ppf(q), 3)
|
|
131
|
+
array([-0.674, 0. , 0.674])
|
|
132
|
+
"""
|
|
133
|
+
return self._deduct_and_call("ppf", 1, q, loc=loc, scale=scale)
|
|
134
|
+
|
|
135
|
+
# --- Pure-NumPy implementations (no budget deduction) ---
|
|
136
|
+
|
|
137
|
+
def _compute_pdf(self, x, loc=0, scale=1):
|
|
138
|
+
z = (x - loc) / scale
|
|
139
|
+
return _INV_SQRT_2PI / scale * np.exp(-0.5 * z * z)
|
|
140
|
+
|
|
141
|
+
def _compute_cdf(self, x, loc=0, scale=1):
|
|
142
|
+
z = (x - loc) / (scale * _SQRT2)
|
|
143
|
+
return 0.5 * (1.0 + _erf(z))
|
|
144
|
+
|
|
145
|
+
def _compute_ppf(self, q, loc=0, scale=1):
|
|
146
|
+
return loc + scale * _ndtri(q)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
norm = NormDistribution()
|