freealg 0.1.7__tar.gz → 0.1.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.
- {freealg-0.1.7 → freealg-0.1.9}/PKG-INFO +1 -2
- freealg-0.1.9/freealg/__version__.py +1 -0
- {freealg-0.1.7 → freealg-0.1.9}/freealg/_sample.py +7 -1
- {freealg-0.1.7 → freealg-0.1.9}/freealg/distributions/kesten_mckay.py +117 -13
- {freealg-0.1.7 → freealg-0.1.9}/freealg/distributions/marchenko_pastur.py +13 -5
- {freealg-0.1.7 → freealg-0.1.9}/freealg/distributions/meixner.py +60 -35
- {freealg-0.1.7 → freealg-0.1.9}/freealg/distributions/wachter.py +14 -4
- {freealg-0.1.7 → freealg-0.1.9}/freealg/distributions/wigner.py +27 -29
- {freealg-0.1.7 → freealg-0.1.9}/freealg/freeform.py +6 -3
- {freealg-0.1.7 → freealg-0.1.9}/freealg.egg-info/PKG-INFO +1 -2
- {freealg-0.1.7 → freealg-0.1.9}/freealg.egg-info/requires.txt +0 -1
- {freealg-0.1.7 → freealg-0.1.9}/requirements.txt +0 -1
- freealg-0.1.7/freealg/__version__.py +0 -1
- {freealg-0.1.7 → freealg-0.1.9}/AUTHORS.txt +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/CHANGELOG.rst +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/LICENSE.txt +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/MANIFEST.in +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/README.rst +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/freealg/__init__.py +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/freealg/_chebyshev.py +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/freealg/_damp.py +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/freealg/_decompress.py +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/freealg/_jacobi.py +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/freealg/_pade.py +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/freealg/_plot_util.py +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/freealg/_util.py +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/freealg/distributions/__init__.py +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/freealg.egg-info/SOURCES.txt +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/freealg.egg-info/dependency_links.txt +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/freealg.egg-info/not-zip-safe +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/freealg.egg-info/top_level.txt +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/pyproject.toml +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/setup.cfg +0 -0
- {freealg-0.1.7 → freealg-0.1.9}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: freealg
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Summary: Free probability for large matrices
|
|
5
5
|
Keywords: leaderboard bot chat
|
|
6
6
|
Platform: Linux
|
|
@@ -30,7 +30,6 @@ Requires-Dist: scipy
|
|
|
30
30
|
Requires-Dist: texplot
|
|
31
31
|
Requires-Dist: matplotlib
|
|
32
32
|
Requires-Dist: colorcet
|
|
33
|
-
Requires-Dist: networkx
|
|
34
33
|
Requires-Dist: statsmodels
|
|
35
34
|
Provides-Extra: test
|
|
36
35
|
Requires-Dist: tox; extra == "test"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.9"
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
# Imports
|
|
11
11
|
# =======
|
|
12
12
|
|
|
13
|
+
import numpy
|
|
13
14
|
from scipy.integrate import cumulative_trapezoid
|
|
14
15
|
from scipy.interpolate import interp1d
|
|
15
16
|
from scipy.stats import qmc
|
|
@@ -35,7 +36,7 @@ def _quantile_func(x, rho):
|
|
|
35
36
|
# qmc sample
|
|
36
37
|
# ==========
|
|
37
38
|
|
|
38
|
-
def qmc_sample(x, rho, num_pts):
|
|
39
|
+
def qmc_sample(x, rho, num_pts, seed=None):
|
|
39
40
|
"""
|
|
40
41
|
Low-discrepancy sampling from a univariate density estimate using
|
|
41
42
|
Quasi-Monte Carlo.
|
|
@@ -52,6 +53,9 @@ def qmc_sample(x, rho, num_pts):
|
|
|
52
53
|
num_pts : int
|
|
53
54
|
Number of sample points to generate from the density estimate.
|
|
54
55
|
|
|
56
|
+
seed : int, default=None
|
|
57
|
+
Seed for random number generator
|
|
58
|
+
|
|
55
59
|
Returns
|
|
56
60
|
-------
|
|
57
61
|
samples : numpy.array, shape (num_pts,)
|
|
@@ -78,6 +82,8 @@ def qmc_sample(x, rho, num_pts):
|
|
|
78
82
|
>>> numpy.allclose(samples.mean(), 0.75, atol=0.02)
|
|
79
83
|
"""
|
|
80
84
|
|
|
85
|
+
numpy.random.rand(seed)
|
|
86
|
+
|
|
81
87
|
quantile = _quantile_func(x, rho)
|
|
82
88
|
engine = qmc.Halton(d=1)
|
|
83
89
|
u = engine.random(num_pts)
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
# =======
|
|
13
13
|
|
|
14
14
|
import numpy
|
|
15
|
-
import networkx as nx
|
|
16
15
|
from scipy.interpolate import interp1d
|
|
17
16
|
from .._plot_util import plot_density, plot_hilbert, plot_stieltjes, \
|
|
18
17
|
plot_stieltjes_on_disk, plot_samples
|
|
@@ -430,8 +429,8 @@ class KestenMcKay(object):
|
|
|
430
429
|
# sample
|
|
431
430
|
# ======
|
|
432
431
|
|
|
433
|
-
def sample(self, size, x_min=None, x_max=None, method='qmc',
|
|
434
|
-
latex=False, save=False):
|
|
432
|
+
def sample(self, size, x_min=None, x_max=None, method='qmc', seed=None,
|
|
433
|
+
plot=False, latex=False, save=False):
|
|
435
434
|
"""
|
|
436
435
|
Sample from distribution.
|
|
437
436
|
|
|
@@ -450,11 +449,14 @@ class KestenMcKay(object):
|
|
|
450
449
|
is used.
|
|
451
450
|
|
|
452
451
|
method : {``'mc'``, ``'qmc'``}, default= ``'qmc'``
|
|
453
|
-
Method of drawing samples from uniform
|
|
452
|
+
Method of drawing samples from uniform distribution:
|
|
454
453
|
|
|
455
454
|
* ``'mc'``: Monte Carlo
|
|
456
455
|
* ``'qmc'``: Quasi Monte Carlo
|
|
457
456
|
|
|
457
|
+
seed : int, default=None,
|
|
458
|
+
Seed for random number generator.
|
|
459
|
+
|
|
458
460
|
plot : bool, default=False
|
|
459
461
|
If `True`, samples histogram is plotted.
|
|
460
462
|
|
|
@@ -492,6 +494,8 @@ class KestenMcKay(object):
|
|
|
492
494
|
:class: custom-dark
|
|
493
495
|
"""
|
|
494
496
|
|
|
497
|
+
numpy.random.seed(seed)
|
|
498
|
+
|
|
495
499
|
if x_min is None:
|
|
496
500
|
x_min = self.lam_m
|
|
497
501
|
|
|
@@ -534,11 +538,44 @@ class KestenMcKay(object):
|
|
|
534
538
|
|
|
535
539
|
return samples
|
|
536
540
|
|
|
541
|
+
# ============
|
|
542
|
+
# Haar unitary
|
|
543
|
+
# ============
|
|
544
|
+
|
|
545
|
+
def _haar_orthogonal(self, n, k, seed=None):
|
|
546
|
+
"""
|
|
547
|
+
Haar-distributed O(n) via the Mezzadri QR trick.
|
|
548
|
+
|
|
549
|
+
References
|
|
550
|
+
----------
|
|
551
|
+
|
|
552
|
+
.. [1] Francesco Mezzadri. How to generate random matrices from the
|
|
553
|
+
classical compact groups. https://arxiv.org/pdf/math-ph/0609050
|
|
554
|
+
|
|
555
|
+
Notes
|
|
556
|
+
-----
|
|
557
|
+
|
|
558
|
+
Taking the QR of a normal-Gaussian matrix gives an orthonormal basis,
|
|
559
|
+
but the columns of that Q are not uniform on the sphere, as they are
|
|
560
|
+
biased by the signs or phases in the R-factor.
|
|
561
|
+
|
|
562
|
+
With Mezzadri method, columns of Q are rescaled by the reciprocals of
|
|
563
|
+
the diagonals of R phase, resulting in a matrix that is exactly
|
|
564
|
+
uniformly distributed under Haar measure O(n).
|
|
565
|
+
"""
|
|
566
|
+
|
|
567
|
+
rng = numpy.random.default_rng(seed)
|
|
568
|
+
Z = rng.standard_normal((n, k))
|
|
569
|
+
Q, R = numpy.linalg.qr(Z, mode='reduced') # Q is n by k
|
|
570
|
+
Q *= numpy.sign(numpy.diag(R))
|
|
571
|
+
|
|
572
|
+
return Q
|
|
573
|
+
|
|
537
574
|
# ======
|
|
538
575
|
# matrix
|
|
539
576
|
# ======
|
|
540
577
|
|
|
541
|
-
def matrix(self, size):
|
|
578
|
+
def matrix(self, size, seed=None):
|
|
542
579
|
"""
|
|
543
580
|
Generate matrix with the spectral density of the distribution.
|
|
544
581
|
|
|
@@ -548,12 +585,52 @@ class KestenMcKay(object):
|
|
|
548
585
|
size : int
|
|
549
586
|
Size :math:`n` of the matrix.
|
|
550
587
|
|
|
588
|
+
seed : int, default=None
|
|
589
|
+
Seed for random number generator.
|
|
590
|
+
|
|
551
591
|
Returns
|
|
552
592
|
-------
|
|
553
593
|
|
|
554
594
|
A : numpy.ndarray
|
|
555
595
|
A matrix of the size :math:`n \\times n`.
|
|
556
596
|
|
|
597
|
+
Notes
|
|
598
|
+
-----
|
|
599
|
+
|
|
600
|
+
If the parameter :math:`d` is even, the matrtix is generated from
|
|
601
|
+
|
|
602
|
+
.. math::
|
|
603
|
+
|
|
604
|
+
\\mathbf{A} = \\sum_{i=1}^{d/2} \\mathbf{O}_i +
|
|
605
|
+
\\mathbf{O}_o^{\\intercal},
|
|
606
|
+
|
|
607
|
+
where :math:`\\mathbf{O}_i` are randomly generated orthogonal matrices
|
|
608
|
+
with Haar. This method is fast but :math:`d` has to be even.
|
|
609
|
+
|
|
610
|
+
If all other :math:`d`, the following is used:
|
|
611
|
+
|
|
612
|
+
.. math::
|
|
613
|
+
|
|
614
|
+
\\mathbf{A} = \\mathbf{P} \\mathbf{O} \\mathbf{D} \\mathbf{O}^{-1}
|
|
615
|
+
\\mathbf{P},
|
|
616
|
+
|
|
617
|
+
where :math:`\\mathbf{D}` is diagonal matrix with entries
|
|
618
|
+
:math:`\\pm 1`, :math:`\\mathbf{O}` is orthogonal with Haar measure,
|
|
619
|
+
and :math:`\\mathbf{P}` is a projection matrix. For more details, see
|
|
620
|
+
Section 5 and 6 of [1]_.
|
|
621
|
+
|
|
622
|
+
The orthogonal matrices are genrated using the method of [2]_.
|
|
623
|
+
|
|
624
|
+
References
|
|
625
|
+
----------
|
|
626
|
+
|
|
627
|
+
.. [1] Iris S. A. Longoria and James A. Mingo, Freely Independent Coin
|
|
628
|
+
Tosses, Standard Young Tableaux, and the Kesten--McKay Law.
|
|
629
|
+
https://arxiv.org/abs/2009.11950
|
|
630
|
+
|
|
631
|
+
.. [2] Francesco Mezzadri. How to generate random matrices from the
|
|
632
|
+
classical compact groups. https://arxiv.org/abs/math-ph/0609050
|
|
633
|
+
|
|
557
634
|
Examples
|
|
558
635
|
--------
|
|
559
636
|
|
|
@@ -564,11 +641,38 @@ class KestenMcKay(object):
|
|
|
564
641
|
>>> A = km.matrix(2000)
|
|
565
642
|
"""
|
|
566
643
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
644
|
+
if (self.d >= 2) and (self.d % 2 == 0):
|
|
645
|
+
# Uses algorithm 1 . Only if d is even. This is much faster than
|
|
646
|
+
# algorithm 2.
|
|
647
|
+
n = size
|
|
648
|
+
rng = numpy.random.default_rng(seed)
|
|
649
|
+
m = self.d // 2
|
|
650
|
+
A = numpy.zeros((n, n))
|
|
651
|
+
|
|
652
|
+
for _ in range(m):
|
|
653
|
+
O_ = self._haar_orthogonal(n, n, seed=seed)
|
|
654
|
+
A += O_ + O_.T
|
|
655
|
+
else:
|
|
656
|
+
# Uses algorithm 2. Only when d is odd, but this algorithm works
|
|
657
|
+
# for any d (even and odd), but it takes much longer to comute
|
|
658
|
+
# especially if d is larger. As such, as only use algorithm 1 when
|
|
659
|
+
# d is even and use algorithm 2 for the rest.
|
|
660
|
+
n = size * self.d
|
|
661
|
+
rng = numpy.random.default_rng(seed)
|
|
662
|
+
|
|
663
|
+
# Deterministic pieces
|
|
664
|
+
k = size
|
|
665
|
+
if k == 0:
|
|
666
|
+
raise ValueError('Choose size larger then d.')
|
|
667
|
+
|
|
668
|
+
# Projection rows of O
|
|
669
|
+
Q = self._haar_orthogonal(n, k)
|
|
670
|
+
O_k = Q.T
|
|
671
|
+
|
|
672
|
+
# diagonal D with equal \pm 1 (trace 0)
|
|
673
|
+
diag = numpy.ones(n, dtype=float)
|
|
674
|
+
diag[:n//2] = -1
|
|
675
|
+
rng.shuffle(diag)
|
|
676
|
+
A = (n/k) * (O_k * diag) @ O_k.T
|
|
677
|
+
|
|
678
|
+
return A
|
|
@@ -436,8 +436,8 @@ class MarchenkoPastur(object):
|
|
|
436
436
|
# sample
|
|
437
437
|
# ======
|
|
438
438
|
|
|
439
|
-
def sample(self, size, x_min=None, x_max=None, method='qmc',
|
|
440
|
-
latex=False, save=False):
|
|
439
|
+
def sample(self, size, x_min=None, x_max=None, method='qmc', seed=None,
|
|
440
|
+
plot=False, latex=False, save=False):
|
|
441
441
|
"""
|
|
442
442
|
Sample from distribution.
|
|
443
443
|
|
|
@@ -456,11 +456,14 @@ class MarchenkoPastur(object):
|
|
|
456
456
|
is used.
|
|
457
457
|
|
|
458
458
|
method : {``'mc'``, ``'qmc'``}, default= ``'qmc'``
|
|
459
|
-
Method of drawing samples from uniform
|
|
459
|
+
Method of drawing samples from uniform distribution:
|
|
460
460
|
|
|
461
461
|
* ``'mc'``: Monte Carlo
|
|
462
462
|
* ``'qmc'``: Quasi Monte Carlo
|
|
463
463
|
|
|
464
|
+
seed : int, default=None,
|
|
465
|
+
Seed for random number generator.
|
|
466
|
+
|
|
464
467
|
plot : bool, default=False
|
|
465
468
|
If `True`, samples histogram is plotted.
|
|
466
469
|
|
|
@@ -498,6 +501,8 @@ class MarchenkoPastur(object):
|
|
|
498
501
|
:class: custom-dark
|
|
499
502
|
"""
|
|
500
503
|
|
|
504
|
+
numpy.random.seed(seed)
|
|
505
|
+
|
|
501
506
|
if x_min is None:
|
|
502
507
|
x_min = self.lam_m
|
|
503
508
|
|
|
@@ -544,7 +549,7 @@ class MarchenkoPastur(object):
|
|
|
544
549
|
# matrix
|
|
545
550
|
# ======
|
|
546
551
|
|
|
547
|
-
def matrix(self, size):
|
|
552
|
+
def matrix(self, size, seed=None):
|
|
548
553
|
"""
|
|
549
554
|
Generate matrix with the spectral density of the distribution.
|
|
550
555
|
|
|
@@ -554,6 +559,9 @@ class MarchenkoPastur(object):
|
|
|
554
559
|
size : int
|
|
555
560
|
Size :math:`n` of the matrix.
|
|
556
561
|
|
|
562
|
+
seed : int, default=None
|
|
563
|
+
Seed for random number generator.
|
|
564
|
+
|
|
557
565
|
Returns
|
|
558
566
|
-------
|
|
559
567
|
|
|
@@ -570,7 +578,7 @@ class MarchenkoPastur(object):
|
|
|
570
578
|
>>> A = mp.matrix(2000)
|
|
571
579
|
"""
|
|
572
580
|
|
|
573
|
-
numpy.random.seed(
|
|
581
|
+
numpy.random.seed(seed)
|
|
574
582
|
|
|
575
583
|
# Parameters
|
|
576
584
|
m = int(size / self.lam)
|
|
@@ -71,7 +71,7 @@ class Meixner(object):
|
|
|
71
71
|
\\frac{4(1+b) - (x-a)^2}{2 \\pi (b x^2 + a x + 1)}
|
|
72
72
|
\\mathbf{1}_{x \\in [\\lambda_{-}, \\lambda_{+}]} \\mathrm{d}{x}
|
|
73
73
|
|
|
74
|
-
where :math:`a, b` are the shape parameters of the
|
|
74
|
+
where :math:`a, b` are the shape parameters of the distribution. The edges
|
|
75
75
|
of the support are
|
|
76
76
|
|
|
77
77
|
.. math::
|
|
@@ -98,15 +98,16 @@ class Meixner(object):
|
|
|
98
98
|
# init
|
|
99
99
|
# ====
|
|
100
100
|
|
|
101
|
-
def __init__(self, a, b):
|
|
101
|
+
def __init__(self, a, b, c):
|
|
102
102
|
"""
|
|
103
103
|
Initialization.
|
|
104
104
|
"""
|
|
105
105
|
|
|
106
106
|
self.a = a
|
|
107
107
|
self.b = b
|
|
108
|
-
self.
|
|
109
|
-
self.
|
|
108
|
+
self.c = c
|
|
109
|
+
self.lam_p = self.a + 2.0 * numpy.sqrt(self.b)
|
|
110
|
+
self.lam_m = self.a - 2.0 * numpy.sqrt(self.b)
|
|
110
111
|
self.support = (self.lam_m, self.lam_p)
|
|
111
112
|
|
|
112
113
|
# =======
|
|
@@ -172,9 +173,19 @@ class Meixner(object):
|
|
|
172
173
|
rho = numpy.zeros_like(x)
|
|
173
174
|
mask = numpy.logical_and(x > self.lam_m, x < self.lam_p)
|
|
174
175
|
|
|
175
|
-
rho[mask] = \
|
|
176
|
-
|
|
177
|
-
|
|
176
|
+
# rho[mask] = \
|
|
177
|
+
# numpy.sqrt(4.0 * (1.0 + self.b) - (x[mask] - self.a)**2) / \
|
|
178
|
+
# (2.0 * numpy.pi * (self.b * x[mask]**2 + self.a * x[mask] + 1))
|
|
179
|
+
|
|
180
|
+
numer = numpy.zeros_like(x)
|
|
181
|
+
denom = numpy.ones_like(x)
|
|
182
|
+
numer[mask] = self.c * numpy.sqrt(4.0 * self.b - (x[mask] - self.a)**2)
|
|
183
|
+
denom[mask] = (1 - self.c)*(x[mask] - self.a)**2
|
|
184
|
+
denom[mask] += self.a * (2 - self.c)*(x[mask] - self.a)
|
|
185
|
+
denom[mask] += self.a**2 + self.b * self.c**2
|
|
186
|
+
denom[mask] *= 2 * numpy.pi
|
|
187
|
+
|
|
188
|
+
rho[mask] = numer[mask] / denom[mask]
|
|
178
189
|
|
|
179
190
|
if plot:
|
|
180
191
|
plot_density(x, rho, label='', latex=latex, save=save)
|
|
@@ -239,12 +250,17 @@ class Meixner(object):
|
|
|
239
250
|
x = numpy.linspace(x_min, x_max, 500)
|
|
240
251
|
|
|
241
252
|
def _P(x):
|
|
242
|
-
denom = 1.0 + self.b
|
|
243
|
-
return ((1.0 + 2.0 * self.b) * x + self.a) / denom
|
|
253
|
+
# denom = 1.0 + self.b
|
|
254
|
+
# return ((1.0 + 2.0 * self.b) * x + self.a) / denom
|
|
255
|
+
P = ((self.c - 2.0) * x - self.a * self.c) / 2.0
|
|
256
|
+
return P
|
|
244
257
|
|
|
245
258
|
def _Q(x):
|
|
246
|
-
denom = 1.0 + self.b
|
|
247
|
-
return (self.b * x**2 + self.a * x + 1.0) / denom
|
|
259
|
+
# denom = 1.0 + self.b
|
|
260
|
+
# return (self.b * x**2 + self.a * x + 1.0) / denom
|
|
261
|
+
Q = ((1.0 - self.c) * x**2 + self.a * self.c * x +
|
|
262
|
+
self.b * self.c**2) / 4.0
|
|
263
|
+
return Q
|
|
248
264
|
|
|
249
265
|
P = _P(x)
|
|
250
266
|
Q = _Q(x)
|
|
@@ -272,21 +288,32 @@ class Meixner(object):
|
|
|
272
288
|
"""
|
|
273
289
|
|
|
274
290
|
sign = -1 if alt_branch else 1
|
|
275
|
-
denom = 1.0 + self.b
|
|
276
|
-
A = (self.b * z**2 + self.a * z + 1.0) / denom
|
|
277
|
-
B = ((1.0 + 2.0 * self.b) * z + self.a) / denom
|
|
278
|
-
|
|
279
|
-
|
|
291
|
+
# denom = 1.0 + self.b
|
|
292
|
+
# A = (self.b * z**2 + self.a * z + 1.0) / denom
|
|
293
|
+
# B = ((1.0 + 2.0 * self.b) * z + self.a) / denom
|
|
294
|
+
A = ((1.0 - self.c) * z**2 + self.a * self.c * z +
|
|
295
|
+
self.b * self.c**2) / 4.0
|
|
296
|
+
B = ((self.c - 2.0) * z - self.a * self.c) / 2.0
|
|
297
|
+
|
|
298
|
+
# D = B**2 - 4 * A
|
|
299
|
+
# sqrtD = numpy.sqrt(D)
|
|
300
|
+
|
|
301
|
+
# Avoid numpy picking the wrong branch
|
|
302
|
+
d = 2 * numpy.sqrt(1.0 + self.b)
|
|
303
|
+
r_min = self.a - d
|
|
304
|
+
r_max = self.a + d
|
|
305
|
+
sqrtD = numpy.sqrt(z - r_min) * numpy.sqrt(z - r_max)
|
|
306
|
+
|
|
280
307
|
m1 = (-B + sqrtD) / (2 * A)
|
|
281
308
|
m2 = (-B - sqrtD) / (2 * A)
|
|
282
309
|
|
|
283
310
|
# pick correct branch only for non‑masked entries
|
|
284
311
|
upper = z.imag >= 0
|
|
285
312
|
branch = numpy.empty_like(m1)
|
|
286
|
-
branch[upper] = numpy.where(
|
|
287
|
-
|
|
288
|
-
branch[~upper] = numpy.where(
|
|
289
|
-
|
|
313
|
+
branch[upper] = numpy.where(
|
|
314
|
+
sign*m1[upper].imag > 0, m1[upper], m2[upper])
|
|
315
|
+
branch[~upper] = numpy.where(
|
|
316
|
+
sign*m1[~upper].imag < 0, m1[~upper], m2[~upper])
|
|
290
317
|
m = branch
|
|
291
318
|
|
|
292
319
|
return m
|
|
@@ -434,8 +461,8 @@ class Meixner(object):
|
|
|
434
461
|
# sample
|
|
435
462
|
# ======
|
|
436
463
|
|
|
437
|
-
def sample(self, size, x_min=None, x_max=None, method='qmc',
|
|
438
|
-
latex=False, save=False):
|
|
464
|
+
def sample(self, size, x_min=None, x_max=None, method='qmc', seed=None,
|
|
465
|
+
plot=False, latex=False, save=False):
|
|
439
466
|
"""
|
|
440
467
|
Sample from distribution.
|
|
441
468
|
|
|
@@ -454,11 +481,14 @@ class Meixner(object):
|
|
|
454
481
|
is used.
|
|
455
482
|
|
|
456
483
|
method : {``'mc'``, ``'qmc'``}, default= ``'qmc'``
|
|
457
|
-
Method of drawing samples from uniform
|
|
484
|
+
Method of drawing samples from uniform distribution:
|
|
458
485
|
|
|
459
486
|
* ``'mc'``: Monte Carlo
|
|
460
487
|
* ``'qmc'``: Quasi Monte Carlo
|
|
461
488
|
|
|
489
|
+
seed : int, default=None,
|
|
490
|
+
Seed for random number generator.
|
|
491
|
+
|
|
462
492
|
plot : bool, default=False
|
|
463
493
|
If `True`, samples histogram is plotted.
|
|
464
494
|
|
|
@@ -496,6 +526,8 @@ class Meixner(object):
|
|
|
496
526
|
:class: custom-dark
|
|
497
527
|
"""
|
|
498
528
|
|
|
529
|
+
numpy.random.seed(seed)
|
|
530
|
+
|
|
499
531
|
if x_min is None:
|
|
500
532
|
x_min = self.lam_m
|
|
501
533
|
|
|
@@ -542,7 +574,7 @@ class Meixner(object):
|
|
|
542
574
|
# matrix
|
|
543
575
|
# ======
|
|
544
576
|
|
|
545
|
-
def matrix(self, size):
|
|
577
|
+
def matrix(self, size, seed=None):
|
|
546
578
|
"""
|
|
547
579
|
Generate matrix with the spectral density of the distribution.
|
|
548
580
|
|
|
@@ -552,6 +584,9 @@ class Meixner(object):
|
|
|
552
584
|
size : int
|
|
553
585
|
Size :math:`n` of the matrix.
|
|
554
586
|
|
|
587
|
+
seed : int, default=None
|
|
588
|
+
Seed for random number generator.
|
|
589
|
+
|
|
555
590
|
Returns
|
|
556
591
|
-------
|
|
557
592
|
|
|
@@ -571,14 +606,4 @@ class Meixner(object):
|
|
|
571
606
|
>>> A = mx.matrix(2000)
|
|
572
607
|
"""
|
|
573
608
|
|
|
574
|
-
|
|
575
|
-
m1 = int(self.a * n)
|
|
576
|
-
m2 = int(self.b * n)
|
|
577
|
-
|
|
578
|
-
X = numpy.random.randn(n, m1)
|
|
579
|
-
Y = numpy.random.randn(n, m2)
|
|
580
|
-
|
|
581
|
-
Sx = X @ X.T
|
|
582
|
-
Sy = Y @ Y.T
|
|
583
|
-
|
|
584
|
-
return Sx, Sy
|
|
609
|
+
raise NotImplementedError
|
|
@@ -436,8 +436,8 @@ class Wachter(object):
|
|
|
436
436
|
# sample
|
|
437
437
|
# ======
|
|
438
438
|
|
|
439
|
-
def sample(self, size, x_min=None, x_max=None, method='qmc',
|
|
440
|
-
latex=False, save=False):
|
|
439
|
+
def sample(self, size, x_min=None, x_max=None, method='qmc', seed=None,
|
|
440
|
+
plot=False, latex=False, save=False):
|
|
441
441
|
"""
|
|
442
442
|
Sample from distribution.
|
|
443
443
|
|
|
@@ -456,11 +456,14 @@ class Wachter(object):
|
|
|
456
456
|
is used.
|
|
457
457
|
|
|
458
458
|
method : {``'mc'``, ``'qmc'``}, default= ``'qmc'``
|
|
459
|
-
Method of drawing samples from uniform
|
|
459
|
+
Method of drawing samples from uniform distribution:
|
|
460
460
|
|
|
461
461
|
* ``'mc'``: Monte Carlo
|
|
462
462
|
* ``'qmc'``: Quasi Monte Carlo
|
|
463
463
|
|
|
464
|
+
seed : int, default=None,
|
|
465
|
+
Seed for random number generator.
|
|
466
|
+
|
|
464
467
|
plot : bool, default=False
|
|
465
468
|
If `True`, samples histogram is plotted.
|
|
466
469
|
|
|
@@ -498,6 +501,8 @@ class Wachter(object):
|
|
|
498
501
|
:class: custom-dark
|
|
499
502
|
"""
|
|
500
503
|
|
|
504
|
+
numpy.random.seed(seed)
|
|
505
|
+
|
|
501
506
|
if x_min is None:
|
|
502
507
|
x_min = self.lam_m
|
|
503
508
|
|
|
@@ -544,7 +549,7 @@ class Wachter(object):
|
|
|
544
549
|
# matrix
|
|
545
550
|
# ======
|
|
546
551
|
|
|
547
|
-
def matrix(self, size):
|
|
552
|
+
def matrix(self, size, seed=None):
|
|
548
553
|
"""
|
|
549
554
|
Generate matrix with the spectral density of the distribution.
|
|
550
555
|
|
|
@@ -554,6 +559,9 @@ class Wachter(object):
|
|
|
554
559
|
size : int
|
|
555
560
|
Size :math:`n` of the matrix.
|
|
556
561
|
|
|
562
|
+
seed : int, default=None
|
|
563
|
+
Seed for random number generator.
|
|
564
|
+
|
|
557
565
|
Returns
|
|
558
566
|
-------
|
|
559
567
|
|
|
@@ -573,6 +581,8 @@ class Wachter(object):
|
|
|
573
581
|
>>> A = wa.matrix(2000)
|
|
574
582
|
"""
|
|
575
583
|
|
|
584
|
+
numpy.random.seed(seed)
|
|
585
|
+
|
|
576
586
|
n = size
|
|
577
587
|
m1 = int(self.a * n)
|
|
578
588
|
m2 = int(self.b * n)
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
# =======
|
|
13
13
|
|
|
14
14
|
import numpy
|
|
15
|
-
import networkx as nx
|
|
16
15
|
from scipy.interpolate import interp1d
|
|
17
16
|
from .._plot_util import plot_density, plot_hilbert, plot_stieltjes, \
|
|
18
17
|
plot_stieltjes_on_disk, plot_samples
|
|
@@ -77,20 +76,20 @@ class Wigner(object):
|
|
|
77
76
|
.. code-block:: python
|
|
78
77
|
|
|
79
78
|
>>> from freealg.distributions import Wigner
|
|
80
|
-
>>> wg = Wigner()
|
|
79
|
+
>>> wg = Wigner(1)
|
|
81
80
|
"""
|
|
82
81
|
|
|
83
82
|
# ====
|
|
84
83
|
# init
|
|
85
84
|
# ====
|
|
86
85
|
|
|
87
|
-
def __init__(self):
|
|
86
|
+
def __init__(self, r):
|
|
88
87
|
"""
|
|
89
88
|
Initialization.
|
|
90
89
|
"""
|
|
91
|
-
|
|
92
|
-
self.lam_p =
|
|
93
|
-
self.lam_m = -
|
|
90
|
+
self.r = r
|
|
91
|
+
self.lam_p = self.r
|
|
92
|
+
self.lam_m = -self.r
|
|
94
93
|
self.support = (self.lam_m, self.lam_p)
|
|
95
94
|
|
|
96
95
|
# =======
|
|
@@ -136,7 +135,7 @@ class Wigner(object):
|
|
|
136
135
|
.. code-block::python
|
|
137
136
|
|
|
138
137
|
>>> from freealg.distributions import Wigner
|
|
139
|
-
>>> wg = Wigner()
|
|
138
|
+
>>> wg = Wigner(1)
|
|
140
139
|
>>> rho = wg.density(plot=True)
|
|
141
140
|
|
|
142
141
|
.. image:: ../_static/images/plots/wg_density.png
|
|
@@ -156,8 +155,8 @@ class Wigner(object):
|
|
|
156
155
|
rho = numpy.zeros_like(x)
|
|
157
156
|
mask = numpy.logical_and(x >= self.lam_m, x <= self.lam_p)
|
|
158
157
|
|
|
159
|
-
rho[mask] = (
|
|
160
|
-
numpy.sqrt(
|
|
158
|
+
rho[mask] = (2.0 / (numpy.pi * self.r**2)) * \
|
|
159
|
+
numpy.sqrt(self.r**2 - x[mask]**2)
|
|
161
160
|
|
|
162
161
|
if plot:
|
|
163
162
|
plot_density(x, rho, label='', latex=latex, save=save)
|
|
@@ -204,7 +203,7 @@ class Wigner(object):
|
|
|
204
203
|
.. code-block::python
|
|
205
204
|
|
|
206
205
|
>>> from freealg.distributions import Wigner
|
|
207
|
-
>>> wg = Wigner()
|
|
206
|
+
>>> wg = Wigner(1)
|
|
208
207
|
>>> hilb = wg.hilbert(plot=True)
|
|
209
208
|
|
|
210
209
|
.. image:: ../_static/images/plots/wg_hilbert.png
|
|
@@ -225,7 +224,7 @@ class Wigner(object):
|
|
|
225
224
|
return x
|
|
226
225
|
|
|
227
226
|
def _Q(x):
|
|
228
|
-
return
|
|
227
|
+
return (self.r**2) / 4.0
|
|
229
228
|
|
|
230
229
|
P = _P(x)
|
|
231
230
|
Q = _Q(x)
|
|
@@ -256,7 +255,7 @@ class Wigner(object):
|
|
|
256
255
|
|
|
257
256
|
# Use quadratic form
|
|
258
257
|
sign = -1 if alt_branch else 1
|
|
259
|
-
A =
|
|
258
|
+
A = (self.r**2) / 4.0
|
|
260
259
|
B = z
|
|
261
260
|
D = B**2 - 4 * A
|
|
262
261
|
sqrtD = numpy.sqrt(D)
|
|
@@ -346,7 +345,7 @@ class Wigner(object):
|
|
|
346
345
|
.. code-block:: python
|
|
347
346
|
|
|
348
347
|
>>> from freealg.distributions import Wigner
|
|
349
|
-
>>> wg = Wigner()
|
|
348
|
+
>>> wg = Wigner(1)
|
|
350
349
|
>>> m1, m2 = wg.stieltjes(plot=True)
|
|
351
350
|
|
|
352
351
|
.. image:: ../_static/images/plots/wg_stieltjes.png
|
|
@@ -417,8 +416,8 @@ class Wigner(object):
|
|
|
417
416
|
# sample
|
|
418
417
|
# ======
|
|
419
418
|
|
|
420
|
-
def sample(self, size, x_min=None, x_max=None, method='qmc',
|
|
421
|
-
latex=False, save=False):
|
|
419
|
+
def sample(self, size, x_min=None, x_max=None, method='qmc', seed=None,
|
|
420
|
+
plot=False, latex=False, save=False):
|
|
422
421
|
"""
|
|
423
422
|
Sample from distribution.
|
|
424
423
|
|
|
@@ -437,7 +436,7 @@ class Wigner(object):
|
|
|
437
436
|
is used.
|
|
438
437
|
|
|
439
438
|
method : {``'mc'``, ``'qmc'``}, default= ``'qmc'``
|
|
440
|
-
Method of drawing samples from uniform
|
|
439
|
+
Method of drawing samples from uniform distribution:
|
|
441
440
|
|
|
442
441
|
* ``'mc'``: Monte Carlo
|
|
443
442
|
* ``'qmc'``: Quasi Monte Carlo
|
|
@@ -471,7 +470,7 @@ class Wigner(object):
|
|
|
471
470
|
.. code-block::python
|
|
472
471
|
|
|
473
472
|
>>> from freealg.distributions import Wigner
|
|
474
|
-
>>> wg = Wigner()
|
|
473
|
+
>>> wg = Wigner(1)
|
|
475
474
|
>>> s = wg.sample(2000)
|
|
476
475
|
|
|
477
476
|
.. image:: ../_static/images/plots/wg_samples.png
|
|
@@ -479,6 +478,8 @@ class Wigner(object):
|
|
|
479
478
|
:class: custom-dark
|
|
480
479
|
"""
|
|
481
480
|
|
|
481
|
+
numpy.random.seed(seed)
|
|
482
|
+
|
|
482
483
|
if x_min is None:
|
|
483
484
|
x_min = self.lam_m
|
|
484
485
|
|
|
@@ -525,7 +526,7 @@ class Wigner(object):
|
|
|
525
526
|
# matrix
|
|
526
527
|
# ======
|
|
527
528
|
|
|
528
|
-
def matrix(self, size):
|
|
529
|
+
def matrix(self, size, seed=None):
|
|
529
530
|
"""
|
|
530
531
|
Generate matrix with the spectral density of the distribution.
|
|
531
532
|
|
|
@@ -535,6 +536,9 @@ class Wigner(object):
|
|
|
535
536
|
size : int
|
|
536
537
|
Size :math:`n` of the matrix.
|
|
537
538
|
|
|
539
|
+
seed : int, default=None
|
|
540
|
+
Seed for random number generator.
|
|
541
|
+
|
|
538
542
|
Returns
|
|
539
543
|
-------
|
|
540
544
|
|
|
@@ -551,17 +555,11 @@ class Wigner(object):
|
|
|
551
555
|
>>> A = wg.matrix(2000)
|
|
552
556
|
"""
|
|
553
557
|
|
|
558
|
+
numpy.random.seed(seed)
|
|
559
|
+
|
|
554
560
|
# Parameters
|
|
555
561
|
n = size
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
# Random graph
|
|
559
|
-
G = nx.erdos_renyi_graph(n, p)
|
|
560
|
-
|
|
561
|
-
# Adjancency
|
|
562
|
-
A = nx.to_numpy_array(G) # shape (n,n), 0/1 entries
|
|
563
|
-
|
|
564
|
-
# Center & scale to get the semicircle
|
|
565
|
-
A_c = (A - p) / numpy.sqrt(n * p * (1-p))
|
|
562
|
+
X = numpy.random.randn(n, n)
|
|
563
|
+
X = (numpy.triu(X, 0) + numpy.triu(X, 1).T)
|
|
566
564
|
|
|
567
|
-
return
|
|
565
|
+
return X * (self.r / (2.0 * numpy.sqrt(n)))
|
|
@@ -839,8 +839,8 @@ class FreeForm(object):
|
|
|
839
839
|
# ==========
|
|
840
840
|
|
|
841
841
|
def decompress(self, size, x=None, delta=1e-6, iterations=500,
|
|
842
|
-
step_size=0.1, tolerance=1e-4,
|
|
843
|
-
save=False):
|
|
842
|
+
step_size=0.1, tolerance=1e-4, seed=None, plot=False,
|
|
843
|
+
latex=False, save=False):
|
|
844
844
|
"""
|
|
845
845
|
Free decompression of spectral density.
|
|
846
846
|
|
|
@@ -868,6 +868,9 @@ class FreeForm(object):
|
|
|
868
868
|
Tolerance for the solution obtained by the Newton solver. Also
|
|
869
869
|
used for the finite difference approximation to the derivative.
|
|
870
870
|
|
|
871
|
+
seed : int, default=None
|
|
872
|
+
Seed for random number generator. Used for QMC sampling.
|
|
873
|
+
|
|
871
874
|
plot : bool, default=False
|
|
872
875
|
If `True`, density is plotted.
|
|
873
876
|
|
|
@@ -925,6 +928,6 @@ class FreeForm(object):
|
|
|
925
928
|
plot_density(x, rho, support=(lb, ub),
|
|
926
929
|
label='Decompression', latex=latex, save=save)
|
|
927
930
|
|
|
928
|
-
eigs = numpy.sort(qmc_sample(x, rho, size))
|
|
931
|
+
eigs = numpy.sort(qmc_sample(x, rho, size, seed=seed))
|
|
929
932
|
|
|
930
933
|
return rho, eigs
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: freealg
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Summary: Free probability for large matrices
|
|
5
5
|
Keywords: leaderboard bot chat
|
|
6
6
|
Platform: Linux
|
|
@@ -30,7 +30,6 @@ Requires-Dist: scipy
|
|
|
30
30
|
Requires-Dist: texplot
|
|
31
31
|
Requires-Dist: matplotlib
|
|
32
32
|
Requires-Dist: colorcet
|
|
33
|
-
Requires-Dist: networkx
|
|
34
33
|
Requires-Dist: statsmodels
|
|
35
34
|
Provides-Extra: test
|
|
36
35
|
Requires-Dist: tox; extra == "test"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.1.7"
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|