freealg 0.7.1__py3-none-any.whl → 0.7.4__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 (34) hide show
  1. freealg/__init__.py +1 -1
  2. freealg/__version__.py +1 -1
  3. freealg/_algebraic_form/_continuation_algebraic.py +48 -5
  4. freealg/_algebraic_form/_decompress2.py +86 -0
  5. freealg/_algebraic_form/_homotopy.py +138 -0
  6. freealg/_algebraic_form/algebraic_form.py +171 -114
  7. freealg/{_freeform → _free_form}/__init__.py +1 -1
  8. freealg/{_freeform → _free_form}/_linalg.py +1 -1
  9. freealg/{_freeform → _free_form}/_support.py +5 -5
  10. freealg/distributions/_chiral_block.py +69 -15
  11. freealg/distributions/_deformed_marchenko_pastur.py +71 -13
  12. freealg/distributions/_deformed_wigner.py +46 -16
  13. freealg/distributions/_kesten_mckay.py +1 -1
  14. freealg/distributions/_marchenko_pastur.py +1 -1
  15. freealg/distributions/_meixner.py +1 -1
  16. freealg/distributions/_wachter.py +1 -1
  17. freealg/distributions/_wigner.py +1 -1
  18. {freealg-0.7.1.dist-info → freealg-0.7.4.dist-info}/METADATA +1 -1
  19. freealg-0.7.4.dist-info/RECORD +49 -0
  20. {freealg-0.7.1.dist-info → freealg-0.7.4.dist-info}/WHEEL +1 -1
  21. freealg-0.7.1.dist-info/RECORD +0 -47
  22. /freealg/{_freeform → _free_form}/_chebyshev.py +0 -0
  23. /freealg/{_freeform → _free_form}/_damp.py +0 -0
  24. /freealg/{_freeform → _free_form}/_decompress.py +0 -0
  25. /freealg/{_freeform → _free_form}/_density_util.py +0 -0
  26. /freealg/{_freeform → _free_form}/_jacobi.py +0 -0
  27. /freealg/{_freeform → _free_form}/_pade.py +0 -0
  28. /freealg/{_freeform → _free_form}/_plot_util.py +0 -0
  29. /freealg/{_freeform → _free_form}/_sample.py +0 -0
  30. /freealg/{_freeform → _free_form}/_series.py +0 -0
  31. /freealg/{_freeform/freeform.py → _free_form/free_form.py} +0 -0
  32. {freealg-0.7.1.dist-info → freealg-0.7.4.dist-info}/licenses/AUTHORS.txt +0 -0
  33. {freealg-0.7.1.dist-info → freealg-0.7.4.dist-info}/licenses/LICENSE.txt +0 -0
  34. {freealg-0.7.1.dist-info → freealg-0.7.4.dist-info}/top_level.txt +0 -0
freealg/__init__.py CHANGED
@@ -6,7 +6,7 @@
6
6
  # under the terms of the license found in the LICENSE.txt file in the root
7
7
  # directory of this source tree.
8
8
 
9
- from ._freeform import FreeForm, eigvalsh, cond, norm, trace, slogdet, supp, \
9
+ from ._free_form import FreeForm, eigvalsh, cond, norm, trace, slogdet, supp, \
10
10
  sample, kde
11
11
  from ._algebraic_form import AlgebraicForm
12
12
  from ._geometric_form import GeometricForm
freealg/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.7.1"
1
+ __version__ = "0.7.4"
@@ -14,10 +14,50 @@
14
14
  import numpy
15
15
  from .._geometric_form._continuation_genus0 import joukowski_z
16
16
 
17
- __all__ = [
18
- 'sample_z_joukowski', 'filter_z_away_from_cuts', 'powers',
19
- 'fit_polynomial_relation', 'eval_P', 'eval_roots',
20
- 'build_sheets_from_roots']
17
+ __all__ = ['sample_z_joukowski', 'filter_z_away_from_cuts', 'powers',
18
+ 'fit_polynomial_relation', 'eval_P', 'eval_roots',
19
+ 'build_sheets_from_roots']
20
+
21
+
22
+ # ======================
23
+ # normalize coefficients
24
+ # ======================
25
+
26
+ def _normalize_coefficients(arr):
27
+ """
28
+ Trim rows and columns on the sides (equivalent to factorizing or reducing
29
+ degree) and normalize so that the sum of the first column is one.
30
+ """
31
+
32
+ a = numpy.asarray(arr).copy()
33
+
34
+ if a.size == 0:
35
+ return a
36
+
37
+ # --- Trim zero rows (top and bottom) ---
38
+ non_zero_rows = numpy.any(a != 0, axis=1)
39
+ if not numpy.any(non_zero_rows):
40
+ return a[:0, :0]
41
+
42
+ first_row = numpy.argmax(non_zero_rows)
43
+ last_row = len(non_zero_rows) - numpy.argmax(non_zero_rows[::-1])
44
+ a = a[first_row:last_row, :]
45
+
46
+ # --- Trim zero columns (left and right) ---
47
+ non_zero_cols = numpy.any(a != 0, axis=0)
48
+ if not numpy.any(non_zero_cols):
49
+ return a[:, :0]
50
+
51
+ first_col = numpy.argmax(non_zero_cols)
52
+ last_col = len(non_zero_cols) - numpy.argmax(non_zero_cols[::-1])
53
+ a = a[:, first_col:last_col]
54
+
55
+ # --- Normalize so first column sums to 1 ---
56
+ col_sum = numpy.sum(numpy.abs(a[:, 0]))
57
+ if col_sum != 0:
58
+ a = a / col_sum
59
+
60
+ return a
21
61
 
22
62
 
23
63
  # ==================
@@ -91,7 +131,7 @@ def powers(x, deg):
91
131
  # =======================
92
132
 
93
133
  def fit_polynomial_relation(z, m, s, deg_z, ridge_lambda=0.0, weights=None,
94
- triangular=None):
134
+ triangular=None, normalize=False):
95
135
 
96
136
  z = numpy.asarray(z, dtype=complex).ravel()
97
137
  m = numpy.asarray(m, dtype=complex).ravel()
