freealg 0.7.8__tar.gz → 0.7.9__tar.gz

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 (63) hide show
  1. {freealg-0.7.8 → freealg-0.7.9}/PKG-INFO +1 -1
  2. freealg-0.7.9/freealg/__version__.py +1 -0
  3. {freealg-0.7.8 → freealg-0.7.9}/freealg/_algebraic_form/_homotopy.py +23 -12
  4. {freealg-0.7.8 → freealg-0.7.9}/freealg/_algebraic_form/_moments.py +0 -7
  5. {freealg-0.7.8 → freealg-0.7.9}/freealg/_algebraic_form/algebraic_form.py +50 -107
  6. {freealg-0.7.8 → freealg-0.7.9}/freealg.egg-info/PKG-INFO +1 -1
  7. freealg-0.7.8/freealg/__version__.py +0 -1
  8. {freealg-0.7.8 → freealg-0.7.9}/AUTHORS.txt +0 -0
  9. {freealg-0.7.8 → freealg-0.7.9}/CHANGELOG.rst +0 -0
  10. {freealg-0.7.8 → freealg-0.7.9}/LICENSE.txt +0 -0
  11. {freealg-0.7.8 → freealg-0.7.9}/MANIFEST.in +0 -0
  12. {freealg-0.7.8 → freealg-0.7.9}/README.rst +0 -0
  13. {freealg-0.7.8 → freealg-0.7.9}/freealg/__init__.py +0 -0
  14. {freealg-0.7.8 → freealg-0.7.9}/freealg/_algebraic_form/__init__.py +0 -0
  15. {freealg-0.7.8 → freealg-0.7.9}/freealg/_algebraic_form/_constraints.py +0 -0
  16. {freealg-0.7.8 → freealg-0.7.9}/freealg/_algebraic_form/_continuation_algebraic.py +0 -0
  17. {freealg-0.7.8 → freealg-0.7.9}/freealg/_algebraic_form/_decompress.py +0 -0
  18. {freealg-0.7.8 → freealg-0.7.9}/freealg/_algebraic_form/_decompress2.py +0 -0
  19. {freealg-0.7.8 → freealg-0.7.9}/freealg/_algebraic_form/_discriminant.py +0 -0
  20. {freealg-0.7.8 → freealg-0.7.9}/freealg/_algebraic_form/_edge.py +0 -0
  21. {freealg-0.7.8 → freealg-0.7.9}/freealg/_algebraic_form/_sheets_util.py +0 -0
  22. {freealg-0.7.8 → freealg-0.7.9}/freealg/_free_form/__init__.py +0 -0
  23. {freealg-0.7.8 → freealg-0.7.9}/freealg/_free_form/_chebyshev.py +0 -0
  24. {freealg-0.7.8 → freealg-0.7.9}/freealg/_free_form/_damp.py +0 -0
  25. {freealg-0.7.8 → freealg-0.7.9}/freealg/_free_form/_decompress.py +0 -0
  26. {freealg-0.7.8 → freealg-0.7.9}/freealg/_free_form/_density_util.py +0 -0
  27. {freealg-0.7.8 → freealg-0.7.9}/freealg/_free_form/_jacobi.py +0 -0
  28. {freealg-0.7.8 → freealg-0.7.9}/freealg/_free_form/_linalg.py +0 -0
  29. {freealg-0.7.8 → freealg-0.7.9}/freealg/_free_form/_pade.py +0 -0
  30. {freealg-0.7.8 → freealg-0.7.9}/freealg/_free_form/_plot_util.py +0 -0
  31. {freealg-0.7.8 → freealg-0.7.9}/freealg/_free_form/_sample.py +0 -0
  32. {freealg-0.7.8 → freealg-0.7.9}/freealg/_free_form/_series.py +0 -0
  33. {freealg-0.7.8 → freealg-0.7.9}/freealg/_free_form/_support.py +0 -0
  34. {freealg-0.7.8 → freealg-0.7.9}/freealg/_free_form/free_form.py +0 -0
  35. {freealg-0.7.8 → freealg-0.7.9}/freealg/_geometric_form/__init__.py +0 -0
  36. {freealg-0.7.8 → freealg-0.7.9}/freealg/_geometric_form/_continuation_genus0.py +0 -0
  37. {freealg-0.7.8 → freealg-0.7.9}/freealg/_geometric_form/_continuation_genus1.py +0 -0
  38. {freealg-0.7.8 → freealg-0.7.9}/freealg/_geometric_form/_elliptic_functions.py +0 -0
  39. {freealg-0.7.8 → freealg-0.7.9}/freealg/_geometric_form/_sphere_maps.py +0 -0
  40. {freealg-0.7.8 → freealg-0.7.9}/freealg/_geometric_form/_torus_maps.py +0 -0
  41. {freealg-0.7.8 → freealg-0.7.9}/freealg/_geometric_form/geometric_form.py +0 -0
  42. {freealg-0.7.8 → freealg-0.7.9}/freealg/_util.py +0 -0
  43. {freealg-0.7.8 → freealg-0.7.9}/freealg/distributions/__init__.py +0 -0
  44. {freealg-0.7.8 → freealg-0.7.9}/freealg/distributions/_chiral_block.py +0 -0
  45. {freealg-0.7.8 → freealg-0.7.9}/freealg/distributions/_deformed_marchenko_pastur.py +0 -0
  46. {freealg-0.7.8 → freealg-0.7.9}/freealg/distributions/_deformed_wigner.py +0 -0
  47. {freealg-0.7.8 → freealg-0.7.9}/freealg/distributions/_kesten_mckay.py +0 -0
  48. {freealg-0.7.8 → freealg-0.7.9}/freealg/distributions/_marchenko_pastur.py +0 -0
  49. {freealg-0.7.8 → freealg-0.7.9}/freealg/distributions/_meixner.py +0 -0
  50. {freealg-0.7.8 → freealg-0.7.9}/freealg/distributions/_wachter.py +0 -0
  51. {freealg-0.7.8 → freealg-0.7.9}/freealg/distributions/_wigner.py +0 -0
  52. {freealg-0.7.8 → freealg-0.7.9}/freealg/visualization/__init__.py +0 -0
  53. {freealg-0.7.8 → freealg-0.7.9}/freealg/visualization/_glue_util.py +0 -0
  54. {freealg-0.7.8 → freealg-0.7.9}/freealg/visualization/_rgb_hsv.py +0 -0
  55. {freealg-0.7.8 → freealg-0.7.9}/freealg.egg-info/SOURCES.txt +0 -0
  56. {freealg-0.7.8 → freealg-0.7.9}/freealg.egg-info/dependency_links.txt +0 -0
  57. {freealg-0.7.8 → freealg-0.7.9}/freealg.egg-info/not-zip-safe +0 -0
  58. {freealg-0.7.8 → freealg-0.7.9}/freealg.egg-info/requires.txt +0 -0
  59. {freealg-0.7.8 → freealg-0.7.9}/freealg.egg-info/top_level.txt +0 -0
  60. {freealg-0.7.8 → freealg-0.7.9}/pyproject.toml +0 -0
  61. {freealg-0.7.8 → freealg-0.7.9}/requirements.txt +0 -0
  62. {freealg-0.7.8 → freealg-0.7.9}/setup.cfg +0 -0
  63. {freealg-0.7.8 → freealg-0.7.9}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: freealg
