freealg 0.7.11__py3-none-any.whl → 0.7.14__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.
- freealg/__init__.py +2 -2
- freealg/__version__.py +1 -1
- freealg/_algebraic_form/__init__.py +2 -1
- freealg/_algebraic_form/_constraints.py +53 -12
- freealg/_algebraic_form/_cusp.py +357 -0
- freealg/_algebraic_form/_cusp_wrap.py +268 -0
- freealg/_algebraic_form/_decompress.py +330 -381
- freealg/_algebraic_form/_decompress2.py +120 -0
- freealg/_algebraic_form/_decompress4.py +739 -0
- freealg/_algebraic_form/_decompress5.py +738 -0
- freealg/_algebraic_form/_decompress6.py +492 -0
- freealg/_algebraic_form/_decompress7.py +355 -0
- freealg/_algebraic_form/_decompress8.py +369 -0
- freealg/_algebraic_form/_decompress9.py +363 -0
- freealg/_algebraic_form/_decompress_new.py +431 -0
- freealg/_algebraic_form/_decompress_new_2.py +1631 -0
- freealg/_algebraic_form/_decompress_util.py +172 -0
- freealg/_algebraic_form/_edge.py +46 -68
- freealg/_algebraic_form/_homotopy.py +62 -30
- freealg/_algebraic_form/_homotopy2.py +289 -0
- freealg/_algebraic_form/_homotopy3.py +215 -0
- freealg/_algebraic_form/_homotopy4.py +320 -0
- freealg/_algebraic_form/_homotopy5.py +185 -0
- freealg/_algebraic_form/_moments.py +43 -57
- freealg/_algebraic_form/_support.py +132 -177
- freealg/_algebraic_form/algebraic_form.py +163 -30
- freealg/distributions/__init__.py +3 -1
- freealg/distributions/_compound_poisson.py +464 -0
- freealg/distributions/_deformed_marchenko_pastur.py +51 -0
- freealg/distributions/_deformed_wigner.py +44 -0
- {freealg-0.7.11.dist-info → freealg-0.7.14.dist-info}/METADATA +2 -1
- {freealg-0.7.11.dist-info → freealg-0.7.14.dist-info}/RECORD +36 -20
- {freealg-0.7.11.dist-info → freealg-0.7.14.dist-info}/WHEEL +1 -1
- {freealg-0.7.11.dist-info → freealg-0.7.14.dist-info}/licenses/AUTHORS.txt +0 -0
- {freealg-0.7.11.dist-info → freealg-0.7.14.dist-info}/licenses/LICENSE.txt +0 -0
- {freealg-0.7.11.dist-info → freealg-0.7.14.dist-info}/top_level.txt +0 -0
|
@@ -14,6 +14,8 @@ from ._meixner import Meixner
|
|
|
14
14
|
from ._chiral_block import ChiralBlock
|
|
15
15
|
from ._deformed_wigner import DeformedWigner
|
|
16
16
|
from ._deformed_marchenko_pastur import DeformedMarchenkoPastur
|
|
17
|
+
from ._compound_poisson import CompoundPoisson
|
|
17
18
|
|
|
18
19
|
__all__ = ['MarchenkoPastur', 'Wigner', 'KestenMcKay', 'Wachter', 'Meixner',
|
|
19
|
-
'ChiralBlock', 'DeformedWigner', 'DeformedMarchenkoPastur'
|
|
20
|
+
'ChiralBlock', 'DeformedWigner', 'DeformedMarchenkoPastur',
|
|
21
|
+
'CompoundPoisson']
|
|
@@ -0,0 +1,464 @@
|
|
|
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__ = ['CompoundPoisson']
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# ================
|
|
21
|
+
# Compound Poisson
|
|
22
|
+
# ================
|
|
23
|
+
|
|
24
|
+
class CompoundPoisson(object):
|
|
25
|
+
"""
|
|
26
|
+
Two-atom free compound Poisson model (MP-like, FD-closed).
|
|
27
|
+
|
|
28
|
+
Notes
|
|
29
|
+
-----
|
|
30
|
+
|
|
31
|
+
This model has atom at zero with mass :math:`\\max(1-e^{-\\lambda}, 0)`.
|
|
32
|
+
|
|
33
|
+
This model is the additive free compound Poisson law whose R-transform is
|
|
34
|
+
|
|
35
|
+
.. math::
|
|
36
|
+
|
|
37
|
+
R(w) = \\lambda \\left(
|
|
38
|
+
w_1 \\frac{a_1}{1-a_1 w} + (1-w_1) \\frac{a_2}{1-a_2 w}
|
|
39
|
+
\\right),
|
|
40
|
+
|
|
41
|
+
where :math:`\\lambda>0` is the total rate (intensity),
|
|
42
|
+
:math:`a_1,a_2>0` are jump sizes, and :math:`w_1 \\in (0,1)` is the mixture
|
|
43
|
+
weight for the first jump.
|
|
44
|
+
|
|
45
|
+
The Stieltjes transform :math:`m(z)` satisfies
|
|
46
|
+
|
|
47
|
+
.. math::
|
|
48
|
+
|
|
49
|
+
z = 1/m(z) + R(m(z)).
|
|
50
|
+
|
|
51
|
+
For two atoms, clearing denominators yields a cubic polynomial in
|
|
52
|
+
:math:`m`:
|
|
53
|
+
|
|
54
|
+
.. math::
|
|
55
|
+
|
|
56
|
+
a_3(z)m^3 + a_2(z)m^2 + a_1(z)m + a_0(z) = 0.
|
|
57
|
+
|
|
58
|
+
FD-closure (free decompression):
|
|
59
|
+
Under the FD rule that scales the argument of R, this family stays
|
|
60
|
+
closed by scaling the jump sizes: :math:`a_i(t) = e^{-t} a_i`
|
|
61
|
+
(keeping :math:`\\lambda,w_1` fixed). If your convention uses
|
|
62
|
+
:math:`R_t(w)=R_0(e^{+t}w)`, then use :math:`a_i(t)=e^{+t}a_i` instead.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
# ====
|
|
66
|
+
# init
|
|
67
|
+
# ====
|
|
68
|
+
|
|
69
|
+
def __init__(self, a1, a2, w1, lam):
|
|
70
|
+
"""
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
a1, a2 : float
|
|
74
|
+
Jump sizes (must be > 0). For PSD-like support, keep them > 0.
|
|
75
|
+
|
|
76
|
+
w1 : float
|
|
77
|
+
Mixture weight in (0, 1) for a1. Second weight is 1-w1.
|
|
78
|
+
|
|
79
|
+
lam : float
|
|
80
|
+
Total rate (intensity), must be > 0.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
a1 = float(a1)
|
|
84
|
+
a2 = float(a2)
|
|
85
|
+
w1 = float(w1)
|
|
86
|
+
lam = float(lam)
|
|
87
|
+
|
|
88
|
+
if a1 <= 0.0 or a2 <= 0.0:
|
|
89
|
+
raise ValueError("a1 and a2 must be > 0.")
|
|
90
|
+
|
|
91
|
+
if not (0.0 < w1 < 1.0):
|
|
92
|
+
raise ValueError("w1 must be in (0, 1).")
|
|
93
|
+
|
|
94
|
+
if lam <= 0.0:
|
|
95
|
+
raise ValueError("lam must be > 0.")
|
|
96
|
+
|
|
97
|
+
self.a1 = a1
|
|
98
|
+
self.a2 = a2
|
|
99
|
+
self.w1 = w1
|
|
100
|
+
self.lam = lam
|
|
101
|
+
|
|
102
|
+
# ====================
|
|
103
|
+
# roots cubic m scalar
|
|
104
|
+
# ====================
|
|
105
|
+
|
|
106
|
+
def _roots_cubic_m_scalar(self, z):
|
|
107
|
+
"""
|
|
108
|
+
Return the three roots of the cubic equation in m at scalar z.
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
a1 = float(self.a1)
|
|
112
|
+
a2 = float(self.a2)
|
|
113
|
+
w1 = float(self.w1)
|
|
114
|
+
lam = float(self.lam)
|
|
115
|
+
w2 = 1.0 - w1
|
|
116
|
+
|
|
117
|
+
lam1 = lam * w1
|
|
118
|
+
lam2 = lam * w2
|
|
119
|
+
|
|
120
|
+
z = complex(z)
|
|
121
|
+
|
|
122
|
+
# Coefficients for:
|
|
123
|
+
# a3(z)m^3 + a2(z)m^2 + a1(z)m + a0(z) = 0
|
|
124
|
+
c3 = z * a1 * a2
|
|
125
|
+
c2 = (-z * (a1 + a2)) - (a1 * a2) * (1.0 - (lam1 + lam2))
|
|
126
|
+
c1 = z + (a1 + a2) - (lam1 * a1 + lam2 * a2)
|
|
127
|
+
c0 = -1.0
|
|
128
|
+
|
|
129
|
+
coeffs = numpy.array([c3, c2, c1, c0], dtype=numpy.complex128)
|
|
130
|
+
roots = numpy.roots(coeffs)
|
|
131
|
+
return roots
|
|
132
|
+
|
|
133
|
+
# =====================
|
|
134
|
+
# solve m newton scalar
|
|
135
|
+
# =====================
|
|
136
|
+
|
|
137
|
+
def _solve_m_newton(self, z, m0=None, max_iter=100, tol=1e-12):
|
|
138
|
+
"""
|
|
139
|
+
Solve z = 1/m + R(m) for scalar z using Newton iterations.
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
a1 = float(self.a1)
|
|
143
|
+
a2 = float(self.a2)
|
|
144
|
+
w1 = float(self.w1)
|
|
145
|
+
lam = float(self.lam)
|
|
146
|
+
w2 = 1.0 - w1
|
|
147
|
+
|
|
148
|
+
lam1 = lam * w1
|
|
149
|
+
lam2 = lam * w2
|
|
150
|
+
|
|
151
|
+
z = complex(z)
|
|
152
|
+
if m0 is None:
|
|
153
|
+
m = -1.0 / z
|
|
154
|
+
else:
|
|
155
|
+
m = complex(m0)
|
|
156
|
+
|
|
157
|
+
for _ in range(int(max_iter)):
|
|
158
|
+
d1 = 1.0 - a1 * m
|
|
159
|
+
d2 = 1.0 - a2 * m
|
|
160
|
+
|
|
161
|
+
# f(m) = 1/m + R(m) - z
|
|
162
|
+
f = (1.0 / m) + (lam1 * a1 / d1) + (lam2 * a2 / d2) - z
|
|
163
|
+
|
|
164
|
+
# f'(m) = -1/m^2 + sum lam_i a_i^2/(1-a_i m)^2
|
|
165
|
+
fp = (-1.0 / (m * m)) + (
|
|
166
|
+
lam1 * (a1 * a1) / (d1 * d1) +
|
|
167
|
+
lam2 * (a2 * a2) / (d2 * d2)
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
step = f / fp
|
|
171
|
+
m2 = m - step
|
|
172
|
+
|
|
173
|
+
if abs(step) < tol * (1.0 + abs(m2)):
|
|
174
|
+
return m2, True
|
|
175
|
+
|
|
176
|
+
m = m2
|
|
177
|
+
|
|
178
|
+
return m, False
|
|
179
|
+
|
|
180
|
+
# =========
|
|
181
|
+
# stieltjes
|
|
182
|
+
# =========
|
|
183
|
+
|
|
184
|
+
def stieltjes(self, z, max_iter=100, tol=1e-12):
|
|
185
|
+
"""
|
|
186
|
+
Physical/Herglotz branch of m(z) for the two-atom compound Poisson law.
|
|
187
|
+
Fast masked Newton in m, keeping z's original shape.
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
# Unpack parameters
|
|
191
|
+
a1 = float(self.a1)
|
|
192
|
+
a2 = float(self.a2)
|
|
193
|
+
w1 = float(self.w1)
|
|
194
|
+
lam = float(self.lam)
|
|
195
|
+
w2 = 1.0 - w1
|
|
196
|
+
|
|
197
|
+
lam1 = lam * w1
|
|
198
|
+
lam2 = lam * w2
|
|
199
|
+
|
|
200
|
+
z = numpy.asarray(z, dtype=numpy.complex128)
|
|
201
|
+
scalar = (z.ndim == 0)
|
|
202
|
+
if scalar:
|
|
203
|
+
z = z.reshape((1,))
|
|
204
|
+
|
|
205
|
+
# m initial guess
|
|
206
|
+
m = -1.0 / z
|
|
207
|
+
active = numpy.isfinite(m)
|
|
208
|
+
|
|
209
|
+
for _ in range(int(max_iter)):
|
|
210
|
+
if not numpy.any(active):
|
|
211
|
+
break
|
|
212
|
+
|
|
213
|
+
idx = numpy.flatnonzero(active)
|
|
214
|
+
ma = m.ravel()[idx]
|
|
215
|
+
za = z.ravel()[idx]
|
|
216
|
+
|
|
217
|
+
d1 = 1.0 - a1 * ma
|
|
218
|
+
d2 = 1.0 - a2 * ma
|
|
219
|
+
|
|
220
|
+
f = (1.0 / ma) + (lam1 * a1 / d1) + (lam2 * a2 / d2) - za
|
|
221
|
+
|
|
222
|
+
fp = (-1.0 / (ma * ma)) + (
|
|
223
|
+
lam1 * (a1 * a1) / (d1 * d1) +
|
|
224
|
+
lam2 * (a2 * a2) / (d2 * d2)
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
step = f / fp
|
|
228
|
+
mn = ma - step
|
|
229
|
+
|
|
230
|
+
# write back m
|
|
231
|
+
m_flat = m.ravel()
|
|
232
|
+
m_flat[idx] = mn
|
|
233
|
+
|
|
234
|
+
converged = numpy.abs(step) < tol * (1.0 + numpy.abs(mn))
|
|
235
|
+
still = (~converged) & numpy.isfinite(mn)
|
|
236
|
+
|
|
237
|
+
a_flat = active.ravel()
|
|
238
|
+
a_flat[idx] = still
|
|
239
|
+
|
|
240
|
+
# Herglotz sanity: sign(Im z) == sign(Im m)
|
|
241
|
+
sign = numpy.where(numpy.imag(z) >= 0.0, 1.0, -1.0)
|
|
242
|
+
bad = (~numpy.isfinite(m)) | (sign * numpy.imag(m) <= 0.0)
|
|
243
|
+
|
|
244
|
+
if numpy.any(bad):
|
|
245
|
+
zb = z.ravel()
|
|
246
|
+
mb = m.ravel()
|
|
247
|
+
bad_idx = numpy.flatnonzero(bad)
|
|
248
|
+
for i in bad_idx:
|
|
249
|
+
zi = zb[i]
|
|
250
|
+
m_roots = self._roots_cubic_m_scalar(zi)
|
|
251
|
+
mb[i] = _pick_physical_root_scalar(zi, m_roots)
|
|
252
|
+
m = mb.reshape(z.shape)
|
|
253
|
+
|
|
254
|
+
if scalar:
|
|
255
|
+
return m.reshape(())
|
|
256
|
+
return m
|
|
257
|
+
|
|
258
|
+
# =======
|
|
259
|
+
# density
|
|
260
|
+
# =======
|
|
261
|
+
|
|
262
|
+
def density(self, x, eta=2e-4, max_iter=100, tol=1e-12):
|
|
263
|
+
"""
|
|
264
|
+
Density rho(x) from Im m(x + i eta) / pi.
|
|
265
|
+
"""
|
|
266
|
+
|
|
267
|
+
z = numpy.asarray(x, dtype=numpy.float64) + 1j * float(eta)
|
|
268
|
+
m = self.stieltjes(z, max_iter=max_iter, tol=tol)
|
|
269
|
+
rho = numpy.imag(m) / numpy.pi
|
|
270
|
+
return rho
|
|
271
|
+
|
|
272
|
+
# =====
|
|
273
|
+
# roots
|
|
274
|
+
# =====
|
|
275
|
+
|
|
276
|
+
def roots(self, z):
|
|
277
|
+
"""
|
|
278
|
+
Return all algebraic branches (roots of the cubic) at scalar z.
|
|
279
|
+
"""
|
|
280
|
+
|
|
281
|
+
z = numpy.asarray(z, dtype=numpy.complex128)
|
|
282
|
+
if z.ndim != 0:
|
|
283
|
+
raise ValueError("roots(z) expects scalar z.")
|
|
284
|
+
return self._roots_cubic_m_scalar(z.reshape(()))
|
|
285
|
+
|
|
286
|
+
# =======
|
|
287
|
+
# support
|
|
288
|
+
# =======
|
|
289
|
+
|
|
290
|
+
def support(self, eta=2e-4, n_probe=4000, thr=5e-4, x_max=None,
|
|
291
|
+
x_pad=0.05, method='probe'):
|
|
292
|
+
"""
|
|
293
|
+
Estimate support intervals by probing rho(x) on a grid.
|
|
294
|
+
|
|
295
|
+
Parameters
|
|
296
|
+
----------
|
|
297
|
+
method : {'probe'}
|
|
298
|
+
Only probing is implemented here.
|
|
299
|
+
"""
|
|
300
|
+
|
|
301
|
+
_ = method # keep signature compatible
|
|
302
|
+
|
|
303
|
+
a1 = float(self.a1)
|
|
304
|
+
a2 = float(self.a2)
|
|
305
|
+
lam = float(self.lam)
|
|
306
|
+
|
|
307
|
+
if x_max is None:
|
|
308
|
+
# Heuristic: scale grows ~ O(lam * max(a))
|
|
309
|
+
x_max = (1.0 + lam) * max(a1, a2) * 6.0
|
|
310
|
+
x_max = float(x_max)
|
|
311
|
+
if x_max <= 0.0:
|
|
312
|
+
raise ValueError("x_max must be > 0.")
|
|
313
|
+
|
|
314
|
+
x = numpy.linspace(0.0, x_max, int(n_probe))
|
|
315
|
+
rho = self.density(x, eta=eta)
|
|
316
|
+
|
|
317
|
+
mask = rho > float(thr)
|
|
318
|
+
if not numpy.any(mask):
|
|
319
|
+
return []
|
|
320
|
+
|
|
321
|
+
idx = numpy.flatnonzero(mask)
|
|
322
|
+
# split contiguous indices into intervals
|
|
323
|
+
splits = numpy.where(numpy.diff(idx) > 1)[0]
|
|
324
|
+
starts = numpy.r_[idx[0], idx[splits + 1]]
|
|
325
|
+
ends = numpy.r_[idx[splits], idx[-1]]
|
|
326
|
+
|
|
327
|
+
intervals = []
|
|
328
|
+
for s, e in zip(starts, ends):
|
|
329
|
+
xa = x[int(s)]
|
|
330
|
+
xb = x[int(e)]
|
|
331
|
+
pad = float(x_pad) * (xb - xa)
|
|
332
|
+
intervals.append((float(max(0.0, xa - pad)), float(xb + pad)))
|
|
333
|
+
|
|
334
|
+
return intervals
|
|
335
|
+
|
|
336
|
+
# ==========
|
|
337
|
+
# rho scalar
|
|
338
|
+
# ==========
|
|
339
|
+
|
|
340
|
+
def rho_scalar(self, x, eta=2e-4, max_iter=100, tol=1e-12):
|
|
341
|
+
"""
|
|
342
|
+
Scalar density helper (returns float).
|
|
343
|
+
"""
|
|
344
|
+
|
|
345
|
+
x = float(x)
|
|
346
|
+
z = x + 1j * float(eta)
|
|
347
|
+
m = self.stieltjes(z, max_iter=max_iter, tol=tol)
|
|
348
|
+
return float(numpy.imag(m) / numpy.pi)
|
|
349
|
+
|
|
350
|
+
# ======
|
|
351
|
+
# matrix
|
|
352
|
+
# ======
|
|
353
|
+
|
|
354
|
+
def matrix(self, size, seed=None):
|
|
355
|
+
"""
|
|
356
|
+
Generate a PSD random matrix whose ESD approximates this law.
|
|
357
|
+
|
|
358
|
+
Construction
|
|
359
|
+
------------
|
|
360
|
+
Use a sum of two independent (rotationally invariant) Wishart terms,
|
|
361
|
+
which are asymptotically free:
|
|
362
|
+
|
|
363
|
+
A = s1 * (1/m1) Z1 Z1^T + s2 * (1/m2) Z2 Z2^T,
|
|
364
|
+
|
|
365
|
+
where Zi are n x mi i.i.d. N(0,1). Choose aspect ratios ci = n/mi and
|
|
366
|
+
scales si so each term has R-transform
|
|
367
|
+
|
|
368
|
+
Ri(w) = lam_i * a_i / (1 - a_i w),
|
|
369
|
+
|
|
370
|
+
with lam_1 = lam*w1, lam_2 = lam*(1-w1). This is achieved by setting
|
|
371
|
+
|
|
372
|
+
c_i = 1/lam_i,
|
|
373
|
+
s_i = a_i * lam_i.
|
|
374
|
+
|
|
375
|
+
Parameters
|
|
376
|
+
----------
|
|
377
|
+
size : int
|
|
378
|
+
Matrix size n.
|
|
379
|
+
|
|
380
|
+
seed : int, default=None
|
|
381
|
+
RNG seed.
|
|
382
|
+
|
|
383
|
+
Returns
|
|
384
|
+
-------
|
|
385
|
+
A : numpy.ndarray
|
|
386
|
+
Symmetric PSD matrix (n x n).
|
|
387
|
+
"""
|
|
388
|
+
|
|
389
|
+
n = int(size)
|
|
390
|
+
if n <= 0:
|
|
391
|
+
raise ValueError("size must be a positive integer.")
|
|
392
|
+
|
|
393
|
+
a1 = float(self.a1)
|
|
394
|
+
a2 = float(self.a2)
|
|
395
|
+
w1 = float(self.w1)
|
|
396
|
+
lam = float(self.lam)
|
|
397
|
+
w2 = 1.0 - w1
|
|
398
|
+
|
|
399
|
+
lam1 = lam * w1
|
|
400
|
+
lam2 = lam * w2
|
|
401
|
+
|
|
402
|
+
rng = numpy.random.default_rng(seed)
|
|
403
|
+
|
|
404
|
+
A = numpy.zeros((n, n), dtype=numpy.float64)
|
|
405
|
+
|
|
406
|
+
# term 1
|
|
407
|
+
c1 = 1.0 / lam1
|
|
408
|
+
m1 = max(1, int(round(n / c1)))
|
|
409
|
+
s1 = a1 * lam1
|
|
410
|
+
Z1 = rng.standard_normal((n, m1))
|
|
411
|
+
A += s1 * (Z1 @ Z1.T) / float(m1)
|
|
412
|
+
|
|
413
|
+
# term 2
|
|
414
|
+
c2 = 1.0 / lam2
|
|
415
|
+
m2 = max(1, int(round(n / c2)))
|
|
416
|
+
s2 = a2 * lam2
|
|
417
|
+
Z2 = rng.standard_normal((n, m2))
|
|
418
|
+
A += s2 * (Z2 @ Z2.T) / float(m2)
|
|
419
|
+
|
|
420
|
+
return A
|
|
421
|
+
|
|
422
|
+
# ====
|
|
423
|
+
# poly
|
|
424
|
+
# ====
|
|
425
|
+
|
|
426
|
+
def poly(self):
|
|
427
|
+
"""
|
|
428
|
+
Return a_coeffs for the exact cubic P(z,m)=0 of the two-atom free
|
|
429
|
+
compound Poisson model.
|
|
430
|
+
|
|
431
|
+
a_coeffs[i, j] is the coefficient of z^i m^j.
|
|
432
|
+
Shape is (2, 4) since deg_z=1 and deg_m=3.
|
|
433
|
+
|
|
434
|
+
Coefficients match _roots_cubic_m_scalar.
|
|
435
|
+
"""
|
|
436
|
+
|
|
437
|
+
a1 = float(self.a1)
|
|
438
|
+
a2 = float(self.a2)
|
|
439
|
+
w1 = float(self.w1)
|
|
440
|
+
w2 = 1.0 - w1
|
|
441
|
+
lam = float(self.lam)
|
|
442
|
+
|
|
443
|
+
lam1 = lam * w1
|
|
444
|
+
lam2 = lam * w2
|
|
445
|
+
|
|
446
|
+
a = numpy.zeros((2, 4), dtype=numpy.complex128)
|
|
447
|
+
|
|
448
|
+
# c3 = z * a1 * a2
|
|
449
|
+
a[0, 3] = 0.0
|
|
450
|
+
a[1, 3] = a1 * a2
|
|
451
|
+
|
|
452
|
+
# c2 = -z (a1+a2) - a1 a2 (1 - (lam1+lam2))
|
|
453
|
+
a[0, 2] = -(a1 * a2) * (1.0 - (lam1 + lam2))
|
|
454
|
+
a[1, 2] = -(a1 + a2)
|
|
455
|
+
|
|
456
|
+
# c1 = z + (a1+a2) - (lam1 a1 + lam2 a2)
|
|
457
|
+
a[0, 1] = (a1 + a2) - (lam1 * a1 + lam2 * a2)
|
|
458
|
+
a[1, 1] = 1.0
|
|
459
|
+
|
|
460
|
+
# c0 = -1
|
|
461
|
+
a[0, 0] = -1.0
|
|
462
|
+
a[1, 0] = 0.0
|
|
463
|
+
|
|
464
|
+
return a
|
|
@@ -673,3 +673,54 @@ class DeformedMarchenkoPastur(object):
|
|
|
673
673
|
S = X @ X.T
|
|
674
674
|
|
|
675
675
|
return S
|
|
676
|
+
|
|
677
|
+
# ====
|
|
678
|
+
# poly
|
|
679
|
+
# ====
|
|
680
|
+
|
|
681
|
+
def poly(self):
|
|
682
|
+
"""
|
|
683
|
+
Return a_coeffs for the exact cubic P(z,m)=0 of the two-atom deformed
|
|
684
|
+
MP model.
|
|
685
|
+
|
|
686
|
+
This is the eliminated polynomial in m (not underline{m}).
|
|
687
|
+
a_coeffs[i, j] is the coefficient of z^i m^j.
|
|
688
|
+
Shape is (3, 4).
|
|
689
|
+
"""
|
|
690
|
+
|
|
691
|
+
t1 = float(self.t1)
|
|
692
|
+
t2 = float(self.t2)
|
|
693
|
+
w1 = float(self.w1)
|
|
694
|
+
w2 = 1.0 - w1
|
|
695
|
+
c = float(self.c)
|
|
696
|
+
|
|
697
|
+
# mu1 = w1 * t1 + w2 * t2
|
|
698
|
+
|
|
699
|
+
a = numpy.zeros((3, 4), dtype=numpy.complex128)
|
|
700
|
+
|
|
701
|
+
# NOTE: This polynomial is defined up to a global nonzero factor.
|
|
702
|
+
# The scaling below is chosen so that the m^3 term is (-c^3 t1 t2) z^2.
|
|
703
|
+
|
|
704
|
+
# ---- m^3: (-c^3 t1 t2) z^2
|
|
705
|
+
a[2, 3] = -(c**3) * t1 * t2
|
|
706
|
+
|
|
707
|
+
# ---- m^2: -( 2 c^3 t1 t2 z - 2 c^2 t1 t2 z + c^2 (t1+t2) z^2 )
|
|
708
|
+
a[0, 2] = 0.0
|
|
709
|
+
a[1, 2] = -(2.0 * (c**3) * t1 * t2 - 2.0 * (c**2) * t1 * t2)
|
|
710
|
+
a[2, 2] = -(c**2) * (t1 + t2)
|
|
711
|
+
|
|
712
|
+
# ---- m^1:
|
|
713
|
+
# -c * [ c^2 t1 t2 - 2 c t1 t2 + t1 t2
|
|
714
|
+
# + z^2
|
|
715
|
+
# + z*( -c*w1*t1 + 2c*t1 + c*w1*t2 + c*t2 - t1 - t2 ) ]
|
|
716
|
+
a[0, 1] = -c * ((c**2) * t1 * t2 - 2.0 * c * t1 * t2 + t1 * t2)
|
|
717
|
+
a[1, 1] = -c * ((-c * w1 * t1) + (2.0 * c * t1) + (c * w1 * t2) +
|
|
718
|
+
(c * t2) - t1 - t2)
|
|
719
|
+
a[2, 1] = -c * (1.0)
|
|
720
|
+
|
|
721
|
+
# ---- m^0: -c z + c(1-c) (w2 t1 + w1 t2)
|
|
722
|
+
a[0, 0] = c * (1.0 - c) * (w2 * t1 + w1 * t2)
|
|
723
|
+
a[1, 0] = -c
|
|
724
|
+
a[2, 0] = 0.0
|
|
725
|
+
|
|
726
|
+
return a
|
|
@@ -340,3 +340,47 @@ class DeformedWigner(object):
|
|
|
340
340
|
A = T + sigma * W
|
|
341
341
|
|
|
342
342
|
return A
|
|
343
|
+
|
|
344
|
+
# ====
|
|
345
|
+
# poly
|
|
346
|
+
# ====
|
|
347
|
+
|
|
348
|
+
def poly(self):
|
|
349
|
+
"""
|
|
350
|
+
Return a_coeffs for the exact cubic P(z,m)=0 of the two-atom deformed
|
|
351
|
+
Wigner model.
|
|
352
|
+
|
|
353
|
+
a_coeffs[i, j] is the coefficient of z^i m^j.
|
|
354
|
+
Shape is (deg_z+1, deg_m+1) = (3, 4).
|
|
355
|
+
"""
|
|
356
|
+
|
|
357
|
+
t1 = float(self.t1)
|
|
358
|
+
t2 = float(self.t2)
|
|
359
|
+
w1 = float(self.w1)
|
|
360
|
+
w2 = 1.0 - w1
|
|
361
|
+
sigma = float(self.sigma)
|
|
362
|
+
s2 = sigma * sigma
|
|
363
|
+
|
|
364
|
+
a = numpy.zeros((3, 4), dtype=numpy.complex128)
|
|
365
|
+
|
|
366
|
+
# m^0 column (a0(z) = z - (w1 t2 + w2 t1))
|
|
367
|
+
a[0, 0] = -(w1 * t2 + w2 * t1)
|
|
368
|
+
a[1, 0] = 1.0
|
|
369
|
+
a[2, 0] = 0.0
|
|
370
|
+
|
|
371
|
+
# m^1 column (a1(z) = z^2 - (t1+t2)z + t1 t2 + s2)
|
|
372
|
+
a[0, 1] = t1 * t2 + s2
|
|
373
|
+
a[1, 1] = -(t1 + t2)
|
|
374
|
+
a[2, 1] = 1.0
|
|
375
|
+
|
|
376
|
+
# m^2 column (a2(z) = s2 z - s2 (t1+t2))
|
|
377
|
+
a[0, 2] = -s2 * (t1 + t2)
|
|
378
|
+
a[1, 2] = 2.0 * s2
|
|
379
|
+
a[2, 2] = 0.0
|
|
380
|
+
|
|
381
|
+
# m^3 column (a3(z) = s2^2)
|
|
382
|
+
a[0, 3] = s2 * s2
|
|
383
|
+
a[1, 3] = 0.0
|
|
384
|
+
a[2, 3] = 0.0
|
|
385
|
+
|
|
386
|
+
return a
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: freealg
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.14
|
|
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
|
|
@@ -37,6 +37,7 @@ Requires-Dist: matplotlib
|
|
|
37
37
|
Requires-Dist: colorcet
|
|
38
38
|
Requires-Dist: statsmodels
|
|
39
39
|
Requires-Dist: numba
|
|
40
|
+
Requires-Dist: tqdm
|
|
40
41
|
Provides-Extra: test
|
|
41
42
|
Provides-Extra: docs
|
|
42
43
|
Dynamic: classifier
|
|
@@ -1,18 +1,33 @@
|
|
|
1
|
-
freealg/__init__.py,sha256=
|
|
2
|
-
freealg/__version__.py,sha256=
|
|
1
|
+
freealg/__init__.py,sha256=is4de7kygj1be0S3EAcAlW_vGriWjdjHCR-J9NN6wyk,873
|
|
2
|
+
freealg/__version__.py,sha256=7BOggTpADa3sz2Lo7K_EuX10-Jk_mW3PS3k2rLh8AF8,23
|
|
3
3
|
freealg/_util.py,sha256=RzccUCORgzrI9NdNqwMVugiHU0uDKkJFcIyjFMUOnv8,2518
|
|
4
|
-
freealg/_algebraic_form/__init__.py,sha256=
|
|
4
|
+
freealg/_algebraic_form/__init__.py,sha256=etgaRiuipcmxtwHzMVxZwO_qbX8R7m9j39mKvgRyTZg,463
|
|
5
5
|
freealg/_algebraic_form/_branch_points.py,sha256=jzvHszw7xFe9B15a5RZV3pGfCGtndvrKJ4GIX6F3qhc,7814
|
|
6
|
-
freealg/_algebraic_form/_constraints.py,sha256=
|
|
6
|
+
freealg/_algebraic_form/_constraints.py,sha256=xBpsKAL0-Czxf9ZF9tspLpTaFJ1m2DDyqc2KH9bl5Xg,3601
|
|
7
7
|
freealg/_algebraic_form/_continuation_algebraic.py,sha256=vVHFlMJYeXm97pgwEceJB2rGJeGOVhk_Ywg6mjoIA-g,19390
|
|
8
|
-
freealg/_algebraic_form/
|
|
9
|
-
freealg/_algebraic_form/
|
|
10
|
-
freealg/_algebraic_form/
|
|
11
|
-
freealg/_algebraic_form/
|
|
12
|
-
freealg/_algebraic_form/
|
|
8
|
+
freealg/_algebraic_form/_cusp.py,sha256=Vbk3V7pT9iyQSIGOoTMSzN7r7nfyoyXUMCIPXuHFVI4,10581
|
|
9
|
+
freealg/_algebraic_form/_cusp_wrap.py,sha256=HkpJj6HEE_Qi2eVBPJYcpKUfDOAGqpbHfF7ccC0sEKE,8309
|
|
10
|
+
freealg/_algebraic_form/_decompress.py,sha256=yCGTT3F-0NtGi3oENIS11Zcc7SVaMv_hxvzWuho5huw,22274
|
|
11
|
+
freealg/_algebraic_form/_decompress2.py,sha256=2eSoIOj8R1ZuxIuDTXaKgMXY5OXfsNmaTIbE0IiUukk,6585
|
|
12
|
+
freealg/_algebraic_form/_decompress4.py,sha256=kq0KJIf_il8ed_wy66hOiwD91ixr77ru3Ovdpz-aetY,21586
|
|
13
|
+
freealg/_algebraic_form/_decompress5.py,sha256=I2y2Qvc09LjsSlW8Q1cdIdAFRTJm0cQDDBMBZ6XmuME,22618
|
|
14
|
+
freealg/_algebraic_form/_decompress6.py,sha256=Kn2TqWOjH8ifZEnfJ2UlLJZTgYZR1pWQ6nEZwNsadcQ,16774
|
|
15
|
+
freealg/_algebraic_form/_decompress7.py,sha256=hRstLXa2hD0QvDhdhsycHujjqFWWn0Z7PbKsFBH1COs,10128
|
|
16
|
+
freealg/_algebraic_form/_decompress8.py,sha256=IH05swHhA4vieOUa-4Kbapk5Q4XRggGC2c30W1QpMsY,11717
|
|
17
|
+
freealg/_algebraic_form/_decompress9.py,sha256=PR5uSo6BUZZWDyx19MA8KSQVrIxG0sUVn178lo75dq8,11445
|
|
18
|
+
freealg/_algebraic_form/_decompress_new.py,sha256=fOHtc1iTvpep3ccQPQFUTWaluv_GS1ahrGE11fJhtAw,12162
|
|
19
|
+
freealg/_algebraic_form/_decompress_new_2.py,sha256=kzjYSa4roWm8-ntCjSSG88y_82ZjSHY7jQOPSBgUrUg,54182
|
|
20
|
+
freealg/_algebraic_form/_decompress_util.py,sha256=TIaqr3tdMhsKvFskmb5-RNxKWUR-hKkHuCWqq8eWo8o,4836
|
|
21
|
+
freealg/_algebraic_form/_edge.py,sha256=X91GeX8nZZ_Lf7C3l7u-JpESDmwRqACYA_G2l1KVs2Y,9604
|
|
22
|
+
freealg/_algebraic_form/_homotopy.py,sha256=FdKQhUTjdk6Rmdd5zb8IzDJN0pteHUcgJL3eG_ySUzM,10912
|
|
23
|
+
freealg/_algebraic_form/_homotopy2.py,sha256=gvfm0cabEw57zLuOMgGNJGFVqJ8ScF4Zs2FoCQSWbYs,8868
|
|
24
|
+
freealg/_algebraic_form/_homotopy3.py,sha256=OfvvX6uc_fpcPuMa53zM8o7XHrCeWeRVjDoSjUlFySE,6345
|
|
25
|
+
freealg/_algebraic_form/_homotopy4.py,sha256=dxHisWPIPdzyw1NsW1qS0EbLWtM_uyIcTrHQV3jYGis,10013
|
|
26
|
+
freealg/_algebraic_form/_homotopy5.py,sha256=lHWA5tknnZBMymcWt_KQXcI0qLrd_ftUGgd_Qp-o3fs,6306
|
|
27
|
+
freealg/_algebraic_form/_moments.py,sha256=R1-EepGsni4he-kNfiP3E3tFqR2Z27fz-ixtSVU2fSE,12427
|
|
13
28
|
freealg/_algebraic_form/_sheets_util.py,sha256=6OLzWQKu-gN8rxM2rbpbN8TjNZFmD8UJ-8t9kcZdkCo,4174
|
|
14
|
-
freealg/_algebraic_form/_support.py,sha256=
|
|
15
|
-
freealg/_algebraic_form/algebraic_form.py,sha256=
|
|
29
|
+
freealg/_algebraic_form/_support.py,sha256=Gjp4nVQJb_Syou3M_uroSl52bPTafqKk6IUSJgglKu4,6791
|
|
30
|
+
freealg/_algebraic_form/algebraic_form.py,sha256=14bKYTLdYb4F1vgIdEeFHi-PI_-AZGoAaEfzf5HAaJk,37762
|
|
16
31
|
freealg/_free_form/__init__.py,sha256=5cnSX7kHci3wKx6-BEFhmVY_NjjmQAq1JjWPTEqETTg,611
|
|
17
32
|
freealg/_free_form/_chebyshev.py,sha256=zkyVA8NLf7uUKlJdLz4ijd_SurdsqUgkA5nHGWSybaE,6916
|
|
18
33
|
freealg/_free_form/_damp.py,sha256=k2vtBtWOxQBf4qXaWu_En81lQBXbEO4QbxxWpvuVhdE,1802
|
|
@@ -33,10 +48,11 @@ freealg/_geometric_form/_elliptic_functions.py,sha256=Rr_pb1A_FjrJlraYQj2G5shdO6
|
|
|
33
48
|
freealg/_geometric_form/_sphere_maps.py,sha256=NlhTgWXKWXKdyR2dQxMmePsIwHp7IWyYh6uoxgW5Osc,1465
|
|
34
49
|
freealg/_geometric_form/_torus_maps.py,sha256=7m5QsbmnXTWHJE5rWjKG3_TnErHEEQ41vW-3hsOc3lo,3338
|
|
35
50
|
freealg/_geometric_form/geometric_form.py,sha256=whHKYQdakqShtR-jCEugevnje72JEr9M0HSvZ2BYoKs,33379
|
|
36
|
-
freealg/distributions/__init__.py,sha256=
|
|
51
|
+
freealg/distributions/__init__.py,sha256=sCx2NVcRTaHwvxXpFRU_9unN98ZED6B-xFoFZ2eU9-E,875
|
|
37
52
|
freealg/distributions/_chiral_block.py,sha256=YSC_Sk1u1UKlWVE1GGJEjX6VrWqpEEYNxBZ2j8Csc3A,13897
|
|
38
|
-
freealg/distributions/
|
|
39
|
-
freealg/distributions/
|
|
53
|
+
freealg/distributions/_compound_poisson.py,sha256=weckLA0ix0gHLnacPPOxs0WhqAtlvVVxcUuRZQUWuJM,11810
|
|
54
|
+
freealg/distributions/_deformed_marchenko_pastur.py,sha256=iZixcZiXUKpe9Vi4I1_x_p_lIVqJeo7Tlb8ENqbZa94,20929
|
|
55
|
+
freealg/distributions/_deformed_wigner.py,sha256=0933XQAplP3mifJKdSU7qXgrndqUs1MUpYMJHR-NId8,9086
|
|
40
56
|
freealg/distributions/_kesten_mckay.py,sha256=Uv3QuUYsfXbPMovXSO_pN3wdkc1fTKGVX7iuHDgBRqk,20089
|
|
41
57
|
freealg/distributions/_marchenko_pastur.py,sha256=eemaxDosKpV37TAn9uSiYpljIkVNoTWDJ9ZfYb8tAeY,20646
|
|
42
58
|
freealg/distributions/_meixner.py,sha256=GbcWeHrXMxK3Hdj4pCTESlMts9dEPQE1DhClxYprWfg,17590
|
|
@@ -45,9 +61,9 @@ freealg/distributions/_wigner.py,sha256=epgx6ne6R_7to5j6-QsWIAVFJQFquWMmYgnZYMN4
|
|
|
45
61
|
freealg/visualization/__init__.py,sha256=NLq_zwueF7ytZ8sl8zLPqm-AODxxXNvfMozHGmmklcE,435
|
|
46
62
|
freealg/visualization/_glue_util.py,sha256=2oKnEYjUOS4OZfivmciVLauVr53kyHMwi6c2zRKilTQ,693
|
|
47
63
|
freealg/visualization/_rgb_hsv.py,sha256=rEskxXxSlKKxIrHRslVkgxHtD010L3ge9YtcVsOPl8E,3650
|
|
48
|
-
freealg-0.7.
|
|
49
|
-
freealg-0.7.
|
|
50
|
-
freealg-0.7.
|
|
51
|
-
freealg-0.7.
|
|
52
|
-
freealg-0.7.
|
|
53
|
-
freealg-0.7.
|
|
64
|
+
freealg-0.7.14.dist-info/licenses/AUTHORS.txt,sha256=0b67Nz4_JgIzUupHJTAZxu5QdSUM_HRM_X_w4xCb17o,30
|
|
65
|
+
freealg-0.7.14.dist-info/licenses/LICENSE.txt,sha256=J-EEYEtxb3VVf_Bn1TYfWnpY5lMFIM15iLDDcnaDTPA,1443
|
|
66
|
+
freealg-0.7.14.dist-info/METADATA,sha256=9QtOauh9E-xiAUPG5Dg9-H7f9ldRLg6buhnkBapCoik,5537
|
|
67
|
+
freealg-0.7.14.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
68
|
+
freealg-0.7.14.dist-info/top_level.txt,sha256=eR2wrgYwDdnnJ9Zf5PruPqe4kQav0GMvRsqct6y00Q8,8
|
|
69
|
+
freealg-0.7.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|