@@ -167,6 +207,9 @@ def fit_polynomial_relation(z, m, s, deg_z, ridge_lambda=0.0, weights=None,
167
207
  for k, (i, j) in enumerate(pairs):
168
208
  full[i, j] = coef[k]
169
209
 
210
+ if normalize:
211
+ full = _normalize_coefficients(full)
212
+
170
213
  return full
171
214
 
172
215
 
@@ -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=1e4, 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
@@ -11,13 +11,18 @@
11
11
  # Imports
12
12
  # =======
13
13
 
14
+ import inspect
14
15
  import numpy
15
- from .._util import resolve_complex_dtype
16
+ from .._util import resolve_complex_dtype, compute_eig
16
17
  # from .._util import compute_eig
17
18
  from ._continuation_algebraic import sample_z_joukowski, \
18
19
  filter_z_away_from_cuts, fit_polynomial_relation, 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,66 @@ 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, stieltjes, support=None, delta=1e-5, dtype='complex128',
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
- # self.A = None
139
- # self.eig = None
140
- self.stieltjes = 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
- # # Eigenvalues
148
- # if A.ndim == 1:
149
- # # When A is a 1D array, it is assumed A is the eigenvalue array.
150
- # self.eig = A
151
- # self.n = len(A)
152
- # elif A.ndim == 2:
153
- # # When A is a 2D array, it is assumed A is the actual array,
154
- # # and its eigenvalues will be computed.
155
- # self.A = A
156
- # self.n = A.shape[0]
157
- # assert A.shape[0] == A.shape[1], \
158
- # 'Only square matrices are permitted.'
159
- # self.eig = compute_eig(A)
152
+ if inspect.isclass(A) and hasattr(A, "stieltjes") and \
153
+ callable(getattr(A, "stieltjes", None)):
154
+ # This is one of the distribution objects, like MarchenkoPastur
155
+ self.stieltjes = A.stieltjes
156
+ self.n = 1
157
+
158
+ elif callable(A):
159
+ # This is a custom function
160
+ self.stieltjes = A
161
+ self.n = 1
162
+
163
+ else:
164
+ # Eigenvalues
165
+ if A.ndim == 1:
166
+ # If A is a 1D array, it is assumed A is the eigenvalues array.
167
+ self.eig = A
168
+ self.n = len(A)
169
+ elif A.ndim == 2:
170
+ # When A is a 2D array, it is assumed A is the actual array,
171
+ # and its eigenvalues will be computed.
172
+ self.A = A
173
+ self.n = A.shape[0]
174
+ assert A.shape[0] == A.shape[1], \
175
+ 'Only square matrices are permitted.'
176
+ self.eig = compute_eig(A)
177
+
178
+ # Use empirical Stieltjes function
179
+ self.stieltjes = lambda z: \
180
+ numpy.mean(1.0/(self.eig-z[:, numpy.newaxis]), axis=-1)
160
181
 
161
182
  # Support
162
- # if support is None:
163
- # # Detect support
164
- # self.lam_m, self.lam_p = supp(self.eig, **kwargs)
165
- # else:
166
- # self.lam_m = float(support[0])
167
- # self.lam_p = float(support[1])
168
- # self.support = (self.lam_m, self.lam_p)
183
+ if support is None:
184
+ if self.eig is None:
185
+ raise RuntimeError("Support must be provided without data")
186
+ # Detect support
187
+ self.lam_m, self.lam_p = supp(self.eig, **kwargs)
188
+ self.support = [(self.lam_m, self.lam_p)]
189
+ self.broad_support = self.support[0]
190
+ else:
191
+ self.support = support
192
+ self.lam_m = min([s[0] for s in self.support])
193
+ self.lam_p = max([s[1] for s in self.support])
194
+ self.broad_support = (self.lam_m, self.lam_p)
169
195
 
170
196
  # Initialize
171
- # self.method = None # fitting rho: jacobi, chebyshev
172
197
  self.a_coeffs = None # Polynomial coefficients
173
198
  self.cache = {} # Cache inner-computations
174
199
 
@@ -183,6 +208,7 @@ class AlgebraicForm(object):
183
208
  y_eps=2e-2,
184
209
  x_pad=0.0,
185
210
  triangular=None,
211
+ normalize=False,
186
212
  verbose=False):
187
213
  """
188
214
  Fits polynomial.
@@ -192,8 +218,6 @@ class AlgebraicForm(object):
192
218
  # also empties all references holdign a cache copy.
193
219
  # self.cache.clear()
194
220
 
195
- # return self.a_coeffs
196
-
197
221
  z_fits = []
198
222
  for sup in self.support:
199
223
  a, b = sup
@@ -204,16 +228,15 @@ class AlgebraicForm(object):
204
228
 
205
229
  z_fit = numpy.concatenate(z_fits)
206
230
 
207
- # Remove points too close to ANY cut
231
+ # Remove points too close to any cut
208
232
  z_fit = filter_z_away_from_cuts(z_fit, self.support, y_eps=y_eps,
209
233
  x_pad=x_pad)
210
234
 
211
- # ---------
212
-
213
235
  m1_fit = self.stieltjes(z_fit)
214
236
  a_coeffs = fit_polynomial_relation(z_fit, m1_fit, s=deg_m, deg_z=deg_z,
215
237
  ridge_lambda=reg,
216
- triangular=triangular)
238
+ triangular=triangular,
239
+ normalize=normalize)
217
240
 
218
241
  self.a_coeffs = a_coeffs
219
242
 
@@ -223,7 +246,7 @@ class AlgebraicForm(object):
223
246
  print("fit residual 99.9%:",
224
247
  numpy.quantile(P_res[numpy.isfinite(P_res)], 0.999))
225
248
 
226
- print('\nCoefficinets')
249
+ print('\nCoefficients')
227
250
  with numpy.printoptions(precision=4, suppress=True):
228
251
  for i in range(a_coeffs.shape[0]):
229
252
  for j in range(a_coeffs.shape[1]):
@@ -231,7 +254,7 @@ class AlgebraicForm(object):
231
254
  print(f"{v.real:>+0.4f}{v.imag:>+0.4f}j", end=" ")
232
255
  print('')
233
256
 
234
- print('\nCoefficients mangitudes')
257
+ print('\nCoefficient Magnitudes')
235
258
  with numpy.printoptions(precision=6, suppress=True):
236
259
  print(numpy.abs(a_coeffs))
237
260
 
@@ -241,22 +264,22 @@ class AlgebraicForm(object):
241
264
  # generate grid
242
265
  # =============
243
266
 
244
- # def _generate_grid(self, scale, extend=1.0, N=500):
245
- # """
246
- # Generate a grid of points to evaluate density / Hilbert / Stieltjes
247
- # transforms.
248
- # """
249
- #
250
- # radius = 0.5 * (self.lam_p - self.lam_m)
251
- # center = 0.5 * (self.lam_p + self.lam_m)
252
- #
253
- # x_min = numpy.floor(extend * (center - extend * radius * scale))
254
- # x_max = numpy.ceil(extend * (center + extend * radius * scale))
255
- #
256
- # x_min /= extend
257
- # x_max /= extend
258
- #
259
- # return numpy.linspace(x_min, x_max, N)
267
+ def _generate_grid(self, scale, extend=1.0, N=500):
268
+ """
269
+ Generate a grid of points to evaluate density / Hilbert / Stieltjes
270
+ transforms.
271
+ """
272
+
273
+ radius = 0.5 * (self.lam_p - self.lam_m)
274
+ center = 0.5 * (self.lam_p + self.lam_m)
275
+
276
+ x_min = numpy.floor(extend * (center - extend * radius * scale))
277
+ x_max = numpy.ceil(extend * (center + extend * radius * scale))
278
+
279
+ x_min /= extend
280
+ x_max /= extend
281
+
282
+ return numpy.linspace(x_min, x_max, N)
260
283
 
