freealg 0.3.1__py3-none-any.whl → 0.3.3__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/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.3.1"
1
+ __version__ = "0.3.3"
freealg/_support.py CHANGED
@@ -127,7 +127,7 @@ def detect_support(eigs, method='asymp', k=None, p=0.001, **kwargs):
127
127
  * ``'interior'``: estimates a support assuming the range overestimates;
128
128
  uses quantiles (p, 1-p).
129
129
  * ``'interior_smooth'``: same as ``'interior'`` but using kernel
130
- density estimation, from [2].
130
+ density estimation, from [2]_.
131
131
 
132
132
  k : int, default = None
133
133
  Number of extreme order statistics to use for ``method='regression'``.
freealg/eigh.py CHANGED
@@ -17,6 +17,42 @@ from .freeform import FreeForm
17
17
  __all__ = ['eigh', 'cond', 'norm', 'trace', 'slogdet']
18
18
 
19
19
 
20
+ # ===============
21
+ # subsample apply
22
+ # ===============
23
+
24
+ def _subsample_apply(f, A, output_array=False):
25
+ """
26
+ Compute f(A_n) over subsamples A_n of A. If the output of
27
+ f is an array (e.g. eigvals), specify output_array to be True.
28
+ """
29
+
30
+ if A.ndim != 2 or A.shape[0] != A.shape[1]:
31
+ raise RuntimeError("Only square matrices are permitted.")
32
+
33
+ n = A.shape[0]
34
+
35
+ # Size of sample matrix
36
+ n_s = int(80*(1 + numpy.log(n)))
37
+ # If matrix is not large enough, return eigenvalues
38
+ if n < n_s:
39
+ return f(A), n, n
40
+
41
+ # Number of samples
42
+ num_samples = int(10 * (n / n_s)**0.5)
43
+
44
+ # Collect eigenvalue samples
45
+ samples = []
46
+ for _ in range(num_samples):
47
+ indices = numpy.random.choice(n, n_s, replace=False)
48
+ samples.append(f(A[numpy.ix_(indices, indices)]))
49
+
50
+ if output_array:
51
+ return numpy.concatenate(samples).ravel(), n, n_s
52
+
53
+ return numpy.array(samples), n, n_s
54
+
55
+
20
56
  # ====
21
57
  # eigh
22
58
  # ====
@@ -87,28 +123,11 @@ def eigh(A, N=None, psd=None, plots=False):
87
123
  >>> eigs = eigh(A)
88
124
  """
89
125
 
90
- if A.ndim != 2 or A.shape[0] != A.shape[1]:
91
- raise RuntimeError("Only square matrices are permitted.")
92
- n = A.shape[0]
126
+ samples, n, n_s = _subsample_apply(compute_eig, A, output_array=True)
93
127
 
94
128
  if N is None:
95
129
  N = n
96
130
 
97
- # Size of sample matrix
98
- n_s = int(80*(1 + numpy.log(n)))
99
- # If matrix is not large enough, return eigenvalues
100
- if n < n_s:
101
- return compute_eig(A)
102
- # Number of samples
103
- num_samples = int(10 * (n / n_s)**0.5)
104
-
105
- # Collect eigenvalue samples
106
- samples = []
107
- for _ in range(num_samples):
108
- indices = numpy.random.choice(n, n_s, replace=False)
109
- samples.append(compute_eig(A[numpy.ix_(indices, indices)]))
110
- samples = numpy.concatenate(samples).ravel()
111
-
112
131
  # If all eigenvalues are positive, set PSD flag
113
132
  if psd is None:
114
133
  psd = samples.min() > 0
@@ -224,7 +243,7 @@ def norm(A, N=None, order=None):
224
243
  order : {float, ``''inf``, ``'-inf'``, ``'fro'``, ``'nuc'``}, default=2
225
244
  Order of the norm.
226
245
 
227
- * float :math:`p`: Schtten p-norm.
246
+ * float :math:`p`: Schatten p-norm.
228
247
  * ``'inf'``: Largest absolute eigenvalue
229
248
  :math:`\\max \\vert \\lambda_i \\vert)`
230
249
  * ``'-inf'``: Smallest absolute eigenvalue
@@ -300,19 +319,19 @@ def norm(A, N=None, order=None):
300
319
  # trace
301
320
  # =====
302
321
 
303
- def trace(A, N=None):
322
+ def trace(A, N=None, p=1.0):
304
323
  """
