freealg 0.6.3__py3-none-any.whl → 0.7.1__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 (48) hide show
  1. freealg/__init__.py +8 -7
  2. freealg/__version__.py +1 -1
  3. freealg/_algebraic_form/__init__.py +11 -0
  4. freealg/_algebraic_form/_continuation_algebraic.py +503 -0
  5. freealg/_algebraic_form/_decompress.py +648 -0
  6. freealg/_algebraic_form/_edge.py +352 -0
  7. freealg/_algebraic_form/_sheets_util.py +145 -0
  8. freealg/_algebraic_form/algebraic_form.py +987 -0
  9. freealg/_freeform/__init__.py +16 -0
  10. freealg/_freeform/_density_util.py +243 -0
  11. freealg/{_linalg.py → _freeform/_linalg.py} +1 -1
  12. freealg/{freeform.py → _freeform/freeform.py} +2 -1
  13. freealg/_geometric_form/__init__.py +13 -0
  14. freealg/_geometric_form/_continuation_genus0.py +175 -0
  15. freealg/_geometric_form/_continuation_genus1.py +275 -0
  16. freealg/_geometric_form/_elliptic_functions.py +174 -0
  17. freealg/_geometric_form/_sphere_maps.py +63 -0
  18. freealg/_geometric_form/_torus_maps.py +118 -0
  19. freealg/_geometric_form/geometric_form.py +1094 -0
  20. freealg/_util.py +1 -228
  21. freealg/distributions/__init__.py +5 -1
  22. freealg/distributions/_chiral_block.py +440 -0
  23. freealg/distributions/_deformed_marchenko_pastur.py +617 -0
  24. freealg/distributions/_deformed_wigner.py +312 -0
  25. freealg/distributions/_kesten_mckay.py +2 -2
  26. freealg/distributions/_marchenko_pastur.py +199 -82
  27. freealg/distributions/_meixner.py +2 -2
  28. freealg/distributions/_wachter.py +2 -2
  29. freealg/distributions/_wigner.py +2 -2
  30. freealg/visualization/__init__.py +12 -0
  31. freealg/visualization/_glue_util.py +32 -0
  32. freealg/visualization/_rgb_hsv.py +125 -0
  33. {freealg-0.6.3.dist-info → freealg-0.7.1.dist-info}/METADATA +1 -1
  34. freealg-0.7.1.dist-info/RECORD +47 -0
  35. freealg-0.6.3.dist-info/RECORD +0 -26
  36. /freealg/{_chebyshev.py → _freeform/_chebyshev.py} +0 -0
  37. /freealg/{_damp.py → _freeform/_damp.py} +0 -0
  38. /freealg/{_decompress.py → _freeform/_decompress.py} +0 -0
  39. /freealg/{_jacobi.py → _freeform/_jacobi.py} +0 -0
  40. /freealg/{_pade.py → _freeform/_pade.py} +0 -0
  41. /freealg/{_plot_util.py → _freeform/_plot_util.py} +0 -0
  42. /freealg/{_sample.py → _freeform/_sample.py} +0 -0
  43. /freealg/{_series.py → _freeform/_series.py} +0 -0
  44. /freealg/{_support.py → _freeform/_support.py} +0 -0
  45. {freealg-0.6.3.dist-info → freealg-0.7.1.dist-info}/WHEEL +0 -0
  46. {freealg-0.6.3.dist-info → freealg-0.7.1.dist-info}/licenses/AUTHORS.txt +0 -0
  47. {freealg-0.6.3.dist-info → freealg-0.7.1.dist-info}/licenses/LICENSE.txt +0 -0
  48. {freealg-0.6.3.dist-info → freealg-0.7.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,312 @@
1
+ # SPDX-FileCopyrightText: Copyright 2026, 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
+
10
+ # =======
11
+ # Imports
12
+ # =======
13
+
14
+ import numpy
15
+ from .._algebraic_form._sheets_util import _pick_physical_root_scalar
16
+
17
+ __all__ = ['DeformedWigner']
18
+
19
+
20
+ # ===============
21
+ # Deformed Wigner
22
+ # ===============
23
+
24
+ class DeformedWigner(object):
25
+ """
26
+ Deformed Wiger
27
+ """
28
+
29
+ # ====
30
+ # init
31
+ # ====
32
+
33
+ def __init__(self, t1, t2, w1, sigma=1.0):
34
+ """
35
+ Initialization.
36
+ """
37
+
38
+ self.t1 = t1
39
+ self.t2 = t2
40
+ self.w1 = w1
41
+ self.sigma = sigma
42
+
43
+ # ==================
44
+ # roots cubic scalar
45
+ # ==================
46
+
47
+ def _roots_cubic_scalar(self, z):
48
+ """
49
+ """
50
+
51
+ # Unpack parameters
52
+ t1 = self.t1
53
+ t2 = self.t2
54
+ w1 = self.w1
55
+ sigma = self.sigma
56
+
57
+ w2 = 1.0 - w1
58
+ s2 = sigma * sigma
59
+ a1 = t1 - z
60
+ a2 = t2 - z
61
+
62
+ c3 = s2 * s2
63
+ c2 = -s2 * (a1 + a2)
64
+ c1 = (a1 * a2) + s2
65
+ c0 = -(w1 * a2 + w2 * a1)
66
+
67
+ return numpy.roots([c3, c2, c1, c0])
68
+
69
+ # =========
70
+ # stieltjes
71
+ # =========
72
+
73
+ def stieltjes(self, z, max_iter=100, tol=1e-12):
74
+ """
75
+ """
76
+
77
+ # Unpack parameters
78
+ t1 = self.t1
79
+ t2 = self.t2
80
+ w1 = self.w1
81
+ sigma = self.sigma
82
+
83
+ w2 = 1.0 - w1
84
+ s2 = sigma * sigma
85
+
86
+ z = numpy.asarray(z, dtype=numpy.complex128)
87
+ scalar = (z.ndim == 0)
88
+ if scalar:
89
+ z = z.reshape((1,))
90
+
91
+ m = -1.0 / z
92
+ active = numpy.isfinite(m)
93
+
94
+ for _ in range(int(max_iter)):
95
+ if not numpy.any(active):
96
+ break
97
+
98
+ ma = m[active]
99
+ za = z[active]
100
+
101
+ d1 = (t1 - za - s2 * ma)
102
+ d2 = (t2 - za - s2 * ma)
103
+
104
+ f = ma - (w1 / d1 + w2 / d2)
105
+ fp = 1.0 - (w1 * s2 / (d1 * d1) + w2 * s2 / (d2 * d2))
106
+
107
+ step = f / fp
108
+ ma2 = ma - step
109
+ m[active] = ma2
110
+
111
+ conv = numpy.abs(step) < tol * (1.0 + numpy.abs(ma2))
112
+ idx = numpy.where(active)[0]
113
+ active[idx[conv]] = False
114
+
115
+ sign = numpy.where(numpy.imag(z) >= 0.0, 1.0, -1.0)
116
+ bad = (sign * numpy.imag(m) <= 0.0) | (~numpy.isfinite(m))
117
+
118
+ if numpy.any(bad):
119
+ zf = z.ravel()
120
+ mf = m.ravel()
121
+ bad_idx = numpy.where(bad.ravel())[0]
122
+ for i in bad_idx:
123
+ r = self._roots_cubic_scalar(zf[i])
124
+ mf[i] = _pick_physical_root_scalar(zf[i], r)
125
+ m = mf.reshape(z.shape)
126
+
127
+ if scalar:
128
+ return m.reshape(())
129
+ return m
130
+
131
+ # =======
132
+ # density
133
+ # =======
134
+
135
+ def density(self, x, eta=1e-3):
136
+ """
137
+ """
138
+
139
+ # Unpack parameters
140
+ t1 = self.t1
141
+ t2 = self.t2
142
+ w1 = self.w1
143
+ sigma = self.sigma
144
+
145
+ x = numpy.asarray(x, dtype=numpy.float64)
146
+ z = x + 1j * float(eta)
147
+
148
+ zf = z.ravel()
149
+ m = numpy.empty_like(zf, dtype=numpy.complex128)
150
+
151
+ m_prev = None
152
+ for i in range(zf.size):
153
+ zi = zf[i]
154
+ if m_prev is None:
155
+ mi = -1.0 / zi
156
+ else:
157
+ mi = complex(m_prev)
158
+
159
+ for _ in range(80):
160
+ d1 = (t1 - zi - (sigma * sigma) * mi)
161
+ d2 = (t2 - zi - (sigma * sigma) * mi)
162
+
163
+ f = mi - (w1 / d1 + (1.0 - w1) / d2)
164
+ fp = 1.0 - (
165
+ w1 * (sigma * sigma) / (d1 * d1) +
166
+ (1.0 - w1) * (sigma * sigma) / (d2 * d2)
167
+ )
168
+
169
+ step = f / fp
170
+ mi2 = mi - step
171
+ if abs(step) < 1e-12 * (1.0 + abs(mi2)):
172
+ mi = mi2
173
+ break
174
+ mi = mi2
175
+
176
+ m[i] = mi
177
+ m_prev = mi
178
+
179
+ m = m.reshape(z.shape)
180
+ rho = numpy.imag(m) / numpy.pi
181
+ rho = numpy.maximum(rho, 0.0)
182
+ return rho
183
+
184
+ # =====
185
+ # roots
186
+ # =====
187
+
188
+ def roots(self, z):
189
+ """
190
+ """
191
+
192
+ z = numpy.asarray(z, dtype=numpy.complex128)
193
+ scalar = (z.ndim == 0)
194
+ if scalar:
195
+ z = z.reshape((1,))
196
+
197
+ zf = z.ravel()
198
+ out = numpy.empty((zf.size, 3), dtype=numpy.complex128)
199
+ for i in range(zf.size):
200
+ out[i, :] = self._roots_cubic_scalar(zf[i])
201
+
202
+ out = out.reshape(z.shape + (3,))
203
+ if scalar:
204
+ return out.reshape((3,))
205
+ return out
206
+
207
+ # =======
208
+ # support
209
+ # =======
210
+
211
+ def support(self, y_probe=1e-6):
212
+ """
213
+ """
214
+
215
+ # Unpack parameters
216
+ t1 = self.t1
217
+ t2 = self.t2
218
+ w1 = self.w1
219
+ sigma = self.sigma
220
+
221
+ w2 = 1.0 - w1
222
+
223
+ p_a = numpy.poly1d([-1.0, t1])
224
+ p_b = numpy.poly1d([-1.0, t2])
225
+
226
+ pa2 = p_a * p_a
227
+ pb2 = p_b * p_b
228
+
229
+ eq = pa2 * pb2 - (sigma * sigma) * (w1 * pb2 + w2 * pa2)
230
+ u_roots = numpy.roots(eq.coeffs)
231
+
232
+ ucrit = []
233
+ for r in u_roots:
234
+ if numpy.isfinite(r) and abs(r.imag) < 1e-10:
235
+ ucrit.append(float(r.real))
236
+ ucrit.sort()
237
+
238
+ def G(u):
239
+ return w1 / (t1 - u) + w2 / (t2 - u)
240
+
241
+ def z_of_u(u):
242
+ return u - (sigma * sigma) * G(u)
243
+
244
+ edges = []
245
+ for u in ucrit:
246
+ x = z_of_u(u)
247
+ if numpy.isfinite(x):
248
+ x = float(numpy.real(x))
249
+ if (len(edges) == 0) or (abs(x - edges[-1]) > 1e-8):
250
+ edges.append(x)
251
+
252
+ if len(edges) < 2:
253
+ return []
254
+
255
+ thr = 100.0 * float(y_probe)
256
+ cuts = []
257
+ for i in range(len(edges) - 1):
258
+ xm = 0.5 * (edges[i] + edges[i + 1])
259
+ z = xm + 1j * float(y_probe)
260
+ r = self._roots_cubic_scalar(z)
261
+ m = _pick_physical_root_scalar(z, r)
262
+ if numpy.imag(m) > thr:
263
+ cuts.append((edges[i], edges[i + 1]))
264
+
265
+ return cuts
266
+
267
+ # ======
268
+ # matrix
269
+ # ======
270
+
271
+ def matrix(self, size, seed=None):
272
+ """
273
+ Generate matrix with the spectral density of the distribution.
274
+
275
+ Parameters
276
+ ----------
277
+
278
+ size : int
279
+ Size :math:`n` of the matrix.
280
+
281
+ seed : int, default=None
282
+ Seed for random number generator.
283
+
284
+ Returns
285
+ -------
286
+
287
+ A : numpy.ndarray
288
+ A matrix of the size :math:`n \\times n`.
289
+
290
+ Examples
291
+ --------
292
+
293
+ .. code-block::python
294
+
295
+ >>> from freealg.distributions import MarchenkoPastur
296
+ >>> mp = MarchenkoPastur(1/50)
297
+ >>> A = mp.matrix(2000)
298
+ """
299
+
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
@@ -13,8 +13,8 @@
13
13
 
14
14
  import numpy
15
15
  from scipy.interpolate import interp1d
16
- from .._plot_util import plot_density, plot_hilbert, plot_stieltjes, \
17
- plot_stieltjes_on_disk, plot_samples
16
+ from .._freeform._plot_util import plot_density, plot_hilbert, \
17
+ plot_stieltjes, plot_stieltjes_on_disk, plot_samples
18
18
 
19
19
  try:
20
20
  from scipy.integrate import cumtrapz