261
284
  # =======
262
285
  # density
@@ -310,16 +333,19 @@ class AlgebraicForm(object):
310
333
  raise RuntimeError('The model needs to be fit using the .fit() ' +
311
334
  'function.')
312
335
 
313
- # # Create x if not given
314
- # if x is None:
315
- # x = self._generate_grid(1.25)
316
- #
317
- # # Preallocate density to zero
318
- # rho = numpy.zeros_like(x)
319
- #
320
- # # Compute density only inside support
321
- # mask = numpy.logical_and(x >= self.lam_m, x <= self.lam_p)
322
- #
336
+ # Create x if not given
337
+ if x is None:
338
+ x = self._generate_grid(1.25)
339
+
340
+ # Preallocate density to zero
341
+ rho = numpy.zeros_like(x)
342
+
343
+ for idx, x_i in enumerate(x):
344
+ m_i = stieltjes_poly(x_i, self.a_coeffs)
345
+ rho[idx] = m_i.imag
346
+
347
+ rho = rho / numpy.pi
348
+
323
349
  # if self.method == 'jacobi':
324
350
  # rho[mask] = jacobi_density(x[mask], self.psi, self.support,
325
351
  # self.alpha, self.beta)
@@ -339,12 +365,12 @@ class AlgebraicForm(object):
339
365
  # if min_rho < 0.0 - 1e-3:
340
366
  # print(f'"rho" is not positive. min_rho: {min_rho:>0.3f}. Set ' +
341
367
  # r'"force=True".')
342
- #
343
- # if plot:
344
- # plot_density(x, rho, eig=self.eig, support=self.support,
345
- # label='Estimate', latex=latex, save=save)
346
- #
347
- # return rho
368
+
369
+ if plot:
370
+ plot_density(x, rho, eig=self.eig, support=self.broad_support,
371
+ label='Estimate', latex=latex, save=save)
372
+
373
+ return rho
348
374
 
349
375
  # =======
350
376
  # hilbert
@@ -566,68 +592,99 @@ class AlgebraicForm(object):
566
592
  # decompress
567
593
  # ==========
568
594
 
569
- def decompress(self, x, t,
570
- max_iter=50,
571
- tol=1e-12,
572
- armijo=1e-4,
573
- min_lam=1e-6,
574
- w_min=1e-14,
575
- sweep=True,
576
- verbose=False):
595
+ def decompress(self, size, x=None, method='one', plot=False, latex=False,
596
+ save=False, verbose=False, newton_opt={
597
+ 'max_iter': 50, 'tol': 1e-12, 'armijo': 1e-4,
598
+ 'min_lam': 1e-6, 'w_min': 1e-14, 'sweep': True}):
577
599
  """
578
600
  Free decompression of spectral density.
579
601
  """
580
602
 
581
603
  # Check size argument
582
- # if numpy.isscalar(size):
583
- # size = int(size)
584
- # else:
585
- # # Check monotonic increment (either all increasing or decreasing)
586
- # diff = numpy.diff(size)
587
- # if not (numpy.all(diff >= 0) or numpy.all(diff <= 0)):
588
- # raise ValueError('"size" increment should be monotonic.')
604
+ if numpy.isscalar(size):
605
+ size = int(size)
606
+ else:
607
+ # Check monotonic increment (either all increasing or decreasing)
608
+ diff = numpy.diff(size)
609
+ if not (numpy.all(diff >= 0) or numpy.all(diff <= 0)):
610
+ raise ValueError('"size" increment should be monotonic.')
589
611
 
590
612
  # Decompression ratio equal to e^{t}.
591
- # alpha = numpy.atleast_1d(size) / self.n
613
+ alpha = numpy.atleast_1d(size) / self.n
592
614
 
593
- # # If the input size was only a scalar, return a 1D rho, otherwise 2D.
594
- # if numpy.isscalar(size):
595
- # rho = numpy.squeeze(rho)
596
- #
597
- # # Plot only the last size
598
- # if plot:
599
- # if numpy.isscalar(size):
600
- # rho_last = rho
601
- # else:
602
- # rho_last = rho[-1, :]
603
- # plot_density(x, rho_last, support=(lb, ub),
604
- # label='Decompression', latex=latex, save=save)
605
- #
606
- # return rho, x
615
+ def m_fn(z):
616
+ return stieltjes_poly(z, self.a_coeffs)
607
617
 
608
- # Query grid on the real axis + a small imaginary buffer
609
- z_query = x + 1j * self.delta
618
+ # Lower and upper bound on new support
619
+ hilb_lb = (1.0 / m_fn(self.lam_m + self.delta * 1j).item()).real
620
+ hilb_ub = (1.0 / m_fn(self.lam_p + self.delta * 1j).item()).real
621
+ lb = self.lam_m - (numpy.max(alpha) - 1) * hilb_lb
622
+ ub = self.lam_p - (numpy.max(alpha) - 1) * hilb_ub
610
623
 
611
- # Initial condition at t=0 (physical branch)
612
- w0_list = self.stieltjes(z_query)
624
+ # Create x if not given
625
+ if x is None:
626
+ radius = 0.5 * (ub - lb)
627
+ center = 0.5 * (ub + lb)
628
+ scale = 1.25
629
+ x_min = numpy.floor(center - radius * scale)
630
+ x_max = numpy.ceil(center + radius * scale)
631
+ x = numpy.linspace(x_min, x_max, 200)
632
+ else:
633
+ x = numpy.asarray(x)
613
634
 
614
- # Evolve
615
- W, ok = decompress_newton(
616
- z_query, t, self.a_coeffs,
617
- w0_list=w0_list,
618
- max_iter=max_iter,
619
- tol=tol,
620
- armijo=armijo,
621
- min_lam=min_lam,
622
- w_min=w_min,
623
- sweep=sweep)
635
+ if method == 'one':
624
636
 
