freealg 0.1.1__tar.gz → 0.1.3__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 (32) hide show
  1. {freealg-0.1.1/freealg.egg-info → freealg-0.1.3}/PKG-INFO +1 -1
  2. freealg-0.1.3/freealg/__version__.py +1 -0
  3. {freealg-0.1.1 → freealg-0.1.3}/freealg/_util.py +61 -4
  4. {freealg-0.1.1 → freealg-0.1.3}/freealg/freeform.py +32 -9
  5. {freealg-0.1.1 → freealg-0.1.3/freealg.egg-info}/PKG-INFO +1 -1
  6. freealg-0.1.1/freealg/__version__.py +0 -1
  7. {freealg-0.1.1 → freealg-0.1.3}/CHANGELOG.rst +0 -0
  8. {freealg-0.1.1 → freealg-0.1.3}/LICENSE.txt +0 -0
  9. {freealg-0.1.1 → freealg-0.1.3}/MANIFEST.in +0 -0
  10. {freealg-0.1.1 → freealg-0.1.3}/README.rst +0 -0
  11. {freealg-0.1.1 → freealg-0.1.3}/freealg/__init__.py +0 -0
  12. {freealg-0.1.1 → freealg-0.1.3}/freealg/_chebyshev.py +0 -0
  13. {freealg-0.1.1 → freealg-0.1.3}/freealg/_damp.py +0 -0
  14. {freealg-0.1.1 → freealg-0.1.3}/freealg/_decompress.py +0 -0
  15. {freealg-0.1.1 → freealg-0.1.3}/freealg/_jacobi.py +0 -0
  16. {freealg-0.1.1 → freealg-0.1.3}/freealg/_pade.py +0 -0
  17. {freealg-0.1.1 → freealg-0.1.3}/freealg/_plot_util.py +0 -0
  18. {freealg-0.1.1 → freealg-0.1.3}/freealg/_sample.py +0 -0
  19. {freealg-0.1.1 → freealg-0.1.3}/freealg/distributions/__init__.py +0 -0
  20. {freealg-0.1.1 → freealg-0.1.3}/freealg/distributions/kesten_mckay.py +0 -0
  21. {freealg-0.1.1 → freealg-0.1.3}/freealg/distributions/marchenko_pastur.py +0 -0
  22. {freealg-0.1.1 → freealg-0.1.3}/freealg/distributions/wachter.py +0 -0
  23. {freealg-0.1.1 → freealg-0.1.3}/freealg/distributions/wigner.py +0 -0
  24. {freealg-0.1.1 → freealg-0.1.3}/freealg.egg-info/SOURCES.txt +0 -0
  25. {freealg-0.1.1 → freealg-0.1.3}/freealg.egg-info/dependency_links.txt +0 -0
  26. {freealg-0.1.1 → freealg-0.1.3}/freealg.egg-info/not-zip-safe +0 -0
  27. {freealg-0.1.1 → freealg-0.1.3}/freealg.egg-info/requires.txt +0 -0
  28. {freealg-0.1.1 → freealg-0.1.3}/freealg.egg-info/top_level.txt +0 -0
  29. {freealg-0.1.1 → freealg-0.1.3}/pyproject.toml +0 -0
  30. {freealg-0.1.1 → freealg-0.1.3}/requirements.txt +0 -0
  31. {freealg-0.1.1 → freealg-0.1.3}/setup.cfg +0 -0
  32. {freealg-0.1.1 → freealg-0.1.3}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: freealg
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: Free probability for large matrices
5
5
  Keywords: leaderboard bot chat
6
6
  Platform: Linux
@@ -0,0 +1 @@
1
+ __version__ = "0.1.3"
@@ -13,9 +13,10 @@
13
13
 
14
14
  import numpy
15
15
  import scipy
16
+ from scipy.stats import beta
16
17
  from scipy.optimize import minimize
17
18
 
18
- __all__ = ['compute_eig', 'force_density']
19
+ __all__ = ['compute_eig', 'beta_kde', 'force_density']
19
20
 
20
21
 
21
22
  # ===========
@@ -32,6 +33,54 @@ def compute_eig(A, lower=False):
32
33
  return eig
33
34
 
34
35
 
