freealg 0.7.11__py3-none-any.whl → 0.7.14__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.
- freealg/__init__.py +2 -2
- freealg/__version__.py +1 -1
- freealg/_algebraic_form/__init__.py +2 -1
- freealg/_algebraic_form/_constraints.py +53 -12
- freealg/_algebraic_form/_cusp.py +357 -0
- freealg/_algebraic_form/_cusp_wrap.py +268 -0
- freealg/_algebraic_form/_decompress.py +330 -381
- freealg/_algebraic_form/_decompress2.py +120 -0
- freealg/_algebraic_form/_decompress4.py +739 -0
- freealg/_algebraic_form/_decompress5.py +738 -0
- freealg/_algebraic_form/_decompress6.py +492 -0
- freealg/_algebraic_form/_decompress7.py +355 -0
- freealg/_algebraic_form/_decompress8.py +369 -0
- freealg/_algebraic_form/_decompress9.py +363 -0
- freealg/_algebraic_form/_decompress_new.py +431 -0
- freealg/_algebraic_form/_decompress_new_2.py +1631 -0
- freealg/_algebraic_form/_decompress_util.py +172 -0
- freealg/_algebraic_form/_edge.py +46 -68
- freealg/_algebraic_form/_homotopy.py +62 -30
- freealg/_algebraic_form/_homotopy2.py +289 -0
- freealg/_algebraic_form/_homotopy3.py +215 -0
- freealg/_algebraic_form/_homotopy4.py +320 -0
- freealg/_algebraic_form/_homotopy5.py +185 -0
- freealg/_algebraic_form/_moments.py +43 -57
- freealg/_algebraic_form/_support.py +132 -177
- freealg/_algebraic_form/algebraic_form.py +163 -30
- freealg/distributions/__init__.py +3 -1
- freealg/distributions/_compound_poisson.py +464 -0
- freealg/distributions/_deformed_marchenko_pastur.py +51 -0
- freealg/distributions/_deformed_wigner.py +44 -0
- {freealg-0.7.11.dist-info → freealg-0.7.14.dist-info}/METADATA +2 -1
- {freealg-0.7.11.dist-info → freealg-0.7.14.dist-info}/RECORD +36 -20
- {freealg-0.7.11.dist-info → freealg-0.7.14.dist-info}/WHEEL +1 -1
- {freealg-0.7.11.dist-info → freealg-0.7.14.dist-info}/licenses/AUTHORS.txt +0 -0
- {freealg-0.7.11.dist-info → freealg-0.7.14.dist-info}/licenses/LICENSE.txt +0 -0
- {freealg-0.7.11.dist-info → freealg-0.7.14.dist-info}/top_level.txt +0 -0
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
# =======
|
|
4
4
|
|
|
5
5
|
import numpy
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
6
7
|
from scipy.special import comb
|
|
8
|
+
import texplot
|
|
7
9
|
from ._continuation_algebraic import _normalize_coefficients
|
|
8
10
|
|
|
9
11
|
__all__ = ['decompress_coeffs']
|
|
@@ -33,7 +35,9 @@ def decompress_coeffs(a, t, normalize=True):
|
|
|
33
35
|
sum_{r=0..L} sum_{s=0..L+K} A[r, s](t) z^r m^s = 0,
|
|
34
36
|
normalized by normalize_coefficients.
|
|
35
37
|
"""
|
|
38
|
+
|
|
36
39
|
a = numpy.asarray(a)
|
|
40
|
+
a[-1, 0] = 0.0
|
|
37
41
|
if a.ndim != 2:
|
|
38
42
|
raise ValueError("a must be a 2D array-like of shape (L+1, K+1).")
|
|
39
43
|
|
|
@@ -84,3 +88,119 @@ def decompress_coeffs(a, t, normalize=True):
|
|
|
84
88
|
return _normalize_coefficients(a_out)
|
|
85
89
|
|
|
86
90
|
return a_out
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def plot_candidates(a, x, delta=1e-4, size=None, latex=False, verbose=False):
|
|
94
|
+
"""
|
|
95
|
+
Visualize candidate densities implied by an algebraic Stieltjes-transform
|
|
96
|
+
relation:
|
|
97
|
+
P(z, m) = sum_{i=0..I} sum_{j=0..J} a[i, j] z^i m^j,
|
|
98
|
+
where m(z) is defined implicitly by P(z, m(z)) = 0.
|
|
99
|
+
|
|
100
|
+
For each grid point x_k, set z = x_k + i * delta, form the polynomial in m
|
|
101
|
+
given by P(z, m) = 0, solve for its roots, and plot the cloud of candidate
|
|
102
|
+
densities:
|
|
103
|
+
(1 / pi) * Im(m_root),
|
|
104
|
+
keeping only roots with Im(m_root) > 0 (roots are not tracked/paired across
|
|
105
|
+
x-values).
|
|
106
|
+
|
|
107
|
+
Parameters
|
|
108
|
+
----------
|
|
109
|
+
a : array_like of complex or float, shape (I+1, J+1)
|
|
110
|
+
Coefficients defining P(z, m) in the monomial basis:
|
|
111
|
+
P(z, m) = sum_{i=0..I} sum_{j=0..J} a[i, j] z^i m^j.
|
|
112
|
+
x : array_like of float, shape (N,)
|
|
113
|
+
1D array of real x-values (evaluation grid).
|
|
114
|
+
delta : float, optional
|
|
115
|
+
Small positive imaginary offset used to evaluate m(x + i * delta).
|
|
116
|
+
size : integer, optional
|
|
117
|
+
For labelling purposes, the size of the corresponding matrix can
|
|
118
|
+
be provided.
|
|
119
|
+
|
|
120
|
+
Returns
|
|
121
|
+
-------
|
|
122
|
+
fig : matplotlib.figure.Figure
|
|
123
|
+
The created figure.
|
|
124
|
+
ax : matplotlib.axes.Axes
|
|
125
|
+
The axes the scatter plot was drawn on.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
if not (isinstance(delta, (float, int)) and delta > 0):
|
|
129
|
+
raise ValueError("delta must be a positive scalar.")
|
|
130
|
+
|
|
131
|
+
x = numpy.asarray(x)
|
|
132
|
+
if x.ndim != 1:
|
|
133
|
+
raise ValueError("x must be a 1D NumPy array.")
|
|
134
|
+
|
|
135
|
+
a = numpy.asarray(a)
|
|
136
|
+
if a.ndim != 2:
|
|
137
|
+
raise ValueError("a must be a 2D NumPy array with a[i, j] coefficients.")
|
|
138
|
+
if not numpy.issubdtype(a.dtype, numpy.number):
|
|
139
|
+
raise ValueError("a must be numeric.")
|
|
140
|
+
|
|
141
|
+
i_degree = a.shape[0] - 1
|
|
142
|
+
|
|
143
|
+
xs = []
|
|
144
|
+
ys = []
|
|
145
|
+
max_ys = numpy.zeros_like(x)
|
|
146
|
+
|
|
147
|
+
# Precompute i-powers indices to avoid repeated arange creation.
|
|
148
|
+
i_idx = numpy.arange(i_degree + 1)
|
|
149
|
+
|
|
150
|
+
for idx, xk in enumerate(x):
|
|
151
|
+
z = complex(float(xk), float(delta)) # x + i * delta
|
|
152
|
+
|
|
153
|
+
# b[j] = sum_i a[i, j] * z^i => polynomial in m:
|
|
154
|
+
# sum_{j=0..J} b[j] m^j = 0
|
|
155
|
+
z_pows = z ** i_idx # length I+1
|
|
156
|
+
b = (z_pows[:, None] * a).sum(axis=0) # length J+1, low->high in m
|
|
157
|
+
|
|
158
|
+
# Trim trailing (highest-degree) coefficients near zero to avoid
|
|
159
|
+
# numerical issues in numpy.roots. b is low->high, so trim from end.
|
|
160
|
+
tol = 1e-14
|
|
161
|
+
b_trim = b.copy()
|
|
162
|
+
while b_trim.size > 1 and abs(b_trim[-1]) < tol:
|
|
163
|
+
b_trim = b_trim[:-1]
|
|
164
|
+
|
|
165
|
+
# If constant polynomial (no roots), skip.
|
|
166
|
+
if b_trim.size <= 1:
|
|
167
|
+
continue
|
|
168
|
+
|
|
169
|
+
# numpy.roots expects highest degree first.
|
|
170
|
+
coeffs_high_to_low = b_trim[::-1]
|
|
171
|
+
roots = numpy.roots(coeffs_high_to_low)
|
|
172
|
+
|
|
173
|
+
# Keep only roots with positive imaginary part.
|
|
174
|
+
im = numpy.imag(roots)
|
|
175
|
+
mask = im > 0
|
|
176
|
+
if numpy.any(mask):
|
|
177
|
+
xs.append(numpy.full(mask.sum(), float(xk)))
|
|
178
|
+
ys.append(im[mask] / numpy.pi)
|
|
179
|
+
max_ys[idx] = max(ys[-1])
|
|
180
|
+
|
|
181
|
+
if verbose:
|
|
182
|
+
max_density = numpy.trapezoid(max_ys, x)
|
|
183
|
+
print("Max density: {}".format(max_density))
|
|
184
|
+
|
|
185
|
+
if xs:
|
|
186
|
+
xs = numpy.concatenate(xs)
|
|
187
|
+
ys = numpy.concatenate(ys)
|
|
188
|
+
else:
|
|
189
|
+
xs = numpy.array([], dtype=float)
|
|
190
|
+
ys = numpy.array([], dtype=float)
|
|
191
|
+
|
|
192
|
+
with texplot.theme(use_latex=latex):
|
|
193
|
+
fig, ax = plt.subplots(figsize=(6, 2.7))
|
|
194
|
+
ax.scatter(xs, ys, s=8, alpha=1, linewidths=0, c='k')
|
|
195
|
+
|
|
196
|
+
ax.set_xlabel(r'$\lambda$')
|
|
197
|
+
ax.set_ylabel(r'$\rho(\lambda)$''')
|
|
198
|
+
ax.set_title("Candidate Density Cloud")
|
|
199
|
+
if size is not None:
|
|
200
|
+
ax.set_title("Candidate Density Cloud (size = {})".format(size))
|
|
201
|
+
ax.grid(True, alpha=1)
|
|
202
|
+
save_status = False
|
|
203
|
+
save_filename = ''
|
|
204
|
+
texplot.show_or_save_plot(plt, default_filename=save_filename,
|
|
205
|
+
transparent_background=True, dpi=400,
|
|
206
|
+
show_and_save=save_status, verbose=True)
|