625
- rho = W.imag / numpy.pi
637
+ # Query grid on the real axis + a small imaginary buffer
638
+ z_query = x + 1j * self.delta
626
639
 
627
- if verbose:
628
- print("success rate per t:", ok.mean(axis=1))
640
+ # Initial condition at t=0 (physical branch)
641
+ w0_list = self.stieltjes(z_query)
629
642
 
630
- return rho
643
+ # Times
644
+ t = numpy.log(alpha)
645
+
646
+ # Evolve
647
+ W, ok = decompress_newton(
648
+ z_query, t, self.a_coeffs,
649
+ w0_list=w0_list, **newton_opt)
650
+
651
+ rho = W.imag / numpy.pi
652
+
653
+ if verbose:
654
+ print("success rate per t:", ok.mean(axis=1))
655
+
656
+ elif method == 'two':
657
+
658
+ # Preallocate density to zero
659
+ rho = numpy.zeros((alpha.size, x.size), dtype=float)
660
+
661
+ # Decompress to each alpha
662
+ for i in range(alpha.size):
663
+ coeffs_i = decompress_coeffs(self.a_coeffs,
664
+ numpy.log(alpha[i]))
665
+ for j, x_j in enumerate(x):
666
+ m_j = stieltjes_poly(x_j, coeffs_i)
667
+ rho[i, j] = m_j.imag
668
+
669
+ rho = rho / numpy.pi
670
+
671
+ else:
672
+ raise ValueError('"method" is invalid.')
673
+
674
+ # If the input size was only a scalar, return a 1D rho, otherwise 2D.
675
+ if numpy.isscalar(size):
676
+ rho = numpy.squeeze(rho)
677
+
678
+ # Plot only the last size
679
+ if plot:
680
+ if numpy.isscalar(size):
681
+ rho_last = rho
682
+ else:
683
+ rho_last = rho[-1, :]
684
+ plot_density(x, rho_last, support=(lb, ub),
685
+ label='Decompression', latex=latex, save=save)
686
+
687
+ return rho, x
631
688
 
632
689
  # ====
633
690
  # edge
@@ -6,7 +6,7 @@
6
6
  # under the terms of the license found in the LICENSE.txt file in the root
7
7
  # directory of this source tree.
8
8
 
9
- from .freeform import FreeForm
9
+ from .free_form import FreeForm
10
10
  from ._linalg import eigvalsh, cond, norm, trace, slogdet
11
11
  from ._support import supp
12
12
  from ._sample import sample
@@ -12,7 +12,7 @@
12
12
 
13
13
  import numpy
14
14
  from .._util import compute_eig
15
- from .freeform import FreeForm
15
+ from .free_form import FreeForm
16
16
 
17
17
  __all__ = ['eigvalsh', 'cond', 'norm', 'trace', 'slogdet']
18
18
 
@@ -11,7 +11,7 @@
11
11
  # =======
12
12
 
13
13
  import numpy
14
- import numba
14
+ # import numba
15
15
  from scipy.stats import gaussian_kde
16
16
 
17
17
  __all__ = ['support_from_density', 'supp']
@@ -21,10 +21,10 @@ __all__ = ['support_from_density', 'supp']
21
21
  # support from density
22
22
  # ====================
23
23
 
24
- @numba.njit(numba.types.UniTuple(numba.types.int64, 2)(
25
- numba.types.float64,
26
- numba.types.float64[::1]
27
- ))
24
+ # @numba.njit(numba.types.UniTuple(numba.types.int64, 2)(
25
+ # numba.types.float64,
26
+ # numba.types.float64[::1]
27
+ # ))
28
28
  def support_from_density(dx, density):
29
29
  """
30
30
  Estimates the support from a collection of noisy observations of a
@@ -404,7 +404,7 @@ class ChiralBlock(object):
404
404
  ----------
405
405
 
406
406
  size : int
407
- Size :math:`n` of the matrix.
407
+ Total size :math:`N = n + m` of the returned matrix.
408
408
 
409
409
  seed : int, default=None
410
410
  Seed for random number generator.
@@ -413,7 +413,24 @@ class ChiralBlock(object):
413
413
  -------
414
414
 
415
415
  A : numpy.ndarray
416
- A matrix of the size :math:`n \\times n`.
416
+ Symmetric matrix of shape :math:`N \\times N`.
417
+
418
+ Notes
419
+ -----
420
+
421
+ Generate a :math:`(n+m) x (n+m)` matrix
422
+
423
+ .. math::
424
+
425
+ H =
426
+ \\begin{bmatrix}
427
+ \\alpha \\mathbf{I}_n & (1/\\sqrt{m})) \\mathbf{X} \\
428
+ (1/\\sqrt{m})) \\mathbf{X}^{\\intercal} & \\beta \\mathbf{I}_m
429
+ \\end{bmatrix}
430
+
431
+
432
+ where :math:`\\mathbf{X}` has i.i.d. :math:`N(0,1)` entries and
433
+ :math:`n/m` approximates :math:`c`.
417
434
 
418
435
  Examples
419
436
  --------
@@ -425,16 +442,53 @@ class ChiralBlock(object):
425
442
  >>> A = mp.matrix(2000)
426
443
  """
427
444
 
428
- # Parameters
429
- # m = int(size / self.lam)
430
- #
431
- # # Generate random matrix X (n x m) with i.i.d.
432
- # rng = numpy.random.default_rng(seed)
433
- # X = rng.standard_normal((size, m))
434
- #
435
- # # Form the sample covariance matrix A = (1/m)*XX^T.
436
- # A = X @ X.T / m
437
- #
438
- # return A
439
-
440
- pass
445
+ N = int(size)
446
+ if N <= 1:
447
+ raise ValueError("size must be an integer >= 2.")
448
+
449
+ # Unpack parameters
450
+ alpha = float(self.alpha)
451
+ beta = float(self.beta)
452
+ c = float(self.c)
453
+
454
+ rng = numpy.random.default_rng(seed)
455
+
456
+ # Choose n,m so that n/m approx c and n+m = N.
457
+ # Solve n = c m and n + m = N -> m = N/(c+1), n = cN/(c+1).
458
+ m = int(round(N / (c + 1.0)))
459
+ m = max(1, min(N - 1, m))
460
+ n = N - m
461
+
462
+ # Optionally refine to get ratio closer to c (cheap local search).
463
+ # This keeps deterministic behavior.
464
+ best_n = n
465
+ best_m = m
466
+ best_err = abs((n / float(m)) - c)
467
+ for dm in (-2, -1, 0, 1, 2):
468
+ mm = m + dm
469
+ if mm <= 0 or mm >= N:
470
+ continue
471
+ nn = N - mm
472
+ err = abs((nn / float(mm)) - c)
473
+ if err < best_err:
474
+ best_err = err
475
+ best_n = nn
476
+ best_m = mm
477
+ n = best_n
478
+ m = best_m
479
+
480
+ # Draw X (n x m) with i.i.d. entries
481
+ X = rng.standard_normal((n, m))
482
+
483
+ # Assemble H
484
+ H = numpy.zeros((N, N), dtype=numpy.float64)
485
+
486
+ H[:n, :n] = alpha * numpy.eye(n, dtype=numpy.float64)
487
+ H[n:, n:] = beta * numpy.eye(m, dtype=numpy.float64)
488
+
489
+ s = 1.0 / numpy.sqrt(float(m))
490
+ B = s * X
491
+ H[:n, n:] = B
492
+ H[n:, :n] = B.T
493
+
494
+ return H
@@ -70,6 +70,15 @@ class DeformedMarchenkoPastur(object):
70
70
  Initialization.
