freealg 0.1.11__py3-none-any.whl → 0.7.12__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 (59) hide show
  1. freealg/__init__.py +8 -2
  2. freealg/__version__.py +1 -1
  3. freealg/_algebraic_form/__init__.py +12 -0
  4. freealg/_algebraic_form/_branch_points.py +288 -0
  5. freealg/_algebraic_form/_constraints.py +139 -0
  6. freealg/_algebraic_form/_continuation_algebraic.py +706 -0
  7. freealg/_algebraic_form/_decompress.py +641 -0
  8. freealg/_algebraic_form/_decompress2.py +204 -0
  9. freealg/_algebraic_form/_edge.py +330 -0
  10. freealg/_algebraic_form/_homotopy.py +323 -0
  11. freealg/_algebraic_form/_moments.py +448 -0
  12. freealg/_algebraic_form/_sheets_util.py +145 -0
  13. freealg/_algebraic_form/_support.py +309 -0
  14. freealg/_algebraic_form/algebraic_form.py +1232 -0
  15. freealg/_free_form/__init__.py +16 -0
  16. freealg/{_chebyshev.py → _free_form/_chebyshev.py} +75 -43
  17. freealg/_free_form/_decompress.py +993 -0
  18. freealg/_free_form/_density_util.py +243 -0
  19. freealg/_free_form/_jacobi.py +359 -0
  20. freealg/_free_form/_linalg.py +508 -0
  21. freealg/{_pade.py → _free_form/_pade.py} +42 -208
  22. freealg/{_plot_util.py → _free_form/_plot_util.py} +37 -22
  23. freealg/{_sample.py → _free_form/_sample.py} +58 -22
  24. freealg/_free_form/_series.py +454 -0
  25. freealg/_free_form/_support.py +214 -0
  26. freealg/_free_form/free_form.py +1362 -0
  27. freealg/_geometric_form/__init__.py +13 -0
  28. freealg/_geometric_form/_continuation_genus0.py +175 -0
  29. freealg/_geometric_form/_continuation_genus1.py +275 -0
  30. freealg/_geometric_form/_elliptic_functions.py +174 -0
  31. freealg/_geometric_form/_sphere_maps.py +63 -0
  32. freealg/_geometric_form/_torus_maps.py +118 -0
  33. freealg/_geometric_form/geometric_form.py +1094 -0
  34. freealg/_util.py +56 -110
  35. freealg/distributions/__init__.py +7 -1
  36. freealg/distributions/_chiral_block.py +494 -0
  37. freealg/distributions/_deformed_marchenko_pastur.py +726 -0
  38. freealg/distributions/_deformed_wigner.py +386 -0
  39. freealg/distributions/_kesten_mckay.py +29 -15
  40. freealg/distributions/_marchenko_pastur.py +224 -95
  41. freealg/distributions/_meixner.py +47 -37
  42. freealg/distributions/_wachter.py +29 -17
  43. freealg/distributions/_wigner.py +27 -14
  44. freealg/visualization/__init__.py +12 -0
  45. freealg/visualization/_glue_util.py +32 -0
  46. freealg/visualization/_rgb_hsv.py +125 -0
  47. freealg-0.7.12.dist-info/METADATA +172 -0
  48. freealg-0.7.12.dist-info/RECORD +53 -0
  49. {freealg-0.1.11.dist-info → freealg-0.7.12.dist-info}/WHEEL +1 -1
  50. freealg/_decompress.py +0 -180
  51. freealg/_jacobi.py +0 -218
  52. freealg/_support.py +0 -85
  53. freealg/freeform.py +0 -967
  54. freealg-0.1.11.dist-info/METADATA +0 -140
  55. freealg-0.1.11.dist-info/RECORD +0 -24
  56. /freealg/{_damp.py → _free_form/_damp.py} +0 -0
  57. {freealg-0.1.11.dist-info → freealg-0.7.12.dist-info}/licenses/AUTHORS.txt +0 -0
  58. {freealg-0.1.11.dist-info → freealg-0.7.12.dist-info}/licenses/LICENSE.txt +0 -0
  59. {freealg-0.1.11.dist-info → freealg-0.7.12.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,16 @@
1
+ # SPDX-FileCopyrightText: Copyright 2025, Siavash Ameli <sameli@berkeley.edu>
2
+ # SPDX-License-Identifier: BSD-3-Clause
3
+ # SPDX-FileType: SOURCE
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify it
6
+ # under the terms of the license found in the LICENSE.txt file in the root
7
+ # directory of this source tree.
8
+
9
+ from .free_form import FreeForm
10
+ from ._linalg import eigvalsh, cond, norm, trace, slogdet
11
+ from ._support import supp
12
+ from ._sample import sample
13
+ from ._density_util import kde
14
+
15
+ __all__ = ['FreeForm', 'eigvalsh', 'cond', 'norm', 'trace', 'slogdet', 'supp',
16
+ 'sample', 'kde']
@@ -13,10 +13,11 @@
13
13
 
14
14
  import numpy
15
15
  from scipy.special import eval_chebyu
16
- from ._pade import wynn_pade
16
+ from ._series import partial_sum, wynn_epsilon, wynn_rho, levin_u, \
17
+ weniger_delta, brezinski_theta
17
18
 
18
19
  __all__ = ['chebyshev_sample_proj', 'chebyshev_kernel_proj',
19
- 'chebyshev_approx', 'chebyshev_stieltjes']
20
+ 'chebyshev_density', 'chebyshev_stieltjes']
20
21
 
