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.
Files changed (115) hide show
  1. benchmarks/__init__.py +1 -0
  2. benchmarks/__main__.py +6 -0
  3. benchmarks/_baseline.py +171 -0
  4. benchmarks/_bitwise.py +231 -0
  5. benchmarks/_complex.py +176 -0
  6. benchmarks/_contractions.py +291 -0
  7. benchmarks/_fft.py +198 -0
  8. benchmarks/_impl_urls.py +139 -0
  9. benchmarks/_linalg.py +197 -0
  10. benchmarks/_linalg_delegates.py +407 -0
  11. benchmarks/_metadata.py +141 -0
  12. benchmarks/_misc.py +653 -0
  13. benchmarks/_perf.py +321 -0
  14. benchmarks/_perm_group_calibration.py +175 -0
  15. benchmarks/_pointwise.py +372 -0
  16. benchmarks/_polynomial.py +193 -0
  17. benchmarks/_random.py +209 -0
  18. benchmarks/_reductions.py +136 -0
  19. benchmarks/_sorting.py +289 -0
  20. benchmarks/_stats.py +137 -0
  21. benchmarks/_window.py +92 -0
  22. benchmarks/accumulation/__init__.py +0 -0
  23. benchmarks/accumulation/bench_cost_compute.py +138 -0
  24. benchmarks/dashboard.py +312 -0
  25. benchmarks/runner.py +636 -0
  26. flopscope/__init__.py +273 -0
  27. flopscope/_accumulation/__init__.py +13 -0
  28. flopscope/_accumulation/_bipartite.py +121 -0
  29. flopscope/_accumulation/_burnside.py +51 -0
  30. flopscope/_accumulation/_cache.py +146 -0
  31. flopscope/_accumulation/_components.py +153 -0
  32. flopscope/_accumulation/_cost.py +1414 -0
  33. flopscope/_accumulation/_cost_descriptions.py +63 -0
  34. flopscope/_accumulation/_detection.py +318 -0
  35. flopscope/_accumulation/_ladder.py +191 -0
  36. flopscope/_accumulation/_output_orbit.py +104 -0
  37. flopscope/_accumulation/_partition.py +290 -0
  38. flopscope/_accumulation/_path_info.py +211 -0
  39. flopscope/_accumulation/_public.py +169 -0
  40. flopscope/_accumulation/_reduction.py +310 -0
  41. flopscope/_accumulation/_regimes.py +303 -0
  42. flopscope/_accumulation/_shape.py +33 -0
  43. flopscope/_accumulation/_wreath.py +209 -0
  44. flopscope/_budget.py +1027 -0
  45. flopscope/_config.py +118 -0
  46. flopscope/_counting_ops.py +451 -0
  47. flopscope/_display.py +478 -0
  48. flopscope/_docstrings.py +59 -0
  49. flopscope/_dtypes.py +20 -0
  50. flopscope/_einsum.py +717 -0
  51. flopscope/_errstate.py +25 -0
  52. flopscope/_flops.py +282 -0
  53. flopscope/_free_ops.py +2654 -0
  54. flopscope/_ndarray.py +1126 -0
  55. flopscope/_opt_einsum/LICENSE +21 -0
  56. flopscope/_opt_einsum/NOTICE +59 -0
  57. flopscope/_opt_einsum/__init__.py +209 -0
  58. flopscope/_opt_einsum/_contract.py +1478 -0
  59. flopscope/_opt_einsum/_helpers.py +164 -0
  60. flopscope/_opt_einsum/_hsluv.py +273 -0
  61. flopscope/_opt_einsum/_path_random.py +462 -0
  62. flopscope/_opt_einsum/_paths.py +1653 -0
  63. flopscope/_opt_einsum/_subgraph_symmetry.py +544 -0
  64. flopscope/_opt_einsum/_symmetry.py +140 -0
  65. flopscope/_opt_einsum/_typing.py +37 -0
  66. flopscope/_perm_group.py +717 -0
  67. flopscope/_pointwise.py +2522 -0
  68. flopscope/_polynomial.py +278 -0
  69. flopscope/_registry.py +3216 -0
  70. flopscope/_sorting_ops.py +571 -0
  71. flopscope/_symmetric.py +812 -0
  72. flopscope/_symmetry_transport.py +510 -0
  73. flopscope/_symmetry_utils.py +669 -0
  74. flopscope/_type_info.py +12 -0
  75. flopscope/_unwrap.py +70 -0
  76. flopscope/_validation.py +83 -0
  77. flopscope/_version_check.py +46 -0
  78. flopscope/_weights.py +195 -0
  79. flopscope/_window.py +177 -0
  80. flopscope/accounting.py +565 -0
  81. flopscope/data/default_weights.json +462 -0
  82. flopscope/data/weights.csv +509 -0
  83. flopscope/errors.py +197 -0
  84. flopscope/numpy/__init__.py +878 -0
  85. flopscope/numpy/fft/__init__.py +55 -0
  86. flopscope/numpy/fft/_free.py +51 -0
  87. flopscope/numpy/fft/_transforms.py +695 -0
  88. flopscope/numpy/linalg/__init__.py +105 -0
  89. flopscope/numpy/linalg/_aliases.py +126 -0
  90. flopscope/numpy/linalg/_compound.py +161 -0
  91. flopscope/numpy/linalg/_decompositions.py +353 -0
  92. flopscope/numpy/linalg/_properties.py +533 -0
  93. flopscope/numpy/linalg/_solvers.py +444 -0
  94. flopscope/numpy/linalg/_svd.py +122 -0
  95. flopscope/numpy/random/__init__.py +684 -0
  96. flopscope/numpy/random/_cost_formulas.py +115 -0
  97. flopscope/numpy/random/_counted_classes.py +241 -0
  98. flopscope/numpy/testing/__init__.py +13 -0
  99. flopscope/numpy/typing/__init__.py +30 -0
  100. flopscope/py.typed +0 -0
  101. flopscope/stats/__init__.py +84 -0
  102. flopscope/stats/_base.py +77 -0
  103. flopscope/stats/_cauchy.py +146 -0
  104. flopscope/stats/_erf.py +190 -0
  105. flopscope/stats/_expon.py +146 -0
  106. flopscope/stats/_laplace.py +150 -0
  107. flopscope/stats/_logistic.py +148 -0
  108. flopscope/stats/_lognorm.py +160 -0
  109. flopscope/stats/_ndtri.py +133 -0
  110. flopscope/stats/_norm.py +149 -0
  111. flopscope/stats/_truncnorm.py +186 -0
  112. flopscope/stats/_uniform.py +141 -0
  113. flopscope-0.2.0.dist-info/METADATA +23 -0
  114. flopscope-0.2.0.dist-info/RECORD +115 -0
  115. flopscope-0.2.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,146 @@