3
- Version: 0.7.8
3
+ Version: 0.7.9
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 @@
1
+ __version__ = "0.7.9"
@@ -4,6 +4,7 @@
4
4
 
5
5
  import numpy
6
6
  from ._moments import AlgebraicStieltjesMoments
7
+ from tqdm import tqdm
7
8
 
8
9
  __all__ = ['stieltjes_poly']
9
10
 
@@ -125,13 +126,15 @@ class StieltjesPoly(object):
125
126
  self.steps = steps
126
127
  self.order = order
127
128
 
128
- # Objects depending only on a
129
129
  self.mom = AlgebraicStieltjesMoments(a)
130
- self._zpows_exp = numpy.arange(self.a_l)
131
130
  self.rad = 1.0 + self.height * self.mom.radius(self.order)
131
+ self.z0_p = 1j * self.rad
132
+ self.m0_p = self.mom.stieltjes(self.z0_p, self.order)
133
+ self.z0_m = -1j * self.rad
134
+ self.m0_m = self.mom.stieltjes(self.z0_m, self.order)
132
135
 
133
136
  def _poly_coeffs_m(self, z_val):
134
- z_powers = z_val ** self._zpows_exp
137
+ z_powers = z_val ** numpy.arange(self.a_l)
135
138
  return (z_powers @ self.a)[::-1]
