freealg 0.7.17__py3-none-any.whl → 0.7.18__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 (52) hide show
  1. freealg/__init__.py +8 -6
  2. freealg/__version__.py +1 -1
  3. freealg/_algebraic_form/_branch_points.py +18 -18
  4. freealg/_algebraic_form/_continuation_algebraic.py +13 -13
  5. freealg/_algebraic_form/_cusp.py +15 -15
  6. freealg/_algebraic_form/_cusp_wrap.py +6 -6
  7. freealg/_algebraic_form/_decompress.py +16 -16
  8. freealg/_algebraic_form/_decompress4.py +31 -31
  9. freealg/_algebraic_form/_decompress5.py +23 -23
  10. freealg/_algebraic_form/_decompress6.py +13 -13
  11. freealg/_algebraic_form/_decompress7.py +15 -15
  12. freealg/_algebraic_form/_decompress8.py +17 -17
  13. freealg/_algebraic_form/_decompress9.py +18 -18
  14. freealg/_algebraic_form/_decompress_new.py +17 -17
  15. freealg/_algebraic_form/_decompress_new_2.py +57 -57
  16. freealg/_algebraic_form/_decompress_util.py +10 -10
  17. freealg/_algebraic_form/_decompressible.py +292 -0
  18. freealg/_algebraic_form/_edge.py +10 -10
  19. freealg/_algebraic_form/_homotopy4.py +9 -9
  20. freealg/_algebraic_form/_homotopy5.py +9 -9
  21. freealg/_algebraic_form/_support.py +19 -19
  22. freealg/_algebraic_form/algebraic_form.py +262 -468
  23. freealg/_base_form.py +401 -0
  24. freealg/_free_form/__init__.py +1 -4
  25. freealg/_free_form/_density_util.py +1 -1
  26. freealg/_free_form/_plot_util.py +3 -511
  27. freealg/_free_form/free_form.py +8 -367
  28. freealg/_util.py +59 -11
  29. freealg/distributions/__init__.py +2 -1
  30. freealg/distributions/_base_distribution.py +163 -0
  31. freealg/distributions/_chiral_block.py +137 -11
  32. freealg/distributions/_compound_poisson.py +141 -47
  33. freealg/distributions/_deformed_marchenko_pastur.py +138 -33
  34. freealg/distributions/_deformed_wigner.py +98 -9
  35. freealg/distributions/_fuss_catalan.py +269 -0
  36. freealg/distributions/_kesten_mckay.py +4 -130
  37. freealg/distributions/_marchenko_pastur.py +8 -196
  38. freealg/distributions/_meixner.py +4 -130
  39. freealg/distributions/_wachter.py +4 -130
  40. freealg/distributions/_wigner.py +10 -127
  41. freealg/visualization/__init__.py +2 -2
  42. freealg/visualization/{_rgb_hsv.py → _domain_coloring.py} +37 -29
  43. freealg/visualization/_plot_util.py +513 -0
  44. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/METADATA +1 -1
  45. freealg-0.7.18.dist-info/RECORD +74 -0
  46. freealg-0.7.17.dist-info/RECORD +0 -69
  47. /freealg/{_free_form/_sample.py → _sample.py} +0 -0
  48. /freealg/{_free_form/_support.py → _support.py} +0 -0
  49. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/WHEEL +0 -0
  50. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/licenses/AUTHORS.txt +0 -0
  51. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/licenses/LICENSE.txt +0 -0
  52. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/top_level.txt +0 -0
@@ -12,7 +12,9 @@
12
12
  # =======
13
13
 
14
14
  import numpy
15
+ from ..visualization._plot_util import plot_density
15
16
  from .._algebraic_form._sheets_util import _pick_physical_root_scalar
17
+ from ._base_distribution import BaseDistribution
16
18
 
17
19
  __all__ = ['DeformedMarchenkoPastur']
18
20
 
@@ -21,9 +23,45 @@ __all__ = ['DeformedMarchenkoPastur']
21
23
  # Deformed Marchenko Pastur
22
24
  # =========================
23
25
 