71
71
  """
72
72
 
73
+ if not (0.0 <= w1 <= 1.0):
74
+ raise ValueError("w1 must be in [0, 1].")
75
+
76
+ if c < 0.0:
77
+ raise ValueError("c must be >= 0.")
78
+
79
+ if t1 < 0.0 or t2 < 0.0:
80
+ raise ValueError("t1 and t2 must be >= 0 for a covariance model.")
81
+
73
82
  self.t1 = t1
74
83
  self.t2 = t2
75
84
  self.w1 = w1
@@ -592,6 +601,24 @@ class DeformedMarchenkoPastur(object):
592
601
  A : numpy.ndarray
593
602
  A matrix of the size :math:`n \\times n`.
594
603
 
604
+ Notes
605
+ -----
606
+
607
+ Generate an :math:`n x n` sample covariance matrix :math:`\\mathbf{S}`
608
+ whose ESD converges to :math:`H \\boxtimes MP_c`, where
609
+ :math:`H = w_1 \\delta_{t_1} + (1-w_1) \\delta_{t_2}`.
610
+
611
+ Finite :math:`n` construction:
612
+
613
+ * :math:`m` is chosen so that :math:`n/m` approx :math:`c` (when
614
+ :math:`c>0`),
615
+ * :math:`Z` has i.i.d. :math:`N(0,1)`,
616
+ * :math:`\\boldsymbol{\\Sigma}` has eigenvalues :math:`t_1`,
617
+ :math:`t_2` with proportions
618
+ :math:`w_1`, and :math:`1-w_1`,
619
+ * :math:`\\mathbf{S} = (1/m) \\boldsymbol{\\Sigma}^{1/2} \\mathbf{Z}
620
+ \\mathbf{Z}^T \\boldsymbol{\\Sigma}^{1/2}`.
621
+
595
622
  Examples
596
623
  --------
597
624
 
@@ -602,16 +629,47 @@ class DeformedMarchenkoPastur(object):
602
629
  >>> A = mp.matrix(2000)
603
630
  """
604
631
 
605
- # Parameters
606
- # m = int(size / self.lam)
607
- #
608
- # # Generate random matrix X (n x m) with i.i.d.
609
- # rng = numpy.random.default_rng(seed)
610
- # X = rng.standard_normal((size, m))
611
- #
612
- # # Form the sample covariance matrix A = (1/m)*XX^T.
613
- # A = X @ X.T / m
614
- #
615
- # return A
616
-
617
- pass
632
+ n = int(size)
633
+ if n <= 0:
634
+ raise ValueError("size must be a positive integer.")
635
+
636
+ # Unpack parameters
637
+ t1 = float(self.t1)
638
+ t2 = float(self.t2)
639
+ w1 = float(self.w1)
640
+ c = float(self.c)
641
+
642
+ rng = numpy.random.default_rng(seed)
643
+
644
+ # Choose m so that n/m approx c (for c>0). For c=0, return population
645
+ # Sigma.
646
+ if c == 0.0:
647
+ n1 = int(round(w1 * n))
648
+ n1 = max(0, min(n, n1))
649
+ d = numpy.empty(n, dtype=numpy.float64)
650
+ d[:n1] = t1
651
+ d[n1:] = t2
652
+ rng.shuffle(d)
653
+ return numpy.diag(d)
654
+
655
+ # m must be positive integer
656
+ m = int(round(n / c)) if c > 0.0 else n
657
+ m = max(1, m)
658
+
659
+ # Build diagonal Sigma^{1/2} with two atoms
660
+ n1 = int(round(w1 * n))
661
+ n1 = max(0, min(n, n1))
662
+
663
+ s = numpy.empty(n, dtype=numpy.float64)
664
+ s[:n1] = numpy.sqrt(t1)
665
+ s[n1:] = numpy.sqrt(t2)
666
+ rng.shuffle(s)
667
+
668
+ # Draw Z and form X = Sigma^{1/2} Z / sqrt(m)
669
+ Z = rng.standard_normal((n, m))
670
+ X = (s[:, None] * Z) / numpy.sqrt(m)
671
+
672
+ # Sample covariance
673
+ S = X @ X.T
674
+
675
+ return S
@@ -35,6 +35,9 @@ class DeformedWigner(object):
35
35
  Initialization.
36
36
  """
37
37
 
38
+ if not (0.0 <= w1 <= 1.0):
39
+ raise ValueError("w1 must be in [0, 1].")
40
+
38
41
  self.t1 = t1
39
42
  self.t2 = t2
40
43
  self.w1 = w1
@@ -287,26 +290,53 @@ class DeformedWigner(object):
287
290
  A : numpy.ndarray
288
291
  A matrix of the size :math:`n \\times n`.
289
292
 
293
+ Notes
294
+ -----
295
+
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}`.
301
+
290
302
  Examples
291
303
  --------
292
304
 
293
305
  .. code-block::python
294
306
 
295
- >>> from freealg.distributions import MarchenkoPastur
296
- >>> mp = MarchenkoPastur(1/50)
297
- >>> A = mp.matrix(2000)
307
+ >>> from freealg.distributions import DeformedWigner
308
+ >>> dwg = DeformedWigner(1/50)
309
+ >>> A = dwg.matrix(2000)
298
310
  """
299
311
 
