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.
- freealg/__init__.py +8 -6
- freealg/__version__.py +1 -1
- freealg/_algebraic_form/_branch_points.py +18 -18
- freealg/_algebraic_form/_continuation_algebraic.py +13 -13
- freealg/_algebraic_form/_cusp.py +15 -15
- freealg/_algebraic_form/_cusp_wrap.py +6 -6
- freealg/_algebraic_form/_decompress.py +16 -16
- freealg/_algebraic_form/_decompress4.py +31 -31
- freealg/_algebraic_form/_decompress5.py +23 -23
- freealg/_algebraic_form/_decompress6.py +13 -13
- freealg/_algebraic_form/_decompress7.py +15 -15
- freealg/_algebraic_form/_decompress8.py +17 -17
- freealg/_algebraic_form/_decompress9.py +18 -18
- freealg/_algebraic_form/_decompress_new.py +17 -17
- freealg/_algebraic_form/_decompress_new_2.py +57 -57
- freealg/_algebraic_form/_decompress_util.py +10 -10
- freealg/_algebraic_form/_decompressible.py +292 -0
- freealg/_algebraic_form/_edge.py +10 -10
- freealg/_algebraic_form/_homotopy4.py +9 -9
- freealg/_algebraic_form/_homotopy5.py +9 -9
- freealg/_algebraic_form/_support.py +19 -19
- freealg/_algebraic_form/algebraic_form.py +262 -468
- freealg/_base_form.py +401 -0
- freealg/_free_form/__init__.py +1 -4
- freealg/_free_form/_density_util.py +1 -1
- freealg/_free_form/_plot_util.py +3 -511
- freealg/_free_form/free_form.py +8 -367
- freealg/_util.py +59 -11
- freealg/distributions/__init__.py +2 -1
- freealg/distributions/_base_distribution.py +163 -0
- freealg/distributions/_chiral_block.py +137 -11
- freealg/distributions/_compound_poisson.py +141 -47
- freealg/distributions/_deformed_marchenko_pastur.py +138 -33
- freealg/distributions/_deformed_wigner.py +98 -9
- freealg/distributions/_fuss_catalan.py +269 -0
- freealg/distributions/_kesten_mckay.py +4 -130
- freealg/distributions/_marchenko_pastur.py +8 -196
- freealg/distributions/_meixner.py +4 -130
- freealg/distributions/_wachter.py +4 -130
- freealg/distributions/_wigner.py +10 -127
- freealg/visualization/__init__.py +2 -2
- freealg/visualization/{_rgb_hsv.py → _domain_coloring.py} +37 -29
- freealg/visualization/_plot_util.py +513 -0
- {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/METADATA +1 -1
- freealg-0.7.18.dist-info/RECORD +74 -0
- freealg-0.7.17.dist-info/RECORD +0 -69
- /freealg/{_free_form/_sample.py → _sample.py} +0 -0
- /freealg/{_free_form/_support.py → _support.py} +0 -0
- {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/WHEEL +0 -0
- {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/licenses/AUTHORS.txt +0 -0
- {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/licenses/LICENSE.txt +0 -0
- {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/top_level.txt +0 -0
freealg/_base_form.py
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright 2026, Siavash Ameli <sameli@berkeley.edu>
|
|
2
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
3
|
+
# SPDX-FileType: SOURCE
|
|
4
|
+
#
|
|
5
|
+
# This program is free software: you can redistribute it and/or modify it under
|
|
6
|
+
# the terms of the license found in the LICENSE.txt file in the root directory
|
|
7
|
+
# of this source tree.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# =======
|
|
11
|
+
# Imports
|
|
12
|
+
# =======
|
|
13
|
+
|
|
14
|
+
import numpy
|
|
15
|
+
from ._util import resolve_complex_dtype
|
|
16
|
+
from ._sample import sample
|
|
17
|
+
|
|
18
|
+
__all__ = ['BaseForm']
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# =========
|
|
22
|
+
# Base Form
|
|
23
|
+
# =========
|
|
24
|
+
|
|
25
|
+
class BaseForm(object):
|
|
26
|
+
"""
|
|
27
|
+
Base for other "Form" classes. This class itself not a part of API, but the
|
|
28
|
+
inheritted member methods are exposed to the API.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
# ====
|
|
32
|
+
# init
|
|
33
|
+
# ====
|
|
34
|
+
|
|
35
|
+
def __init__(self, delta, dtype='complex128'):
|
|
36
|
+
|
|
37
|
+
self.A = None
|
|
38
|
+
self.eig = None
|
|
39
|
+
self.delta = delta # Offset above real axis to apply Plemelj formula
|
|
40
|
+
self.n = None
|
|
41
|
+
self.lam_m = None
|
|
42
|
+
self.lam_p = None
|
|
43
|
+
|
|
44
|
+
# Data type for complex arrays
|
|
45
|
+
self.dtype = resolve_complex_dtype(dtype)
|
|
46
|
+
|
|
47
|
+
# =============
|
|
48
|
+
# generate grid
|
|
49
|
+
# =============
|
|
50
|
+
|
|
51
|
+
def _generate_grid(self, scale, extend=1.0, N=500):
|
|
52
|
+
"""
|
|
53
|
+
Generate a grid of points to evaluate density / Hilbert / Stieltjes
|
|
54
|
+
transforms.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
radius = 0.5 * (self.lam_p - self.lam_m)
|
|
58
|
+
center = 0.5 * (self.lam_p + self.lam_m)
|
|
59
|
+
|
|
60
|
+
x_min = numpy.floor(extend * (center - extend * radius * scale))
|
|
61
|
+
x_max = numpy.ceil(extend * (center + extend * radius * scale))
|
|
62
|
+
|
|
63
|
+
x_min /= extend
|
|
64
|
+
x_max /= extend
|
|
65
|
+
|
|
66
|
+
return numpy.linspace(x_min, x_max, N)
|
|
67
|
+
|
|
68
|
+
# ========
|
|
69
|
+
# eigvalsh
|
|
70
|
+
# ========
|
|
71
|
+
|
|
72
|
+
def eigvalsh(self, size=None, seed=None, **kwargs):
|
|
73
|
+
"""
|
|
74
|
+
Estimate the eigenvalues.
|
|
75
|
+
|
|
76
|
+
This function estimates the eigenvalues of the freeform matrix
|
|
77
|
+
or a larger matrix containing it using free decompression.
|
|
78
|
+
|
|
79
|
+
Parameters
|
|
80
|
+
----------
|
|
81
|
+
|
|
82
|
+
size : int, default=None
|
|
83
|
+
The size of the matrix containing :math:`\\mathbf{A}` to estimate
|
|
84
|
+
eigenvalues of. If None, returns estimates of the eigenvalues of
|
|
85
|
+
:math:`\\mathbf{A}` itself.
|
|
86
|
+
|
|
87
|
+
seed : int, default=None
|
|
88
|
+
The seed for the Quasi-Monte Carlo sampler.
|
|
89
|
+
|
|
90
|
+
**kwargs : dict, optional
|
|
91
|
+
Pass additional options to the underlying
|
|
92
|
+
:func:`FreeForm.decompress` function.
|
|
93
|
+
|
|
94
|
+
Returns
|
|
95
|
+
-------
|
|
96
|
+
|
|
97
|
+
eigs : numpy.array
|
|
98
|
+
Eigenvalues of decompressed matrix
|
|
99
|
+
|
|
100
|
+
See Also
|
|
101
|
+
--------
|
|
102
|
+
|
|
103
|
+
FreeForm.decompress
|
|
104
|
+
FreeForm.cond
|
|
105
|
+
|
|
106
|
+
Notes
|
|
107
|
+
-----
|
|
108
|
+
|
|
109
|
+
All arguments to the :func:`decompress` procedure can be provided.
|
|
110
|
+
|
|
111
|
+
Examples
|
|
112
|
+
--------
|
|
113
|
+
|
|
114
|
+
.. code-block:: python
|
|
115
|
+
:emphasize-lines: 1
|
|
116
|
+
|
|
117
|
+
>>> from freealg import FreeForm
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
if size is None:
|
|
121
|
+
size = self.n
|
|
122
|
+
|
|
123
|
+
rho, x = self.decompress(size, **kwargs)
|
|
124
|
+
eigs = numpy.sort(sample(x, rho, size, method='qmc', seed=seed))
|
|
125
|
+
|
|
126
|
+
return eigs
|
|
127
|
+
|
|
128
|
+
# ====
|
|
129
|
+
# cond
|
|
130
|
+
# ====
|
|
131
|
+
|
|
132
|
+
def cond(self, size=None, seed=None, **kwargs):
|
|
133
|
+
"""
|
|
134
|
+
Estimate the condition number.
|
|
135
|
+
|
|
136
|
+
This function estimates the condition number of the matrix
|
|
137
|
+
:math:`\\mathbf{A}` or a larger matrix containing :math:`\\mathbf{A}`
|
|
138
|
+
using free decompression.
|
|
139
|
+
|
|
140
|
+
Parameters
|
|
141
|
+
----------
|
|
142
|
+
|
|
143
|
+
size : int, default=None
|
|
144
|
+
The size of the matrix containing :math:`\\mathbf{A}` to estimate
|
|
145
|
+
eigenvalues of. If None, returns estimates of the eigenvalues of
|
|
146
|
+
:math:`\\mathbf{A}` itself.
|
|
147
|
+
|
|
148
|
+
**kwargs : dict, optional
|
|
149
|
+
Pass additional options to the underlying
|
|
150
|
+
:func:`FreeForm.decompress` function.
|
|
151
|
+
|
|
152
|
+
Returns
|
|
153
|
+
-------
|
|
154
|
+
|
|
155
|
+
c : float
|
|
156
|
+
Condition number
|
|
157
|
+
|
|
158
|
+
See Also
|
|
159
|
+
--------
|
|
160
|
+
|
|
161
|
+
FreeForm.eigvalsh
|
|
162
|
+
FreeForm.norm
|
|
163
|
+
FreeForm.slogdet
|
|
164
|
+
FreeForm.trace
|
|
165
|
+
|
|
166
|
+
Examples
|
|
167
|
+
--------
|
|
168
|
+
|
|
169
|
+
.. code-block:: python
|
|
170
|
+
:emphasize-lines: 1
|
|
171
|
+
|
|
172
|
+
>>> from freealg import FreeForm
|
|
173
|
+
"""
|
|
174
|
+
|
|
175
|
+
eigs = self.eigvalsh(size=size, **kwargs)
|
|
176
|
+
return eigs.max() / eigs.min()
|
|
177
|
+
|
|
178
|
+
# =====
|
|
179
|
+
# trace
|
|
180
|
+
# =====
|
|
181
|
+
|
|
182
|
+
def trace(self, size=None, p=1.0, seed=None, **kwargs):
|
|
183
|
+
"""
|
|
184
|
+
Estimate the trace of a power.
|
|
185
|
+
|
|
186
|
+
This function estimates the trace of the matrix power
|
|
187
|
+
:math:`\\mathbf{A}^p` of the freeform or that of a larger matrix
|
|
188
|
+
containing it.
|
|
189
|
+
|
|
190
|
+
Parameters
|
|
191
|
+
----------
|
|
192
|
+
|
|
193
|
+
size : int, default=None
|
|
194
|
+
The size of the matrix containing :math:`\\mathbf{A}` to estimate
|
|
195
|
+
eigenvalues of. If None, returns estimates of the eigenvalues of
|
|
196
|
+
:math:`\\mathbf{A}` itself.
|
|
197
|
+
|
|
198
|
+
p : float, default=1.0
|
|
199
|
+
The exponent :math:`p` in :math:`\\mathbf{A}^p`.
|
|
200
|
+
|
|
201
|
+
seed : int, default=None
|
|
202
|
+
The seed for the Quasi-Monte Carlo sampler.
|
|
203
|
+
|
|
204
|
+
**kwargs : dict, optional
|
|
205
|
+
Pass additional options to the underlying
|
|
206
|
+
:func:`FreeForm.decompress` function.
|
|
207
|
+
|
|
208
|
+
Returns
|
|
209
|
+
-------
|
|
210
|
+
|
|
211
|
+
trace : float
|
|
212
|
+
matrix trace
|
|
213
|
+
|
|
214
|
+
See Also
|
|
215
|
+
--------
|
|
216
|
+
|
|
217
|
+
FreeForm.eigvalsh
|
|
218
|
+
FreeForm.cond
|
|
219
|
+
FreeForm.slogdet
|
|
220
|
+
FreeForm.norm
|
|
221
|
+
|
|
222
|
+
Notes
|
|
223
|
+
-----
|
|
224
|
+
|
|
225
|
+
The trace is highly amenable to subsampling: under free decompression
|
|
226
|
+
the average eigenvalue is assumed constant, so the trace increases
|
|
227
|
+
linearly. Traces of powers fall back to :func:`eigvalsh`.
|
|
228
|
+
All arguments to the `.decompress()` procedure can be provided.
|
|
229
|
+
|
|
230
|
+
Examples
|
|
231
|
+
--------
|
|
232
|
+
|
|
233
|
+
.. code-block:: python
|
|
234
|
+
:emphasize-lines: 1
|
|
235
|
+
|
|
236
|
+
>>> from freealg import FreeForm
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
if numpy.isclose(p, 1.0):
|
|
240
|
+
return numpy.mean(self.eig) * (size / self.n)
|
|
241
|
+
|
|
242
|
+
eig = self.eigvalsh(size=size, seed=seed, **kwargs)
|
|
243
|
+
return numpy.sum(eig ** p)
|
|
244
|
+
|
|
245
|
+
# =======
|
|
246
|
+
# slogdet
|
|
247
|
+
# =======
|
|
248
|
+
|
|
249
|
+
def slogdet(self, size=None, seed=None, **kwargs):
|
|
250
|
+
"""
|
|
251
|
+
Estimate the sign and logarithm of the determinant.
|
|
252
|
+
|
|
253
|
+
This function estimates the *slogdet* of the freeform or that of
|
|
254
|
+
a larger matrix containing it using free decompression.
|
|
255
|
+
|
|
256
|
+
Parameters
|
|
257
|
+
----------
|
|
258
|
+
|
|
259
|
+
size : int, default=None
|
|
260
|
+
The size of the matrix containing :math:`\\mathbf{A}` to estimate
|
|
261
|
+
eigenvalues of. If None, returns estimates of the eigenvalues of
|
|
262
|
+
:math:`\\mathbf{A}` itself.
|
|
263
|
+
|
|
264
|
+
seed : int, default=None
|
|
265
|
+
The seed for the Quasi-Monte Carlo sampler.
|
|
266
|
+
|
|
267
|
+
Returns
|
|
268
|
+
-------
|
|
269
|
+
|
|
270
|
+
sign : float
|
|
271
|
+
Sign of determinant
|
|
272
|
+
|
|
273
|
+
ld : float
|
|
274
|
+
natural logarithm of the absolute value of the determinant
|
|
275
|
+
|
|
276
|
+
See Also
|
|
277
|
+
--------
|
|
278
|
+
|
|
279
|
+
FreeForm.eigvalsh
|
|
280
|
+
FreeForm.cond
|
|
281
|
+
FreeForm.trace
|
|
282
|
+
FreeForm.norm
|
|
283
|
+
|
|
284
|
+
Notes
|
|
285
|
+
-----
|
|
286
|
+
|
|
287
|
+
All arguments to the `.decompress()` procedure can be provided.
|
|
288
|
+
|
|
289
|
+
Examples
|
|
290
|
+
--------
|
|
291
|
+
|
|
292
|
+
.. code-block:: python
|
|
293
|
+
:emphasize-lines: 1
|
|
294
|
+
|
|
295
|
+
>>> from freealg import FreeForm
|
|
296
|
+
"""
|
|
297
|
+
|
|
298
|
+
eigs = self.eigvalsh(size=size, seed=seed, **kwargs)
|
|
299
|
+
sign = numpy.prod(numpy.sign(eigs))
|
|
300
|
+
ld = numpy.sum(numpy.log(numpy.abs(eigs)))
|
|
301
|
+
return sign, ld
|
|
302
|
+
|
|
303
|
+
# ====
|
|
304
|
+
# norm
|
|
305
|
+
# ====
|
|
306
|
+
|
|
307
|
+
def norm(self, size=None, order=2, seed=None, **kwargs):
|
|
308
|
+
"""
|
|
309
|
+
Estimate the Schatten norm.
|
|
310
|
+
|
|
311
|
+
This function estimates the norm of the freeform or a larger
|
|
312
|
+
matrix containing it using free decompression.
|
|
313
|
+
|
|
314
|
+
Parameters
|
|
315
|
+
----------
|
|
316
|
+
|
|
317
|
+
size : int, default=None
|
|
318
|
+
The size of the matrix containing :math:`\\mathbf{A}` to estimate
|
|
319
|
+
eigenvalues of. If None, returns estimates of the eigenvalues of
|
|
320
|
+
:math:`\\mathbf{A}` itself.
|
|
321
|
+
|
|
322
|
+
order : {float, ``''inf``, ``'-inf'``, ``'fro'``, ``'nuc'``}, default=2
|
|
323
|
+
Order of the norm.
|
|
324
|
+
|
|
325
|
+
* float :math:`p`: Schatten p-norm.
|
|
326
|
+
* ``'inf'``: Largest absolute eigenvalue
|
|
327
|
+
:math:`\\max \\vert \\lambda_i \\vert)`
|
|
328
|
+
* ``'-inf'``: Smallest absolute eigenvalue
|
|
329
|
+
:math:`\\min \\vert \\lambda_i \\vert)`
|
|
330
|
+
* ``'fro'``: Frobenius norm corresponding to :math:`p=2`
|
|
331
|
+
* ``'nuc'``: Nuclear (or trace) norm corresponding to :math:`p=1`
|
|
332
|
+
|
|
333
|
+
seed : int, default=None
|
|
334
|
+
The seed for the Quasi-Monte Carlo sampler.
|
|
335
|
+
|
|
336
|
+
**kwargs : dict, optional
|
|
337
|
+
Pass additional options to the underlying
|
|
338
|
+
:func:`FreeForm.decompress` function.
|
|
339
|
+
|
|
340
|
+
Returns
|
|
341
|
+
-------
|
|
342
|
+
|
|
343
|
+
norm : float
|
|
344
|
+
matrix norm
|
|
345
|
+
|
|
346
|
+
See Also
|
|
347
|
+
--------
|
|
348
|
+
|
|
349
|
+
FreeForm.eigvalsh
|
|
350
|
+
FreeForm.cond
|
|
351
|
+
FreeForm.slogdet
|
|
352
|
+
FreeForm.trace
|
|
353
|
+
|
|
354
|
+
Notes
|
|
355
|
+
-----
|
|
356
|
+
|
|
357
|
+
Thes Schatten :math:`p`-norm is defined by
|
|
358
|
+
|
|
359
|
+
.. math::
|
|
360
|
+
|
|
361
|
+
\\Vert \\mathbf{A} \\Vert_p = \\left(
|
|
362
|
+
\\sum_{i=1}^N \\vert \\lambda_i \\vert^p \\right)^{1/p}.
|
|
363
|
+
|
|
364
|
+
Examples
|
|
365
|
+
--------
|
|
366
|
+
|
|
367
|
+
.. code-block:: python
|
|
368
|
+
:emphasize-lines: 1
|
|
369
|
+
|
|
370
|
+
>>> from freealg import FreeForm
|
|
371
|
+
"""
|
|
372
|
+
|
|
373
|
+
eigs = self.eigvalsh(size, seed=seed, **kwargs)
|
|
374
|
+
|
|
375
|
+
# Check order type and convert to float
|
|
376
|
+
if order == 'nuc':
|
|
377
|
+
order = 1
|
|
378
|
+
elif order == 'fro':
|
|
379
|
+
order = 2
|
|
380
|
+
elif order == 'inf':
|
|
381
|
+
order = float('inf')
|
|
382
|
+
elif order == '-inf':
|
|
383
|
+
order = -float('inf')
|
|
384
|
+
elif not isinstance(order,
|
|
385
|
+
(int, float, numpy.integer, numpy.floating)) \
|
|
386
|
+
and not isinstance(order, (bool, numpy.bool_)):
|
|
387
|
+
raise ValueError('"order" is invalid.')
|
|
388
|
+
|
|
389
|
+
# Compute norm
|
|
390
|
+
if numpy.isinf(order) and not numpy.isneginf(order):
|
|
391
|
+
norm_ = max(numpy.abs(eigs))
|
|
392
|
+
|
|
393
|
+
elif numpy.isneginf(order):
|
|
394
|
+
norm_ = min(numpy.abs(eigs))
|
|
395
|
+
|
|
396
|
+
elif isinstance(order, (int, float, numpy.integer, numpy.floating)) \
|
|
397
|
+
and not isinstance(order, (bool, numpy.bool_)):
|
|
398
|
+
norm_q = numpy.sum(numpy.abs(eigs)**order)
|
|
399
|
+
norm_ = norm_q**(1.0 / order)
|
|
400
|
+
|
|
401
|
+
return norm_
|
freealg/_free_form/__init__.py
CHANGED
|
@@ -8,9 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
from .free_form import FreeForm
|
|
10
10
|
from ._linalg import eigvalsh, cond, norm, trace, slogdet
|
|
11
|
-
from ._support import supp
|
|
12
|
-
from ._sample import sample
|
|
13
11
|
from ._density_util import kde
|
|
14
12
|
|
|
15
|
-
__all__ = ['FreeForm', 'eigvalsh', 'cond', 'norm', 'trace', 'slogdet', '
|
|
16
|
-
'sample', 'kde']
|
|
13
|
+
__all__ = ['FreeForm', 'eigvalsh', 'cond', 'norm', 'trace', 'slogdet', 'kde']
|
|
@@ -18,7 +18,7 @@ from scipy.stats import beta
|
|
|
18
18
|
from scipy.optimize import minimize
|
|
19
19
|
import matplotlib.pyplot as plt
|
|
20
20
|
import texplot
|
|
21
|
-
from ._plot_util import _auto_bins
|
|
21
|
+
from ..visualization._plot_util import _auto_bins
|
|
22
22
|
|
|
23
23
|
# Fallback to previous API
|
|
24
24
|
if not hasattr(numpy, 'trapezoid'):
|