24
- class DeformedMarchenkoPastur(object):
26
+ class DeformedMarchenkoPastur(BaseDistribution):
25
27
  """
26
- Deformed Marchenko-Pastur model.
28
+ Deformed Marchenko-Pastur distribution
29
+
30
+ Parameters
31
+ ----------
32
+
33
+ t1, t2 : float
34
+ Jump sizes (must be > 0). For PSD-like support, keep them > 0.
35
+
36
+ w1 : float
37
+ Mixture weight in (0, 1) for ``t1``. Second weight is ``1-w1``.
38
+
39
+ c : float
40
+ Ratio parameter of Marchenko-Pastur distribution, must be > 0.
41
+
42
+ Methods
43
+ -------
44
+
45
+ density
46
+ Spectral density of distribution.
47
+
48
+ roots
49
+ Roots of polynomial implicitly representing Stieltjes transform
50
+
51
+ stieltjes
52
+ Stieltjes transform
53
+
54
+ support
55
+ Support intervals of distribution
56
+
57
+ sample
58
+ Sample from distribution.
59
+
60
+ matrix
61
+ Generate matrix with its empirical spectral density of distribution
62
+
63
+ poly
64
+ Polynomial coefficients implicitly representing the Stieltjes
27
65
 
28
66
  Notes
29
67
  -----
@@ -84,6 +122,14 @@ class DeformedMarchenkoPastur(object):
84
122
  self.w1 = w1
85
123
  self.c = c
86
124
 
125
+ # Bounds for smallest and largest eigenvalues
126
+ if c > 1.0:
127
+ # In this case, there is an atom at the origin
128
+ self.lam_lb = 0.0
129
+ else:
130
+ self.lam_lb = numpy.min([t1, t2]) * (1 - numpy.sqrt(c))**2
131
+ self.lam_ub = numpy.max([t1, t2]) * (1 + numpy.sqrt(c))**2
132
+
87
133
  # ====================
88
134
  # roots cubic u scalar
89
135
  # ====================
@@ -105,8 +151,6 @@ class DeformedMarchenkoPastur(object):
105
151
  mu1 = w1 * t1 + w2 * t2
106
152
 
107
153
  # Cubic coefficients for u:
108
- # (z t1 t2) u^3 + ( z(t1+t2) + t1 t2(1-c) ) u^2
109
- # + ( z + (t1+t2) - c*mu1 ) u + 1 = 0
110
154
  c3 = z * (t1 * t2)
111
155
  c2 = z * (t1 + t2) + (t1 * t2) * (1.0 - c)
112
156
  c1 = z + (t1 + t2) - c * mu1
@@ -138,10 +182,7 @@ class DeformedMarchenkoPastur(object):
138
182
  d1 = 1.0 + t1 * u
139
183
  d2 = 1.0 + t2 * u
140
184
 
141
- # f(u) = -1/u + c*(w1*t1/d1 + w2*t2/d2) - z
142
185
  f = (-1.0 / u) + c * (w1 * t1 / d1 + w2 * t2 / d2) - z
143
-
144
- # f'(u) = 1/u^2 - c*(w1*t1^2/d1^2 + w2*t2^2/d2^2)
145
186
  fp = (1.0 / (u * u)) - c * (w1 * (t1 * t1) / (d1 * d1) +
146
187
  w2 * (t2 * t2) / (d2 * d2))
147
188
 
@@ -159,6 +200,8 @@ class DeformedMarchenkoPastur(object):
159
200
 
160
201
  def stieltjes(self, z, max_iter=100, tol=1e-12):
161
202
  """
203
+ Stieltjes transform
204
+
162
205
  Physical/Herglotz branch of m(z) for \\mu = H \\boxtimes MP_c with
163
206
  H = w_1 \\delta_{t_1} + (1-w_1) \\delta_{t_2}.
164
207
  Fast masked Newton in u (companion Stieltjes), keeping z's original
@@ -246,35 +289,101 @@ class DeformedMarchenkoPastur(object):
246
289
  # density
247
290
  # =======
248
291
 