136
139
 
137
140
  def _poly_roots(self, z_val):
@@ -165,14 +168,18 @@ class StieltjesPoly(object):
165
168
  if half_sign == 0.0:
166
169
  half_sign = 1.0
167
170
 
168
- # If z is outside radius of convergence, no homotopy
169
- # necessary
170
- if numpy.abs(z) > self.rad:
171
- target = self.mom.stieltjes(z, self.order)
172
- return select_root(self._poly_roots(z), z, target)
171
+ # # If z is outside radius of convergence, no homotopy
172
+ # # necessary
173
+ # if numpy.abs(z) > self.rad:
174
+ # target = self.mom.stieltjes(z, self.order)
175
+ # return select_root(self._poly_roots(z), z, target)
173
176
 
174
- z0 = 1j * float(half_sign) * self.rad
175
- target = self.mom.stieltjes(z0, self.order)
177
+ if half_sign > 0.0:
178
+ z0 = self.z0_p
179
+ target = self.m0_p
180
+ else:
181
+ z0 = self.z0_m
182
+ target = self.m0_m
176
183
 
177
184
  # Initialize at z0
178
185
  w_prev = select_root(self._poly_roots(z0), z0, target)
@@ -184,7 +191,7 @@ class StieltjesPoly(object):
184
191
 
185
192
  return w_prev
186
193
 
187
- def __call__(self, z):
194
+ def __call__(self, z, progress=False):
188
195
  # Scalar fast-path
189
196
  if numpy.isscalar(z):
190
197
  return self.evaluate(z)
@@ -194,7 +201,11 @@ class StieltjesPoly(object):
194
201
  out = numpy.empty(z_arr.shape, dtype=numpy.complex128)
195
202
 
196
203
  # Iterate over indices so we can pass Python scalars into evaluate()
197
- for idx in numpy.ndindex(z_arr.shape):
204
+ if progress:
205
+ indices = tqdm(numpy.ndindex(z_arr.shape),total=z_arr.size)
206
+ else:
207
+ indices = numpy.ndindex(z_arr.shape)
208
+ for idx in indices:
198
209
  out[idx] = self.evaluate(z_arr[idx])
199
210
 
200
211
  return out
@@ -441,10 +441,3 @@ class AlgebraicStieltjesMoments(object):
441
441
  mu = self.moments(N)
442
442
  return -numpy.sum(z[..., numpy.newaxis]**(-numpy.arange(N+1)-1) * mu,
443
443
  axis=-1)
444
-
445
- def target_pt(self, N=15):
446
- # Obtain an estimate of the Stieltjes transform at a
447
- # single point z where the estimate is likely reliable
448
- z = 1j + 2j * self.radius(N)
449
- return z, self.stieltjes(z, N)
450
-
@@ -24,7 +24,7 @@ from ._homotopy import StieltjesPoly
24
24
  from ._discriminant import compute_singular_points
25
25
  from ._moments import MomentsESD
26
26
  from .._free_form._support import supp
27
- from .._free_form._plot_util import plot_density
27
+ from .._free_form._plot_util import plot_density, plot_hilbert, plot_stieltjes
28
28
 
29
29
  # Fallback to previous numpy API
30
30
  if not hasattr(numpy, 'trapezoid'):
@@ -144,7 +144,7 @@ class AlgebraicForm(object):
144
144
 