36
+ # ========
37
+ # beta kde
38
+ # ========
39
+
40
+ def beta_kde(eig, xs, lam_m, lam_p, h):
41
+ """
42
+ Beta-kernel KDE with automatic guards against NaNs.
43
+
44
+ Parameters
45
+ ----------
46
+ eig : (n,) 1-D array of samples
47
+ xs : evaluation grid (must lie within [lam_m, lam_p])
48
+ lam_m, lam_p : float, support endpoints (lam_m < lam_p)
49
+ h : bandwidth in rescaled units (0 < h < 1)
50
+
51
+ Returns
52
+ -------
53
+ pdf : ndarray same length as xs
54
+ """
55
+
56
+ span = lam_p - lam_m
57
+ if span <= 0:
58
+ raise ValueError("lam_p must be larger than lam_m")
59
+
60
+ # map samples and grid to [0,1]
61
+ u = (eig - lam_m) / span
62
+ t = (xs - lam_m) / span
63
+
64
+ if u.min() < 0 or u.max() > 1:
65
+ mask = (u > 0) & (u < 1)
66
+ u = u[mask]
67
+
68
+ pdf = numpy.zeros_like(xs, dtype=float)
69
+ n = len(u)
70
+
71
+ # tiny positive number to keep shape parameters >0
72
+ eps = 1e-6
73
+ for ui in u:
74
+ a = max(ui / h + 1.0, eps)
75
+ b = max((1.0 - ui) / h + 1.0, eps)
76
+ pdf += beta.pdf(t, a, b)
77
+
78
+ pdf /= n * span # renormalise
79
+ pdf[(t < 0) | (t > 1)] = 0.0 # exact zeros outside
80
+
81
+ return pdf
82
+
83
+
35
84
  # =============
36
85
  # force density
37
86
  # =============
@@ -72,14 +121,14 @@ def force_density(psi0, support, approx, grid, alpha=0.0, beta=0.0):
72
121
  if beta <= 0.0 and beta > -0.5:
73
122
  constraints.append({
74
123
  'type': 'eq',
75
- 'fun': lambda psi: approx(numpy.array([lam_m], psi))[0]
124
+ 'fun': lambda psi: approx(numpy.array([lam_m]), psi)[0]
76
125
  })
77
126
 
78
127
  # Enforce zero at right edge
79
128
  if alpha <= 0.0 and alpha > -0.5:
80
129
  constraints.append({
81
130
  'type': 'eq',
82
- 'fun': lambda psi: approx(numpy.array([lam_p], psi))[0]
131
+ 'fun': lambda psi: approx(numpy.array([lam_p]), psi)[0]
83
132
  })
84
133
 
85
134
  # Solve a small quadratic programming
@@ -89,4 +138,12 @@ def force_density(psi0, support, approx, grid, alpha=0.0, beta=0.0):
89
138
  method='SLSQP',
90
139
  options={'maxiter': 1000, 'ftol': 1e-9, 'eps': 1e-8})
91
140
 
92
- return res.x
141
+ psi = res.x
142
+
143
+ # Normalize first mode to unit mass
144
+ x = numpy.linspace(lam_m, lam_p, 1000)
145
+ rho = approx(x, psi)
146
+ mass = numpy.trapz(rho, x)
147
+ psi[0] = psi[0] / mass
148
+
149
+ return psi
@@ -15,7 +15,7 @@ import numpy
15
15
  from scipy.stats import gaussian_kde
16
16
  # from statsmodels.nonparametric.kde import KDEUnivariate
17
17
  from functools import partial
18
- from ._util import compute_eig, force_density
18
+ from ._util import compute_eig, beta_kde, force_density
19
19
  from ._jacobi import jacobi_sample_proj, jacobi_kernel_proj, jacobi_approx, \
20
20
  jacobi_stieltjes
21
21
  from ._chebyshev import chebyshev_sample_proj, chebyshev_kernel_proj, \
@@ -177,7 +177,7 @@ class FreeForm(object):
177
177
  # ===
178
178
 
179
179
  def fit(self, method='jacobi', K=10, alpha=0.0, beta=0.0, reg=0.0,
180
- projection='kernel', kernel_bw=None, damp=None, force=False,
180
+ projection='gaussian', kernel_bw=None, damp=None, force=False,
181
181
  pade_p=0, pade_q=1, odd_side='left', pade_reg=0.0, optimizer='ls',
182
182
  plot=False, latex=False, save=False):
