freealg 0.7.3__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.3 → freealg-0.7.5}/PKG-INFO +1 -1
- freealg-0.7.5/freealg/__version__.py +1 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_algebraic_form/_continuation_algebraic.py +88 -7
- freealg-0.7.5/freealg/_algebraic_form/_decompress2.py +86 -0
- freealg-0.7.5/freealg/_algebraic_form/_homotopy.py +138 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_algebraic_form/algebraic_form.py +198 -124
- {freealg-0.7.3 → freealg-0.7.5}/freealg/distributions/_deformed_wigner.py +7 -19
- {freealg-0.7.3 → freealg-0.7.5}/freealg.egg-info/PKG-INFO +1 -1
- {freealg-0.7.3 → freealg-0.7.5}/freealg.egg-info/SOURCES.txt +2 -0
- freealg-0.7.3/freealg/__version__.py +0 -1
- {freealg-0.7.3 → freealg-0.7.5}/AUTHORS.txt +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/CHANGELOG.rst +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/LICENSE.txt +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/MANIFEST.in +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/README.rst +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/__init__.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_algebraic_form/__init__.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_algebraic_form/_decompress.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_algebraic_form/_edge.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_algebraic_form/_sheets_util.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_free_form/__init__.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_free_form/_chebyshev.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_free_form/_damp.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_free_form/_decompress.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_free_form/_density_util.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_free_form/_jacobi.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_free_form/_linalg.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_free_form/_pade.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_free_form/_plot_util.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_free_form/_sample.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_free_form/_series.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_free_form/_support.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_free_form/free_form.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_geometric_form/__init__.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_geometric_form/_continuation_genus0.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_geometric_form/_continuation_genus1.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_geometric_form/_elliptic_functions.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_geometric_form/_sphere_maps.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_geometric_form/_torus_maps.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_geometric_form/geometric_form.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/_util.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/distributions/__init__.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/distributions/_chiral_block.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/distributions/_deformed_marchenko_pastur.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/distributions/_kesten_mckay.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/distributions/_marchenko_pastur.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/distributions/_meixner.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/distributions/_wachter.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/distributions/_wigner.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/visualization/__init__.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/visualization/_glue_util.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg/visualization/_rgb_hsv.py +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg.egg-info/dependency_links.txt +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg.egg-info/not-zip-safe +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg.egg-info/requires.txt +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/freealg.egg-info/top_level.txt +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/pyproject.toml +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/requirements.txt +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/setup.cfg +0 -0
- {freealg-0.7.3 → freealg-0.7.5}/setup.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.7.5"
|
|
@@ -15,20 +15,22 @@ 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
|
# ======================
|
|
23
23
|
# normalize coefficients
|
|
24
24
|
# ======================
|
|
25
25
|
|
|
26
|
-
def _normalize_coefficients(
|
|
26
|
+
def _normalize_coefficients(arr):
|
|
27
27
|
"""
|
|
28
28
|
Trim rows and columns on the sides (equivalent to factorizing or reducing
|
|
29
29
|
degree) and normalize so that the sum of the first column is one.
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
|
+
a = numpy.asarray(arr).copy()
|
|
33
|
+
|
|
32
34
|
if a.size == 0:
|
|
33
35
|
return a
|
|
34
36
|
|
|
@@ -51,7 +53,7 @@ def _normalize_coefficients(a):
|
|
|
51
53
|
a = a[:, first_col:last_col]
|
|
52
54
|
|
|
53
55
|
# --- Normalize so first column sums to 1 ---
|
|
54
|
-
col_sum = numpy.sum(a[:, 0])
|
|
56
|
+
col_sum = numpy.sum(numpy.abs(a[:, 0]))
|
|
55
57
|
if col_sum != 0:
|
|
56
58
|
a = a / col_sum
|
|
57
59
|
|
|
@@ -189,12 +191,15 @@ def fit_polynomial_relation(z, m, s, deg_z, ridge_lambda=0.0, weights=None,
|
|
|
189
191
|
if w is not None:
|
|
190
192
|
A = A * w[:, None]
|
|
191
193
|
|
|
192
|
-
|
|
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)
|
|
193
198
|
s_col[s_col == 0.0] = 1.0
|
|
194
|
-
As =
|
|
199
|
+
As = Ar / s_col[None, :]
|
|
195
200
|
|
|
196
201
|
if ridge_lambda > 0.0:
|
|
197
|
-
L = numpy.sqrt(ridge_lambda) * numpy.eye(n_coef, dtype=
|
|
202
|
+
L = numpy.sqrt(ridge_lambda) * numpy.eye(n_coef, dtype=float)
|
|
198
203
|
As = numpy.vstack([As, L])
|
|
199
204
|
|
|
200
205
|
_, _, vh = numpy.linalg.svd(As, full_matrices=False)
|
|
@@ -211,6 +216,77 @@ def fit_polynomial_relation(z, m, s, deg_z, ridge_lambda=0.0, weights=None,
|
|
|
211
216
|
return full
|
|
212
217
|
|
|
213
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
|
+
|
|
214
290
|
# ======
|
|
215
291
|
# eval P
|
|
216
292
|
# ======
|
|
@@ -359,6 +435,10 @@ def eval_roots(z, a_coeffs):
|
|
|
359
435
|
# =======================
|
|
360
436
|
|
|
361
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
|
+
|
|
362
442
|
z = numpy.asarray(z)
|
|
363
443
|
n_y, n_x = z.shape
|
|
364
444
|
s = roots.shape[1]
|
|
@@ -465,6 +545,7 @@ def track_one_sheet_on_grid(z, roots, sheet_seed, cuts=None, i0=None, j0=None):
|
|
|
465
545
|
# =======================
|
|
466
546
|
|
|
467
547
|
def build_sheets_from_roots(z, roots, m1, cuts=None, i0=None, j0=None):
|
|
548
|
+
|
|
468
549
|
z = numpy.asarray(z)
|
|
469
550
|
m1 = numpy.asarray(m1)
|
|
470
551
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# =======
|
|
2
|
+
# Imports
|
|
3
|
+
# =======
|
|
4
|
+
|
|
5
|
+
import numpy
|
|
6
|
+
from scipy.special import comb
|
|
7
|
+
from ._continuation_algebraic import _normalize_coefficients
|
|
8
|
+
|
|
9
|
+
__all__ = ['decompress_coeffs']
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# =================
|
|
13
|
+
# decompress_coeffs
|
|
14
|
+
# =================
|
|
15
|
+
|
|
16
|
+
def decompress_coeffs(a, t, normalize=True):
|
|
17
|
+
"""
|
|
18
|
+
Compute the decompressed coefficients A[r, s](t) induced by
|
|
19
|
+
the transform Q_t(z, m) = m^L P(z + (1 - e^{-t}) / m, e^t m).
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
a : array_like of float, shape (L+1, K+1)
|
|
24
|
+
Coefficients defining P(z, m) in the monomial basis:
|
|
25
|
+
P(z, m) = sum_{j=0..L} sum_{k=0..K} a[j, k] z^j m^k.
|
|
26
|
+
t : float
|
|
27
|
+
Time parameter.
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
A : ndarray, shape (L+1, L+K+1)
|
|
32
|
+
Coefficients A[r, s](t) such that
|
|
33
|
+
sum_{r=0..L} sum_{s=0..L+K} A[r, s](t) z^r m^s = 0,
|
|
34
|
+
normalized by normalize_coefficients.
|
|
35
|
+
"""
|
|
36
|
+
a = numpy.asarray(a)
|
|
37
|
+
if a.ndim != 2:
|
|
38
|
+
raise ValueError("a must be a 2D array-like of shape (L+1, K+1).")
|
|
39
|
+
|
|
40
|
+
l_degree = a.shape[0] - 1
|
|
41
|
+
k_degree = a.shape[1] - 1
|
|
42
|
+
|
|
43
|
+
c = 1.0 - numpy.exp(-t)
|
|
44
|
+
|
|
45
|
+
# Scale columns of a by e^{t k}: scaled[j, k] = a[j, k] e^{t k}.
|
|
46
|
+
exp_factors = numpy.exp(numpy.arange(k_degree + 1) * t)
|
|
47
|
+
scaled = a * exp_factors
|
|
48
|
+
|
|
49
|
+
# Output coefficients.
|
|
50
|
+
out_dtype = numpy.result_type(a, float)
|
|
51
|
+
a_out = numpy.zeros((l_degree + 1, l_degree + k_degree + 1),
|
|
52
|
+
dtype=out_dtype)
|
|
53
|
+
|
|
54
|
+
# Precompute binomial(j, r) * c^{j-r} for all j, r (lower-triangular).
|
|
55
|
+
j_inds = numpy.arange(l_degree + 1)[:, None]
|
|
56
|
+
r_inds = numpy.arange(l_degree + 1)[None, :]
|
|
57
|
+
mask = r_inds <= j_inds
|
|
58
|
+
|
|
59
|
+
binom_weights = numpy.zeros((l_degree + 1, l_degree + 1), dtype=float)
|
|
60
|
+
binom_weights[mask] = comb(j_inds, r_inds, exact=False)[mask]
|
|
61
|
+
binom_weights[mask] *= (c ** (j_inds - r_inds))[mask]
|
|
62
|
+
|
|
63
|
+
# Main accumulation:
|
|
64
|
+
# For fixed j and r, add:
|
|
65
|
+
# A[r, (L - j + r) + k] += binom_weights[j, r] * scaled[j, k],
|
|
66
|
+
# for k = 0..K.
|
|
67
|
+
for j in range(l_degree + 1):
|
|
68
|
+
row_scaled = scaled[j]
|
|
69
|
+
if numpy.all(row_scaled == 0):
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
base0 = l_degree - j
|
|
73
|
+
row_b = binom_weights[j]
|
|
74
|
+
|
|
75
|
+
for r in range(j + 1):
|
|
76
|
+
coeff = row_b[r]
|
|
77
|
+
if coeff == 0:
|
|
78
|
+
continue
|
|
79
|
+
|
|
80
|
+
start = base0 + r
|
|
81
|
+
a_out[r, start:start + (k_degree + 1)] += coeff * row_scaled
|
|
82
|
+
|
|
83
|
+
if normalize:
|
|
84
|
+
return _normalize_coefficients(a_out)
|
|
85
|
+
|
|
86
|
+
return a_out
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# =======
|
|
2
|
+
# Imports
|
|
3
|
+
# =======
|
|
4
|
+
|
|
5
|
+
import numpy
|
|
6
|
+
|
|
7
|
+
__all__ = ['stieltjes_poly']
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# =====================
|
|
11
|
+
# stieltjes select root
|
|
12
|
+
# =====================
|
|
13
|
+
|
|
14
|
+
def stieltjes_select_root(roots, z, w_prev=None):
|
|
15
|
+
"""
|
|
16
|
+
Select the Stieltjes-branch root among candidates at a given z.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
roots : array_like of complex
|
|
21
|
+
Candidate roots for m at the given z.
|
|
22
|
+
z : complex
|
|
23
|
+
Evaluation point. The Stieltjes/Herglotz branch satisfies
|
|
24
|
+
sign(Im(m)) = sign(Im(z)) away from the real axis.
|
|
25
|
+
w_prev : complex or None, optional
|
|
26
|
+
Previous continuation value used to enforce continuity. If None,
|
|
27
|
+
the asymptotic target -1/z is used.
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
w : complex
|
|
32
|
+
Selected root corresponding to the Stieltjes branch.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
z = complex(z)
|
|
36
|
+
roots = numpy.asarray(roots, dtype=numpy.complex128).ravel()
|
|
37
|
+
|
|
38
|
+
if roots.size == 0:
|
|
39
|
+
raise ValueError("roots must contain at least one candidate root.")
|
|
40
|
+
|
|
41
|
+
desired_sign = numpy.sign(z.imag)
|
|
42
|
+
|
|
43
|
+
if w_prev is None:
|
|
44
|
+
target = -1.0 / z
|
|
45
|
+
else:
|
|
46
|
+
target = complex(w_prev)
|
|
47
|
+
|
|
48
|
+
# Apply a soft Herglotz sign filter: prefer roots with Im(w) having the
|
|
49
|
+
# same sign as Im(z), allowing tiny numerical violations near the axis.
|
|
50
|
+
imag_roots = numpy.imag(roots)
|
|
51
|
+
|
|
52
|
+
good = roots[numpy.sign(imag_roots) == desired_sign]
|
|
53
|
+
if good.size == 0:
|
|
54
|
+
good = roots[(imag_roots * desired_sign) > -1e-12]
|
|
55
|
+
|
|
56
|
+
candidates = good if good.size > 0 else roots
|
|
57
|
+
idx = int(numpy.argmin(numpy.abs(candidates - target)))
|
|
58
|
+
return candidates[idx]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# ==============
|
|
62
|
+
# stieltjes poly
|
|
63
|
+
# ==============
|
|
64
|
+
|
|
65
|
+
def stieltjes_poly(z, a, eps=None, height=1e+4, steps=100):
|
|
66
|
+
"""
|
|
67
|
+
Evaluate the Stieltjes-branch solution m(z) of an algebraic equation.
|
|
68
|
+
|
|
69
|
+
The coefficients `a` define a polynomial relation
|
|
70
|
+
P(z, m) = 0,
|
|
71
|
+
where P is a polynomial in z and m with monomial-basis coefficients
|
|
72
|
+
arranged so that for fixed z, the coefficients of the polynomial in m
|
|
73
|
+
can be assembled from powers of z.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
z : complex
|
|
78
|
+
Evaluation point. Must be a single value.
|
|
79
|
+
a : ndarray, shape (L, K)
|
|
80
|
+
Coefficient matrix defining P(z, m) in the monomial basis.
|
|
81
|
+
eps : float or None, optional
|
|
82
|
+
If Im(z) == 0, use z + i*eps as the boundary evaluation point.
|
|
83
|
+
If None and Im(z) == 0, eps is set to 1e-8 * max(1, |z|).
|
|
84
|
+
height : float, optional
|
|
85
|
+
Imaginary height used for the starting point z0 in the same
|
|
86
|
+
half-plane as the evaluation point.
|
|
87
|
+
steps : int, optional
|
|
88
|
+
Number of continuation steps along the homotopy path.
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
w : complex
|
|
93
|
+
Value of the Stieltjes-branch solution m(z) (or m(z+i*eps) if z is
|
|
94
|
+
real).
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
z = complex(z)
|
|
98
|
+
a = numpy.asarray(a)
|
|
99
|
+
|
|
100
|
+
if a.ndim != 2:
|
|
101
|
+
raise ValueError('a must be a 2D array.')
|
|
102
|
+
|
|
103
|
+
if steps < 1:
|
|
104
|
+
raise ValueError("steps must be a positive integer.")
|
|
105
|
+
|
|
106
|
+
a_l, _ = a.shape
|
|
107
|
+
|
|
108
|
+
def poly_coeffs_m(z_val):
|
|
109
|
+
z_powers = z_val ** numpy.arange(a_l)
|
|
110
|
+
return (z_powers @ a)[::-1]
|
|
111
|
+
|
|
112
|
+
def poly_roots(z_val):
|
|
113
|
+
coeffs = numpy.asarray(poly_coeffs_m(z_val), dtype=numpy.complex128)
|
|
114
|
+
return numpy.roots(coeffs)
|
|
115
|
+
|
|
116
|
+
# If user asked for a real-axis value, interpret as boundary value from C+.
|
|
117
|
+
if z.imag == 0.0:
|
|
118
|
+
if eps is None:
|
|
119
|
+
eps = 1e-8 * max(1.0, abs(z))
|
|
120
|
+
z_eval = z + 1j * float(eps)
|
|
121
|
+
else:
|
|
122
|
+
z_eval = z
|
|
123
|
+
|
|
124
|
+
half_sign = numpy.sign(z_eval.imag)
|
|
125
|
+
if half_sign == 0.0:
|
|
126
|
+
half_sign = 1.0
|
|
127
|
+
|
|
128
|
+
z0 = 1j * float(half_sign) * float(height)
|
|
129
|
+
|
|
130
|
+
# Initialize at z0 via asymptotic / Im-sign selection.
|
|
131
|
+
w_prev = stieltjes_select_root(poly_roots(z0), z0, w_prev=None)
|
|
132
|
+
|
|
133
|
+
# Straight-line homotopy from z0 to z_eval.
|
|
134
|
+
for tau in numpy.linspace(0.0, 1.0, int(steps) + 1)[1:]:
|
|
135
|
+
z_tau = z0 + tau * (z_eval - z0)
|
|
136
|
+
w_prev = stieltjes_select_root(poly_roots(z_tau), z_tau, w_prev=w_prev)
|
|
137
|
+
|
|
138
|
+
return w_prev
|
|
@@ -12,12 +12,17 @@
|
|
|
12
12
|
# =======
|
|
13
13
|
|
|
14
14
|
import numpy
|
|
15
|
-
from .._util import resolve_complex_dtype
|
|
15
|
+
from .._util import resolve_complex_dtype, compute_eig
|
|
16
16
|
# from .._util import compute_eig
|
|
17
17
|
from ._continuation_algebraic import sample_z_joukowski, \
|
|
18
|
-
filter_z_away_from_cuts, fit_polynomial_relation,
|
|
18
|
+
filter_z_away_from_cuts, fit_polynomial_relation, \
|
|
19
|
+
sanity_check_stieltjes_branch, eval_P
|
|
19
20
|
from ._edge import evolve_edges, merge_edges
|
|
20
21
|
from ._decompress import decompress_newton
|
|
22
|
+
from ._decompress2 import decompress_coeffs
|
|
23
|
+
from ._homotopy import stieltjes_poly
|
|
24
|
+
from .._free_form._support import supp
|
|
25
|
+
from .._free_form._plot_util import plot_density
|
|
21
26
|
|
|
22
27
|
# Fallback to previous numpy API
|
|
23
28
|
if not hasattr(numpy, 'trapezoid'):
|
|
@@ -129,46 +134,65 @@ class AlgebraicForm(object):
|
|
|
129
134
|
# def __init__(self, A, support=None, delta=1e-6, dtype='complex128',
|
|
130
135
|
# **kwargs):
|
|
131
136
|
|
|
132
|
-
def __init__(self,
|
|
137
|
+
def __init__(self, A, support=None, delta=1e-5, dtype='complex128',
|
|
133
138
|
**kwargs):
|
|
134
139
|
"""
|
|
135
140
|
Initialization.
|
|
136
141
|
"""
|
|
137
142
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
self.stieltjes =
|
|
143
|
+
self.A = None
|
|
144
|
+
self.eig = None
|
|
145
|
+
self.stieltjes = None
|
|
141
146
|
self.support = support
|
|
142
147
|
self.delta = delta # Offset above real axis to apply Plemelj formula
|
|
143
148
|
|
|
144
149
|
# Data type for complex arrays
|
|
145
150
|
self.dtype = resolve_complex_dtype(dtype)
|
|
146
151
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
152
|
+
if hasattr(A, 'stieltjes') and callable(getattr(A, 'stieltjes', None)):
|
|
153
|
+
# This is one of the distribution objects, like MarchenkoPastur
|
|
154
|
+
self.stieltjes = A.stieltjes
|
|
155
|
+
self.n = 1
|
|
156
|
+
|
|
157
|
+
elif callable(A):
|
|
158
|
+
# This is a custom function
|
|
159
|
+
self.stieltjes = A
|
|
160
|
+
self.n = 1
|
|
161
|
+
|
|
162
|
+
else:
|
|
163
|
+
# Eigenvalues
|
|
164
|
+
if A.ndim == 1:
|
|
165
|
+
# If A is a 1D array, it is assumed A is the eigenvalues array.
|
|
166
|
+
self.eig = A
|
|
167
|
+
self.n = len(A)
|
|
168
|
+
elif A.ndim == 2:
|
|
169
|
+
# When A is a 2D array, it is assumed A is the actual array,
|
|
170
|
+
# and its eigenvalues will be computed.
|
|
171
|
+
self.A = A
|
|
172
|
+
self.n = A.shape[0]
|
|
173
|
+
assert A.shape[0] == A.shape[1], \
|
|
174
|
+
'Only square matrices are permitted.'
|
|
175
|
+
self.eig = compute_eig(A)
|
|
176
|
+
|
|
177
|
+
# Use empirical Stieltjes function
|
|
178
|
+
self.stieltjes = lambda z: \
|
|
179
|
+
numpy.mean(1.0/(self.eig-z[:, numpy.newaxis]), axis=-1)
|
|
160
180
|
|
|
161
181
|
# Support
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
182
|
+
if support is None:
|
|
183
|
+
if self.eig is None:
|
|
184
|
+
raise RuntimeError("Support must be provided without data")
|
|
185
|
+
# Detect support
|
|
186
|
+
self.lam_m, self.lam_p = supp(self.eig, **kwargs)
|
|
187
|
+
self.support = [(self.lam_m, self.lam_p)]
|
|
188
|
+
self.broad_support = self.support[0]
|
|
189
|
+
else:
|
|
190
|
+
self.support = support
|
|
191
|
+
self.lam_m = min([s[0] for s in self.support])
|
|
192
|
+
self.lam_p = max([s[1] for s in self.support])
|
|
193
|
+
self.broad_support = (self.lam_m, self.lam_p)
|
|
169
194
|
|
|
170
195
|
# Initialize
|
|
171
|
-
# self.method = None # fitting rho: jacobi, chebyshev
|
|
172
196
|
self.a_coeffs = None # Polynomial coefficients
|
|
173
197
|
self.cache = {} # Cache inner-computations
|
|
174
198
|
|
|
@@ -190,11 +214,9 @@ class AlgebraicForm(object):
|
|
|
190
214
|
"""
|
|
191
215
|
|
|
192
216
|
# Very important: reset cache whenever this function is called. This
|
|
193
|
-
# also empties all references
|
|
217
|
+
# also empties all references holding a cache copy.
|
|
194
218
|
# self.cache.clear()
|
|
195
219
|
|
|
196
|
-
# return self.a_coeffs
|
|
197
|
-
|
|
198
220
|
z_fits = []
|
|
199
221
|
for sup in self.support:
|
|
200
222
|
a, b = sup
|
|
@@ -205,12 +227,10 @@ class AlgebraicForm(object):
|
|
|
205
227
|
|
|
206
228
|
z_fit = numpy.concatenate(z_fits)
|
|
207
229
|
|
|
208
|
-
# Remove points too close to
|
|
230
|
+
# Remove points too close to any cut
|
|
209
231
|
z_fit = filter_z_away_from_cuts(z_fit, self.support, y_eps=y_eps,
|
|
210
232
|
x_pad=x_pad)
|
|
211
233
|
|
|
212
|
-
# ---------
|
|
213
|
-
|
|
214
234
|
m1_fit = self.stieltjes(z_fit)
|
|
215
235
|
a_coeffs = fit_polynomial_relation(z_fit, m1_fit, s=deg_m, deg_z=deg_z,
|
|
216
236
|
ridge_lambda=reg,
|
|
@@ -219,46 +239,66 @@ class AlgebraicForm(object):
|
|
|
219
239
|
|
|
220
240
|
self.a_coeffs = a_coeffs
|
|
221
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
|
+
|
|
222
257
|
if verbose:
|
|
223
|
-
|
|
224
|
-
print(
|
|
225
|
-
print("fit residual 99.9%:",
|
|
226
|
-
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}')
|
|
227
260
|
|
|
228
|
-
print('\
|
|
229
|
-
with numpy.printoptions(precision=
|
|
261
|
+
print('\nCoefficients (real)')
|
|
262
|
+
with numpy.printoptions(precision=8, suppress=True):
|
|
230
263
|
for i in range(a_coeffs.shape[0]):
|
|
231
264
|
for j in range(a_coeffs.shape[1]):
|
|
232
265
|
v = a_coeffs[i, j]
|
|
233
|
-
print(f
|
|
266
|
+
print(f'{v.real:>+0.8f}', end=' ')
|
|
234
267
|
print('')
|
|
235
268
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
print(numpy.abs(a_coeffs))
|
|
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}')
|
|
239
271
|
|
|
240
|
-
|
|
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')
|
|
279
|
+
|
|
280
|
+
return a_coeffs, status
|
|
241
281
|
|
|
242
282
|
# =============
|
|
243
283
|
# generate grid
|
|
244
284
|
# =============
|
|
245
285
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
286
|
+
def _generate_grid(self, scale, extend=1.0, N=500):
|
|
287
|
+
"""
|
|
288
|
+
Generate a grid of points to evaluate density / Hilbert / Stieltjes
|
|
289
|
+
transforms.
|
|
290
|
+
"""
|
|
291
|
+
|
|
292
|
+
radius = 0.5 * (self.lam_p - self.lam_m)
|
|
293
|
+
center = 0.5 * (self.lam_p + self.lam_m)
|
|
294
|
+
|
|
295
|
+
x_min = numpy.floor(extend * (center - extend * radius * scale))
|
|
296
|
+
x_max = numpy.ceil(extend * (center + extend * radius * scale))
|
|
297
|
+
|
|
298
|
+
x_min /= extend
|
|
299
|
+
x_max /= extend
|
|
300
|
+
|
|
301
|
+
return numpy.linspace(x_min, x_max, N)
|
|
262
302
|
|
|
263
303
|
# =======
|
|
264
304
|
# density
|
|
@@ -312,16 +352,19 @@ class AlgebraicForm(object):
|
|
|
312
352
|
raise RuntimeError('The model needs to be fit using the .fit() ' +
|
|
313
353
|
'function.')
|
|
314
354
|
|
|
315
|
-
#
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
#
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
355
|
+
# Create x if not given
|
|
356
|
+
if x is None:
|
|
357
|
+
x = self._generate_grid(1.25)
|
|
358
|
+
|
|
359
|
+
# Preallocate density to zero
|
|
360
|
+
rho = numpy.zeros_like(x)
|
|
361
|
+
|
|
362
|
+
for idx, x_i in enumerate(x):
|
|
363
|
+
m_i = stieltjes_poly(x_i, self.a_coeffs)
|
|
364
|
+
rho[idx] = m_i.imag
|
|
365
|
+
|
|
366
|
+
rho = rho / numpy.pi
|
|
367
|
+
|
|
325
368
|
# if self.method == 'jacobi':
|
|
326
369
|
# rho[mask] = jacobi_density(x[mask], self.psi, self.support,
|
|
327
370
|
# self.alpha, self.beta)
|
|
@@ -341,12 +384,12 @@ class AlgebraicForm(object):
|
|
|
341
384
|
# if min_rho < 0.0 - 1e-3:
|
|
342
385
|
# print(f'"rho" is not positive. min_rho: {min_rho:>0.3f}. Set ' +
|
|
343
386
|
# r'"force=True".')
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
387
|
+
|
|
388
|
+
if plot:
|
|
389
|
+
plot_density(x, rho, eig=self.eig, support=self.broad_support,
|
|
390
|
+
label='Estimate', latex=latex, save=save)
|
|
391
|
+
|
|
392
|
+
return rho
|
|
350
393
|
|
|
351
394
|
# =======
|
|
352
395
|
# hilbert
|
|
@@ -568,68 +611,99 @@ class AlgebraicForm(object):
|
|
|
568
611
|
# decompress
|
|
569
612
|
# ==========
|
|
570
613
|
|
|
571
|
-
def decompress(self, x,
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
min_lam=1e-6,
|
|
576
|
-
w_min=1e-14,
|
|
577
|
-
sweep=True,
|
|
578
|
-
verbose=False):
|
|
614
|
+
def decompress(self, size, x=None, method='one', plot=False, latex=False,
|
|
615
|
+
save=False, verbose=False, newton_opt={
|
|
616
|
+
'max_iter': 50, 'tol': 1e-12, 'armijo': 1e-4,
|
|
617
|
+
'min_lam': 1e-6, 'w_min': 1e-14, 'sweep': True}):
|
|
579
618
|
"""
|
|
580
619
|
Free decompression of spectral density.
|
|
581
620
|
"""
|
|
582
621
|
|
|
583
622
|
# Check size argument
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
623
|
+
if numpy.isscalar(size):
|
|
624
|
+
size = int(size)
|
|
625
|
+
else:
|
|
626
|
+
# Check monotonic increment (either all increasing or decreasing)
|
|
627
|
+
diff = numpy.diff(size)
|
|
628
|
+
if not (numpy.all(diff >= 0) or numpy.all(diff <= 0)):
|
|
629
|
+
raise ValueError('"size" increment should be monotonic.')
|
|
591
630
|
|
|
592
631
|
# Decompression ratio equal to e^{t}.
|
|
593
|
-
|
|
632
|
+
alpha = numpy.atleast_1d(size) / self.n
|
|
594
633
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
# rho = numpy.squeeze(rho)
|
|
598
|
-
#
|
|
599
|
-
# # Plot only the last size
|
|
600
|
-
# if plot:
|
|
601
|
-
# if numpy.isscalar(size):
|
|
602
|
-
# rho_last = rho
|
|
603
|
-
# else:
|
|
604
|
-
# rho_last = rho[-1, :]
|
|
605
|
-
# plot_density(x, rho_last, support=(lb, ub),
|
|
606
|
-
# label='Decompression', latex=latex, save=save)
|
|
607
|
-
#
|
|
608
|
-
# return rho, x
|
|
634
|
+
def m_fn(z):
|
|
635
|
+
return stieltjes_poly(z, self.a_coeffs)
|
|
609
636
|
|
|
610
|
-
#
|
|
611
|
-
|
|
637
|
+
# Lower and upper bound on new support
|
|
638
|
+
hilb_lb = (1.0 / m_fn(self.lam_m + self.delta * 1j).item()).real
|
|
639
|
+
hilb_ub = (1.0 / m_fn(self.lam_p + self.delta * 1j).item()).real
|
|
640
|
+
lb = self.lam_m - (numpy.max(alpha) - 1) * hilb_lb
|
|
641
|
+
ub = self.lam_p - (numpy.max(alpha) - 1) * hilb_ub
|
|
612
642
|
|
|
613
|
-
#
|
|
614
|
-
|
|
643
|
+
# Create x if not given
|
|
644
|
+
if x is None:
|
|
645
|
+
radius = 0.5 * (ub - lb)
|
|
646
|
+
center = 0.5 * (ub + lb)
|
|
647
|
+
scale = 1.25
|
|
648
|
+
x_min = numpy.floor(center - radius * scale)
|
|
649
|
+
x_max = numpy.ceil(center + radius * scale)
|
|
650
|
+
x = numpy.linspace(x_min, x_max, 200)
|
|
651
|
+
else:
|
|
652
|
+
x = numpy.asarray(x)
|
|
615
653
|
|
|
616
|
-
|
|
617
|
-
W, ok = decompress_newton(
|
|
618
|
-
z_query, t, self.a_coeffs,
|
|
619
|
-
w0_list=w0_list,
|
|
620
|
-
max_iter=max_iter,
|
|
621
|
-
tol=tol,
|
|
622
|
-
armijo=armijo,
|
|
623
|
-
min_lam=min_lam,
|
|
624
|
-
w_min=w_min,
|
|
625
|
-
sweep=sweep)
|
|
654
|
+
if method == 'one':
|
|
626
655
|
|
|
627
|
-
|
|
656
|
+
# Query grid on the real axis + a small imaginary buffer
|
|
657
|
+
z_query = x + 1j * self.delta
|
|
628
658
|
|
|
629
|
-
|
|
630
|
-
|
|
659
|
+
# Initial condition at t=0 (physical branch)
|
|
660
|
+
w0_list = self.stieltjes(z_query)
|
|
631
661
|
|
|
632
|
-
|
|
662
|
+
# Times
|
|
663
|
+
t = numpy.log(alpha)
|
|
664
|
+
|
|
665
|
+
# Evolve
|
|
666
|
+
W, ok = decompress_newton(
|
|
667
|
+
z_query, t, self.a_coeffs,
|
|
668
|
+
w0_list=w0_list, **newton_opt)
|
|
669
|
+
|
|
670
|
+
rho = W.imag / numpy.pi
|
|
671
|
+
|
|
672
|
+
if verbose:
|
|
673
|
+
print("success rate per t:", ok.mean(axis=1))
|
|
674
|
+
|
|
675
|
+
elif method == 'two':
|
|
676
|
+
|
|
677
|
+
# Preallocate density to zero
|
|
678
|
+
rho = numpy.zeros((alpha.size, x.size), dtype=float)
|
|
679
|
+
|
|
680
|
+
# Decompress to each alpha
|
|
681
|
+
for i in range(alpha.size):
|
|
682
|
+
coeffs_i = decompress_coeffs(self.a_coeffs,
|
|
683
|
+
numpy.log(alpha[i]))
|
|
684
|
+
for j, x_j in enumerate(x):
|
|
685
|
+
m_j = stieltjes_poly(x_j, coeffs_i)
|
|
686
|
+
rho[i, j] = m_j.imag
|
|
687
|
+
|
|
688
|
+
rho = rho / numpy.pi
|
|
689
|
+
|
|
690
|
+
else:
|
|
691
|
+
raise ValueError('"method" is invalid.')
|
|
692
|
+
|
|
693
|
+
# If the input size was only a scalar, return a 1D rho, otherwise 2D.
|
|
694
|
+
if numpy.isscalar(size):
|
|
695
|
+
rho = numpy.squeeze(rho)
|
|
696
|
+
|
|
697
|
+
# Plot only the last size
|
|
698
|
+
if plot:
|
|
699
|
+
if numpy.isscalar(size):
|
|
700
|
+
rho_last = rho
|
|
701
|
+
else:
|
|
702
|
+
rho_last = rho[-1, :]
|
|
703
|
+
plot_density(x, rho_last, support=(lb, ub),
|
|
704
|
+
label='Decompression', latex=latex, save=save)
|
|
705
|
+
|
|
706
|
+
return rho, x
|
|
633
707
|
|
|
634
708
|
# ====
|
|
635
709
|
# edge
|
|
@@ -290,26 +290,14 @@ class DeformedWigner(object):
|
|
|
290
290
|
A : numpy.ndarray
|
|
291
291
|
A matrix of the size :math:`n \\times n`.
|
|
292
292
|
|
|
293
|
-
Parameters
|
|
294
|
-
----------
|
|
295
|
-
size : int
|
|
296
|
-
Size n of the matrix.
|
|
297
|
-
|
|
298
|
-
seed : int, default=None
|
|
299
|
-
Seed for random number generator.
|
|
300
|
-
|
|
301
|
-
Returns
|
|
302
|
-
-------
|
|
303
|
-
A : numpy.ndarray
|
|
304
|
-
Symmetric matrix of shape (n, n).
|
|
305
|
-
|
|
306
293
|
Notes
|
|
307
294
|
-----
|
|
308
295
|
|
|
309
|
-
Generate an :math:`n
|
|
310
|
-
\\sigma \\mathbf{W}`
|
|
311
|
-
|
|
312
|
-
:math:`H
|
|
296
|
+
Generate an :math:`n \\times n` matrix
|
|
297
|
+
:math:`\\mathbf{A} = \\mathbf{T} + \\sigma \\mathbf{W}`
|
|
298
|
+
whose ESD converges to
|
|
299
|
+
:math:`H \\boxplus \\mathrm{SC}_{\\sigma^2}`, where
|
|
300
|
+
:math:`H = w_1 \\delta_{t_1} + (1 - w_1) \\delta_{t_2}`.
|
|
313
301
|
|
|
314
302
|
Examples
|
|
315
303
|
--------
|
|
@@ -317,8 +305,8 @@ class DeformedWigner(object):
|
|
|
317
305
|
.. code-block::python
|
|
318
306
|
|
|
319
307
|
>>> from freealg.distributions import DeformedWigner
|
|
320
|
-
>>>
|
|
321
|
-
>>> A =
|
|
308
|
+
>>> dwg = DeformedWigner(1/50)
|
|
309
|
+
>>> A = dwg.matrix(2000)
|
|
322
310
|
"""
|
|
323
311
|
|
|
324
312
|
n = int(size)
|
|
@@ -19,7 +19,9 @@ freealg.egg-info/top_level.txt
|
|
|
19
19
|
freealg/_algebraic_form/__init__.py
|
|
20
20
|
freealg/_algebraic_form/_continuation_algebraic.py
|
|
21
21
|
freealg/_algebraic_form/_decompress.py
|
|
22
|
+
freealg/_algebraic_form/_decompress2.py
|
|
22
23
|
freealg/_algebraic_form/_edge.py
|
|
24
|
+
freealg/_algebraic_form/_homotopy.py
|
|
23
25
|
freealg/_algebraic_form/_sheets_util.py
|
|
24
26
|
freealg/_algebraic_form/algebraic_form.py
|
|
25
27
|
freealg/_free_form/__init__.py
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.7.3"
|
|
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
|