145
145
  self.A = None
146
146
  self.eig = None
147
- self.stieltjes = None
147
+ self._stieltjes = None
148
148
  self.moments = None
149
149
  self.support = support
150
150
  self.delta = delta # Offset above real axis to apply Plemelj formula
@@ -154,12 +154,12 @@ class AlgebraicForm(object):
154
154
 
155
155
  if hasattr(A, 'stieltjes') and callable(getattr(A, 'stieltjes', None)):
156
156
  # This is one of the distribution objects, like MarchenkoPastur
157
- self.stieltjes = A.stieltjes
157
+ self._stieltjes = A.stieltjes
158
158
  self.n = 1
159
159
 
160
160
  elif callable(A):
161
161
  # This is a custom function
162
- self.stieltjes = A
162
+ self._stieltjes = A
163
163
  self.n = 1
164
164
 
165
165
  else:
@@ -178,7 +178,7 @@ class AlgebraicForm(object):
178
178
  self.eig = compute_eig(A)
179
179
 
180
180
  # Use empirical Stieltjes function
181
- self.stieltjes = lambda z: \
181
+ self._stieltjes = lambda z: \
182
182
  numpy.mean(1.0/(self.eig-z[:, numpy.newaxis]), axis=-1)
183
183
  self.moments = MomentsESD(self.eig)
184
184
 
@@ -265,7 +265,7 @@ class AlgebraicForm(object):
265
265
  x_pad=x_pad)
266
266
 
267
267
  # Fitting (w_inf = None means adaptive weight selection)