300
- # Parameters
301
- # m = int(size / self.lam)
302
- #
303
- # # Generate random matrix X (n x m) with i.i.d.
304
- # rng = numpy.random.default_rng(seed)
305
- # X = rng.standard_normal((size, m))
306
- #
307
- # # Form the sample covariance matrix A = (1/m)*XX^T.
308
- # A = X @ X.T / m
309
- #
310
- # return A
311
-
312
- pass
312
+ n = int(size)
313
+ if n <= 0:
314
+ raise ValueError("size must be a positive integer.")
315
+
316
+ # Unpack parameters
317
+ t1 = float(self.t1)
318
+ t2 = float(self.t2)
319
+ w1 = float(self.w1)
320
+ sigma = float(self.sigma)
321
+
322
+ # RNG
323
+ rng = numpy.random.default_rng(seed)
324
+
325
+ # T part
326
+ n1 = int(round(w1 * n))
327
+ n1 = max(0, min(n, n1))
328
+
329
+ d = numpy.empty(n, dtype=numpy.float64)
330
+ d[:n1] = t1
331
+ d[n1:] = t2
332
+ rng.shuffle(d) # randomize positions
333
+ T = numpy.diag(d)
334
+
335
+ # W part: Symmetric Wigner with variance 1/n (up to symmetry)
336
+ G = rng.standard_normal((n, n))
337
+ W = (G + G.T) * (0.5 / numpy.sqrt(n))
338
+
339
+ # Compose
340
+ A = T + sigma * W
341
+
342
+ return A
@@ -13,7 +13,7 @@
13
13
 
14
14
  import numpy
15
15
  from scipy.interpolate import interp1d
16
- from .._freeform._plot_util import plot_density, plot_hilbert, \
16
+ from .._free_form._plot_util import plot_density, plot_hilbert, \
17
17
  plot_stieltjes, plot_stieltjes_on_disk, plot_samples
18
18
 
19
19
  try:
@@ -13,7 +13,7 @@
13
13
 
14
14
  import numpy
15
15
  from scipy.interpolate import interp1d
16
- from .._freeform._plot_util import plot_density, plot_hilbert, \
16
+ from .._free_form._plot_util import plot_density, plot_hilbert, \
17
17
  plot_stieltjes, plot_stieltjes_on_disk, plot_samples
18
18
  from ..visualization import glue_branches
19
19
 
@@ -13,7 +13,7 @@
13
13
 
14
14
  import numpy
15
15
  from scipy.interpolate import interp1d
16
- from .._freeform._plot_util import plot_density, plot_hilbert, \
16
+ from .._free_form._plot_util import plot_density, plot_hilbert, \
17
17
  plot_stieltjes, plot_stieltjes_on_disk, plot_samples
18
18
 
19
19
  try:
@@ -13,7 +13,7 @@
13
13
 
14
14
  import numpy
15
15
  from scipy.interpolate import interp1d
16
- from .._freeform._plot_util import plot_density, plot_hilbert, \
16
+ from .._free_form._plot_util import plot_density, plot_hilbert, \
17
17
  plot_stieltjes, plot_stieltjes_on_disk, plot_samples
18
18
 
19
19
  try:
@@ -13,7 +13,7 @@
13
13
 
14
14
  import numpy
15
15
  from scipy.interpolate import interp1d
16
- from .._freeform._plot_util import plot_density, plot_hilbert, \
16
+ from .._free_form._plot_util import plot_density, plot_hilbert, \
17
17
  plot_stieltjes, plot_stieltjes_on_disk, plot_samples
18
18
 
19
19
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: freealg
3
- Version: 0.7.1
3
+ Version: 0.7.4
4
4
  Summary: Free probability for large matrices
5
5
  Home-page: https://github.com/ameli/freealg
6
6
  Download-URL: https://github.com/ameli/freealg/archive/main.zip
