freealg 0.1.14__py3-none-any.whl → 0.2.0__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 CHANGED
@@ -7,9 +7,9 @@
7
7
  # directory of this source tree.
8
8
 
9
9
  from .freeform import FreeForm
10
- from .eigfree import eigfree
10
+ from .eigh import eigh, cond
11
11
  from . import distributions
12
12
 
13
- __all__ = ['FreeForm', 'distributions', 'eigfree']
13
+ __all__ = ['FreeForm', 'distributions', 'eigh', 'cond']
14
14
 
15
15
  from .__version__ import __version__ # noqa: F401 E402
freealg/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.14"
1
+ __version__ = "0.2.0"
freealg/_chebyshev.py CHANGED
@@ -224,14 +224,6 @@ def chebyshev_stieltjes(z, psi, support):
224
224
  psi_zero = numpy.concatenate([[0], psi])
225
225
  S = wynn_pade(psi_zero, J)
226
226
 
227
- # build powers J^(k+1) for k=0..K
228
- # K = len(psi) - 1
229
- # shape: (..., K+1)
230
- # Jpow = J[..., None] ** numpy.arange(1, K+2)
231
-
232
- # sum psi_k * J^(k+1)
233
- # S = numpy.sum(psi * Jpow, axis=-1)
234
-
235
227
  # assemble m(z)
236
228
  m_z = -2 / span * numpy.pi * S
237
229
 
freealg/_decompress.py CHANGED
@@ -12,6 +12,10 @@
12
12
 
13
13
  import numpy
14
14
 
15
+ # Fallback to previous API
16
+ if not hasattr(numpy, 'trapezoid'):
17
+ numpy.trapezoid = numpy.trapz
18
+
15
19
  __all__ = ['decompress', 'reverse_characteristics']
16
20
 
17
21
 
@@ -19,9 +23,8 @@ __all__ = ['decompress', 'reverse_characteristics']
19
23
  # secant method
20
24
  # =============
21
25
 
22
-
23
26
  def secant_complex(f, z0, z1, a=0+0j, tol=1e-12, max_iter=100,
24
- alpha=0.5, max_bt=2, eps=1e-30, step_factor=5.0,
27
+ alpha=0.5, max_bt=1, eps=1e-30, step_factor=5.0,
25
28
  post_smooth=True, jump_tol=10.0, verbose=False):
26
29
  """
27
30
  Solves :math:``f(z) = a`` for many starting points simultaneously
@@ -200,7 +203,6 @@ def secant_complex(f, z0, z1, a=0+0j, tol=1e-12, max_iter=100,
200
203
  # decompress
201
204
  # ==========
202
205
 
203
-
204
206
  def decompress(freeform, size, x=None, delta=1e-4, max_iter=500,
205
207
  tolerance=1e-8):
206
208
  """