183
183
  """
@@ -206,14 +206,19 @@ class FreeForm(object):
206
206
  reg : float, default=0.0
207
207
  Tikhonov regularization coefficient.
208
208
 
209
- projection : {``'sample'``, ``'kernel'``}, default= ``'kernel'``
209
+ projection : {``'sample'``, ``'gaussian'``, ``'beta'``}, \
210
+ default= ``'gaussian'``
210
211
  The method of Galerkin projection:
211
212
 
212
213
  * ``'sample'``: directly project samples (eigenvalues) to the
213
214
  orthogonal polynomials. This method is highly unstable as it
214
215
  treats each sample as a delta Dirac function.
215
- * ``'kernel'``: computes KDE from the samples and project a
216
- smooth KDE to the orthogonal polynomials. This method is stable.
216
+ * ``'gaussian'``: computes Gaussian-Kernel KDE from the samples and
217
+ project a smooth KDE to the orthogonal polynomials. This method
218
+ is stable.
219
+ * ``'beta'``: computes Beta-Kernel KDE from the samples and
220
+ project a smooth KDE to the orthogonal polynomials. This method
221
+ is stable.
217
222
 
218
223
  kernel_bw : float, default=None
219
224
  Kernel band-wdth. See scipy.stats.gaussian_kde. This argument is
@@ -301,7 +306,7 @@ class FreeForm(object):
301
306
  if not (method in ['jacobi', 'chebyshev']):
302
307
  raise ValueError('"method" is invalid.')
303
308
 
304
- if not (projection in ['sample', 'kernel']):
309
+ if not (projection in ['sample', 'gaussian', 'beta']):
305
310
  raise ValueError('"projection" is invalid.')
306
311
 
307
312
  # Project eigenvalues to Jacobi polynomials basis
@@ -313,7 +318,12 @@ class FreeForm(object):
313
318
  else:
314
319
  # smooth KDE on a fixed grid
315
320
  xs = numpy.linspace(self.lam_m, self.lam_p, 2000)
316
- pdf = gaussian_kde(self.eig, bw_method=kernel_bw)(xs)
321
+
322
+ if projection == 'gaussian':
323
+ pdf = gaussian_kde(self.eig, bw_method=kernel_bw)(xs)
324
+ else:
325
+ pdf = beta_kde(self.eig, xs, self.lam_m, self.lam_p,
326
+ kernel_bw)
317
327
 
318
328
  # Adaptive KDE
319
329
  # k = KDEUnivariate(self.eig)
@@ -321,6 +331,12 @@ class FreeForm(object):
321
331
  # adaptive=True)
322
332
  # pdf = k.evaluate(xs)
323
333
 
334
+ # TEST
335
+ # import matplotlib.pyplot as plt
336
+ # plt.plot(xs, pdf)
337
+ # plt.grid(True)
338
+ # plt.show()
339
+
324
340
  psi = jacobi_kernel_proj(xs, pdf, support=self.support, K=K,
325
341
  alpha=alpha, beta=beta, reg=reg)
326
342
 
@@ -332,7 +348,12 @@ class FreeForm(object):
332
348
  else:
333
349
  # smooth KDE on a fixed grid
334
350
  xs = numpy.linspace(self.lam_m, self.lam_p, 2000)
335
- pdf = gaussian_kde(self.eig, bw_method=kernel_bw)(xs)
351
+
352
+ if projection == 'gaussian':
353
+ pdf = gaussian_kde(self.eig, bw_method=kernel_bw)(xs)
354
+ else:
355
+ pdf = beta_kde(self.eig, xs, self.lam_m, self.lam_p,
356
+ kernel_bw)
336
357
 
337
358
  # Adaptive KDE
338
359
  # k = KDEUnivariate(self.eig)
@@ -477,7 +498,7 @@ class FreeForm(object):
477
498
 
478
499
  # Check density is unit mass
479
500
  mass = numpy.trapz(rho, x)
480
- if not numpy.isclose(mass, 1.0, atol=1e-3):
501
+ if not numpy.isclose(mass, 1.0, atol=1e-2):
481
502
  # raise RuntimeWarning(f'"rho" is not unit mass. mass: {mass}. ' +
482
503
  # r'Set "force=True".')
483
504
  print(f'"rho" is not unit mass. mass: {mass}. Set "force=True".')
@@ -893,6 +914,8 @@ class FreeForm(object):
893
914
  >>> from freealg import FreeForm
894
915
  """
895
916
 
917
+ size = int(size)
918
+
896
919
  rho, x, (lb, ub) = decompress(self, size, x=x, delta=delta,
897
920
  iterations=iterations,
898
921
  step_size=step_size, tolerance=tolerance)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: freealg
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: Free probability for large matrices
5
5
  Keywords: leaderboard bot chat
6
6
  Platform: Linux
@@ -1 +0,0 @@
1
- __version__ = "0.1.1"
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
File without changes
File without changes
File without changes
File without changes
File without changes