249
- def density(self, x, eta=1e-3, ac_only=True):
292
+ def density(self, x=None, eta=1e-3, ac_only=True, plot=False, latex=False,
293
+ save=False, eig=None):
250
294
  """
251
- Density via Stieltjes inversion with robust x-continuation.
295
+ Density of distribution.
296
+
297
+ Parameters
298
+ ----------
299
+
300
+ x : numpy.array, default=None
301
+ The locations where density is evaluated at. If `None`, an interval
302
+ slightly larger than the supp interval of the spectral density
303
+ is used.
304
+
305
+ rho : numpy.array, default=None
306
+ Density. If `None`, it will be computed.
307
+
308
+ eta : float, default=1e-3
309
+ The offset :math:`\\eta` from the real axis where the density
310
+ is evaluated using Plemelj formula at :math:`z = x + i \\eta`.
311
+
312
+ ac_only : bool, default=True
313
+ If `True`, it returns the absolutely-continuous part of density.
314
+
315
+ plot : bool, default=False
316
+ If `True`, density is plotted.
317
+
318
+ latex : bool, default=False
319
+ If `True`, the plot is rendered using LaTeX. This option is
320
+ relevant only if ``plot=True``.
321
+
322
+ save : bool, default=False
323
+ If not `False`, the plot is saved. If a string is given, it is
324
+ assumed to the save filename (with the file extension). This option
325
+ is relevant only if ``plot=True``.
326
+
327
+ eig : numpy.array, default=None
328
+ A collection of eigenvalues to compare to via histogram. This
329
+ option is relevant only if ``plot=True``.
330
+
331
+ Returns
332
+ -------
333
+
334
+ rho : numpy.array
335
+ Density.
252
336
 
253
337
  Notes
254
338
  -----
255
339
 
256
- - Do not warm-start across x<0 (MP-type support is >=0).
257
- - Reset warm-start when previous u is (nearly) real.
258
- - If Newton lands on a non-Herglotz root, fall back to cubic roots +
259
- pick.
340
+ * Do not warm-start across x<0 (MP-type support is >=0).
341
+ * Reset warm-start when previous u is (nearly) real.
342
+ * If Newton lands on a non-Herglotz root, fall back to cubic roots +
343
+ pick.
260
344
 
261
345
  If ac_only is True and c < 1, subtract the smeared atom at zero of mass
262
346
  (1-c) for visualization.
263
347
  """
264
348
 
265
- x = numpy.asarray(x, dtype=numpy.float64)
266
- z = x + 1j * float(eta)
349
+ # Create x if not given
350
+ if x is None:
351
+ radius = 0.5 * (self.lam_ub - self.lam_lb)
352
+ center = 0.5 * (self.lam_ub + self.lam_lb)
353
+ scale = 1.25
354
+ x_min = numpy.floor(center - radius * scale)
355
+ x_max = numpy.ceil(center + radius * scale)
356
+ x = numpy.linspace(x_min, x_max, 500)
357
+ else:
358
+ x = numpy.asarray(x, dtype=numpy.float64)
267
359
 
360
+ z = x + 1j * float(eta)
268
361
  m = self.stieltjes(z)
269
362
  rho = numpy.imag(m) / numpy.pi
270
363
 
364
+ # Atoms
365
+ atoms = None
366
+ if self.c > 1.0:
367
+ atom_loc = 0.0
368
+ atom_w = 1.0 - 1.0 / self.c
369
+ atoms = [(atom_loc, atom_w)]
370
+
271
371
  # Optional: remove the atom at zero (only for visualization of AC part)
272
- if ac_only and (self.c > 1.0):
273
- w0 = 1.0 - 1.0 / self.c
274
- rho = rho - w0 * (float(eta) / numpy.pi) / \
372
+ if (atoms is not None) and (ac_only is True):
373
+ atom = atom_w * (float(eta) / numpy.pi) / \
275
374
  (x * x + float(eta) * float(eta))
375
+ rho = rho - atom
376
+ rho = numpy.maximum(rho, 0.0)
377
+
378
+ if plot:
379
+ if eig is not None:
380
+ label = 'Theoretical'
381
+ else:
382
+ label = ''
383
+ plot_density(x, rho, atoms=atoms, label=label, latex=latex,
384
+ save=save, eig=eig)
276
385
 
277
- return numpy.maximum(rho, 0.0)
386
+ return rho
278
387
 
279
388
  # =====
280
389
  # roots
@@ -282,8 +391,7 @@ class DeformedMarchenkoPastur(object):
282
391
 
283
392
  def roots(self, z):
284
393
  """
285
- Return all 3 algebraic roots of m(z) (via roots for u then mapping to
286
- m).
394
+ Roots of polynomial implicitly representing Stieltjes transform
287
395
  """
288
396
 
289
397
  # Unpack parameters
@@ -327,6 +435,8 @@ class DeformedMarchenkoPastur(object):
327
435
  def support(self, eta=2e-4, n_probe=4000, thr=5e-4, x_max=None, x_pad=0.05,
328
436
  method='quartic'):