@@ -287,9 +289,9 @@ def decompress(freeform, size, x=None, delta=1e-4, max_iter=500,
287
289
  def _char_z(z):
288
290
  return z + (1 / m(z)) * (1 - alpha)
289
291
 
290
- z0 = numpy.full(target.shape, numpy.mean(freeform.support) + .1j,
292
+ z0 = numpy.full(target.shape, numpy.mean(freeform.support) + 0.1j,
291
293
  dtype=numpy.complex128)
292
- z1 = z0 - .2j
294
+ z1 = z0 - 0.2j
293
295
 
294
296
  roots, _, _ = secant_complex(
295
297
  _char_z, z0, z1,
freealg/_pade.py CHANGED
@@ -299,7 +299,6 @@ def wynn_pade(coeffs, x):
299
299
  # fit pade
300
300
  # ========
301
301
 
302
-
303
302
  def fit_pade(x, f, lam_m, lam_p, p=1, q=2, odd_side='left', pade_reg=0.0,
304
303
  safety=1.0, max_outer=40, xtol=1e-12, ftol=1e-12, optimizer='ls',
305
304
  verbose=0):
freealg/_support.py CHANGED
@@ -14,6 +14,12 @@ import numpy
14
14
  import numba
15
15
  from scipy.stats import gaussian_kde
16
16
 
17
+ __all__ = ['support_from_density', 'detect_support']
18
+
19
+
20
+ # ====================
21
+ # support from density
22
+ # ====================
17
23
 
18
24
  @numba.njit(numba.types.UniTuple(numba.types.int64, 2)(
19
25
  numba.types.float64,
@@ -24,6 +30,7 @@ def support_from_density(dx, density):
24
30
  Estimates the support from a collection of noisy observations of a
25
31
  density over a grid of x-values with mesh spacing dx.
26
32
  """
33
+
27
34
  n = density.shape[0]
28
35
  target = 1.0 / dx
29
36
 
@@ -92,6 +99,10 @@ def support_from_density(dx, density):
92
99
  return optimal_i, optimal_j
93
100
 
94
101
 
102
+ # ==============
103
+ # detect support
104
+ # ==============
105
+
95
106
  def detect_support(eigs, method='asymp', k=None, p=0.001, **kwargs):
96
107
  """
97
108
  Estimates the support of the eigenvalue density.
freealg/_util.py CHANGED
@@ -16,6 +16,10 @@ import scipy
16
16
  from scipy.stats import beta
17
17
  from scipy.optimize import minimize
18
18
 
19
+ # Fallback to previous API
20
+ if not hasattr(numpy, 'trapezoid'):
21
+ numpy.trapezoid = numpy.trapz
22
+
19
23
  __all__ = ['compute_eig', 'beta_kde', 'force_density']
20
24
 
21
25
 
@@ -178,7 +178,7 @@ class KestenMcKay(object):
178
178
 
179
179
  if plot:
180
180
  if eig is not None:
181
- label = 'Estimate'
181
+ label = 'Theoretical'
182
182
  else:
183
183
  label = ''
184
184
  plot_density(x, rho, label=label, latex=latex, save=save, eig=eig)
@@ -176,7 +176,7 @@ class MarchenkoPastur(object):
176
176
 
177
177
  if plot:
178
178
  if eig is not None:
179
- label = 'Estimate'
179
+ label = 'Theoretical'
180
180
  else:
181
181
  label = ''
182
182
  plot_density(x, rho, label=label, latex=latex, save=save, eig=eig)
@@ -193,7 +193,7 @@ class Meixner(object):
193
193
 
194
194
  if plot:
195
195
  if eig is not None:
196
- label = 'Estimate'
196
+ label = 'Theoretical'
197
197
  else:
198
198
  label = ''
199
199
  plot_density(x, rho, label=label, latex=latex, save=save, eig=eig)
@@ -184,7 +184,7 @@ class Wachter(object):
184
184
 
185
185
  if plot:
186
186
  if eig is not None:
187
- label = 'Estimate'
187
+ label = 'Theoretical'
188
188
  else:
189
189
  label = ''
190
190
  plot_density(x, rho, label=label, latex=latex, save=save, eig=eig)
@@ -164,7 +164,7 @@ class Wigner(object):
164
164
 
165
165
  if plot:
166
166
  if eig is not None:
167
- label = 'Estimate'
167
+ label = 'Theoretical'
168
168
  else:
169
169
  label = ''
170
170
  plot_density(x, rho, label=label, latex=latex, save=save, eig=eig)
@@ -1,4 +1,3 @@
1
- # SPDX-FileCopyrightText: Copyright 2025, Siavash Ameli <sameli@berkeley.edu>
2
1
  # SPDX-License-Identifier: BSD-3-Clause
3
2
  # SPDX-FileType: SOURCE
4
3
  #
@@ -15,15 +14,14 @@ import numpy
15
14
  from ._util import compute_eig
16
15
  from .freeform import FreeForm
17
16
 
18
- __all__ = ['eigfree']
17
+ __all__ = ['eigh', 'cond']
19
18
 
20
19
 
21
- # ========
22
- # eig free
23
- # ========
20
+ # ====
21
+ # eigh
22
+ # ====
24
23
 
25
-
26
- def eigfree(A, N=None, psd=None, plots=False):
24
+ def eigh(A, N=None, psd=None, plots=False):
27
25
  """
28
26
  Estimate the eigenvalues of a matrix.
29
27
 
@@ -43,21 +41,32 @@ def eigfree(A, N=None, psd=None, plots=False):
43
41
  eigenvalues of. If None, returns estimates of the eigenvalues of
44
42
  :math:`\\mathbf{A}` itself.
45
43
 
46
- psd: bool, default=None
44
+ psd : bool, default=None
47
45
  Determines whether the matrix is positive-semidefinite (PSD; all
48
- eigenvalues are non-negative). If None, the matrix is considered PSD if
49
- all sampled eigenvalues are positive.
46
+ eigenvalues are non-negative). If `None`, the matrix is considered PSD
47
+ if all sampled eigenvalues are positive.
50
48
 
51
49
  plots : bool, default=False
52
50
  Print out all relevant plots for diagnosing eigenvalue accuracy.
53
51
 
52
+ Returns
53
+ -------
54
+
55
+ eigs : numpy.array
56
+ Eigenvalues of decompressed matrix
57
+
58
+ See Also
59
+ --------
60
+
61
+ cond
62
+
54
63
  Notes
55
64
  -----
56
65
 
57
- This is a convenience function for the FreeForm class with some effective
58
- defaults that work well for common random matrix ensembles. For improved
59
- performance and plotting utilites, consider finetuning parameters using
60
- the FreeForm class.
66
+ This is a convenience function for the :class:`freealg.FreeForm` class with
67
+ some effective defaults that work well for common random matrix ensembles.
68
+ For improved performance and plotting utilites, consider fine-tuning
69
+ parameters using the FreeForm class.
61
70
 
62
71
  References
63
72
  ----------
@@ -68,8 +77,14 @@ def eigfree(A, N=None, psd=None, plots=False):
68
77
  --------
69
78
 
70
79
  .. code-block:: python
80
+ :emphasize-lines: 6
71
81
 
72
- >>> from freealg import FreeForm
82
+ >>> from freealg import cond
83
+ >>> from freealg.distributions import MarchenkoPastur
84
+
85
+ >>> mp = MarchenkoPastur(1/50)
86
+ >>> A = mp.matrix(3000)
87
+ >>> eigs = eigh(A)
73
88
  """
74
89
 
75
90
  if A.ndim != 2 or A.shape[0] != A.shape[1]:
@@ -118,3 +133,62 @@ def eigfree(A, N=None, psd=None, plots=False):
118
133
  eigs.sort()
119
134
 
120
135
  return eigs
136
+
137
+
138
+ # ====
139
+ # cond
140
+ # ====
141
+
142
+ def cond(A, N=None):
143
+ """
144
+ Estimate the condition number of a positive-definite matrix.
145
+
146
+ This function estimates the condition number of the matrix
147
+ :math:`\\mathbf{A}` or a larger matrix containing :math:`\\mathbf{A}`
148
+ using free decompression.
149
+
150
+ Parameters
151
+ ----------
152
+
153
+ A : numpy.ndarray
154
+ The symmetric real-valued matrix :math:`\\mathbf{A}` whose condition
155
+ number (or that of a matrix containing :math:`\\mathbf{A}`) are to be
156
+ computed.
157
+
158
+ N : int, default=None
159
+ The size of the matrix containing :math:`\\mathbf{A}` to estimate
160
+ eigenvalues of. If None, returns estimates of the eigenvalues of
161
+ :math:`\\mathbf{A}` itself.
162
+
163
+ Returns
164
+ -------
165
+
166
+ c : float
167
+ Condition number
168
+
169
+ See Also
170
+ --------
171
+
172
+ eigh
173
+
174
+ Notes
175
+ -----
176
+
177
+ This is a convenience function using :func:`freealg.eigh`.
178
+
179
+ Examples
180
+ --------
181
+
182
+ .. code-block:: python
183
+ :emphasize-lines: 6
184
+
185
+ >>> from freealg import cond
186
+ >>> from freealg.distributions import MarchenkoPastur
187
+
188
+ >>> mp = MarchenkoPastur(1/50)
189
+ >>> A = mp.matrix(3000)
190
+ >>> cond(A)
191
+ """
192
+
193
+ eigs = eigh(A, N)
194
+ return eigs.max() / eigs.min()
freealg/freeform.py CHANGED
@@ -28,6 +28,10 @@ from ._decompress import decompress
28
28
  from ._sample import qmc_sample
29
29
  from ._support import detect_support
30
30
 
31
+ # Fallback to previous API
32
+ if not hasattr(numpy, 'trapezoid'):
33
+ numpy.trapezoid = numpy.trapz
34
+
31
35
  __all__ = ['FreeForm']
32
36
 
33
37
 
@@ -890,103 +894,3 @@ class FreeForm(object):
890
894
  return x, rho, eigs
891
895
  else:
892
896
  return x, rho
893
-
894
-
895
- def eigfree(A, N=None, psd=None, plots=False):
896
- """
897
- Estimate the eigenvalues of a matrix :math:`\\mathbf{A}` or a larger matrix
898
- containing :math:`\\mathbf{A}` using free decompression.
899
-
900
- This is a convenience function for the FreeForm class with some effective
901
- defaults that work well for common random matrix ensembles. For improved
902
- performance and plotting utilites, consider finetuning parameters using
903
- the FreeForm class.
904
-
905
- Parameters
906
- ----------
907
-
908
- A : numpy.ndarray
909
- The symmetric real-valued matrix :math:`\\mathbf{A}` whose eigenvalues
910
- (or those of a matrix containing :math:`\\mathbf{A}`) are to be
911
- computed.
912
-
913
- N : int, default=None
914
- The size of the matrix containing :math:`\\mathbf{A}` to estimate
915
- eigenvalues of. If None, returns estimates of the eigenvalues of
916
- :math:`\\mathbf{A}` itself.
917
-
918
- psd : bool, default=None
919
- Determines whether the matrix is positive-semidefinite (PSD; all
920
- eigenvalues are non-negative). If None, the matrix is considered PSD if
921
- all sampled eigenvalues are positive.
922
-
923
- plots : bool, default=False
924
- Print out all relevant plots for diagnosing eigenvalue accuracy.
925
-
926
- Notes
927
- -----
928
-
929
- Notes.
930
-
931
- References
932
- ----------
933
-
934
- .. [1] Reference.
935
-
936
- Examples
937
- --------
938
-
939
- .. code-block:: python
940
-
941
- >>> from freealg import FreeForm
942
- """
943
- if A.ndim != 2 or A.shape[0] != A.shape[1]:
944
- raise RuntimeError("Only square matrices are permitted.")
945
- n = A.shape[0]
946
-
947
- if N is None:
948
- N = n
949
-
950
- # Size of sample matrix
951
- n_s = int(80*(1 + numpy.log(n)))
952
- # If matrix is not large enough, return eigenvalues
953
- if n < n_s:
954
- return compute_eig(A)
955
- # Number of samples
956
- num_samples = int(10 * (n / n_s)**0.5)
957
- # else:
958
- # # Use the entire matrix given
959
- # n_s = n
960
- # num_samples = 1
961
-
962
- # Collect eigenvalue samples
963
- samples = []
964
- for _ in range(num_samples):
965
- indices = numpy.random.choice(n, n_s, replace=False)
966
- samples.append(compute_eig(A[numpy.ix_(indices, indices)]))
967
- samples = numpy.concatenate(samples).ravel()
968
-
969
- # If all eigenvalues are positive, set PSD flag
970
- if psd is None:
971
- psd = samples.min() > 0
972
-
973
- ff = FreeForm(samples)
974
- # Since we are resampling, we need to provide the correct matrix size
975
- ff.n = n_s
976
-
977
- # Perform fit and estimate eigenvalues
978
- order = 1 + int(len(samples)**.2)
979
- ff.fit(method='chebyshev', K=order, projection='sample',
980
- force=True, plot=False, latex=False, save=False)
981
-
982
- if plots:
983
- ff.density(plot=True)
984
- ff.stieltjes(plot=True)
985
-
986
- _, _, eigs = ff.decompress(N, plot=plots)
987
-
988
- if psd:
989
- eigs = numpy.abs(eigs)
990
- eigs.sort()
991
-
992
- return eigs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: freealg
3
- Version: 0.1.14
3
+ Version: 0.2.0
4
4
  Summary: Free probability for large matrices
5
5
  Keywords: leaderboard bot chat
6
6
  Platform: Linux
@@ -0,0 +1,25 @@
1
+ freealg/__init__.py,sha256=hxGvn8bF29NI4J7QnHrUfI7j_qh5lSwOF5g-QL5W7fc,553
2
+ freealg/__version__.py,sha256=Zn1KFblwuFHiDRdRAiRnDBRkbPttWh44jKa5zG2ov0E,22
3
+ freealg/_chebyshev.py,sha256=dsAj3YEpmkzB65smluZ0Fi5IZSdpnQXBSIuKMg19grA,5523
4
+ freealg/_damp.py,sha256=k2vtBtWOxQBf4qXaWu_En81lQBXbEO4QbxxWpvuVhdE,1802
5
+ freealg/_decompress.py,sha256=0MYoO3lqwMgNYlVriaRNUqUwY3XYyZZsDAtNRBq6rhE,10470
6
+ freealg/_jacobi.py,sha256=AT4ONSHGGDxVKE3MGMLyMR8uDFiO-e9u3x5udYfdJJk,5635
7
+ freealg/_pade.py,sha256=Diw850oH2OLQeUrBR-q19TmjSBoBvXl6ogp4o1s2UIo,15184
8
+ freealg/_plot_util.py,sha256=U4alp7Pzg315_7jJdu1UB0tIUcxUovQgHDHsUYoa2Z0,19728
9
+ freealg/_sample.py,sha256=ckC75eqv-mRP1F5BnhvsjfLTaoAzHK8bebl9bCRZYDo,2561
10
+ freealg/_support.py,sha256=sxp867DxfmvYqyQNOyla3zlcVyxm7KL0M-fxZaRIw8E,6299
11
+ freealg/_util.py,sha256=8Tvz-XODtKYoU76ODmF1TBaIYLlr6-AXiyoMDwDSxVg,3779
12
+ freealg/eigh.py,sha256=L_KGD75mKgfVmUs0AcMpZcWc_lAZxChhT-bGesxwrHA,4744
13
+ freealg/freeform.py,sha256=_0hUqIJJ3jGiWY-yJSQUkDG-hXr2VQ83WwChrnkxmu0,28558
14
+ freealg/distributions/__init__.py,sha256=t_yZyEkW_W_tSV9IvgYXtVASxD2BEdiNVXcV2ebMy8M,579
15
+ freealg/distributions/_kesten_mckay.py,sha256=210RF2OQEYLZBeLB6wmbdHnZPs_9ldDNHm_FMlg5tis,19881
16
+ freealg/distributions/_marchenko_pastur.py,sha256=kchFccRMuVF2Cus_99vdEwuRimkHzEUV8xt5kZFg7ZI,16994
17
+ freealg/distributions/_meixner.py,sha256=ws7t_EUa7V0s97dgMQIJLv1b6qMLqf9fLLbTJQudf_8,17512
18
+ freealg/distributions/_wachter.py,sha256=Hna_MXqAPjuRkeilLPMf4Xg_3C6tTu5oZLEQnA-RuE4,16897
19
+ freealg/distributions/_wigner.py,sha256=SxgPLtvIVBi9m4De-oBD0x6-2Je_eBqpDrpDYcoLuis,15871
20
+ freealg-0.2.0.dist-info/licenses/AUTHORS.txt,sha256=0b67Nz4_JgIzUupHJTAZxu5QdSUM_HRM_X_w4xCb17o,30
21
+ freealg-0.2.0.dist-info/licenses/LICENSE.txt,sha256=J-EEYEtxb3VVf_Bn1TYfWnpY5lMFIM15iLDDcnaDTPA,1443
22
+ freealg-0.2.0.dist-info/METADATA,sha256=eqW_KJcQirHZZ2hg_iFEVklzPgF9FjStyqMPMf89fEA,4496
23
+ freealg-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
+ freealg-0.2.0.dist-info/top_level.txt,sha256=eR2wrgYwDdnnJ9Zf5PruPqe4kQav0GMvRsqct6y00Q8,8
25
+ freealg-0.2.0.dist-info/RECORD,,
@@ -1,25 +0,0 @@
1
- freealg/__init__.py,sha256=Imwnrlv7nvy8ddvbbcEklOx82me9NKkbixoR_zaEB5E,548
2
- freealg/__version__.py,sha256=PIBqEOI-nqKFL9oJAWQQwlHuujG9Cd7EmdxDrThNQto,23
3
- freealg/_chebyshev.py,sha256=iNtEh5PwI0TrtO08LqUGUD5jWb2EdK1pgZw73NA5P2s,5727
4
- freealg/_damp.py,sha256=k2vtBtWOxQBf4qXaWu_En81lQBXbEO4QbxxWpvuVhdE,1802
5
- freealg/_decompress.py,sha256=gLcO13odPpegNkh1Y64iTdG65qXUClLuSVCuWkLm7tM,10372
6
- freealg/_jacobi.py,sha256=AT4ONSHGGDxVKE3MGMLyMR8uDFiO-e9u3x5udYfdJJk,5635
7
- freealg/_pade.py,sha256=wer31W6c6lDCag4THKGdW69r5d7uimsH_Y53wJih144,15185
8
- freealg/_plot_util.py,sha256=U4alp7Pzg315_7jJdu1UB0tIUcxUovQgHDHsUYoa2Z0,19728
9
- freealg/_sample.py,sha256=ckC75eqv-mRP1F5BnhvsjfLTaoAzHK8bebl9bCRZYDo,2561
10
- freealg/_support.py,sha256=LIM_VWH8TzLJlp_q5A0ql-xawPUNyH2YI9ZKBlHHuzo,6122
11
- freealg/_util.py,sha256=PWLXcsTb0-FinGWvNiY12D-f4CHQB5bP_W3ThqfY4FY,3681
12
- freealg/eigfree.py,sha256=45NJ46MkwO3q_C10ef1KDP6JkVSKcrXRnDwwTDfnZbk,3247
13
- freealg/freeform.py,sha256=j1oECmOyc-v6o7bIrbW844QZqAG6hJm6NjGvLXRMvEo,31263
14
- freealg/distributions/__init__.py,sha256=t_yZyEkW_W_tSV9IvgYXtVASxD2BEdiNVXcV2ebMy8M,579
15
- freealg/distributions/_kesten_mckay.py,sha256=zHm356GmY_-UP8Db4aphOIYU4lnj-hu8wqrm8mEax3w,19878
16
- freealg/distributions/_marchenko_pastur.py,sha256=YHZvP7pFfUuTeQ-4vacKlZCwh6vfhBiz62bdPeQDGl4,16991
17
- freealg/distributions/_meixner.py,sha256=hEj5JXL5KTcCcw8B-pXypOPEPw0HyJ3xPw5GER4blDw,17509
18
- freealg/distributions/_wachter.py,sha256=uets28sPbxwptix7bysaoan0dPfYULP2nrfs-7Oxg08,16894
19
- freealg/distributions/_wigner.py,sha256=2DbAgmFlGl1ACc_uip3C22etH4Bbr_R6yEe_6Tx0poI,15868
20
- freealg-0.1.14.dist-info/licenses/AUTHORS.txt,sha256=0b67Nz4_JgIzUupHJTAZxu5QdSUM_HRM_X_w4xCb17o,30
21
- freealg-0.1.14.dist-info/licenses/LICENSE.txt,sha256=J-EEYEtxb3VVf_Bn1TYfWnpY5lMFIM15iLDDcnaDTPA,1443
22
- freealg-0.1.14.dist-info/METADATA,sha256=BRocp1GTnrULT9LSb3g1AI47pakgFP3_vWCyJoB0rBc,4497
23
- freealg-0.1.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
- freealg-0.1.14.dist-info/top_level.txt,sha256=eR2wrgYwDdnnJ9Zf5PruPqe4kQav0GMvRsqct6y00Q8,8
25
- freealg-0.1.14.dist-info/RECORD,,