268
- m1_fit = self.stieltjes(z_fit)
268
+ m1_fit = self._stieltjes(z_fit)
269
269
  a_coeffs, fit_metrics = fit_polynomial_relation(
270
270
  z_fit, m1_fit, s=deg_m, deg_z=deg_z, ridge_lambda=reg,
271
271
  triangular=triangular, normalize=normalize, mu=mu,
@@ -294,7 +294,7 @@ class AlgebraicForm(object):
294
294
  status['res_99_9'] = float(res_99_9)
295
295
  status['fit_metrics'] = fit_metrics
296
296
  self.status = status
297
- self.stieltjes = StieltjesPoly(self.a_coeffs)
297
+ self._stieltjes = StieltjesPoly(self.a_coeffs)
298
298
 
299
299
  if verbose:
300
300
  print(f'fit residual max : {res_max:>0.4e}')
@@ -388,8 +388,6 @@ class AlgebraicForm(object):
388
388
  >>> from freealg import FreeForm
389
389
  """
390
390
 
391
- pass
392
-
393
391
  if self.a_coeffs is None:
394
392
  raise RuntimeError('The model needs to be fit using the .fit() ' +
395
393
  'function.')
@@ -399,27 +397,7 @@ class AlgebraicForm(object):
399
397
  x = self._generate_grid(1.25)
400
398
 
401
399
  # Preallocate density to zero
402
- rho = self.stieltjes(x).imag / numpy.pi
403
-
404
- # if self.method == 'jacobi':
405
- # rho[mask] = jacobi_density(x[mask], self.psi, self.support,
406
- # self.alpha, self.beta)
407
- # elif self.method == 'chebyshev':
408
- # rho[mask] = chebyshev_density(x[mask], self.psi, self.support)
409
- # else:
410
- # raise RuntimeError('"method" is invalid.')
411
- #
412
- # # Check density is unit mass
413
- # mass = numpy.trapezoid(rho, x)
414
- # if not numpy.isclose(mass, 1.0, atol=1e-2):
415
- # print(f'"rho" is not unit mass. mass: {mass:>0.3f}. Set ' +
416
- # r'"force=True".')
417
- #
418
- # # Check density is positive
419
- # min_rho = numpy.min(rho)
420
- # if min_rho < 0.0 - 1e-3:
421
- # print(f'"rho" is not positive. min_rho: {min_rho:>0.3f}. Set ' +
422
- # r'"force=True".')
400
+ rho = self._stieltjes(x).imag / numpy.pi
423
401
 
424
402
  if plot:
425
403
  plot_density(x, rho, eig=self.eig, support=self.broad_support,
@@ -431,7 +409,7 @@ class AlgebraicForm(object):
431
409
  # hilbert
432
410
  # =======
433
411
 
434
- def hilbert(self, x=None, rho=None, plot=False, latex=False, save=False):
412
+ def hilbert(self, x=None, plot=False, latex=False, save=False):
435
413
  """
436
414
  Compute Hilbert transform of the spectral density.
437
415
 
@@ -443,9 +421,6 @@ class AlgebraicForm(object):
443
421
  an interval slightly larger than the support interval of the
444
422
  spectral density is used.
445
423
 
446
- rho : numpy.array, default=None
447
- Density. If `None`, it will be computed.
448
-
449
424
  plot : bool, default=False
450
425
  If `True`, density is plotted.
451
426
 
@@ -477,49 +452,22 @@ class AlgebraicForm(object):
477
452
  >>> from freealg import FreeForm
478
453
  """
479
454
 
480
- pass
481
-
482
455
  if self.a_coeffs is None:
483
456
  raise RuntimeError('The model needs to be fit using the .fit() ' +
484
457
  'function.')
485
458
 
486
- # # Create x if not given
487
- # if x is None:
488
- # x = self._generate_grid(1.25)
489
- #
490
- # # if (numpy.min(x) > self.lam_m) or (numpy.max(x) < self.lam_p):
491
- # # raise ValueError('"x" does not encompass support interval.')
492
- #
493
- # # Preallocate density to zero
494
- # if rho is None:
495
- # rho = self.density(x)
496
- #
497
- # # mask of support [lam_m, lam_p]
498
- # mask = numpy.logical_and(x >= self.lam_m, x <= self.lam_p)
499
- # x_s = x[mask]
500
- # rho_s = rho[mask]
501
- #
502
- # # Form the matrix of integrands: rho_s / (t - x_i)
503
- # # Here, we have diff[i,j] = x[i] - x_s[j]
504
- # diff = x[:, None] - x_s[None, :]
505
- # D = rho_s[None, :] / diff
506
- #
507
- # # Principal-value: wherever t == x_i, then diff == 0, zero that entry
508
- # # (numpy.isclose handles floating-point exactly)
509
- # D[numpy.isclose(diff, 0.0)] = 0.0
510
- #
511
- # # Integrate each row over t using trapezoid rule on x_s
512
- # # Namely, hilb[i] = int rho_s(t)/(t - x[i]) dt
513
- # hilb = numpy.trapezoid(D, x_s, axis=1) / numpy.pi
514
- #
515
- # # We use negative sign convention
516
- # hilb = -hilb
517
- #
518
- # if plot:
519
- # plot_hilbert(x, hilb, support=self.support, latex=latex,
520
- # save=save)
521
- #
522
- # return hilb
459
+ # Create x if not given
460
+ if x is None:
461
+ x = self._generate_grid(1.25)
462
+
463
+ # Preallocate density to zero
464
+ hilb = -self._stieltjes(x).real / numpy.pi
465
+
466
+ if plot:
467
+ plot_hilbert(x, hilb, support=self.support, latex=latex,
468
+ save=save)
469
+
470
+ return hilb
523
471
 
524
472
  # =========
525
473
  # stieltjes
@@ -559,12 +507,9 @@ class AlgebraicForm(object):
559
507
  Returns
560
508
  -------
561
509
 
562
- m_p : numpy.ndarray
510
+ m : numpy.ndarray
563
511
  The Stieltjes transform on the principal branch.
564
512
 
565
- m_m : numpy.ndarray
566
- The Stieltjes transform continued to the secondary branch.
567
-
568
513
  See Also
569
514
  --------
570
515
 
@@ -579,36 +524,34 @@ class AlgebraicForm(object):
579
524
  >>> from freealg import FreeForm
580
525
  """
581
526
 
582
- pass
583
-
584
527
  if self.a_coeffs is None:
585
528
  raise RuntimeError('The model needs to be fit using the .fit() ' +
586
529
  'function.')
587
530
 
588
- # # Create x if not given
589
- # if x is None:
590
- # x = self._generate_grid(2.0, extend=2.0)
591
- #
592
- # # Create y if not given
593
- # if (plot is False) and (y is None):
594
- # # Do not use a Cartesian grid. Create a 1D array z slightly above
595
- # # the real line.
596
- # y = self.delta * 1j
597
- # z = x.astype(complex) + y # shape (Nx,)
598
- # else:
599
- # # Use a Cartesian grid
600
- # if y is None:
601
- # y = numpy.linspace(-1, 1, 400)
602
- # x_grid, y_grid = numpy.meshgrid(x.real, y.real)
603
- # z = x_grid + 1j * y_grid # shape (Ny, Nx)
604
- #
605
- # m1, m2 = self._eval_stieltjes(z, branches=True)
606
- #
607
- # if plot:
608
- # plot_stieltjes(x, y, m1, m2, self.support, latex=latex,
609
- # save=save)
610
- #
611
- # return m1, m2
531
+ # Create x if not given
532
+ if x is None:
533
+ x = self._generate_grid(2.0, extend=2.0)[::2]
534
+
535
+ # Create y if not given
536
+ if (plot is False) and (y is None):
537
+ # Do not use a Cartesian grid. Create a 1D array z slightly above
538
+ # the real line.
539
+ y = self.delta * 1j
540
+ z = x.astype(complex) + y # shape (Nx,)
541
+ else:
542
+ # Use a Cartesian grid
543
+ if y is None:
544
+ y = numpy.linspace(-1, 1, 200)
545
+ x_grid, y_grid = numpy.meshgrid(x.real, y.real)
546
+ z = x_grid + 1j * y_grid # shape (Ny, Nx)
547
+
548
+ m = self._stieltjes(z, progress=True)
549
+
550
+ if plot:
551
+ plot_stieltjes(x, y, m, m, self.broad_support, latex=latex,
552
+ save=save)
553
+
554
+ return m
612
555
 
613
556
  # ==============
614
557
  # eval stieltjes
@@ -668,8 +611,8 @@ class AlgebraicForm(object):
668
611
  alpha = numpy.atleast_1d(size) / self.n
669
612
 
670
613
  # Lower and upper bound on new support
671
- hilb_lb = (1.0 / self.stieltjes(self.lam_m + self.delta * 1j).item()).real
672
- hilb_ub = (1.0 / self.stieltjes(self.lam_p + self.delta * 1j).item()).real
614
+ hilb_lb = (1.0 / self._stieltjes(self.lam_m + self.delta * 1j).item()).real
615
+ hilb_ub = (1.0 / self._stieltjes(self.lam_p + self.delta * 1j).item()).real
673
616
  lb = self.lam_m - (numpy.max(alpha) - 1) * hilb_lb
674
617
  ub = self.lam_p - (numpy.max(alpha) - 1) * hilb_ub
675
618
 
@@ -690,7 +633,7 @@ class AlgebraicForm(object):
690
633
  z_query = x + 1j * self.delta
691
634
 
692
635
  # Initial condition at t=0 (physical branch)
693
- w0_list = self.stieltjes(z_query)
636
+ w0_list = self._stieltjes(z_query)
694
637
 
695
638
  # Times
696
639
  t = numpy.log(alpha)
@@ -721,7 +664,7 @@ class AlgebraicForm(object):
721
664
  coeffs_i = decompress_coeffs(self.a_coeffs,
722
665
  numpy.log(alpha[i]))
723
666
  stieltjes_i = StieltjesPoly(coeffs_i)
724
- rho[i, :] = stieltjes_i.imag
667
+ rho[i, :] = stieltjes_i(x).imag
725
668
 
726
669
  rho = rho / numpy.pi
727
670
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: freealg
3
- Version: 0.7.8
3
+ Version: 0.7.9
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
@@ -1 +0,0 @@
1
- __version__ = "0.7.8"
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
File without changes
File without changes