freealg 0.7.4__tar.gz → 0.7.5__tar.gz
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-0.7.4 → freealg-0.7.5}/PKG-INFO +1 -1
- freealg-0.7.5/freealg/__version__.py +1 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_algebraic_form/_continuation_algebraic.py +84 -5
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_algebraic_form/_homotopy.py +1 -1
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_algebraic_form/algebraic_form.py +35 -16
- {freealg-0.7.4 → freealg-0.7.5}/freealg.egg-info/PKG-INFO +1 -1
- freealg-0.7.4/freealg/__version__.py +0 -1
- {freealg-0.7.4 → freealg-0.7.5}/AUTHORS.txt +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/CHANGELOG.rst +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/LICENSE.txt +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/MANIFEST.in +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/README.rst +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/__init__.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_algebraic_form/__init__.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_algebraic_form/_decompress.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_algebraic_form/_decompress2.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_algebraic_form/_edge.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_algebraic_form/_sheets_util.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_free_form/__init__.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_free_form/_chebyshev.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_free_form/_damp.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_free_form/_decompress.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_free_form/_density_util.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_free_form/_jacobi.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_free_form/_linalg.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_free_form/_pade.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_free_form/_plot_util.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_free_form/_sample.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_free_form/_series.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_free_form/_support.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_free_form/free_form.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_geometric_form/__init__.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_geometric_form/_continuation_genus0.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_geometric_form/_continuation_genus1.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_geometric_form/_elliptic_functions.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_geometric_form/_sphere_maps.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_geometric_form/_torus_maps.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_geometric_form/geometric_form.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/_util.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/distributions/__init__.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/distributions/_chiral_block.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/distributions/_deformed_marchenko_pastur.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/distributions/_deformed_wigner.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/distributions/_kesten_mckay.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/distributions/_marchenko_pastur.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/distributions/_meixner.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/distributions/_wachter.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/distributions/_wigner.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/visualization/__init__.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/visualization/_glue_util.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg/visualization/_rgb_hsv.py +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg.egg-info/SOURCES.txt +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg.egg-info/dependency_links.txt +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg.egg-info/not-zip-safe +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg.egg-info/requires.txt +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/freealg.egg-info/top_level.txt +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/pyproject.toml +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/requirements.txt +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/setup.cfg +0 -0
- {freealg-0.7.4 → freealg-0.7.5}/setup.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.7.5"
|
|
@@ -15,8 +15,8 @@ import numpy
|
|
|
15
15
|
from .._geometric_form._continuation_genus0 import joukowski_z
|
|
16
16
|
|
|
17
17
|
__all__ = ['sample_z_joukowski', 'filter_z_away_from_cuts', 'powers',
|
|
18
|
-
'fit_polynomial_relation', '
|
|
19
|
-
'build_sheets_from_roots']
|
|
18
|
+
'fit_polynomial_relation', 'sanity_check_stieltjes_branch',
|
|
19
|
+
'eval_P', 'eval_roots', 'build_sheets_from_roots']
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
# ======================
|
|
@@ -191,12 +191,15 @@ def fit_polynomial_relation(z, m, s, deg_z, ridge_lambda=0.0, weights=None,
|
|
|
191
191
|
if w is not None:
|
|
192
192
|
A = A * w[:, None]
|
|
193
193
|
|
|
194
|
-
|
|
194
|
+
# Enforce real coefficients by solving: Re(A) c = 0 and Im(A) c = 0
|
|
195
|
+
Ar = numpy.vstack([A.real, A.imag])
|
|
196
|
+
|
|
197
|
+
s_col = numpy.max(numpy.abs(Ar), axis=0)
|
|
195
198
|
s_col[s_col == 0.0] = 1.0
|
|
196
|
-
As =
|
|
199
|
+
As = Ar / s_col[None, :]
|
|
197
200
|
|
|
198
201
|
if ridge_lambda > 0.0:
|
|
199
|
-
L = numpy.sqrt(ridge_lambda) * numpy.eye(n_coef, dtype=
|
|
202
|
+
L = numpy.sqrt(ridge_lambda) * numpy.eye(n_coef, dtype=float)
|
|
200
203
|
As = numpy.vstack([As, L])
|
|
201
204
|
|
|
202
205
|
_, _, vh = numpy.linalg.svd(As, full_matrices=False)
|
|
@@ -213,6 +216,77 @@ def fit_polynomial_relation(z, m, s, deg_z, ridge_lambda=0.0, weights=None,
|
|
|
213
216
|
return full
|
|
214
217
|
|
|
215
218
|
|
|
219
|
+
# =============================
|
|
220
|
+
# sanity check stieltjes branch
|
|
221
|
+
# =============================
|
|
222
|
+
|
|
223
|
+
def sanity_check_stieltjes_branch(a_coeffs, x_min, x_max, eta=0.1,
|
|
224
|
+
n_x=64, y0=None, max_bad_frac=0.05):
|
|
225
|
+
"""
|
|
226
|
+
Quick sanity check: does P(z,m)=0 admit a continuously trackable root with
|
|
227
|
+
Im(m)>0 along z=x+i*eta.
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
x_min = float(x_min)
|
|
231
|
+
x_max = float(x_max)
|
|
232
|
+
eta = float(eta)
|
|
233
|
+
n_x = int(n_x)
|
|
234
|
+
if n_x < 4:
|
|
235
|
+
n_x = 4
|
|
236
|
+
|
|
237
|
+
if y0 is None:
|
|
238
|
+
y0 = 10.0 * max(1.0, abs(x_min), abs(x_max))
|
|
239
|
+
y0 = float(y0)
|
|
240
|
+
|
|
241
|
+
z0 = 1j * y0
|
|
242
|
+
m0_target = -1.0 / z0
|
|
243
|
+
|
|
244
|
+
c0 = _poly_coef_in_m(numpy.array([z0]), a_coeffs)[0]
|
|
245
|
+
r0 = numpy.roots(c0[::-1])
|
|
246
|
+
if r0.size == 0:
|
|
247
|
+
return {'ok': False, 'frac_bad': 1.0, 'n_test': 0, 'n_bad': 0}
|
|
248
|
+
|
|
249
|
+
k0 = int(numpy.argmin(numpy.abs(r0 - m0_target)))
|
|
250
|
+
m_prev = r0[k0]
|
|
251
|
+
|
|
252
|
+
xs = numpy.linspace(x_min, x_max, n_x)
|
|
253
|
+
zs = xs + 1j * eta
|
|
254
|
+
|
|
255
|
+
n_bad = 0
|
|
256
|
+
n_ok = 0
|
|
257
|
+
|
|
258
|
+
for z in zs:
|
|
259
|
+
c = _poly_coef_in_m(numpy.array([z]), a_coeffs)[0]
|
|
260
|
+
r = numpy.roots(c[::-1])
|
|
261
|
+
if r.size == 0 or not numpy.all(numpy.isfinite(r)):
|
|
262
|
+
n_bad += 1
|
|
263
|
+
continue
|
|
264
|
+
|
|
265
|
+
k = int(numpy.argmin(numpy.abs(r - m_prev)))
|
|
266
|
+
m_sel = r[k]
|
|
267
|
+
m_prev = m_sel
|
|
268
|
+
n_ok += 1
|
|
269
|
+
|
|
270
|
+
if not numpy.isfinite(m_sel) or (m_sel.imag <= 0.0):
|
|
271
|
+
n_bad += 1
|
|
272
|
+
|
|
273
|
+
n_test = n_ok + (n_bad - (n_x - n_ok))
|
|
274
|
+
if n_test <= 0:
|
|
275
|
+
n_test = n_x
|
|
276
|
+
|
|
277
|
+
frac_bad = float(n_bad) / float(n_x)
|
|
278
|
+
ok = frac_bad <= float(max_bad_frac)
|
|
279
|
+
|
|
280
|
+
status = {
|
|
281
|
+
'ok': ok,
|
|
282
|
+
'frac_bad': frac_bad,
|
|
283
|
+
'n_test': n_x,
|
|
284
|
+
'n_bad': n_bad
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return status
|
|
288
|
+
|
|
289
|
+
|
|
216
290
|
# ======
|
|
217
291
|
# eval P
|
|
218
292
|
# ======
|
|
@@ -361,6 +435,10 @@ def eval_roots(z, a_coeffs):
|
|
|
361
435
|
# =======================
|
|
362
436
|
|
|
363
437
|
def track_one_sheet_on_grid(z, roots, sheet_seed, cuts=None, i0=None, j0=None):
|
|
438
|
+
"""
|
|
439
|
+
This is mostly used for visualization of the sheets.
|
|
440
|
+
"""
|
|
441
|
+
|
|
364
442
|
z = numpy.asarray(z)
|
|
365
443
|
n_y, n_x = z.shape
|
|
366
444
|
s = roots.shape[1]
|
|
@@ -467,6 +545,7 @@ def track_one_sheet_on_grid(z, roots, sheet_seed, cuts=None, i0=None, j0=None):
|
|
|
467
545
|
# =======================
|
|
468
546
|
|
|
469
547
|
def build_sheets_from_roots(z, roots, m1, cuts=None, i0=None, j0=None):
|
|
548
|
+
|
|
470
549
|
z = numpy.asarray(z)
|
|
471
550
|
m1 = numpy.asarray(m1)
|
|
472
551
|
|
|
@@ -62,7 +62,7 @@ def stieltjes_select_root(roots, z, w_prev=None):
|
|
|
62
62
|
# stieltjes poly
|
|
63
63
|
# ==============
|
|
64
64
|
|
|
65
|
-
def stieltjes_poly(z, a, eps=None, height=
|
|
65
|
+
def stieltjes_poly(z, a, eps=None, height=1e+4, steps=100):
|
|
66
66
|
"""
|
|
67
67
|
Evaluate the Stieltjes-branch solution m(z) of an algebraic equation.
|
|
68
68
|
|
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
# Imports
|
|
12
12
|
# =======
|
|
13
13
|
|
|
14
|
-
import inspect
|
|
15
14
|
import numpy
|
|
16
15
|
from .._util import resolve_complex_dtype, compute_eig
|
|
17
16
|
# from .._util import compute_eig
|
|
18
17
|
from ._continuation_algebraic import sample_z_joukowski, \
|
|
19
|
-
filter_z_away_from_cuts, fit_polynomial_relation,
|
|
18
|
+
filter_z_away_from_cuts, fit_polynomial_relation, \
|
|
19
|
+
sanity_check_stieltjes_branch, eval_P
|
|
20
20
|
from ._edge import evolve_edges, merge_edges
|
|
21
21
|
from ._decompress import decompress_newton
|
|
22
22
|
from ._decompress2 import decompress_coeffs
|
|
@@ -149,8 +149,7 @@ class AlgebraicForm(object):
|
|
|
149
149
|
# Data type for complex arrays
|
|
150
150
|
self.dtype = resolve_complex_dtype(dtype)
|
|
151
151
|
|
|
152
|
-
if
|
|
153
|
-
callable(getattr(A, "stieltjes", None)):
|
|
152
|
+
if hasattr(A, 'stieltjes') and callable(getattr(A, 'stieltjes', None)):
|
|
154
153
|
# This is one of the distribution objects, like MarchenkoPastur
|
|
155
154
|
self.stieltjes = A.stieltjes
|
|
156
155
|
self.n = 1
|
|
@@ -215,7 +214,7 @@ class AlgebraicForm(object):
|
|
|
215
214
|
"""
|
|
216
215
|
|
|
217
216
|
# Very important: reset cache whenever this function is called. This
|
|
218
|
-
# also empties all references
|
|
217
|
+
# also empties all references holding a cache copy.
|
|
219
218
|
# self.cache.clear()
|
|
220
219
|
|
|
221
220
|
z_fits = []
|
|
@@ -240,25 +239,45 @@ class AlgebraicForm(object):
|
|
|
240
239
|
|
|
241
240
|
self.a_coeffs = a_coeffs
|
|
242
241
|
|
|
242
|
+
# Reporting error
|
|
243
|
+
P_res = numpy.abs(eval_P(z_fit, m1_fit, a_coeffs))
|
|
244
|
+
res_max = numpy.max(P_res[numpy.isfinite(P_res)])
|
|
245
|
+
res_99_9 = numpy.quantile(P_res[numpy.isfinite(P_res)], 0.999)
|
|
246
|
+
|
|
247
|
+
# Check polynomial has Stieltjes root
|
|
248
|
+
x_min = self.lam_m - 1.0
|
|
249
|
+
x_max = self.lam_p + 1.0
|
|
250
|
+
status = sanity_check_stieltjes_branch(a_coeffs, x_min, x_max,
|
|
251
|
+
eta=max(y_eps, 1e-2), n_x=128,
|
|
252
|
+
max_bad_frac=0.05)
|
|
253
|
+
|
|
254
|
+
status['res_max'] = res_max
|
|
255
|
+
status['res_99_9'] = res_99_9
|
|
256
|
+
|
|
243
257
|
if verbose:
|
|
244
|
-
|
|
245
|
-
print(
|
|
246
|
-
print("fit residual 99.9%:",
|
|
247
|
-
numpy.quantile(P_res[numpy.isfinite(P_res)], 0.999))
|
|
258
|
+
print(f'fit residual max : {res_max:>0.4e}')
|
|
259
|
+
print(f'fit residual 99.9%: {res_99_9:>0.4e}')
|
|
248
260
|
|
|
249
|
-
print('\nCoefficients')
|
|
250
|
-
with numpy.printoptions(precision=
|
|
261
|
+
print('\nCoefficients (real)')
|
|
262
|
+
with numpy.printoptions(precision=8, suppress=True):
|
|
251
263
|
for i in range(a_coeffs.shape[0]):
|
|
252
264
|
for j in range(a_coeffs.shape[1]):
|
|
253
265
|
v = a_coeffs[i, j]
|
|
254
|
-
print(f
|
|
266
|
+
print(f'{v.real:>+0.8f}', end=' ')
|
|
255
267
|
print('')
|
|
256
268
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
269
|
+
a_coeffs_img_norm = numpy.linalg.norm(a_coeffs.imag, ord='fro')
|
|
270
|
+
print(f'\nCoefficients (imag) norm: {a_coeffs_img_norm:>0.4e}')
|
|
271
|
+
|
|
272
|
+
if not status['ok']:
|
|
273
|
+
print("\nWARNING: sanity check failed:\n" +
|
|
274
|
+
f"\tfrac_bad: {status['frac_bad']:>0.3f}\n" +
|
|
275
|
+
f"\tn_bad : {status['n_bad']}\n" +
|
|
276
|
+
f"\tn_test : {status['n_test']}")
|
|
277
|
+
else:
|
|
278
|
+
print('\nStieltjes sanity check: OK')
|
|
260
279
|
|
|
261
|
-
return a_coeffs
|
|
280
|
+
return a_coeffs, status
|
|
262
281
|
|
|
263
282
|
# =============
|
|
264
283
|
# generate grid
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.7.4"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|