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.
Files changed (34) hide show
  1. {freealg-0.1.7 → freealg-0.1.9}/PKG-INFO +1 -2
  2. freealg-0.1.9/freealg/__version__.py +1 -0
  3. {freealg-0.1.7 → freealg-0.1.9}/freealg/_sample.py +7 -1
  4. {freealg-0.1.7 → freealg-0.1.9}/freealg/distributions/kesten_mckay.py +117 -13
  5. {freealg-0.1.7 → freealg-0.1.9}/freealg/distributions/marchenko_pastur.py +13 -5
  6. {freealg-0.1.7 → freealg-0.1.9}/freealg/distributions/meixner.py +60 -35
  7. {freealg-0.1.7 → freealg-0.1.9}/freealg/distributions/wachter.py +14 -4
  8. {freealg-0.1.7 → freealg-0.1.9}/freealg/distributions/wigner.py +27 -29
  9. {freealg-0.1.7 → freealg-0.1.9}/freealg/freeform.py +6 -3
  10. {freealg-0.1.7 → freealg-0.1.9}/freealg.egg-info/PKG-INFO +1 -2
  11. {freealg-0.1.7 → freealg-0.1.9}/freealg.egg-info/requires.txt +0 -1
  12. {freealg-0.1.7 → freealg-0.1.9}/requirements.txt +0 -1
  13. freealg-0.1.7/freealg/__version__.py +0 -1
  14. {freealg-0.1.7 → freealg-0.1.9}/AUTHORS.txt +0 -0
  15. {freealg-0.1.7 → freealg-0.1.9}/CHANGELOG.rst +0 -0
  16. {freealg-0.1.7 → freealg-0.1.9}/LICENSE.txt +0 -0
  17. {freealg-0.1.7 → freealg-0.1.9}/MANIFEST.in +0 -0
  18. {freealg-0.1.7 → freealg-0.1.9}/README.rst +0 -0
  19. {freealg-0.1.7 → freealg-0.1.9}/freealg/__init__.py +0 -0
  20. {freealg-0.1.7 → freealg-0.1.9}/freealg/_chebyshev.py +0 -0
  21. {freealg-0.1.7 → freealg-0.1.9}/freealg/_damp.py +0 -0
  22. {freealg-0.1.7 → freealg-0.1.9}/freealg/_decompress.py +0 -0
  23. {freealg-0.1.7 → freealg-0.1.9}/freealg/_jacobi.py +0 -0
  24. {freealg-0.1.7 → freealg-0.1.9}/freealg/_pade.py +0 -0
  25. {freealg-0.1.7 → freealg-0.1.9}/freealg/_plot_util.py +0 -0
  26. {freealg-0.1.7 → freealg-0.1.9}/freealg/_util.py +0 -0
  27. {freealg-0.1.7 → freealg-0.1.9}/freealg/distributions/__init__.py +0 -0
  28. {freealg-0.1.7 → freealg-0.1.9}/freealg.egg-info/SOURCES.txt +0 -0
  29. {freealg-0.1.7 → freealg-0.1.9}/freealg.egg-info/dependency_links.txt +0 -0
  30. {freealg-0.1.7 → freealg-0.1.9}/freealg.egg-info/not-zip-safe +0 -0
  31. {freealg-0.1.7 → freealg-0.1.9}/freealg.egg-info/top_level.txt +0 -0
  32. {freealg-0.1.7 → freealg-0.1.9}/pyproject.toml +0 -0
  33. {freealg-0.1.7 → freealg-0.1.9}/setup.cfg +0 -0
  34. {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.7
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', plot=False,
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 distirbution:
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
- n = size
568
- G = nx.random_regular_graph(self.d, n)
569
- A = nx.to_numpy_array(G, dtype=float) # shape (n,n)
570
-
571
- mu = self.d / n
572
- A_c = A - mu * numpy.ones((n, n))
573
-
574
- return A_c
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', plot=False,
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 distirbution:
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(0)
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 distributon. The edges
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.lam_p = self.a + 2.0 * numpy.sqrt(1.0 + self.b)
109
- self.lam_m = self.a - 2.0 * numpy.sqrt(1.0 + self.b)
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
- numpy.sqrt(4.0 * (1.0 + self.b) - (x[mask] - self.a)**2) / \
177
- (2.0 * numpy.pi * (self.b * x[mask]**2 + self.a * x[mask] + 1))
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
- D = B**2 - 4 * A
279
- sqrtD = numpy.sqrt(D)
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(sign*m1[upper].imag > 0, m1[upper],
287
- m2[upper])
288
- branch[~upper] = numpy.where(sign*m1[~upper].imag < 0, m1[~upper],
289
- m2[~upper])
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', plot=False,
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 distirbution:
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
- n = size
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', plot=False,
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 distirbution:
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 = 2.0
93
- self.lam_m = -2.0
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] = (1.0 / (2.0 * numpy.pi)) * \
160
- numpy.sqrt(4.0 - x[mask]**2)
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 1.0
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 = 1.0
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', plot=False,
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 distirbution:
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
- p = 1.0 / size
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 A_c
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, plot=False, latex=False,
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.7
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"
@@ -3,7 +3,6 @@ scipy
3
3
  texplot
4
4
  matplotlib
5
5
  colorcet
6
- networkx
7
6
  statsmodels
8
7
 
9
8
  [docs]
@@ -3,5 +3,4 @@ scipy
3
3
  texplot
4
4
  matplotlib
5
5
  colorcet
6
- networkx
7
6
  statsmodels
@@ -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