329
437
  """
438
+ Support intervals of distribution
439
+
330
440
  Estimate support intervals of μ = H \\boxtimes MP_c where H = w1
331
441
  \\delta_{t1} + (1-w1) \\delta_{t2}.
332
442
 
@@ -459,8 +569,7 @@ class DeformedMarchenkoPastur(object):
459
569
  return cuts
460
570
  method = 'probe'
461
571
 
462
- # --- legacy probing (kept as fallback / comparison) ---
463
- # Heuristic x-range
572
+ # Legacy probing (kept as fallback / comparison). Heuristic x-range
464
573
  tmax = float(max(abs(t1), abs(t2), 1e-12))
465
574
  if x_max is None:
466
575
  s = (1.0 + numpy.sqrt(max(c, 0.0))) ** 2
@@ -623,11 +732,10 @@ class DeformedMarchenkoPastur(object):
623
732
 
624
733
  def poly(self):
625
734
  """
626
- Return a_coeffs for the exact cubic P(z,m)=0 of the two-atom deformed
627
- MP model.
735
+ Polynomial coefficients implicitly representing the Stieltjes
628
736
 
629
737
  This is the eliminated polynomial in m (not underline{m}).
630
- a_coeffs[i, j] is the coefficient of z^i m^j.
738
+ coeffs[i, j] is the coefficient of z^i m^j.
631
739
  Shape is (3, 4).
632
740
  """
633
741
 
@@ -644,24 +752,21 @@ class DeformedMarchenkoPastur(object):
644
752
  # NOTE: This polynomial is defined up to a global nonzero factor.
645
753
  # The scaling below is chosen so that the m^3 term is (-c^3 t1 t2) z^2.
646
754
 
647
- # ---- m^3: (-c^3 t1 t2) z^2
755
+ # Coefficients of m^3:
648
756
  a[2, 3] = -(c**3) * t1 * t2
649
757
 
650
- # ---- m^2: -( 2 c^3 t1 t2 z - 2 c^2 t1 t2 z + c^2 (t1+t2) z^2 )
758
+ # Coefficients of m^2:
651
759
  a[0, 2] = 0.0
652
760
  a[1, 2] = -(2.0 * (c**3) * t1 * t2 - 2.0 * (c**2) * t1 * t2)
653
761
  a[2, 2] = -(c**2) * (t1 + t2)
654
762
 
655
- # ---- m^1:
656
- # -c * [ c^2 t1 t2 - 2 c t1 t2 + t1 t2
657
- # + z^2
658
- # + z*( -c*w1*t1 + 2c*t1 + c*w1*t2 + c*t2 - t1 - t2 ) ]
763
+ # Coefficients of m^1:
659
764
  a[0, 1] = -c * ((c**2) * t1 * t2 - 2.0 * c * t1 * t2 + t1 * t2)
660
765
  a[1, 1] = -c * ((-c * w1 * t1) + (2.0 * c * t1) + (c * w1 * t2) +
661
766
  (c * t2) - t1 - t2)
662
767
  a[2, 1] = -c * (1.0)
663
768
 
664
- # ---- m^0: -c z + c(1-c) (w2 t1 + w1 t2)
769
+ # Coefficients of m^0
665
770
  a[0, 0] = c * (1.0 - c) * (w2 * t1 + w1 * t2)
666
771
  a[1, 0] = -c
667
772
  a[2, 0] = 0.0
@@ -12,7 +12,9 @@
12
12
  # =======
13
13
 
14
14
  import numpy
15
+ from ..visualization._plot_util import plot_density
15
16
  from .._algebraic_form._sheets_util import _pick_physical_root_scalar
17
+ from ._base_distribution import BaseDistribution
16
18
 
17
19
  __all__ = ['DeformedWigner']
18
20
 
@@ -21,9 +23,33 @@ __all__ = ['DeformedWigner']
21
23
  # Deformed Wigner
22
24
  # ===============
23
25
 
24
- class DeformedWigner(object):
26
+ class DeformedWigner(BaseDistribution):
25
27
  """
26
- Deformed Wiger
28
+ Deformed Wiger distribution
29
+
30
+ Methods
31
+ -------
32
+
33
+ density
34
+ Spectral density of distribution.
35
+
36
+ roots
37
+ Roots of polynomial implicitly representing Stieltjes transform
38
+
39
+ stieltjes
40
+ Stieltjes transform
41
+
42
+ support
43
+ Support intervals of distribution
44
+
45
+ sample
46
+ Sample from distribution.
47
+
48
+ matrix
49
+ Generate matrix with its empirical spectral density of distribution
50
+
51
+ poly
52
+ Polynomial coefficients implicitly representing the Stieltjes
27
53
  """
28
54
 
29
55
  # ====
@@ -43,6 +69,10 @@ class DeformedWigner(object):
43
69
  self.w1 = w1
44
70
  self.sigma = sigma
45
71
 
72
+ # Bounds for smallest and largest eigenvalues
73
+ self.lam_lb = numpy.min([t1, t2]) - 2.0 * self.sigma
74
+ self.lam_ub = numpy.max([t1, t2]) + 2.0 * self.sigma
75
+
46
76
  # ==================
47
77
  # roots cubic scalar
48
78
  # ==================
@@ -135,17 +165,75 @@ class DeformedWigner(object):
135
165
  # density
136
166
  # =======
137
167
 
138
- def density(self, x, eta=1e-3):
168
+ def density(self, x=None, eta=1e-3, plot=False, latex=False, save=False,
169
+ eig=None):
139
170
  """