21
22
 
22
23
  # =====================
@@ -29,7 +30,7 @@ def chebyshev_sample_proj(eig, support, K=10, reg=0.0):
29
30
 
30
31
  \\rho(x) = w(t) \\sum_{k=0}^K \\psi_k U_k(t),
31
32
 
32
- where t = (2x(\\lambda_{-} + \\lambda_{+}))/ (\\lambda_{+} - \\lambda_{-})
33
+ where t = (2x-(\\lambda_{-} + \\lambda_{+}))/ (\\lambda_{+} - \\lambda_{-})
33
34
  in [-1, 1] and w(t) = \\sqrt{(1 - t^2}.
34
35
 
35
36
  Parameters
@@ -42,10 +43,10 @@ def chebyshev_sample_proj(eig, support, K=10, reg=0.0):
42
43
  The assumed compact support of rho.
43
44
 
44
45
  K : int
45
- Highest ChebyshevII order.
46
+ Highest Chebyshev-II order.
46
47
 
47
48
  reg : float
48
- Tikhonovstyle ridge on each coefficient (defaults to 0).
49
+ Tikhonov-style ridge on each coefficient (defaults to 0).
49
50
 
50
51
  Returns
51
52
  -------
@@ -56,11 +57,10 @@ def chebyshev_sample_proj(eig, support, K=10, reg=0.0):
56
57
 
57
58
  lam_m, lam_p = support
58
59
 
59
- # Map to [1,1] interval
60
+ # Map to [-1,1] interval
60
61
  t = (2 * eig - (lam_m + lam_p)) / (lam_p - lam_m)
61
- N = eig.size
62
62
 
63
- # Innerproduct norm of each U_k under w(t) = sqrt{1t^2} is \\pi/2
63
+ # Inner-product norm of each U_k under w(t) = sqrt{1-t^2} is \\pi/2
64
64
  norm = numpy.pi / 2
65
65
 
66
66
  psi = numpy.empty(K+1)
@@ -92,19 +92,19 @@ def chebyshev_kernel_proj(xs, pdf, support, K=10, reg=0.0):
92
92
  Projection of a *continuous* density given on a grid (xs, pdf)
93
93
  onto the Chebyshev-II basis.
94
94
 
95
- xs : 1-D numpy array (original xaxis, not the t-variable)
95
+ xs : 1-D numpy array (original x-axis, not the t-variable)
96
96
  pdf : same shape as xs, integrates to 1 on xs
97
97
  """
98
98
 
99
99
  lam_m, lam_p = support
100
- t = (2.0 * xs - (lam_m + lam_p)) / (lam_p - lam_m) # map to [1,1]
100
+ t = (2.0 * xs - (lam_m + lam_p)) / (lam_p - lam_m) # map to [-1,1]
101
101
 
102
102
  norm = numpy.pi / 2.0
103
103
  psi = numpy.empty(K + 1)
104
104
 
105
105
  for k in range(K + 1):
106
106
  Pk = eval_chebyu(k, t) # U_k(t) on the grid
107
- moment = numpy.trapezoid(Pk * pdf, xs) # \int U_k(t) \rho(x) dx
107
+ moment = numpy.trapezoid(Pk * pdf, xs) # \int U_k(t) \rho(x) dx
108
108
 
109
109
  if k == 0:
110
110
  penalty = 0
@@ -116,11 +116,11 @@ def chebyshev_kernel_proj(xs, pdf, support, K=10, reg=0.0):
116
116
  return psi
117
117
 
118
118
 
119
- # ================
120
- # chebyshev approx
121
- # ================
119
+ # =================
120
+ # chebyshev density
121
+ # =================
122
122
 
123
- def chebyshev_approx(x, psi, support):
123
+ def chebyshev_density(x, psi, support):
124
124
  """
125
125
  Given \\psi_k, evaluate the approximate density \\rho(x).
126
126
 
@@ -140,15 +140,15 @@ def chebyshev_approx(x, psi, support):
140
140
  -------
141
141
 
142
142
  rho_x : ndarray, same shape as x
143
- Approximated spectral density on the original xaxis.
143
+ Approximated spectral density on the original x-axis.
144
144
  """
145
145
 
146
146
  lam_m, lam_p = support
147
147
 
148
- # Map to [1,1] interval
148
+ # Map to [-1,1] interval
149
149
  t = (2 * numpy.asarray(x) - (lam_m + lam_p)) / (lam_p - lam_m)
150
150
 
151
- # Weight sqrt{1t^2} (clip for numerical safety)
151
+ # Weight sqrt{1-t^2} (clip for numerical safety)
152
152
  w = numpy.sqrt(numpy.clip(1 - t**2, a_min=0, a_max=None))
153
153
 
154
154
  # Summation approximation
@@ -165,22 +165,23 @@ def chebyshev_approx(x, psi, support):
165
165
  # chebushev stieltjes
166
166
  # ===================
167
167
 
168
- def chebyshev_stieltjes(z, psi, support):
168
+ def chebyshev_stieltjes(z, psi, support, continuation='pade',
169
+ dtype=numpy.complex128):
169
170
  """
170
- Compute the Stieltjes transform m(z) for a ChebyshevII expansion
171
+ Compute the Stieltjes transform m(z) for a Chebyshev-II expansion
171
172
 
172
- rho(x) = (2/(lam_p - lam_m)) * sqrt(1t(x)^2) * sum_{k=0}^K psi_k U_k(t(x))
173
+ rho(x) = (2/(lam_p - lam_m)) * sqrt(1-t(x)^2) * sum_{k=0}^K psi_k U_k(t(x))
173
174
 
174
- via the closedform
175
+ via the closed-form
175
176
 
176
- \\int_{-1}^1 U_k(t) sqrt(1t^2)/(u - t) dt = \\pi J(u)^(k+1),
177
+ \\int_{-1}^1 U_k(t) sqrt(1-t^2)/(u - t) dt = \\pi J(u)^(k+1),
177
178
 
178
179
  where
179
180
 
180
- u = (2(zcenter))/span,
181
+ u = (2(z-center))/span,
181
182
  center = (lam_p + lam_m)/2,
182
183
  span = lam_p - lam_m,
183
- J(u) = u sqrt(u^21)
184
+ J(u) = u - sqrt(u^2-1)
184
185
 
185
186
  and then
186
187
 
@@ -193,11 +194,17 @@ def chebyshev_stieltjes(z, psi, support):
193
194
  Points in the complex plane.
194
195
 
195
196
  psi : array_like, shape (K+1,)
196
- ChebyshevII coefficients \\psi.
197
+ Chebyshev-II coefficients \\psi.
197
198
 
198
199
  support : tuple
199
200
  The support interval of the original density.
200
201
 
202
+ continuation : str, default= ``'pade'``
203
+ Methof of analytiv continuation.
204
+
205
+ dtype : numpy.type, default=numpy.complex128
206
+ Data type for complex arrays. This might enhance series acceleration.
207
+
201
208
  Returns
202
209
  -------
203
210
 
@@ -205,35 +212,60 @@ def chebyshev_stieltjes(z, psi, support):
205
212
  The Stieltjes transform m(z) on the same shape as z.
206
213
  """
207
214
 
208
- z = numpy.asarray(z, dtype=numpy.complex128)
215
+ z = numpy.asarray(z, dtype=dtype)
216
+
209
217
  lam_m, lam_p = support
210
218
  span = lam_p - lam_m
211
219
  center = 0.5 * (lam_m + lam_p)
212
220
 
213
- # map z -> u in the standard [-1,1] domain
221
+ # Map z to u in the standard [-1,1] domain
214
222
  u = (2.0 * (z - center)) / span
215
223
 
216
- # inverse-Joukowski: pick branch sqrt with +Im
217
- root = numpy.sqrt(u*u - 1)
224
+ # Inverse-Joukowski: pick branch sqrt with +Im
225
+ root = numpy.sqrt(u*u - 1.0)
218
226
  Jm = u - root
219
227
  Jp = u + root
220
228
 
221
229
  # Make sure J is Herglotz
222
- J = numpy.zeros_like(Jm)
223
- J = numpy.where(root.imag < 0, Jp, Jm)
224
-
225
- psi_zero = numpy.concatenate([[0], psi])
226
- S = wynn_pade(psi_zero, J)
230
+ J = numpy.zeros_like(Jp)
231
+ J = numpy.where(Jp.imag > 0, Jm, Jp)
232
+
233
+ # This depends on the method of analytic continuation
234
+ if continuation == 'pade':
235
+ # Horner summation for S0(J) = sum_{k=0}^K psi_k * J**k
236
+ K = len(psi) - 1
237
+ S0 = numpy.zeros_like(J)
238
+ for k in range(K, -1, -1):
239
+ S0 = psi[k] + J * S0
240
+ S = J * S0
241
+
242
+ else:
243
+ # Flatten J before passing to any of the acceleration methods.
244
+ psi_zero = numpy.concatenate([[0.0], psi])
245
+ Sn = partial_sum(psi_zero, J.ravel(), p=0)
246
+
247
+ if continuation == 'wynn-eps':
248
+ S = wynn_epsilon(Sn)
249
+ elif continuation == 'wynn-rho':
250
+ S = wynn_rho(Sn)
251
+ elif continuation == 'levin':
252
+ S = levin_u(Sn)
253
+ elif continuation == 'weniger':
254
+ S = weniger_delta(Sn)
255
+ elif continuation == 'brezinski':
256
+ S = brezinski_theta(Sn)
257
+ else:
258
+ raise NotImplementedError('"continuation" is invalid.')
227
259
 
228
- # build powers J^(k+1) for k=0..K
229
- #K = len(psi) - 1
230
- # shape: (..., K+1)
231
- #Jpow = J[..., None] ** numpy.arange(1, K+2)
260
+ S = S.reshape(J.shape)
232
261
 
233
- # sum psi_k * J^(k+1)
234
- #S = numpy.sum(psi * Jpow, axis=-1)
262
+ # Assemble m(z)
263
+ m_z = -(2.0 / span) * numpy.pi * S
235
264
 
236
- # assemble m(z)
237
- m_z = -2 / span * numpy.pi * S
265
+ # Check nan or inf
266
+ if numpy.any(numpy.isinf(m_z)):
267
+ raise RuntimeError('"m" is nan.')
268
+ elif numpy.any(numpy.isnan(numpy.abs(m_z))):
269
+ raise RuntimeError('"m" is inf.')
238
270
 
239
271
  return m_z