305
- Estimate the trace of a Hermitian matrix.
324
+ Estimate the trace of a power of a Hermitian matrix.
306
325
 
307
- This function estimates the trace of the matrix :math:`\\mathbf{A}` or a
308
- larger matrix containing :math:`\\mathbf{A}` using free decompression.
326
+ This function estimates the trace of the matrix power :math:`\\mathbf{A}^p`
327
+ or that of a larger matrix containing :math:`\\mathbf{A}`.
309
328
 
310
329
  Parameters
311
330
  ----------
312
331
 
313
332
  A : numpy.ndarray
314
- The symmetric real-valued matrix :math:`\\mathbf{A}` whose condition
315
- number (or that of a matrix containing :math:`\\mathbf{A}`) are to be
333
+ The symmetric real-valued matrix :math:`\\mathbf{A}` whose trace of
334
+ a power (or that of a matrix containing :math:`\\mathbf{A}`) is to be
316
335
  computed.
317
336
 
318
337
  N : int, default=None
@@ -320,6 +339,10 @@ def trace(A, N=None):
320
339
  eigenvalues of. If None, returns estimates of the eigenvalues of
321
340
  :math:`\\mathbf{A}` itself.
322
341
 
342
+ p : float, default=1.0
343
+ The exponent :math:`p` in :math:`\\mathbf{A}^p`.
344
+
345
+
323
346
  Returns
324
347
  -------
325
348
 
@@ -337,7 +360,9 @@ def trace(A, N=None):
337
360
  Notes
338
361
  -----
339
362
 
340
- This is a convenience function using :func:`freealg.eigh`.
363
+ The trace is highly amenable to subsampling: under free decompression
364
+ the average eigenvalue is assumed constant, so the trace increases
365
+ linearly. Traces of powers fall back to :func:`freealg.eigh`.
341
366
 
342
367
  Examples
343
368
  --------
@@ -353,10 +378,14 @@ def trace(A, N=None):
353
378
  >>> trace(A, 100_000)