171
+ Density of distribution.
172
+
173
+ Parameters
174
+ ----------
175
+
176
+ x : numpy.array, default=None
177
+ The locations where density is evaluated at. If `None`, an interval
178
+ slightly larger than the supp interval of the spectral density
179
+ is used.
180
+
181
+ rho : numpy.array, default=None
182
+ Density. If `None`, it will be computed.
183
+
184
+ eta : float, default=1e-3
185
+ The offset :math:`\\eta` from the real axis where the density
186
+ is evaluated using Plemelj formula at :math:`z = x + i \\eta`.
187
+
188
+ plot : bool, default=False
189
+ If `True`, density is plotted.
190
+
191
+ latex : bool, default=False
192
+ If `True`, the plot is rendered using LaTeX. This option is
193
+ relevant only if ``plot=True``.
194
+
195
+ save : bool, default=False
196
+ If not `False`, the plot is saved. If a string is given, it is
197
+ assumed to the save filename (with the file extension). This option
198
+ is relevant only if ``plot=True``.
199
+
200
+ eig : numpy.array, default=None
201
+ A collection of eigenvalues to compare to via histogram. This
202
+ option is relevant only if ``plot=True``.
203
+
204
+ Returns
205
+ -------
206
+
207
+ rho : numpy.array
208
+ Density.
140
209
  """
141
210
 
142
- x = numpy.asarray(x, dtype=numpy.float64)
143
- z = x + 1j * float(eta)
211
+ # Create x if not given
212
+ if x is None:
213
+ radius = 0.5 * (self.lam_ub - self.lam_lb)
214
+ center = 0.5 * (self.lam_ub + self.lam_lb)
215
+ scale = 1.25
216
+ x_min = numpy.floor(center - radius * scale)
217
+ x_max = numpy.ceil(center + radius * scale)
218
+ x = numpy.linspace(x_min, x_max, 500)
219
+ else:
220
+ x = numpy.asarray(x, dtype=numpy.float64)
144
221
 
222
+ z = x + 1j * float(eta)
145
223
  m = self.stieltjes(z)
146
224
  rho = numpy.imag(m) / numpy.pi
147
225
 
148
- return numpy.maximum(rho, 0.0)
226
+ rho = numpy.maximum(rho, 0.0)
227
+
228
+ if plot:
229
+ if eig is not None:
230
+ label = 'Theoretical'
231
+ else:
232
+ label = ''
233
+ plot_density(x, rho, atoms=None, label=label, latex=latex,
234
+ save=save, eig=eig)
235
+
236
+ return rho
149
237
 
150
238
  # =====
151
239
  # roots
@@ -153,6 +241,7 @@ class DeformedWigner(object):
153
241
 
154
242
  def roots(self, z):
155
243
  """
244
+ Roots of polynomial implicitly representing Stieltjes transform
156
245
  """
157
246
 
158
247
  z = numpy.asarray(z, dtype=numpy.complex128)
@@ -176,6 +265,7 @@ class DeformedWigner(object):
176
265
 
177
266
  def support(self, y_probe=1e-6):
178
267
  """
268
+ Support intervals of distribution
179
269
  """
180
270
 
181
271
  # Unpack parameters
@@ -310,10 +400,9 @@ class DeformedWigner(object):
310
400
 
311
401
  def poly(self):
312
402
  """
313
- Return a_coeffs for the exact cubic P(z,m)=0 of the two-atom deformed
314
- Wigner model.
403
+ Polynomial coefficients implicitly representing the Stieltjes
315
404
 
316
- a_coeffs[i, j] is the coefficient of z^i m^j.
405
+ coeffs[i, j] is the coefficient of z^i m^j.
317
406
  Shape is (deg_z+1, deg_m+1) = (3, 4).
318
407
  """
319
408