freealg 0.7.8__py3-none-any.whl → 0.7.10__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/__version__.py +1 -1
- freealg/_algebraic_form/_decompress.py +1 -0
- freealg/_algebraic_form/_homotopy.py +27 -16
- freealg/_algebraic_form/_moments.py +43 -32
- freealg/_algebraic_form/algebraic_form.py +58 -112
- {freealg-0.7.8.dist-info → freealg-0.7.10.dist-info}/METADATA +1 -1
- {freealg-0.7.8.dist-info → freealg-0.7.10.dist-info}/RECORD +11 -11
- {freealg-0.7.8.dist-info → freealg-0.7.10.dist-info}/WHEEL +0 -0
- {freealg-0.7.8.dist-info → freealg-0.7.10.dist-info}/licenses/AUTHORS.txt +0 -0
- {freealg-0.7.8.dist-info → freealg-0.7.10.dist-info}/licenses/LICENSE.txt +0 -0
- {freealg-0.7.8.dist-info → freealg-0.7.10.dist-info}/top_level.txt +0 -0
freealg/__version__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.7.
|
|
1
|
+
__version__ = "0.7.10"
|
|
@@ -504,6 +504,7 @@ def decompress_newton(z_list, t_grid, a_coeffs, w0_list=None,
|
|
|
504
504
|
ok : ndarray of bool, same shape as W
|
|
505
505
|
Convergence flags from the accepted solve at each point.
|
|
506
506
|
"""
|
|
507
|
+
|
|
507
508
|
z_list = numpy.asarray(z_list, dtype=complex).ravel()
|
|
508
509
|
t_grid = numpy.asarray(t_grid, dtype=float).ravel()
|
|
509
510
|
nt = t_grid.size
|
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
|
|
5
5
|
import numpy
|
|
6
6
|
from ._moments import AlgebraicStieltjesMoments
|
|
7
|
+
from tqdm import tqdm
|
|
7
8
|
|
|
8
|
-
__all__ = ['
|
|
9
|
+
__all__ = ['StieltjesPoly']
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
#
|
|
12
|
+
# ===========
|
|
12
13
|
# select root
|
|
13
|
-
#
|
|
14
|
+
# ===========
|
|
14
15
|
|
|
15
16
|
def select_root(roots, z, target):
|
|
16
17
|
"""
|
|
@@ -125,13 +126,15 @@ class StieltjesPoly(object):
|
|
|
125
126
|
self.steps = steps
|
|
126
127
|
self.order = order
|
|
127
128
|
|
|
128
|
-
# Objects depending only on a
|
|
129
129
|
self.mom = AlgebraicStieltjesMoments(a)
|
|
130
|
-
self._zpows_exp = numpy.arange(self.a_l)
|
|
131
130
|
self.rad = 1.0 + self.height * self.mom.radius(self.order)
|
|
131
|
+
self.z0_p = 1j * self.rad
|
|
132
|
+
self.m0_p = self.mom.stieltjes(self.z0_p, self.order)
|
|
133
|
+
self.z0_m = -1j * self.rad
|
|
134
|
+
self.m0_m = self.mom.stieltjes(self.z0_m, self.order)
|
|
132
135
|
|
|
133
136
|
def _poly_coeffs_m(self, z_val):
|
|
134
|
-
z_powers = z_val ** self.
|
|
137
|
+
z_powers = z_val ** numpy.arange(self.a_l)
|
|
135
138
|
return (z_powers @ self.a)[::-1]
|
|
136
139
|
|
|
137
140
|
def _poly_roots(self, z_val):
|
|
@@ -165,14 +168,18 @@ class StieltjesPoly(object):
|
|
|
165
168
|
if half_sign == 0.0:
|
|
166
169
|
half_sign = 1.0
|
|
167
170
|
|
|
168
|
-
# If z is outside radius of convergence, no homotopy
|
|
169
|
-
# necessary
|
|
170
|
-
if numpy.abs(z) > self.rad:
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
# # If z is outside radius of convergence, no homotopy
|
|
172
|
+
# # necessary
|
|
173
|
+
# if numpy.abs(z) > self.rad:
|
|
174
|
+
# target = self.mom.stieltjes(z, self.order)
|
|
175
|
+
# return select_root(self._poly_roots(z), z, target)
|
|
173
176
|
|
|
174
|
-
|
|
175
|
-
|
|
177
|
+
if half_sign > 0.0:
|
|
178
|
+
z0 = self.z0_p
|
|
179
|
+
target = self.m0_p
|
|
180
|
+
else:
|
|
181
|
+
z0 = self.z0_m
|
|
182
|
+
target = self.m0_m
|
|
176
183
|
|
|
177
184
|
# Initialize at z0
|
|
178
185
|
w_prev = select_root(self._poly_roots(z0), z0, target)
|
|
@@ -184,7 +191,7 @@ class StieltjesPoly(object):
|
|
|
184
191
|
|
|
185
192
|
return w_prev
|
|
186
193
|
|
|
187
|
-
def __call__(self, z):
|
|
194
|
+
def __call__(self, z, progress=False):
|
|
188
195
|
# Scalar fast-path
|
|
189
196
|
if numpy.isscalar(z):
|
|
190
197
|
return self.evaluate(z)
|
|
@@ -194,7 +201,11 @@ class StieltjesPoly(object):
|
|
|
194
201
|
out = numpy.empty(z_arr.shape, dtype=numpy.complex128)
|
|
195
202
|
|
|
196
203
|
# Iterate over indices so we can pass Python scalars into evaluate()
|
|
197
|
-
|
|
204
|
+
if progress:
|
|
205
|
+
indices = tqdm(numpy.ndindex(z_arr.shape), total=z_arr.size)
|
|
206
|
+
else:
|
|
207
|
+
indices = numpy.ndindex(z_arr.shape)
|
|
208
|
+
for idx in indices:
|
|
198
209
|
out[idx] = self.evaluate(z_arr[idx])
|
|
199
210
|
|
|
200
211
|
return out
|
|
@@ -254,7 +265,7 @@ class StieltjesPoly(object):
|
|
|
254
265
|
# coeffs = numpy.asarray(poly_coeffs_m(z_val), dtype=numpy.complex128)
|
|
255
266
|
# return numpy.roots(coeffs)
|
|
256
267
|
|
|
257
|
-
# # If user asked
|
|
268
|
+
# # If user asked a real-axis value, interpret as boundary value from C+.
|
|
258
269
|
# if z.imag == 0.0:
|
|
259
270
|
# if eps is None:
|
|
260
271
|
# eps = 1e-8 * max(1.0, abs(z))
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
# =======
|
|
2
|
+
# Imports
|
|
3
|
+
# =======
|
|
4
|
+
|
|
1
5
|
import numpy
|
|
2
6
|
|
|
3
7
|
|
|
4
|
-
#
|
|
8
|
+
# =======
|
|
5
9
|
# Moments
|
|
6
|
-
#
|
|
10
|
+
# =======
|
|
7
11
|
|
|
8
12
|
class MomentsESD(object):
|
|
9
13
|
"""
|
|
@@ -85,9 +89,9 @@ class MomentsESD(object):
|
|
|
85
89
|
# (a_{n,0},...,a_{n,n-1})
|
|
86
90
|
self._a = {0: numpy.array([1.0])}
|
|
87
91
|
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
#
|
|
92
|
+
# =
|
|
93
|
+
# m
|
|
94
|
+
# =
|
|
91
95
|
|
|
92
96
|
def m(self, n):
|
|
93
97
|
"""
|
|
@@ -111,9 +115,9 @@ class MomentsESD(object):
|
|
|
111
115
|
self._m[n] = numpy.mean(self.eig ** n)
|
|
112
116
|
return self._m[n]
|
|
113
117
|
|
|
114
|
-
#
|
|
115
|
-
#
|
|
116
|
-
#
|
|
118
|
+
# ======
|
|
119
|
+
# coeffs
|
|
120
|
+
# ======
|
|
117
121
|
|
|
118
122
|
def coeffs(self, n):
|
|
119
123
|
"""
|
|
@@ -129,7 +133,8 @@ class MomentsESD(object):
|
|
|
129
133
|
-------
|
|
130
134
|
|
|
131
135
|
a_n : numpy.ndarray
|
|
132
|
-
Array of shape ``(n,)`` containing :math:`(a_{n,0},
|
|
136
|
+
Array of shape ``(n,)`` containing :math:`(a_{n,0},
|
|
137
|
+
\\dots, a_{n,n-1})`.
|
|
133
138
|
"""
|
|
134
139
|
|
|
135
140
|
if n in self._a:
|
|
@@ -143,6 +148,10 @@ class MomentsESD(object):
|
|
|
143
148
|
self._compute_row(n)
|
|
144
149
|
return self._a[n]
|
|
145
150
|
|
|
151
|
+
# ===========
|
|
152
|
+
# compute row
|
|
153
|
+
# ===========
|
|
154
|
+
|
|
146
155
|
def _compute_row(self, n):
|
|
147
156
|
"""
|
|
148
157
|
Compute and memoize the coefficient row :math:`a_n`.
|
|
@@ -212,9 +221,9 @@ class MomentsESD(object):
|
|
|
212
221
|
|
|
213
222
|
self._a[n] = a_n
|
|
214
223
|
|
|
215
|
-
#
|
|
224
|
+
# --------
|
|
216
225
|
# evaluate
|
|
217
|
-
#
|
|
226
|
+
# --------
|
|
218
227
|
|
|
219
228
|
def __call__(self, n, t=0.0):
|
|
220
229
|
"""
|
|
@@ -254,18 +263,18 @@ class MomentsESD(object):
|
|
|
254
263
|
k = numpy.arange(n, dtype=float)
|
|
255
264
|
return numpy.dot(a_n, numpy.exp(k * t))
|
|
256
265
|
|
|
266
|
+
|
|
257
267
|
# ===========================
|
|
258
268
|
# Algebraic Stieltjes Moments
|
|
259
269
|
# ===========================
|
|
260
270
|
|
|
261
|
-
|
|
262
271
|
class AlgebraicStieltjesMoments(object):
|
|
263
272
|
"""
|
|
264
273
|
Given coefficients a[i,j] for P(z,m)=sum_{i,j} a[i,j] z^i m^j,
|
|
265
274
|
compute the large-|z| branch
|
|
266
275
|
m(z) = sum_{k>=0} mu_series[k] / z^{k+1}.
|
|
267
276
|
|
|
268
|
-
Convention here: choose mu0 (the leading coefficient) by solving the
|
|
277
|
+
Convention here: choose mu0 (the leading coefficient) by solving the
|
|
269
278
|
leading-diagonal equation and (by default) picking the root closest
|
|
270
279
|
to -1, i.e. m(z) ~ -1/z.
|
|
271
280
|
|
|
@@ -281,7 +290,7 @@ class AlgebraicStieltjesMoments(object):
|
|
|
281
290
|
if self.a.ndim != 2:
|
|
282
291
|
raise ValueError("a must be a 2D NumPy array with a[i,j]=a_{ij}.")
|
|
283
292
|
|
|
284
|
-
self.I = self.a.shape[0] - 1
|
|
293
|
+
self.I = self.a.shape[0] - 1 # noqa: E741
|
|
285
294
|
self.J = self.a.shape[1] - 1
|
|
286
295
|
|
|
287
296
|
nz = numpy.argwhere(self.a != 0)
|
|
@@ -320,7 +329,8 @@ class AlgebraicStieltjesMoments(object):
|
|
|
320
329
|
if j > 0:
|
|
321
330
|
self.A0 += j * coeff * self.mu0pow[j - 1]
|
|
322
331
|
if self.A0 == 0:
|
|
323
|
-
raise ValueError("A0 is zero for this mu0; the sequential
|
|
332
|
+
raise ValueError("A0 is zero for this mu0; the sequential " +
|
|
333
|
+
"recursion is degenerate.")
|
|
324
334
|
|
|
325
335
|
# Stored series moments mu_series[0..]
|
|
326
336
|
self._mu = [self.mu0]
|
|
@@ -344,14 +354,17 @@ class AlgebraicStieltjesMoments(object):
|
|
|
344
354
|
coeffs[j] = self.a[i, j]
|
|
345
355
|
|
|
346
356
|
if not numpy.any(coeffs != 0):
|
|
347
|
-
raise ValueError("Leading diagonal polynomial is identically
|
|
357
|
+
raise ValueError("Leading diagonal polynomial is identically " +
|
|
358
|
+
"zero; cannot determine mu0.")
|
|
348
359
|
|
|
349
360
|
deg = int(numpy.max(numpy.nonzero(coeffs)[0]))
|
|
350
|
-
|
|
361
|
+
|
|
362
|
+
# descending powers for numpy.roots
|
|
363
|
+
roots = numpy.roots(coeffs[:deg + 1][::-1])
|
|
351
364
|
|
|
352
365
|
# Targetting mu0 = -1 for ~ -1/z asymptotics
|
|
353
366
|
mu0 = roots[numpy.argmin(numpy.abs(roots + 1))]
|
|
354
|
-
|
|
367
|
+
|
|
355
368
|
if abs(mu0.imag) < 1e-12:
|
|
356
369
|
mu0 = mu0.real
|
|
357
370
|
return mu0
|
|
@@ -363,7 +376,8 @@ class AlgebraicStieltjesMoments(object):
|
|
|
363
376
|
|
|
364
377
|
# Compute f[j] = coefficient of w^k in (S_trunc(w))^j,
|
|
365
378
|
# where S_trunc uses mu_0..mu_{k-1} only (i.e. mu_k treated as 0).
|
|
366
|
-
# Key fact: in the true c[j,k], mu_k can only appear linearly as
|
|
379
|
+
# Key fact: in the true c[j,k], mu_k can only appear linearly as
|
|
380
|
+
# j*mu_k*mu0^{j-1}.
|
|
367
381
|
f = [0] * (self.J + 1)
|
|
368
382
|
f[0] = 0
|
|
369
383
|
for j in range(1, self.J + 1):
|
|
@@ -371,8 +385,9 @@ class AlgebraicStieltjesMoments(object):
|
|
|
371
385
|
# sum_{t=1..k-1} mu_t * c[j-1, k-t]
|
|
372
386
|
for t in range(1, k):
|
|
373
387
|
ssum += self._mu[t] * self._c[j - 1][k - t]
|
|
374
|
-
# recurrence: c[j,k] = mu0*c[j-1,k] + sum_{t=1..k-1}
|
|
375
|
-
#
|
|
388
|
+
# recurrence: c[j,k] = mu0*c[j-1,k] + sum_{t=1..k-1}
|
|
389
|
+
# mu_t*c[j-1,k-t] + mu_k*c[j-1,0] with mu_k=0 for f,
|
|
390
|
+
# and c[j-1,k]=f[j-1]
|
|
376
391
|
f[j] = self.mu0 * f[j - 1] + ssum
|
|
377
392
|
|
|
378
393
|
# Build the linear equation for mu_k:
|
|
@@ -386,7 +401,8 @@ class AlgebraicStieltjesMoments(object):
|
|
|
386
401
|
continue
|
|
387
402
|
rest += coeff * f[j]
|
|
388
403
|
|
|
389
|
-
# lower diagonals s=1..k contribute coeff*c[j,k-s] (already known
|
|
404
|
+
# lower diagonals s=1..k contribute coeff*c[j,k-s] (already known
|
|
405
|
+
# since k-s < k)
|
|
390
406
|
for s in range(1, k + 1):
|
|
391
407
|
entries = self.diag.get(s)
|
|
392
408
|
if not entries:
|
|
@@ -402,7 +418,8 @@ class AlgebraicStieltjesMoments(object):
|
|
|
402
418
|
mu_k = -rest / self.A0
|
|
403
419
|
self._mu.append(mu_k)
|
|
404
420
|
|
|
405
|
-
# Now append the new column k to c using the full convolution
|
|
421
|
+
# Now append the new column k to c using the full convolution
|
|
422
|
+
# recurrence:
|
|
406
423
|
# c[j,k] = sum_{t=0..k} mu_t * c[j-1,k-t]
|
|
407
424
|
for j in range(self.J + 1):
|
|
408
425
|
self._c[j].append(0)
|
|
@@ -430,9 +447,10 @@ class AlgebraicStieltjesMoments(object):
|
|
|
430
447
|
# Estimate the radius of convergence of the Stieltjes
|
|
431
448
|
# series
|
|
432
449
|
if N < 3:
|
|
433
|
-
raise RuntimeError("
|
|
450
|
+
raise RuntimeError("N is too small, choose a larger value.")
|
|
434
451
|
self._ensure(N)
|
|
435
|
-
return max([numpy.abs(self._mu[j] / self._mu[j-1])
|
|
452
|
+
return max([numpy.abs(self._mu[j] / self._mu[j-1])
|
|
453
|
+
for j in range(2, N+1)])
|
|
436
454
|
|
|
437
455
|
def stieltjes(self, z, N):
|
|
438
456
|
# Estimate Stieltjes transform (root) using moment
|
|
@@ -441,10 +459,3 @@ class AlgebraicStieltjesMoments(object):
|
|
|
441
459
|
mu = self.moments(N)
|
|
442
460
|
return -numpy.sum(z[..., numpy.newaxis]**(-numpy.arange(N+1)-1) * mu,
|
|
443
461
|
axis=-1)
|
|
444
|
-
|
|
445
|
-
def target_pt(self, N=15):
|
|
446
|
-
# Obtain an estimate of the Stieltjes transform at a
|
|
447
|
-
# single point z where the estimate is likely reliable
|
|
448
|
-
z = 1j + 2j * self.radius(N)
|
|
449
|
-
return z, self.stieltjes(z, N)
|
|
450
|
-
|
|
@@ -24,7 +24,7 @@ from ._homotopy import StieltjesPoly
|
|
|
24
24
|
from ._discriminant import compute_singular_points
|
|
25
25
|
from ._moments import MomentsESD
|
|
26
26
|
from .._free_form._support import supp
|
|
27
|
-
from .._free_form._plot_util import plot_density
|
|
27
|
+
from .._free_form._plot_util import plot_density, plot_hilbert, plot_stieltjes
|
|
28
28
|
|
|
29
29
|
# Fallback to previous numpy API
|
|
30
30
|
if not hasattr(numpy, 'trapezoid'):
|
|
@@ -63,7 +63,7 @@ class AlgebraicForm(object):
|
|
|
63
63
|
* ``'complex128'``: 128-bit complex numbers, equivalent of two double
|
|
64
64
|
precision floating point.
|
|
65
65
|
* ``'complex256'``: 256-bit complex numbers, equivalent of two long
|
|
66
|
-
double precision floating point. This
|
|
66
|
+
double precision floating point. This option is only available on
|
|
67
67
|
Linux machines.
|
|
68
68
|
|
|
69
69
|
When using series acceleration methods (such as setting
|
|
@@ -144,8 +144,8 @@ class AlgebraicForm(object):
|
|
|
144
144
|
|
|
145
145
|
self.A = None
|
|
146
146
|
self.eig = None
|
|
147
|
-
self.
|
|
148
|
-
self.
|
|
147
|
+
self._stieltjes = None
|
|
148
|
+
self._moments = None
|
|
149
149
|
self.support = support
|
|
150
150
|
self.delta = delta # Offset above real axis to apply Plemelj formula
|
|
151
151
|
|
|
@@ -154,12 +154,12 @@ class AlgebraicForm(object):
|
|
|
154
154
|
|
|
155
155
|
if hasattr(A, 'stieltjes') and callable(getattr(A, 'stieltjes', None)):
|
|
156
156
|
# This is one of the distribution objects, like MarchenkoPastur
|
|
157
|
-
self.
|
|
157
|
+
self._stieltjes = A.stieltjes
|
|
158
158
|
self.n = 1
|
|
159
159
|
|
|
160
160
|
elif callable(A):
|
|
161
161
|
# This is a custom function
|
|
162
|
-
self.
|
|
162
|
+
self._stieltjes = A
|
|
163
163
|
self.n = 1
|
|
164
164
|
|
|
165
165
|
else:
|
|
@@ -178,9 +178,9 @@ class AlgebraicForm(object):
|
|
|
178
178
|
self.eig = compute_eig(A)
|
|
179
179
|
|
|
180
180
|
# Use empirical Stieltjes function
|
|
181
|
-
self.
|
|
181
|
+
self._stieltjes = lambda z: \
|
|
182
182
|
numpy.mean(1.0/(self.eig-z[:, numpy.newaxis]), axis=-1)
|
|
183
|
-
self.
|
|
183
|
+
self._moments = MomentsESD(self.eig) # NOTE (never used)
|
|
184
184
|
|
|
185
185
|
# Support
|
|
186
186
|
if support is None:
|
|
@@ -265,13 +265,13 @@ class AlgebraicForm(object):
|
|
|
265
265
|
x_pad=x_pad)
|
|
266
266
|
|
|
267
267
|
# Fitting (w_inf = None means adaptive weight selection)
|
|
268
|
-
m1_fit = self.
|
|
268
|
+
m1_fit = self._stieltjes(z_fit)
|
|
269
269
|
a_coeffs, fit_metrics = fit_polynomial_relation(
|
|
270
270
|
z_fit, m1_fit, s=deg_m, deg_z=deg_z, ridge_lambda=reg,
|
|
271
271
|
triangular=triangular, normalize=normalize, mu=mu,
|
|
272
272
|
mu_reg=mu_reg)
|
|
273
273
|
|
|
274
|
-
# Compute global
|
|
274
|
+
# Compute global branch points, zeros of leading a_j, and support
|
|
275
275
|
branch_points, a_s_zero, support = compute_singular_points(a_coeffs)
|
|
276
276
|
|
|
277
277
|
self.a_coeffs = a_coeffs
|
|
@@ -294,7 +294,7 @@ class AlgebraicForm(object):
|
|
|
294
294
|
status['res_99_9'] = float(res_99_9)
|
|
295
295
|
status['fit_metrics'] = fit_metrics
|
|
296
296
|
self.status = status
|
|
297
|
-
self.
|
|
297
|
+
self._stieltjes = StieltjesPoly(self.a_coeffs) # NOTE overwrite init
|
|
298
298
|
|
|
299
299
|
if verbose:
|
|
300
300
|
print(f'fit residual max : {res_max:>0.4e}')
|
|
@@ -388,8 +388,6 @@ class AlgebraicForm(object):
|
|
|
388
388
|
>>> from freealg import FreeForm
|
|
389
389
|
"""
|
|
390
390
|
|
|
391
|
-
pass
|
|
392
|
-
|
|
393
391
|
if self.a_coeffs is None:
|
|
394
392
|
raise RuntimeError('The model needs to be fit using the .fit() ' +
|
|
395
393
|
'function.')
|
|
@@ -399,27 +397,7 @@ class AlgebraicForm(object):
|
|
|
399
397
|
x = self._generate_grid(1.25)
|
|
400
398
|
|
|
401
399
|
# Preallocate density to zero
|
|
402
|
-
rho = self.
|
|
403
|
-
|
|
404
|
-
# if self.method == 'jacobi':
|
|
405
|
-
# rho[mask] = jacobi_density(x[mask], self.psi, self.support,
|
|
406
|
-
# self.alpha, self.beta)
|
|
407
|
-
# elif self.method == 'chebyshev':
|
|
408
|
-
# rho[mask] = chebyshev_density(x[mask], self.psi, self.support)
|
|
409
|
-
# else:
|
|
410
|
-
# raise RuntimeError('"method" is invalid.')
|
|
411
|
-
#
|
|
412
|
-
# # Check density is unit mass
|
|
413
|
-
# mass = numpy.trapezoid(rho, x)
|
|
414
|
-
# if not numpy.isclose(mass, 1.0, atol=1e-2):
|
|
415
|
-
# print(f'"rho" is not unit mass. mass: {mass:>0.3f}. Set ' +
|
|
416
|
-
# r'"force=True".')
|
|
417
|
-
#
|
|
418
|
-
# # Check density is positive
|
|
419
|
-
# min_rho = numpy.min(rho)
|
|
420
|
-
# if min_rho < 0.0 - 1e-3:
|
|
421
|
-
# print(f'"rho" is not positive. min_rho: {min_rho:>0.3f}. Set ' +
|
|
422
|
-
# r'"force=True".')
|
|
400
|
+
rho = self._stieltjes(x).imag / numpy.pi
|
|
423
401
|
|
|
424
402
|
if plot:
|
|
425
403
|
plot_density(x, rho, eig=self.eig, support=self.broad_support,
|
|
@@ -431,7 +409,7 @@ class AlgebraicForm(object):
|
|
|
431
409
|
# hilbert
|
|
432
410
|
# =======
|
|
433
411
|
|
|
434
|
-
def hilbert(self, x=None,
|
|
412
|
+
def hilbert(self, x=None, plot=False, latex=False, save=False):
|
|
435
413
|
"""
|
|
436
414
|
Compute Hilbert transform of the spectral density.
|
|
437
415
|
|
|
@@ -443,9 +421,6 @@ class AlgebraicForm(object):
|
|
|
443
421
|
an interval slightly larger than the support interval of the
|
|
444
422
|
spectral density is used.
|
|
445
423
|
|
|
446
|
-
rho : numpy.array, default=None
|
|
447
|
-
Density. If `None`, it will be computed.
|
|
448
|
-
|
|
449
424
|
plot : bool, default=False
|
|
450
425
|
If `True`, density is plotted.
|
|
451
426
|
|
|
@@ -477,49 +452,22 @@ class AlgebraicForm(object):
|
|
|
477
452
|
>>> from freealg import FreeForm
|
|
478
453
|
"""
|
|
479
454
|
|
|
480
|
-
pass
|
|
481
|
-
|
|
482
455
|
if self.a_coeffs is None:
|
|
483
456
|
raise RuntimeError('The model needs to be fit using the .fit() ' +
|
|
484
457
|
'function.')
|
|
485
458
|
|
|
486
|
-
#
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
#
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
# mask = numpy.logical_and(x >= self.lam_m, x <= self.lam_p)
|
|
499
|
-
# x_s = x[mask]
|
|
500
|
-
# rho_s = rho[mask]
|
|
501
|
-
#
|
|
502
|
-
# # Form the matrix of integrands: rho_s / (t - x_i)
|
|
503
|
-
# # Here, we have diff[i,j] = x[i] - x_s[j]
|
|
504
|
-
# diff = x[:, None] - x_s[None, :]
|
|
505
|
-
# D = rho_s[None, :] / diff
|
|
506
|
-
#
|
|
507
|
-
# # Principal-value: wherever t == x_i, then diff == 0, zero that entry
|
|
508
|
-
# # (numpy.isclose handles floating-point exactly)
|
|
509
|
-
# D[numpy.isclose(diff, 0.0)] = 0.0
|
|
510
|
-
#
|
|
511
|
-
# # Integrate each row over t using trapezoid rule on x_s
|
|
512
|
-
# # Namely, hilb[i] = int rho_s(t)/(t - x[i]) dt
|
|
513
|
-
# hilb = numpy.trapezoid(D, x_s, axis=1) / numpy.pi
|
|
514
|
-
#
|
|
515
|
-
# # We use negative sign convention
|
|
516
|
-
# hilb = -hilb
|
|
517
|
-
#
|
|
518
|
-
# if plot:
|
|
519
|
-
# plot_hilbert(x, hilb, support=self.support, latex=latex,
|
|
520
|
-
# save=save)
|
|
521
|
-
#
|
|
522
|
-
# return hilb
|
|
459
|
+
# Create x if not given
|
|
460
|
+
if x is None:
|
|
461
|
+
x = self._generate_grid(1.25)
|
|
462
|
+
|
|
463
|
+
# Preallocate density to zero
|
|
464
|
+
hilb = -self._stieltjes(x).real / numpy.pi
|
|
465
|
+
|
|
466
|
+
if plot:
|
|
467
|
+
plot_hilbert(x, hilb, support=self.support, latex=latex,
|
|
468
|
+
save=save)
|
|
469
|
+
|
|
470
|
+
return hilb
|
|
523
471
|
|
|
524
472
|
# =========
|
|
525
473
|
# stieltjes
|
|
@@ -559,12 +507,9 @@ class AlgebraicForm(object):
|
|
|
559
507
|
Returns
|
|
560
508
|
-------
|
|
561
509
|
|
|
562
|
-
|
|
510
|
+
m : numpy.ndarray
|
|
563
511
|
The Stieltjes transform on the principal branch.
|
|
564
512
|
|
|
565
|
-
m_m : numpy.ndarray
|
|
566
|
-
The Stieltjes transform continued to the secondary branch.
|
|
567
|
-
|
|
568
513
|
See Also
|
|
569
514
|
--------
|
|
570
515
|
|
|
@@ -579,36 +524,34 @@ class AlgebraicForm(object):
|
|
|
579
524
|
>>> from freealg import FreeForm
|
|
580
525
|
"""
|
|
581
526
|
|
|
582
|
-
pass
|
|
583
|
-
|
|
584
527
|
if self.a_coeffs is None:
|
|
585
528
|
raise RuntimeError('The model needs to be fit using the .fit() ' +
|
|
586
529
|
'function.')
|
|
587
530
|
|
|
588
|
-
#
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
#
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
531
|
+
# Create x if not given
|
|
532
|
+
if x is None:
|
|
533
|
+
x = self._generate_grid(2.0, extend=2.0)[::2]
|
|
534
|
+
|
|
535
|
+
# Create y if not given
|
|
536
|
+
if (plot is False) and (y is None):
|
|
537
|
+
# Do not use a Cartesian grid. Create a 1D array z slightly above
|
|
538
|
+
# the real line.
|
|
539
|
+
y = self.delta * 1j
|
|
540
|
+
z = x.astype(complex) + y # shape (Nx,)
|
|
541
|
+
else:
|
|
542
|
+
# Use a Cartesian grid
|
|
543
|
+
if y is None:
|
|
544
|
+
y = numpy.linspace(-1, 1, 200)
|
|
545
|
+
x_grid, y_grid = numpy.meshgrid(x.real, y.real)
|
|
546
|
+
z = x_grid + 1j * y_grid # shape (Ny, Nx)
|
|
547
|
+
|
|
548
|
+
m = self._stieltjes(z, progress=True)
|
|
549
|
+
|
|
550
|
+
if plot:
|
|
551
|
+
plot_stieltjes(x, y, m, m, self.broad_support, latex=latex,
|
|
552
|
+
save=save)
|
|
553
|
+
|
|
554
|
+
return m
|
|
612
555
|
|
|
613
556
|
# ==============
|
|
614
557
|
# eval stieltjes
|
|
@@ -668,8 +611,10 @@ class AlgebraicForm(object):
|
|
|
668
611
|
alpha = numpy.atleast_1d(size) / self.n
|
|
669
612
|
|
|
670
613
|
# Lower and upper bound on new support
|
|
671
|
-
hilb_lb =
|
|
672
|
-
|
|
614
|
+
hilb_lb = \
|
|
615
|
+
(1.0 / self._stieltjes(self.lam_m + self.delta * 1j).item()).real
|
|
616
|
+
hilb_ub = \
|
|
617
|
+
(1.0 / self._stieltjes(self.lam_p + self.delta * 1j).item()).real
|
|
673
618
|
lb = self.lam_m - (numpy.max(alpha) - 1) * hilb_lb
|
|
674
619
|
ub = self.lam_p - (numpy.max(alpha) - 1) * hilb_ub
|
|
675
620
|
|
|
@@ -690,13 +635,14 @@ class AlgebraicForm(object):
|
|
|
690
635
|
z_query = x + 1j * self.delta
|
|
691
636
|
|
|
692
637
|
# Initial condition at t=0 (physical branch)
|
|
693
|
-
w0_list = self.
|
|
638
|
+
w0_list = self._stieltjes(z_query)
|
|
694
639
|
|
|
695
640
|
# Times
|
|
696
641
|
t = numpy.log(alpha)
|
|
697
642
|
|
|
698
643
|
# Ensure it starts from t = 0
|
|
699
|
-
t
|
|
644
|
+
if t[0] > 1.0:
|
|
645
|
+
t = numpy.concatenate([numpy.zeros(1), t])
|
|
700
646
|
|
|
701
647
|
# Evolve
|
|
702
648
|
W, ok = decompress_newton(
|
|
@@ -721,7 +667,7 @@ class AlgebraicForm(object):
|
|
|
721
667
|
coeffs_i = decompress_coeffs(self.a_coeffs,
|
|
722
668
|
numpy.log(alpha[i]))
|
|
723
669
|
stieltjes_i = StieltjesPoly(coeffs_i)
|
|
724
|
-
rho[i, :] = stieltjes_i.imag
|
|
670
|
+
rho[i, :] = stieltjes_i(x).imag
|
|
725
671
|
|
|
726
672
|
rho = rho / numpy.pi
|
|
727
673
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
freealg/__init__.py,sha256=SjcYb6HWmaclnnM-m1eC1honZRyfNBWYDYBx23kSdjo,833
|
|
2
|
-
freealg/__version__.py,sha256
|
|
2
|
+
freealg/__version__.py,sha256=-wENBv06wDArd9jlfvr1fdogsjPVMgMwskP7VuEz-2A,23
|
|
3
3
|
freealg/_util.py,sha256=RzccUCORgzrI9NdNqwMVugiHU0uDKkJFcIyjFMUOnv8,2518
|
|
4
4
|
freealg/_algebraic_form/__init__.py,sha256=MIB_jVgw2qI-JW_ypqaFSeNAB6c4GvpjNySnap_a6hg,398
|
|
5
5
|
freealg/_algebraic_form/_constraints.py,sha256=37U7nvtCTocuS7l_nfUznkPi195PY7eXFzeiikrv3B0,2448
|
|
6
6
|
freealg/_algebraic_form/_continuation_algebraic.py,sha256=KundB9VfX61a35VRxLFyuvB5A51QdT4PD2ffAMjrKR0,19383
|
|
7
|
-
freealg/_algebraic_form/_decompress.py,sha256=
|
|
7
|
+
freealg/_algebraic_form/_decompress.py,sha256=EZ005k_a8wXFsyQZie_N-_hoOvQxj2eV8aUlsNNH7UQ,21102
|
|
8
8
|
freealg/_algebraic_form/_decompress2.py,sha256=Ng9w9xmGe9M-DApp35IeNeQlvszfzT4NZx5BQn0lQ3I,2459
|
|
9
9
|
freealg/_algebraic_form/_discriminant.py,sha256=755pproom6-xThFARaH20m4GuBwwZS2rc0Y80Yg6NzY,5331
|
|
10
10
|
freealg/_algebraic_form/_edge.py,sha256=7l9QyLJDxaEY4WB6MCUFtfEZSf04wyHwH7YPHFJXSbM,10690
|
|
11
|
-
freealg/_algebraic_form/_homotopy.py,sha256=
|
|
12
|
-
freealg/_algebraic_form/_moments.py,sha256=
|
|
11
|
+
freealg/_algebraic_form/_homotopy.py,sha256=q5z8YmrT_8m7L3qw_4FD1Sd5eELIvAiAHr2ucOLW258,9508
|
|
12
|
+
freealg/_algebraic_form/_moments.py,sha256=u55RpvQhIMJFGsq8LZ3IlnTKxNgQPhwnPuYUS34YEyw,12400
|
|
13
13
|
freealg/_algebraic_form/_sheets_util.py,sha256=6OLzWQKu-gN8rxM2rbpbN8TjNZFmD8UJ-8t9kcZdkCo,4174
|
|
14
|
-
freealg/_algebraic_form/algebraic_form.py,sha256=
|
|
14
|
+
freealg/_algebraic_form/algebraic_form.py,sha256=TXGgTPexOUx_uXhMF9dPA8kk_uNKXoOWn32TYvmCcO8,30677
|
|
15
15
|
freealg/_free_form/__init__.py,sha256=5cnSX7kHci3wKx6-BEFhmVY_NjjmQAq1JjWPTEqETTg,611
|
|
16
16
|
freealg/_free_form/_chebyshev.py,sha256=zkyVA8NLf7uUKlJdLz4ijd_SurdsqUgkA5nHGWSybaE,6916
|
|
17
17
|
freealg/_free_form/_damp.py,sha256=k2vtBtWOxQBf4qXaWu_En81lQBXbEO4QbxxWpvuVhdE,1802
|
|
@@ -44,9 +44,9 @@ freealg/distributions/_wigner.py,sha256=epgx6ne6R_7to5j6-QsWIAVFJQFquWMmYgnZYMN4
|
|
|
44
44
|
freealg/visualization/__init__.py,sha256=NLq_zwueF7ytZ8sl8zLPqm-AODxxXNvfMozHGmmklcE,435
|
|
45
45
|
freealg/visualization/_glue_util.py,sha256=2oKnEYjUOS4OZfivmciVLauVr53kyHMwi6c2zRKilTQ,693
|
|
46
46
|
freealg/visualization/_rgb_hsv.py,sha256=rEskxXxSlKKxIrHRslVkgxHtD010L3ge9YtcVsOPl8E,3650
|
|
47
|
-
freealg-0.7.
|
|
48
|
-
freealg-0.7.
|
|
49
|
-
freealg-0.7.
|
|
50
|
-
freealg-0.7.
|
|
51
|
-
freealg-0.7.
|
|
52
|
-
freealg-0.7.
|
|
47
|
+
freealg-0.7.10.dist-info/licenses/AUTHORS.txt,sha256=0b67Nz4_JgIzUupHJTAZxu5QdSUM_HRM_X_w4xCb17o,30
|
|
48
|
+
freealg-0.7.10.dist-info/licenses/LICENSE.txt,sha256=J-EEYEtxb3VVf_Bn1TYfWnpY5lMFIM15iLDDcnaDTPA,1443
|
|
49
|
+
freealg-0.7.10.dist-info/METADATA,sha256=zQjA9ZEsQiqu7ooVnkTrWqcMD7Hg29_Ig0xSxFEG3-Y,5517
|
|
50
|
+
freealg-0.7.10.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
51
|
+
freealg-0.7.10.dist-info/top_level.txt,sha256=eR2wrgYwDdnnJ9Zf5PruPqe4kQav0GMvRsqct6y00Q8,8
|
|
52
|
+
freealg-0.7.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|