354
379
  """
355
380
 
356
- eigs = eigh(A, N)
357
- trace_ = numpy.sum(eigs)
381
+ if numpy.isclose(p, 1.0):
382
+ samples, n, n_s = _subsample_apply(numpy.trace, A, output_array=False)
383
+ if N is None:
384
+ N = n
385
+ return numpy.mean(samples) * (N / n_s)
358
386
 
359
- return trace_
387
+ eig = eigh(A, N)
388
+ return numpy.sum(eig ** p)
360
389
 
361
390
 
362
391
  # =======
@@ -1,7 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: freealg
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: Free probability for large matrices
5
+ Home-page: https://github.com/ameli/freealg
6
+ Download-URL: https://github.com/ameli/freealg/archive/main.zip
7
+ Project-URL: Documentation, https://ameli.github.io/freealg
8
+ Project-URL: Source, https://github.com/ameli/freealg
9
+ Project-URL: Tracker, https://github.com/ameli/freealg/issues
5
10
  Keywords: linalg,free-probability
6
11
  Platform: Linux
7
12
  Platform: OSX
@@ -37,30 +42,38 @@ Provides-Extra: docs
37
42
  Dynamic: classifier
38
43
  Dynamic: description
39
44
  Dynamic: description-content-type
45
+ Dynamic: download-url
46
+ Dynamic: home-page
40
47
  Dynamic: keywords
41
48
  Dynamic: license-file
42
49
  Dynamic: platform
50
+ Dynamic: project-url
43
51
  Dynamic: provides-extra
44
52
  Dynamic: requires-dist
45
53
  Dynamic: requires-python
46
54
  Dynamic: summary
47
55
 
48
- .. image:: https://raw.githubusercontent.com/ameli/freealg/refs/heads/main/docs/source/_static/images/icons/logo-freealg-light.png
56
+ .. .. image:: https://raw.githubusercontent.com/ameli/freealg/refs/heads/main/docs/source/_static/images/icons/logo-freealg-light.png
57
+ .. :align: left
58
+ .. :width: 240
59
+ .. :class: custom-dark
60
+
61
+ .. figure:: https://raw.githubusercontent.com/ameli/freealg/refs/heads/main/docs/source/_static/images/icons/logo-freealg-light.png
49
62
  :align: left
50
63
  :width: 240
51
- :class: custom-dark
52
64
 
53
65
  `Paper <https://arxiv.org/abs/2506.11994>`__ |
54
66
  `Slides <https://www.dropbox.com/scl/fi/03gjuyz17k9yhsqy0isoz/free_decomporession_slides.pdf?rlkey=8f82mhciyl2ju02l7hv1md5li&st=26xmhjga&dl=0>`__ |
55
67
  `Docs <https://ameli.github.io/freealg>`__ |
56
- `Live Demo <https://ameli.github.io/freealg/jlite/lab/index.html?path=quick_start.ipynb>`__
68
+ `Live Demo <https://colab.research.google.com/github/ameli/freealg/blob/main/notebooks/quick_start.ipynb>`__
57
69
 
58
70
  .. `Slides <https://ameli.github.io/freealg/_static/data/slides.pdf>`__ |
59
71
 
60
- *freealg* is a Python package that employs **free** probability to evaluate the spectral
61
- densities of large matrix **form**\ s. The fundamental algorithm employed by *freealg* is
62
- **free decompression**, which extrapolates from the empirical spectral densities of small
63
- submatrices to infer the eigenspectrum of extremely large matrices.
72
+ *freealg* is a Python package that employs **free** probability to evaluate the
73
+ spectral densities of large matrix **form**\ s. The fundamental algorithm
74
+ employed by *freealg* is **free decompression**, which extrapolates from the
75
+ empirical spectral densities of small submatrices to infer the eigenspectrum
76
+ of extremely large matrices.
64
77
 
65
78
  Install
66
79
  =======
@@ -86,8 +99,8 @@ Documentation is available at `ameli.github.io/freealg <https://ameli.github.io/
86
99
  Quick Usage
87
100
  ===========
88
101
 
89
- The following code estimates the eigenvalues of a very large Wishart matrix using a much
90
- smaller Wishart matrix.
102
+ The following code estimates the eigenvalues of a very large Wishart matrix
103
+ using a much smaller Wishart matrix.
91
104
 
92
105
  .. code-block:: python
93
106
 
@@ -96,7 +109,8 @@ smaller Wishart matrix.
96
109
  >>> A = mp.matrix(1000) # Sample a 1000 x 1000 Wishart matrix
97
110
  >>> eigs = fa.eigfree(A, 100_000) # Estimate the eigenvalues of 100000 x 100000
98
111
 
99
- For more details on how to interface with *freealg* check out the `Quick Start Guide <https://github.com/ameli/freealg/blob/main/notebooks/quick_start.ipynb>`__.
112
+ For more details on how to interface with *freealg* check out the
113
+ `Quick Start Guide <https://github.com/ameli/freealg/blob/main/notebooks/quick_start.ipynb>`__.
100
114
 
101
115
 
102
116
  Test
@@ -120,14 +134,14 @@ How to Contribute
120
134
  =================
121
135
 
122
136
  We welcome contributions via GitHub's pull request. Developers should review
123
- our [Contributing Guidelines](CONTRIBUTING.rst) before submitting their code.
124
- If you do not feel comfortable modifying the code, we also welcome feature
125
- requests and bug reports.
137
+ our [Contributing Guidelines](https://github.com/ameli/freealg/blob/main/CONTRIBUTING.rst)
138
+ before submitting their code. If you do not feel comfortable modifying the
139
+ code, we also welcome feature requests and bug reports.
126
140
 
127
141
  How to Cite
128
142
  ===========
129
143
 
130
- If you use this work, please cite the `arXiv paper <https://arxiv.org/abs/2506.11994>`__.
144
+ If you use this work, please cite our `arXiv paper <https://arxiv.org/abs/2506.11994>`__.
131
145
 
132
146
  .. code::
133
147
 
@@ -1,5 +1,5 @@
1
1
  freealg/__init__.py,sha256=AM0G2tX7sBgzCTcOVbWynA9NFkQZKyphL9IR1tKOoK4,614
2
- freealg/__version__.py,sha256=r4xAFihOf72W9TD-lpMi6ntWSTKTP2SlzKP1ytkjRbI,22
2
+ freealg/__version__.py,sha256=8KcCYTXH99C2-gCLuPILJvtT9YftRWJsartIx6TQ2ZY,22
3
3
  freealg/_chebyshev.py,sha256=dsAj3YEpmkzB65smluZ0Fi5IZSdpnQXBSIuKMg19grA,5523
4
4
  freealg/_damp.py,sha256=k2vtBtWOxQBf4qXaWu_En81lQBXbEO4QbxxWpvuVhdE,1802
5
5
  freealg/_decompress.py,sha256=0MYoO3lqwMgNYlVriaRNUqUwY3XYyZZsDAtNRBq6rhE,10470
@@ -7,9 +7,9 @@ freealg/_jacobi.py,sha256=AT4ONSHGGDxVKE3MGMLyMR8uDFiO-e9u3x5udYfdJJk,5635
7
7
  freealg/_pade.py,sha256=Diw850oH2OLQeUrBR-q19TmjSBoBvXl6ogp4o1s2UIo,15184
8
8
  freealg/_plot_util.py,sha256=U4alp7Pzg315_7jJdu1UB0tIUcxUovQgHDHsUYoa2Z0,19728
9
9
  freealg/_sample.py,sha256=ckC75eqv-mRP1F5BnhvsjfLTaoAzHK8bebl9bCRZYDo,2561
10
- freealg/_support.py,sha256=4N_nbh-4ubcIC6ZJpoql3LakSt0fEUjQT2p_yE-bdmo,6438
10
+ freealg/_support.py,sha256=mYlrsdLbniqFgFofbHrZIiYSyJudPqtyMQQTPBD9Y6M,6439
11
11
  freealg/_util.py,sha256=8Tvz-XODtKYoU76ODmF1TBaIYLlr6-AXiyoMDwDSxVg,3779
12
- freealg/eigh.py,sha256=rSGAcmp3bjyiRT479wfggvNyOqbjj7lSUjKIA-FfeVE,10119
12
+ freealg/eigh.py,sha256=ybUCE8Qi-H8r-QxDvbeSP9Ow-q8xTuq5o-LNhPvBvIE,10926
13
13
  freealg/freeform.py,sha256=8emyCQ6AUjp_HB1gWQ-ecddlDgfxHGr3PqXSyoPxeMo,28593
14
14
  freealg/distributions/__init__.py,sha256=t_yZyEkW_W_tSV9IvgYXtVASxD2BEdiNVXcV2ebMy8M,579
15
15
  freealg/distributions/_kesten_mckay.py,sha256=210RF2OQEYLZBeLB6wmbdHnZPs_9ldDNHm_FMlg5tis,19881
@@ -17,9 +17,9 @@ freealg/distributions/_marchenko_pastur.py,sha256=kchFccRMuVF2Cus_99vdEwuRimkHzE
17
17
  freealg/distributions/_meixner.py,sha256=ws7t_EUa7V0s97dgMQIJLv1b6qMLqf9fLLbTJQudf_8,17512
18
18
  freealg/distributions/_wachter.py,sha256=Hna_MXqAPjuRkeilLPMf4Xg_3C6tTu5oZLEQnA-RuE4,16897
19
19
  freealg/distributions/_wigner.py,sha256=SxgPLtvIVBi9m4De-oBD0x6-2Je_eBqpDrpDYcoLuis,15871
20
- freealg-0.3.1.dist-info/licenses/AUTHORS.txt,sha256=0b67Nz4_JgIzUupHJTAZxu5QdSUM_HRM_X_w4xCb17o,30
21
- freealg-0.3.1.dist-info/licenses/LICENSE.txt,sha256=J-EEYEtxb3VVf_Bn1TYfWnpY5lMFIM15iLDDcnaDTPA,1443
22
- freealg-0.3.1.dist-info/METADATA,sha256=F2ymhxBRzrg3dCOi-rcZ4StLoLHk51gd6cBlbBzP2NY,4593
23
- freealg-0.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
- freealg-0.3.1.dist-info/top_level.txt,sha256=eR2wrgYwDdnnJ9Zf5PruPqe4kQav0GMvRsqct6y00Q8,8
25
- freealg-0.3.1.dist-info/RECORD,,
20
+ freealg-0.3.3.dist-info/licenses/AUTHORS.txt,sha256=0b67Nz4_JgIzUupHJTAZxu5QdSUM_HRM_X_w4xCb17o,30
21
+ freealg-0.3.3.dist-info/licenses/LICENSE.txt,sha256=J-EEYEtxb3VVf_Bn1TYfWnpY5lMFIM15iLDDcnaDTPA,1443
22
+ freealg-0.3.3.dist-info/METADATA,sha256=DADdzlak4svhV-GaZCt5NohqxbJCk1KXN9hk33Vs9_c,5178
23
+ freealg-0.3.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
+ freealg-0.3.3.dist-info/top_level.txt,sha256=eR2wrgYwDdnnJ9Zf5PruPqe4kQav0GMvRsqct6y00Q8,8
25
+ freealg-0.3.3.dist-info/RECORD,,