@@ -0,0 +1,49 @@
1
+ freealg/__init__.py,sha256=SjcYb6HWmaclnnM-m1eC1honZRyfNBWYDYBx23kSdjo,833
2
+ freealg/__version__.py,sha256=A6fZ_oURo3l_Fa_K29LgV21A4Onqu3NquwGYzL05E1Y,22
3
+ freealg/_util.py,sha256=E254DRTCeST7h1QHrfLeyg9jQntRaOyui1oXD7nMaWQ,1890
4
+ freealg/_algebraic_form/__init__.py,sha256=MIB_jVgw2qI-JW_ypqaFSeNAB6c4GvpjNySnap_a6hg,398
5
+ freealg/_algebraic_form/_continuation_algebraic.py,sha256=q81HNWG6sLx05Gbbpqi1LBI7Y7cxT-1F7uLMyRapAfI,14237
6
+ freealg/_algebraic_form/_decompress.py,sha256=gGtixLOVxlMy5S-NsXgoA7lIrB7u7nUZImQk1mIDo3s,21101
7
+ freealg/_algebraic_form/_decompress2.py,sha256=Ng9w9xmGe9M-DApp35IeNeQlvszfzT4NZx5BQn0lQ3I,2459
8
+ freealg/_algebraic_form/_edge.py,sha256=7l9QyLJDxaEY4WB6MCUFtfEZSf04wyHwH7YPHFJXSbM,10690
9
+ freealg/_algebraic_form/_homotopy.py,sha256=VIAa3ijwm4coZBXBPA_Tp__yCRcvEyipai7tOmvcthU,3989
10
+ freealg/_algebraic_form/_sheets_util.py,sha256=6OLzWQKu-gN8rxM2rbpbN8TjNZFmD8UJ-8t9kcZdkCo,4174
11
+ freealg/_algebraic_form/algebraic_form.py,sha256=mok3Jta_K0Vo1caAm0fI81LNgs0eB3CKM5RzZLEFPY4,30499
12
+ freealg/_free_form/__init__.py,sha256=5cnSX7kHci3wKx6-BEFhmVY_NjjmQAq1JjWPTEqETTg,611
13
+ freealg/_free_form/_chebyshev.py,sha256=zkyVA8NLf7uUKlJdLz4ijd_SurdsqUgkA5nHGWSybaE,6916
14
+ freealg/_free_form/_damp.py,sha256=k2vtBtWOxQBf4qXaWu_En81lQBXbEO4QbxxWpvuVhdE,1802
15
+ freealg/_free_form/_decompress.py,sha256=_i37IToZ6oN9DdLXOM8r4y92EbazzcylhcnWwUOpaj0,32108
16
+ freealg/_free_form/_density_util.py,sha256=C_0lKA5QzKAdxPRLJvajNO9zaw2QliZ-n7SI8g2a53M,6745
17
+ freealg/_free_form/_jacobi.py,sha256=z0X6Ws_BEo_h8EQBzDNHGFhLF9F2PUmnGeBVs0bNL7w,10709
18
+ freealg/_free_form/_linalg.py,sha256=GNiQpT193VWxLOejVdAUPQdNJas4ms8US3YR8ZaYXGA,13143
19
+ freealg/_free_form/_pade.py,sha256=_y89r7rVc2E5lgiN_ZjnxzW2IaVevWwpq5ISor2NVOo,10310
20
+ freealg/_free_form/_plot_util.py,sha256=GKvmc1wjVGeqoomrULPbzBEt6P86FdoR2idBLYh5EDY,20068
21
+ freealg/_free_form/_sample.py,sha256=rhfd_83TCTvvJh8cG8TzEYO4OR8VbtND2YCNtWEhMa8,3205
22
+ freealg/_free_form/_series.py,sha256=33LLCUe4svmV0eWyzhP_XClfDzccQHTW9WBJlYlLfHY,11475
23
+ freealg/_free_form/_support.py,sha256=B6oSqW7MGikpJlTGzNbnMF63LhI5al2ccToqcncTPYs,6624
24
+ freealg/_free_form/free_form.py,sha256=UaRLYSvA0ib5wy1xnLy3_9ndCJ6gUdhNswSm0m9-7go,43571
25
+ freealg/_geometric_form/__init__.py,sha256=mWsXP0nXs3pY8RfUDhPRTgIfhOigKqw_VmoWnJOw2a0,485
26
+ freealg/_geometric_form/_continuation_genus0.py,sha256=4jiXfQaA6w3IhVkJgtKVVjqqtBmavq78FY_YTGUQyY0,4026
27
+ freealg/_geometric_form/_continuation_genus1.py,sha256=X8NZ1_6PxhJJLXZk5ASeGwxej_KwH3-ftuXkBrOFmgU,6021
28
+ freealg/_geometric_form/_elliptic_functions.py,sha256=Rr_pb1A_FjrJlraYQj2G5shdO6f77aVQN2eQzrvIygI,4109
29
+ freealg/_geometric_form/_sphere_maps.py,sha256=NlhTgWXKWXKdyR2dQxMmePsIwHp7IWyYh6uoxgW5Osc,1465
30
+ freealg/_geometric_form/_torus_maps.py,sha256=7m5QsbmnXTWHJE5rWjKG3_TnErHEEQ41vW-3hsOc3lo,3338
31
+ freealg/_geometric_form/geometric_form.py,sha256=whHKYQdakqShtR-jCEugevnje72JEr9M0HSvZ2BYoKs,33379
32
+ freealg/distributions/__init__.py,sha256=POoSAPVazz83y79pfdKeevPtKqpSATNb8S3ocYMdEzI,798
33
+ freealg/distributions/_chiral_block.py,sha256=YSC_Sk1u1UKlWVE1GGJEjX6VrWqpEEYNxBZ2j8Csc3A,13897
34
+ freealg/distributions/_deformed_marchenko_pastur.py,sha256=ov7mIqEj5I5i9euzTSBSng8BrryxVDUhi3hYNah53bI,19394
35
+ freealg/distributions/_deformed_wigner.py,sha256=9rekAGCKSTEWvMP0l25Lor60p4Gq2oxJuxHXmcJJ1AE,8046
36
+ freealg/distributions/_kesten_mckay.py,sha256=Uv3QuUYsfXbPMovXSO_pN3wdkc1fTKGVX7iuHDgBRqk,20089
37
+ freealg/distributions/_marchenko_pastur.py,sha256=eemaxDosKpV37TAn9uSiYpljIkVNoTWDJ9ZfYb8tAeY,20646
38
+ freealg/distributions/_meixner.py,sha256=GbcWeHrXMxK3Hdj4pCTESlMts9dEPQE1DhClxYprWfg,17590
39
+ freealg/distributions/_wachter.py,sha256=5nP4iqxgxltEHhZdb1ytei1zy_bDEI1cvldZdxlIXRk,17090
40
+ freealg/distributions/_wigner.py,sha256=epgx6ne6R_7to5j6-QsWIAVFJQFquWMmYgnZYMN4wUI,16069
41
+ freealg/visualization/__init__.py,sha256=NLq_zwueF7ytZ8sl8zLPqm-AODxxXNvfMozHGmmklcE,435
42
+ freealg/visualization/_glue_util.py,sha256=2oKnEYjUOS4OZfivmciVLauVr53kyHMwi6c2zRKilTQ,693
43
+ freealg/visualization/_rgb_hsv.py,sha256=rEskxXxSlKKxIrHRslVkgxHtD010L3ge9YtcVsOPl8E,3650
44
+ freealg-0.7.4.dist-info/licenses/AUTHORS.txt,sha256=0b67Nz4_JgIzUupHJTAZxu5QdSUM_HRM_X_w4xCb17o,30
45
+ freealg-0.7.4.dist-info/licenses/LICENSE.txt,sha256=J-EEYEtxb3VVf_Bn1TYfWnpY5lMFIM15iLDDcnaDTPA,1443
46
+ freealg-0.7.4.dist-info/METADATA,sha256=PbWMFiZoF0N2_Z5HONh85lI2oGnKzC5k57SklP4UZMc,5516
47
+ freealg-0.7.4.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
48
+ freealg-0.7.4.dist-info/top_level.txt,sha256=eR2wrgYwDdnnJ9Zf5PruPqe4kQav0GMvRsqct6y00Q8,8
49
+ freealg-0.7.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,47 +0,0 @@
1
- freealg/__init__.py,sha256=ApA8Dl6Sm29NN_hrT-YRmLFLhrXWEb5N1mc0e0_tDDE,832
2
- freealg/__version__.py,sha256=2KJZDSMOG7KS82AxYOrZ4ZihYxX0wjfUjDsIZh3L024,22
3
- freealg/_util.py,sha256=E254DRTCeST7h1QHrfLeyg9jQntRaOyui1oXD7nMaWQ,1890
4
- freealg/_algebraic_form/__init__.py,sha256=MIB_jVgw2qI-JW_ypqaFSeNAB6c4GvpjNySnap_a6hg,398
5
- freealg/_algebraic_form/_continuation_algebraic.py,sha256=y2ZKppTM41SBmhD3AsPN02c-MIuJWwrH1EqG385aOdY,13036
6
- freealg/_algebraic_form/_decompress.py,sha256=gGtixLOVxlMy5S-NsXgoA7lIrB7u7nUZImQk1mIDo3s,21101
7
- freealg/_algebraic_form/_edge.py,sha256=7l9QyLJDxaEY4WB6MCUFtfEZSf04wyHwH7YPHFJXSbM,10690
8
- freealg/_algebraic_form/_sheets_util.py,sha256=6OLzWQKu-gN8rxM2rbpbN8TjNZFmD8UJ-8t9kcZdkCo,4174
9
- freealg/_algebraic_form/algebraic_form.py,sha256=MFWS-zxacFprUWgFWDNdygIk4GFU6Bp-Ed_ns4wVBmk,28298
10
- freealg/_freeform/__init__.py,sha256=fxHAqlCBK0AqLrK9VhA3FMeid8nutCy5UwsUSgkIhrI,610
11
- freealg/_freeform/_chebyshev.py,sha256=zkyVA8NLf7uUKlJdLz4ijd_SurdsqUgkA5nHGWSybaE,6916
12
- freealg/_freeform/_damp.py,sha256=k2vtBtWOxQBf4qXaWu_En81lQBXbEO4QbxxWpvuVhdE,1802
13
- freealg/_freeform/_decompress.py,sha256=_i37IToZ6oN9DdLXOM8r4y92EbazzcylhcnWwUOpaj0,32108
14
- freealg/_freeform/_density_util.py,sha256=C_0lKA5QzKAdxPRLJvajNO9zaw2QliZ-n7SI8g2a53M,6745
15
- freealg/_freeform/_jacobi.py,sha256=z0X6Ws_BEo_h8EQBzDNHGFhLF9F2PUmnGeBVs0bNL7w,10709
16
- freealg/_freeform/_linalg.py,sha256=U7b_FJwfjU1itO4R4K831Zm2rnUB5eNOdOzvjPSeH98,13142
17
- freealg/_freeform/_pade.py,sha256=_y89r7rVc2E5lgiN_ZjnxzW2IaVevWwpq5ISor2NVOo,10310
18
- freealg/_freeform/_plot_util.py,sha256=GKvmc1wjVGeqoomrULPbzBEt6P86FdoR2idBLYh5EDY,20068
19
- freealg/_freeform/_sample.py,sha256=rhfd_83TCTvvJh8cG8TzEYO4OR8VbtND2YCNtWEhMa8,3205
20
- freealg/_freeform/_series.py,sha256=33LLCUe4svmV0eWyzhP_XClfDzccQHTW9WBJlYlLfHY,11475
21
- freealg/_freeform/_support.py,sha256=nxDa2OFlWBgjD0_1qoSMWG7kub6-GIuxIA04n5bdaYw,6614
22
- freealg/_freeform/freeform.py,sha256=UaRLYSvA0ib5wy1xnLy3_9ndCJ6gUdhNswSm0m9-7go,43571
23
- freealg/_geometric_form/__init__.py,sha256=mWsXP0nXs3pY8RfUDhPRTgIfhOigKqw_VmoWnJOw2a0,485
24
- freealg/_geometric_form/_continuation_genus0.py,sha256=4jiXfQaA6w3IhVkJgtKVVjqqtBmavq78FY_YTGUQyY0,4026
25
- freealg/_geometric_form/_continuation_genus1.py,sha256=X8NZ1_6PxhJJLXZk5ASeGwxej_KwH3-ftuXkBrOFmgU,6021
26
- freealg/_geometric_form/_elliptic_functions.py,sha256=Rr_pb1A_FjrJlraYQj2G5shdO6f77aVQN2eQzrvIygI,4109
27
- freealg/_geometric_form/_sphere_maps.py,sha256=NlhTgWXKWXKdyR2dQxMmePsIwHp7IWyYh6uoxgW5Osc,1465
28
- freealg/_geometric_form/_torus_maps.py,sha256=7m5QsbmnXTWHJE5rWjKG3_TnErHEEQ41vW-3hsOc3lo,3338
29
- freealg/_geometric_form/geometric_form.py,sha256=whHKYQdakqShtR-jCEugevnje72JEr9M0HSvZ2BYoKs,33379
30
- freealg/distributions/__init__.py,sha256=POoSAPVazz83y79pfdKeevPtKqpSATNb8S3ocYMdEzI,798
31
- freealg/distributions/_chiral_block.py,sha256=NxwD-2qx7-ewg5TwMALnPoesUNIWPDktXhyH8RSKi2w,12350
32
- freealg/distributions/_deformed_marchenko_pastur.py,sha256=cZN3XnAxK4L2zkteE4XL5rlslRz34ArUlInc9TzQIZA,17568
33
- freealg/distributions/_deformed_wigner.py,sha256=ZC7dj-ViSxaYdHRs45Yx6vf9Yw0WaTm4qZ7FumE0EEo,7239
34
- freealg/distributions/_kesten_mckay.py,sha256=Abnpz7cRUPvReqbkfXvOh7onrjjvuLDdUUx3wFpu1yA,20088
35
- freealg/distributions/_marchenko_pastur.py,sha256=G8nzyeZ2kfNIHfv4D2p0uN_9_0Z98JqKvr9PvV9k4o8,20645
36
- freealg/distributions/_meixner.py,sha256=oxtXpFhEnehPuGHp8d0XEdGCGwmP_KoNJABZRV5GgcQ,17589
37
- freealg/distributions/_wachter.py,sha256=qn8-_vBoCcpOtsuxXZK6vGd8XABqAgT5wO5FmoSvrc8,17089
38
- freealg/distributions/_wigner.py,sha256=C8pTM0LMrU79TYIVRvcgPUACG9mwRzMRajS-98YNHPw,16068
39
- freealg/visualization/__init__.py,sha256=NLq_zwueF7ytZ8sl8zLPqm-AODxxXNvfMozHGmmklcE,435
40
- freealg/visualization/_glue_util.py,sha256=2oKnEYjUOS4OZfivmciVLauVr53kyHMwi6c2zRKilTQ,693
41
- freealg/visualization/_rgb_hsv.py,sha256=rEskxXxSlKKxIrHRslVkgxHtD010L3ge9YtcVsOPl8E,3650
42
- freealg-0.7.1.dist-info/licenses/AUTHORS.txt,sha256=0b67Nz4_JgIzUupHJTAZxu5QdSUM_HRM_X_w4xCb17o,30
43
- freealg-0.7.1.dist-info/licenses/LICENSE.txt,sha256=J-EEYEtxb3VVf_Bn1TYfWnpY5lMFIM15iLDDcnaDTPA,1443
44
- freealg-0.7.1.dist-info/METADATA,sha256=xd4C9NmSiyjjLBVQjxFqzMx8VVpQ2rCK-x4tD55afEs,5516
45
- freealg-0.7.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
46
- freealg-0.7.1.dist-info/top_level.txt,sha256=eR2wrgYwDdnnJ9Zf5PruPqe4kQav0GMvRsqct6y00Q8,8
47
- freealg-0.7.1.dist-info/RECORD,,
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