1
+ """Cauchy 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 CauchyDistribution(ContinuousDistribution):
11
+ """Cauchy (Lorentz) continuous random variable.
12
+
13
+ This object mirrors ``scipy.stats.cauchy``.
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 location parameter and ``scale`` is the half-width at
27
+ half-maximum. Each public method deducts ``1 * numel(input)`` FLOPs from
28
+ the active budget.
29
+ """
30
+
31
+ def __init__(self):
32
+ super().__init__("cauchy")
33
+
34
+ def pdf(self, x, loc=0, scale=1):
35
+ """Evaluate the probability density function.
36
+
37
+ Parameters
38
+ ----------
39
+ x : array_like
40
+ Points at which to evaluate the density.
41
+ loc : float, optional
42
+ Location parameter of the distribution. Defaults to ``0``.
43
+ scale : float, optional
44
+ Scale parameter of the distribution. Defaults to ``1``.
45
+
46
+ Returns
47
+ -------
48
+ FlopscopeArray
49
+ Probability density evaluated elementwise at ``x``.
50
+
51
+ Notes
52
+ -----
53
+ Equivalent to ``scipy.stats.cauchy.pdf(x, loc, scale)``.
54
+ FLOP cost: ``1 * numel(x)``.
55
+
56
+ Examples
57
+ --------
58
+ >>> import numpy as np
59
+ >>> import flopscope as flops
60
+ >>> x = np.array([-1.0, 0.0, 1.0])
61
+ >>> np.round(flops.stats.cauchy.pdf(x), 3)
62
+ array([0.159, 0.318, 0.159])
63
+ """
64
+ return self._deduct_and_call("pdf", 1, x, loc=loc, scale=scale)
65
+
66
+ def cdf(self, x, loc=0, scale=1):
67
+ """Evaluate the cumulative distribution function.
68
+
69
+ Parameters
70
+ ----------
71
+ x : array_like
72
+ Points at which to evaluate the cumulative probability.
73
+ loc : float, optional
74
+ Location parameter of the distribution. Defaults to ``0``.
75
+ scale : float, optional
76
+ Scale parameter of the distribution. Defaults to ``1``.
77
+
78
+ Returns
79
+ -------
80
+ FlopscopeArray
81
+ Cumulative probability evaluated elementwise at ``x``.
82
+
83
+ Notes
84
+ -----
85
+ Equivalent to ``scipy.stats.cauchy.cdf(x, loc, scale)``.
86
+ FLOP cost: ``1 * numel(x)``.
87
+
88
+ Examples
89
+ --------
90
+ >>> import numpy as np
91
+ >>> import flopscope as flops
92
+ >>> x = np.array([-1.0, 0.0, 1.0])
93
+ >>> np.round(flops.stats.cauchy.cdf(x), 3)
94
+ array([0.25, 0.5 , 0.75])
95
+ """
96
+ return self._deduct_and_call("cdf", 1, x, loc=loc, scale=scale)
97
+
98
+ def ppf(self, q, loc=0, scale=1):
99
+ """Evaluate the percent-point function.
100
+
101
+ Parameters
102
+ ----------
103
+ q : array_like
104
+ Probabilities in ``[0, 1]``.
105
+ loc : float, optional
106
+ Location parameter of the distribution. Defaults to ``0``.
107
+ scale : float, optional
108
+ Scale parameter of the distribution. Defaults to ``1``.
109
+
110
+ Returns
111
+ -------
112
+ FlopscopeArray
113
+ Quantiles corresponding to ``q``.
114
+
115
+ Notes
116
+ -----
117
+ Equivalent to ``scipy.stats.cauchy.ppf(q, loc, scale)``.
118
+ FLOP cost: ``1 * numel(q)``.
119
+
120
+ Examples
121
+ --------
122
+ >>> import numpy as np
123
+ >>> import flopscope as flops
124
+ >>> q = np.array([0.25, 0.5, 0.75])
125
+ >>> np.round(flops.stats.cauchy.ppf(q), 3)
126
+ array([-1., 0., 1.])
127
+ """
128
+ return self._deduct_and_call("ppf", 1, q, loc=loc, scale=scale)
129
+
130
+ def _compute_pdf(self, x, loc=0, scale=1):
131
+ z = (x - loc) / scale
132
+ return 1.0 / (_np.pi * scale * (1.0 + z * z))
133
+
134
+ def _compute_cdf(self, x, loc=0, scale=1):
135
+ z = (x - loc) / scale
136
+ return 0.5 + _np.arctan(z) / _np.pi
137
+
138
+ def _compute_ppf(self, q, loc=0, scale=1):
139
+ result = loc + scale * _np.tan(_np.pi * (q - 0.5))
140
+ result = _np.where((q > 0) & (q < 1), result, _np.nan)
141
+ result = _np.where(q == 0, -_np.inf, result)
142
+ result = _np.where(q == 1, _np.inf, result)
143
+ return result
144
+
145
+
146
+ cauchy = CauchyDistribution()
@@ -0,0 +1,190 @@
1
+ """Vectorized error function using the fdlibm/Sun rational approximation.
2
+
3
+ Uses the same algorithm and coefficients as the C99 math.erf / glibc / fdlibm
4
+ ``s_erf.c`` implementation, which is the gold-standard for double-precision erf.
5
+
6
+ Four regions:
7
+ |x| < 0.84375 : erf(x) = x + x*P(x^2)/Q(x^2)
8
+ 0.84375<=|x|<1.25 : erf(x) = erx + P(|x|-1)/Q(|x|-1)
9
+ 1.25 <= |x| < ~6 : erfc(x) = exp(-x^2-0.5625+R(1/x^2)/S(1/x^2)) / |x|
10
+ |x| >= 6 : erf(x) = sign(x) * 1.0
11
+
12
+ Accuracy: matches C99 math.erf / scipy.special.erf to ~1 ULP.
13
+
14
+ References
15
+ ----------
16
+ .. [1] Sun Microsystems, "Freely Distributable LIBM (fdlibm) s_erf.c",
17
+ https://www.netlib.org/fdlibm/s_erf.c
18
+ Algorithm and coefficients by Sun Microsystems (see copyright below).
19
+
20
+ .. [2] glibc implementation (derived from fdlibm):
21
+ https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/ieee754/dbl-64/s_erf.c
22
+
23
+ Copyright (original fdlibm source)
24
+ -----------------------------------
25
+ Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
26
+ Developed at SunSoft, a Sun Microsystems, Inc. business.
27
+ Permission to use, copy, modify, and distribute this software is freely
28
+ granted, provided that this notice is preserved.
29
+ """
30
+
31
+ from __future__ import annotations
32
+
33
+ import numpy as np
34
+
35
+ # ---------------------------------------------------------------------------
36
+ # Coefficients from fdlibm s_erf.c (Sun / glibc / OpenBSD)
37
+ # ---------------------------------------------------------------------------
38
+
39
+ # erx = erf(1) to extended precision
40
+ _erx = 8.45062911510467529297e-01
41
+
42
+ # Region 1: |x| < 0.84375 -- erf(x) = x + x * pp(x^2)/qq(x^2)
43
+ _pp0 = 1.28379167095512558561e-01
44
+ _pp1 = -3.25042107247001499370e-01
45
+ _pp2 = -2.84817495755985104766e-02
46
+ _pp3 = -5.77027029648944159157e-03
47
+ _pp4 = -2.37630166566501626084e-05
48
+
49
+ _qq1 = 3.97917223959155352819e-01
50
+ _qq2 = 6.50222499887672944485e-02
51
+ _qq3 = 5.08130628187576562776e-03
52
+ _qq4 = 1.32494738004321644526e-04
53
+ _qq5 = -3.96022827877536812320e-06
54
+
55
+ # Region 2: 0.84375 <= |x| < 1.25 -- erf(x) = erx + P(s)/Q(s), s = |x| - 1
56
+ _pa0 = -2.36211856075265944077e-03
57
+ _pa1 = 4.14856118683748331666e-01
58
+ _pa2 = -3.72207876035701323847e-01
59
+ _pa3 = 3.18346619901161753674e-01
60
+ _pa4 = -1.10894694282396677476e-01
61
+ _pa5 = 3.54783043195201877747e-02
62
+ _pa6 = -2.16637559983254089680e-03
63
+
64
+ _qa1 = 1.06420880400844228286e-01
65
+ _qa2 = 5.40397917702171048937e-01
66
+ _qa3 = 7.18286544141962539399e-02
67
+ _qa4 = 1.26171219808761642112e-01
68
+ _qa5 = 1.36370839120290507362e-02
69
+ _qa6 = 1.19844998467991074170e-02
70
+
71
+ # Region 3a: 1.25 <= |x| < 1/0.35 (~2.857)
72
+ _ra0 = -9.86494403484714822705e-03
73
+ _ra1 = -6.93858572707181764372e-01
74
+ _ra2 = -1.05586262253232909814e01
75
+ _ra3 = -6.23753324503260060396e01
76
+ _ra4 = -1.62396669462573071767e02
77
+ _ra5 = -1.84605092906711035994e02
78
+ _ra6 = -8.12874355063065934246e01
79
+ _ra7 = -9.81432934416914548592e00
80
+
81
+ _sa1 = 1.96512716674392571292e01
82
+ _sa2 = 1.37657754143519702237e02
83
+ _sa3 = 4.34565877475229228608e02
84
+ _sa4 = 6.45387271733267880594e02
85
+ _sa5 = 4.29008140027567833386e02
86
+ _sa6 = 1.08635005541779435134e02
87
+ _sa7 = 6.57024977031928170135e00
88
+ _sa8 = -6.04244152148580987438e-02
89
+
90
+ # Region 3b: 1/0.35 (~2.857) <= |x| < 6
91
+ _rb0 = -9.86494292470009928597e-03
92
+ _rb1 = -7.99283237680523006574e-01
93
+ _rb2 = -1.77579549177547519889e01
94
+ _rb3 = -1.60636384855557935030e02
95
+ _rb4 = -6.37566443368389085394e02
96
+ _rb5 = -1.02509513161107724954e03
97
+ _rb6 = -4.83519191608651397019e02
98
+
99
+ _sb1 = 3.03380607875625778203e01
100
+ _sb2 = 3.25792512996573918826e02
101
+ _sb3 = 1.53672958608443695994e03
102
+ _sb4 = 3.19985821950859553908e03
103
+ _sb5 = 2.55305040643316442583e03
104
+ _sb6 = 4.74528541206955367215e02
105
+ _sb7 = -2.24409524465858183362e01
106
+
107
+
108
+ def _erf(x):
109
+ """Vectorized error function matching scipy.special.erf to ~1 ULP.
110
+
111
+ Algorithm and coefficients from fdlibm ``s_erf.c`` [1]_.
112
+ """
113
+ x = np.asarray(x, dtype=np.float64)
114
+ scalar = x.ndim == 0
115
+ x = np.atleast_1d(x)
116
+
117
+ out = np.empty_like(x)
118
+ ax = np.abs(x)
119
+ sign = np.sign(x)
120
+
121
+ # --- Region 1: |x| < 0.84375 ---
122
+ m1 = ax < 0.84375
123
+ if np.any(m1):
124
+ xm = x[m1]
125
+ s = xm * xm
126
+ r = _pp0 + s * (_pp1 + s * (_pp2 + s * (_pp3 + s * _pp4)))
127
+ S = 1.0 + s * (_qq1 + s * (_qq2 + s * (_qq3 + s * (_qq4 + s * _qq5))))
128
+ out[m1] = xm + xm * (r / S)
129
+
130
+ # --- Region 2: 0.84375 <= |x| < 1.25 ---
131
+ m2 = (ax >= 0.84375) & (ax < 1.25)
132
+ if np.any(m2):
133
+ s = ax[m2] - 1.0
134
+ P = _pa0 + s * (
135
+ _pa1 + s * (_pa2 + s * (_pa3 + s * (_pa4 + s * (_pa5 + s * _pa6))))
136
+ )
137
+ Q = 1.0 + s * (
138
+ _qa1 + s * (_qa2 + s * (_qa3 + s * (_qa4 + s * (_qa5 + s * _qa6))))
139
+ )
140
+ out[m2] = sign[m2] * (_erx + P / Q)
141
+
142
+ # --- Region 3a: 1.25 <= |x| < 1/0.35 (~2.857) ---
143
+ m3a = (ax >= 1.25) & (ax < (1.0 / 0.35))
144
+ if np.any(m3a):
145
+ axm = ax[m3a]
146
+ s = 1.0 / (axm * axm)
147
+ R = _ra0 + s * (
148
+ _ra1
149
+ + s * (_ra2 + s * (_ra3 + s * (_ra4 + s * (_ra5 + s * (_ra6 + s * _ra7)))))
150
+ )
151
+ S = 1.0 + s * (
152
+ _sa1
153
+ + s
154
+ * (
155
+ _sa2
156
+ + s
157
+ * (_sa3 + s * (_sa4 + s * (_sa5 + s * (_sa6 + s * (_sa7 + s * _sa8)))))
158
+ )
159
+ )
160
+ erfc_val = np.exp(-axm * axm - 0.5625 + R / S) / axm
161
+ out[m3a] = sign[m3a] * (1.0 - erfc_val)
162
+
163
+ # --- Region 3b: 1/0.35 <= |x| < 6 ---
164
+ m3b = (ax >= (1.0 / 0.35)) & (ax < 6.0)
165
+ if np.any(m3b):
166
+ axm = ax[m3b]
167
+ s = 1.0 / (axm * axm)
168
+ R = _rb0 + s * (
169
+ _rb1 + s * (_rb2 + s * (_rb3 + s * (_rb4 + s * (_rb5 + s * _rb6))))
170
+ )
171
+ S = 1.0 + s * (
172
+ _sb1
173
+ + s * (_sb2 + s * (_sb3 + s * (_sb4 + s * (_sb5 + s * (_sb6 + s * _sb7)))))
174
+ )
175
+ erfc_val = np.exp(-axm * axm - 0.5625 + R / S) / axm
176
+ out[m3b] = sign[m3b] * (1.0 - erfc_val)
177
+
178
+ # --- Region 4: |x| >= 6 ---
179
+ m4 = ax >= 6.0
180
+ if np.any(m4):
181
+ out[m4] = sign[m4] * 1.0
182
+
183
+ if scalar:
184
+ return float(out[0])
185
+ return out
186
+
187
+
188
+ def _erfc(x):
189
+ """Vectorized complementary error function: erfc(x) = 1 - erf(x)."""
190
+ return 1.0 - _erf(x)
@@ -0,0 +1,146 @@
1
+ """Exponential 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 ExponDistribution(ContinuousDistribution):
11
+ """Exponential continuous random variable.
12
+
13
+ This object mirrors ``scipy.stats.expon``.
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`` shifts the origin and ``scale`` is the reciprocal of the rate.
27
+ Each public method deducts ``1 * numel(input)`` FLOPs from the active
28
+ budget.
29
+ """
30
+
31
+ def __init__(self):
32
+ super().__init__("expon")
33
+
34
+ def pdf(self, x, loc=0, scale=1):
35
+ """Evaluate the probability density function.
36
+
37
+ Parameters
38
+ ----------
39
+ x : array_like
40
+ Points at which to evaluate the density.
41
+ loc : float, optional
42
+ Location parameter that shifts the support. Defaults to ``0``.
43
+ scale : float, optional
44
+ Scale parameter of the distribution. Defaults to ``1``.
45
+
46
+ Returns
47
+ -------
48
+ FlopscopeArray
49
+ Probability density evaluated elementwise at ``x``.
50
+
51
+ Notes
52
+ -----
53
+ Equivalent to ``scipy.stats.expon.pdf(x, loc, scale)``.
54
+ FLOP cost: ``1 * numel(x)``.
55
+
56
+ Examples
57
+ --------
58
+ >>> import numpy as np
59
+ >>> import flopscope as flops
60
+ >>> x = np.array([0.0, 1.0, 2.0])
61
+ >>> np.round(flops.stats.expon.pdf(x), 3)
62
+ array([1. , 0.368, 0.135])
63
+ """
64
+ return self._deduct_and_call("pdf", 1, x, loc=loc, scale=scale)
65
+
66
+ def cdf(self, x, loc=0, scale=1):
67
+ """Evaluate the cumulative distribution function.
68
+
69
+ Parameters
70
+ ----------
71
+ x : array_like
72
+ Points at which to evaluate the cumulative probability.
73
+ loc : float, optional
74
+ Location parameter that shifts the support. Defaults to ``0``.
75
+ scale : float, optional
76
+ Scale parameter of the distribution. Defaults to ``1``.
77
+
78
+ Returns
79
+ -------
80
+ FlopscopeArray
81
+ Cumulative probability evaluated elementwise at ``x``.
82
+
83
+ Notes
84
+ -----
85
+ Equivalent to ``scipy.stats.expon.cdf(x, loc, scale)``.
86
+ FLOP cost: ``1 * numel(x)``.
87
+
88
+ Examples
89
+ --------
90
+ >>> import numpy as np
91
+ >>> import flopscope as flops
92
+ >>> x = np.array([0.0, 1.0, 2.0])
93
+ >>> np.round(flops.stats.expon.cdf(x), 3)
94
+ array([0. , 0.632, 0.865])
95
+ """
96
+ return self._deduct_and_call("cdf", 1, x, loc=loc, scale=scale)
97
+
98
+ def ppf(self, q, loc=0, scale=1):
99
+ """Evaluate the percent-point function.
100
+
101
+ Parameters
102
+ ----------
103
+ q : array_like
104
+ Probabilities in ``[0, 1]``.
105
+ loc : float, optional
106
+ Location parameter that shifts the support. Defaults to ``0``.
107
+ scale : float, optional
108
+ Scale parameter of the distribution. Defaults to ``1``.
109
+
110
+ Returns
111
+ -------
112
+ FlopscopeArray
113
+ Quantiles corresponding to ``q``.
114
+
115
+ Notes
116
+ -----
117
+ Equivalent to ``scipy.stats.expon.ppf(q, loc, scale)``.
118
+ FLOP cost: ``1 * numel(q)``.
119
+
120
+ Examples
121
+ --------
122
+ >>> import numpy as np
123
+ >>> import flopscope as flops
124
+ >>> q = np.array([0.25, 0.5, 0.75])
125
+ >>> np.round(flops.stats.expon.ppf(q), 3)
126
+ array([0.288, 0.693, 1.386])
127
+ """
128
+ return self._deduct_and_call("ppf", 1, q, loc=loc, scale=scale)
129
+
130
+ def _compute_pdf(self, x, loc=0, scale=1):
131
+ z = (x - loc) / scale
132
+ return _np.where(x >= loc, _np.exp(-z) / scale, 0.0)
133
+
134
+ def _compute_cdf(self, x, loc=0, scale=1):
135
+ z = (x - loc) / scale
136
+ return _np.where(x >= loc, 1.0 - _np.exp(-z), 0.0)
137
+
138
+ def _compute_ppf(self, q, loc=0, scale=1):
139
+ result = loc - scale * _np.log1p(-q)
140
+ result = _np.where((q >= 0) & (q <= 1), result, _np.nan)
141
+ result = _np.where(q == 0, loc, result)
142
+ result = _np.where(q == 1, _np.inf, result)
143
+ return result
144
+
145
+
146
+ expon = ExponDistribution()
@@ -0,0 +1,150 @@
1
+ """Laplace 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 LaplaceDistribution(ContinuousDistribution):
11
+ """Laplace (double-exponential) continuous random variable.
12
+
13
+ This object mirrors ``scipy.stats.laplace``.
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 and ``scale`` controls the exponential decay away
27
+ from that center. Each public method deducts ``1 * numel(input)`` FLOPs
28
+ from the active budget.
29
+ """
30
+
31
+ def __init__(self):
32
+ super().__init__("laplace")
33
+
34
+ def pdf(self, x, loc=0, scale=1):
35
+ """Evaluate the probability density function.
36
+
37
+ Parameters
38
+ ----------
39
+ x : array_like
40
+ Points at which to evaluate the density.
41
+ loc : float, optional
42
+ Location parameter of the distribution. Defaults to ``0``.
43
+ scale : float, optional
44
+ Scale parameter of the distribution. Defaults to ``1``.
45
+
46
+ Returns
47
+ -------
48
+ FlopscopeArray
49
+ Probability density evaluated elementwise at ``x``.
50
+
51
+ Notes
52
+ -----
53
+ Equivalent to ``scipy.stats.laplace.pdf(x, loc, scale)``.
54
+ FLOP cost: ``1 * numel(x)``.
55
+
56
+ Examples
57
+ --------
58
+ >>> import numpy as np
59
+ >>> import flopscope as flops
60
+ >>> x = np.array([-1.0, 0.0, 1.0])
61
+ >>> np.round(flops.stats.laplace.pdf(x), 3)
62
+ array([0.184, 0.5 , 0.184])
63
+ """
64
+ return self._deduct_and_call("pdf", 1, x, loc=loc, scale=scale)
65
+
66
+ def cdf(self, x, loc=0, scale=1):
67
+ """Evaluate the cumulative distribution function.
68
+
69
+ Parameters
70
+ ----------
71
+ x : array_like
72
+ Points at which to evaluate the cumulative probability.
73
+ loc : float, optional
74
+ Location parameter of the distribution. Defaults to ``0``.
75
+ scale : float, optional
76
+ Scale parameter of the distribution. Defaults to ``1``.
77
+
78
+ Returns
79
+ -------
80
+ FlopscopeArray
81
+ Cumulative probability evaluated elementwise at ``x``.
82
+
83
+ Notes
84
+ -----
85
+ Equivalent to ``scipy.stats.laplace.cdf(x, loc, scale)``.
86
+ FLOP cost: ``1 * numel(x)``.
87
+
88
+ Examples
89
+ --------
90
+ >>> import numpy as np
91
+ >>> import flopscope as flops
92
+ >>> x = np.array([-1.0, 0.0, 1.0])
93
+ >>> np.round(flops.stats.laplace.cdf(x), 3)
94
+ array([0.184, 0.5 , 0.816])
95
+ """
96
+ return self._deduct_and_call("cdf", 1, x, loc=loc, scale=scale)
97
+
98
+ def ppf(self, q, loc=0, scale=1):
99
+ """Evaluate the percent-point function.
100
+
101
+ Parameters
102
+ ----------
103
+ q : array_like
104
+ Probabilities in ``[0, 1]``.
105
+ loc : float, optional
106
+ Location parameter of the distribution. Defaults to ``0``.
107
+ scale : float, optional
108
+ Scale parameter of the distribution. Defaults to ``1``.
109
+
110
+ Returns
111
+ -------
112
+ FlopscopeArray
113
+ Quantiles corresponding to ``q``.
114
+
115
+ Notes
116
+ -----
117
+ Equivalent to ``scipy.stats.laplace.ppf(q, loc, scale)``.
118
+ FLOP cost: ``1 * numel(q)``.
119
+
120
+ Examples
121
+ --------
122
+ >>> import numpy as np
123
+ >>> import flopscope as flops
124
+ >>> q = np.array([0.25, 0.5, 0.75])
125
+ >>> np.round(flops.stats.laplace.ppf(q), 3)
126
+ array([-0.693, 0. , 0.693])
127
+ """
128
+ return self._deduct_and_call("ppf", 1, q, loc=loc, scale=scale)
129
+
130
+ def _compute_pdf(self, x, loc=0, scale=1):
131
+ z = _np.abs(x - loc) / scale
132
+ return _np.exp(-z) / (2.0 * scale)
133
+
134
+ def _compute_cdf(self, x, loc=0, scale=1):
135
+ z = (x - loc) / scale
136
+ return _np.where(z <= 0, 0.5 * _np.exp(z), 1.0 - 0.5 * _np.exp(-z))
137
+
138
+ def _compute_ppf(self, q, loc=0, scale=1):
139
+ result = _np.where(
140
+ q <= 0.5,
141
+ loc + scale * _np.log(2.0 * _np.maximum(q, 1e-300)),
142
+ loc - scale * _np.log(2.0 * _np.maximum(1.0 - q, 1e-300)),
143
+ )
144
+ result = _np.where((q >= 0) & (q <= 1), result, _np.nan)
145
+ result = _np.where(q == 0, -_np.inf, result)
146
+ result = _np.where(q == 1, _np.inf, result)
147
+ return result
148
+
149
+
150
+ laplace = LaplaceDistribution()