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.
Files changed (52) hide show
  1. freealg/__init__.py +8 -6
  2. freealg/__version__.py +1 -1
  3. freealg/_algebraic_form/_branch_points.py +18 -18
  4. freealg/_algebraic_form/_continuation_algebraic.py +13 -13
  5. freealg/_algebraic_form/_cusp.py +15 -15
  6. freealg/_algebraic_form/_cusp_wrap.py +6 -6
  7. freealg/_algebraic_form/_decompress.py +16 -16
  8. freealg/_algebraic_form/_decompress4.py +31 -31
  9. freealg/_algebraic_form/_decompress5.py +23 -23
  10. freealg/_algebraic_form/_decompress6.py +13 -13
  11. freealg/_algebraic_form/_decompress7.py +15 -15
  12. freealg/_algebraic_form/_decompress8.py +17 -17
  13. freealg/_algebraic_form/_decompress9.py +18 -18
  14. freealg/_algebraic_form/_decompress_new.py +17 -17
  15. freealg/_algebraic_form/_decompress_new_2.py +57 -57
  16. freealg/_algebraic_form/_decompress_util.py +10 -10
  17. freealg/_algebraic_form/_decompressible.py +292 -0
  18. freealg/_algebraic_form/_edge.py +10 -10
  19. freealg/_algebraic_form/_homotopy4.py +9 -9
  20. freealg/_algebraic_form/_homotopy5.py +9 -9
  21. freealg/_algebraic_form/_support.py +19 -19
  22. freealg/_algebraic_form/algebraic_form.py +262 -468
  23. freealg/_base_form.py +401 -0
  24. freealg/_free_form/__init__.py +1 -4
  25. freealg/_free_form/_density_util.py +1 -1
  26. freealg/_free_form/_plot_util.py +3 -511
  27. freealg/_free_form/free_form.py +8 -367
  28. freealg/_util.py +59 -11
  29. freealg/distributions/__init__.py +2 -1
  30. freealg/distributions/_base_distribution.py +163 -0
  31. freealg/distributions/_chiral_block.py +137 -11
  32. freealg/distributions/_compound_poisson.py +141 -47
  33. freealg/distributions/_deformed_marchenko_pastur.py +138 -33
  34. freealg/distributions/_deformed_wigner.py +98 -9
  35. freealg/distributions/_fuss_catalan.py +269 -0
  36. freealg/distributions/_kesten_mckay.py +4 -130
  37. freealg/distributions/_marchenko_pastur.py +8 -196
  38. freealg/distributions/_meixner.py +4 -130
  39. freealg/distributions/_wachter.py +4 -130
  40. freealg/distributions/_wigner.py +10 -127
  41. freealg/visualization/__init__.py +2 -2
  42. freealg/visualization/{_rgb_hsv.py → _domain_coloring.py} +37 -29
  43. freealg/visualization/_plot_util.py +513 -0
  44. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/METADATA +1 -1
  45. freealg-0.7.18.dist-info/RECORD +74 -0
  46. freealg-0.7.17.dist-info/RECORD +0 -69
  47. /freealg/{_free_form/_sample.py → _sample.py} +0 -0
  48. /freealg/{_free_form/_support.py → _support.py} +0 -0
  49. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/WHEEL +0 -0
  50. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/licenses/AUTHORS.txt +0 -0
  51. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/licenses/LICENSE.txt +0 -0
  52. {freealg-0.7.17.dist-info → freealg-0.7.18.dist-info}/top_level.txt +0 -0
@@ -12,15 +12,9 @@
12
12
  # =======
13
13
 
14
14
  import numpy
15
- from scipy.interpolate import interp1d
16
- from .._free_form._plot_util import plot_density, plot_hilbert, \
17
- plot_stieltjes, plot_stieltjes_on_disk, plot_samples
18
-
19
- try:
20
- from scipy.integrate import cumtrapz
21
- except ImportError:
22
- from scipy.integrate import cumulative_trapezoid as cumtrapz
23
- from scipy.stats import qmc
15
+ from ..visualization._plot_util import plot_density, plot_hilbert, \
16
+ plot_stieltjes, plot_stieltjes_on_disk
17
+ from ._base_distribution import BaseDistribution
24
18
 
25
19
  __all__ = ['Meixner']
26
20
 
@@ -29,7 +23,7 @@ __all__ = ['Meixner']
29
23
  # Meixner
30
24
  # =======
31
25
 
32
- class Meixner(object):
26
+ class Meixner(BaseDistribution):
33
27
  """
34
28
  Meixner distribution.
35
29
 
@@ -461,126 +455,6 @@ class Meixner(object):
461
455
 
462
456
  return m1, m2
463
457
 
464
- # ======
465
- # sample
466
- # ======
467
-
468
- def sample(self, size, x_min=None, x_max=None, method='qmc', seed=None,
469
- plot=False, latex=False, save=False):
470
- """
471
- Sample from distribution.
472
-
473
- Parameters
474
- ----------
475
-
476
- size : int
477
- Size of sample.
478
-
479
- x_min : float, default=None
480
- Minimum of sample values. If `None`, the left edge of the support
481
- is used.
482
-
483
- x_max : float, default=None
484
- Maximum of sample values. If `None`, the right edge of the support
485
- is used.
486
-
487
- method : {``'mc'``, ``'qmc'``}, default= ``'qmc'``
488
- Method of drawing samples from uniform distribution:
489
-
490
- * ``'mc'``: Monte Carlo
491
- * ``'qmc'``: Quasi Monte Carlo
492
-
493
- seed : int, default=None,
494
- Seed for random number generator.
495
-
496
- plot : bool, default=False
497
- If `True`, samples histogram is plotted.
498
-
499
- latex : bool, default=False
500
- If `True`, the plot is rendered using LaTeX. This option is
501
- relevant only if ``plot=True``.
502
-
503
- save : bool, default=False
504
- If not `False`, the plot is saved. If a string is given, it is
505
- assumed to the save filename (with the file extension). This option
506
- is relevant only if ``plot=True``.
507
-
508
- Returns
509
- -------
510
-
511
- s : numpy.ndarray
512
- Samples.
513
-
514
- Notes
515
- -----
516
-
517
- This method uses inverse transform sampling.
518
-
519
- Examples
520
- --------
521
-
522
- .. code-block::python
523
-
524
- >>> from freealg.distributions import Meixner
525
- >>> mx = Meixner(2, 3)
526
- >>> s = mx.sample(2000)
527
-
528
- .. image:: ../_static/images/plots/mx_samples.png
529
- :align: center
530
- :class: custom-dark
531
- """
532
-
533
- if x_min is None:
534
- x_min = self.lam_m
535
-
536
- if x_max is None:
537
- x_max = self.lam_p
538
-
539
- # Grid and PDF
540
- xs = numpy.linspace(x_min, x_max, size)
541
- pdf = self.density(xs)
542
-
543
- # CDF (using cumulative trapezoidal rule)
544
- cdf = cumtrapz(pdf, xs, initial=0)
545
- cdf /= cdf[-1] # normalize CDF to 1
546
-
547
- # Inverse CDF interpolator
548
- inv_cdf = interp1d(cdf, xs, bounds_error=False,
549
- fill_value=(x_min, x_max))
550
-
551
- # Random generator
552
- rng = numpy.random.default_rng(seed)
553
-
554
- # Draw from uniform distribution
555
- if method == 'mc':
556
- u = rng.random(size)
557
-
558
- elif method == 'qmc':
559
- try:
560
- engine = qmc.Halton(d=1, scramble=True, rng=rng)
561
- except TypeError:
562
- # Older scipy versions
563
- engine = qmc.Halton(d=1, scramble=True, seed=rng)
564
- u = engine.random(size).ravel()
565
-
566
- else:
567
- raise NotImplementedError('"method" is invalid.')
568
-
569
- # Draw from distribution by mapping from inverse CDF
570
- samples = inv_cdf(u).ravel()
571
-
572
- if plot:
573
- radius = 0.5 * (self.lam_p - self.lam_m)
574
- center = 0.5 * (self.lam_p + self.lam_m)
575
- scale = 1.25
576
- x_min = numpy.floor(center - radius * scale)
577
- x_max = numpy.ceil(center + radius * scale)
578
- x = numpy.linspace(x_min, x_max, 500)
579
- rho = self.density(x)
580
- plot_samples(x, rho, x_min, x_max, samples, latex=latex, save=save)
581
-
582
- return samples
583
-
584
458
  # ======
585
459
  # matrix
586
460
  # ======
@@ -12,15 +12,9 @@
12
12
  # =======
13
13
 
14
14
  import numpy
15
- from scipy.interpolate import interp1d
16
- from .._free_form._plot_util import plot_density, plot_hilbert, \
17
- plot_stieltjes, plot_stieltjes_on_disk, plot_samples
18
-
19
- try:
20
- from scipy.integrate import cumtrapz
21
- except ImportError:
22
- from scipy.integrate import cumulative_trapezoid as cumtrapz
23
- from scipy.stats import qmc
15
+ from ..visualization._plot_util import plot_density, plot_hilbert, \
16
+ plot_stieltjes, plot_stieltjes_on_disk
17
+ from ._base_distribution import BaseDistribution
24
18
 
25
19
  __all__ = ['Wachter']
26
20
 
@@ -29,7 +23,7 @@ __all__ = ['Wachter']
29
23
  # Wachter
30
24
  # =======
31
25
 
32
- class Wachter(object):
26
+ class Wachter(BaseDistribution):
33
27
  """
34
28
  Wachter distribution.
35
29
 
@@ -440,126 +434,6 @@ class Wachter(object):
440
434
 
441
435
  return m1, m2
442
436
 
443
- # ======
444
- # sample
445
- # ======
446
-
447
- def sample(self, size, x_min=None, x_max=None, method='qmc', seed=None,
448
- plot=False, latex=False, save=False):
449
- """
450
- Sample from distribution.
451
-
452
- Parameters
453
- ----------
454
-
455
- size : int
456
- Size of sample.
457
-
458
- x_min : float, default=None
459
- Minimum of sample values. If `None`, the left edge of the support
460
- is used.
461
-
462
- x_max : float, default=None
463
- Maximum of sample values. If `None`, the right edge of the support
464
- is used.
465
-
466
- method : {``'mc'``, ``'qmc'``}, default= ``'qmc'``
467
- Method of drawing samples from uniform distribution:
468
-
469
- * ``'mc'``: Monte Carlo
470
- * ``'qmc'``: Quasi Monte Carlo
471
-
472
- seed : int, default=None,
473
- Seed for random number generator.
474
-
475
- plot : bool, default=False
476
- If `True`, samples histogram is plotted.
477
-
478
- latex : bool, default=False
479
- If `True`, the plot is rendered using LaTeX. This option is
480
- relevant only if ``plot=True``.
481
-
482
- save : bool, default=False
483
- If not `False`, the plot is saved. If a string is given, it is
484
- assumed to the save filename (with the file extension). This option
485
- is relevant only if ``plot=True``.
486
-
487
- Returns
488
- -------
489
-
490
- s : numpy.ndarray
491
- Samples.
492
-
493
- Notes
494
- -----
495
-
496
- This method uses inverse transform sampling.
497
-
498
- Examples
499
- --------
500
-
501
- .. code-block::python
502
-
503
- >>> from freealg.distributions import Wachter
504
- >>> wa = Wachter(2, 3)
505
- >>> s = wa.sample(2000)
506
-
507
- .. image:: ../_static/images/plots/wa_samples.png
508
- :align: center
509
- :class: custom-dark
510
- """
511
-
512
- if x_min is None:
513
- x_min = self.lam_m
514
-
515
- if x_max is None:
516
- x_max = self.lam_p
517
-
518
- # Grid and PDF
519
- xs = numpy.linspace(x_min, x_max, size)
520
- pdf = self.density(xs)
521
-
522
- # CDF (using cumulative trapezoidal rule)
523
- cdf = cumtrapz(pdf, xs, initial=0)
524
- cdf /= cdf[-1] # normalize CDF to 1
525
-
526
- # Inverse CDF interpolator
527
- inv_cdf = interp1d(cdf, xs, bounds_error=False,
528
- fill_value=(x_min, x_max))
529
-
530
- # Random generator
531
- rng = numpy.random.default_rng(seed)
532
-
533
- # Draw from uniform distribution
534
- if method == 'mc':
535
- u = rng.random(size)
536
-
537
- elif method == 'qmc':
538
- try:
539
- engine = qmc.Halton(d=1, scramble=True, rng=rng)
540
- except TypeError:
541
- # Older scipy versions
542
- engine = qmc.Halton(d=1, scramble=True, seed=rng)
543
- u = engine.random(size).ravel()
544
-
545
- else:
546
- raise NotImplementedError('"method" is invalid.')
547
-
548
- # Draw from distribution by mapping from inverse CDF
549
- samples = inv_cdf(u).ravel()
550
-
551
- if plot:
552
- radius = 0.5 * (self.lam_p - self.lam_m)
553
- center = 0.5 * (self.lam_p + self.lam_m)
554
- scale = 1.25
555
- x_min = numpy.floor(center - radius * scale)
556
- x_max = numpy.ceil(center + radius * scale)
557
- x = numpy.linspace(x_min, x_max, 500)
558
- rho = self.density(x)
559
- plot_samples(x, rho, x_min, x_max, samples, latex=latex, save=save)
560
-
561
- return samples
562
-
563
437
  # ======
564
438
  # matrix
565
439
  # ======
@@ -12,15 +12,9 @@
12
12
  # =======
13
13
 
14
14
  import numpy
15
- from scipy.interpolate import interp1d
16
- from .._free_form._plot_util import plot_density, plot_hilbert, \
17
- plot_stieltjes, plot_stieltjes_on_disk, plot_samples
18
-
19
- try:
20
- from scipy.integrate import cumtrapz
21
- except ImportError:
22
- from scipy.integrate import cumulative_trapezoid as cumtrapz
23
- from scipy.stats import qmc
15
+ from ..visualization._plot_util import plot_density, plot_hilbert, \
16
+ plot_stieltjes, plot_stieltjes_on_disk
17
+ from ._base_distribution import BaseDistribution
24
18
 
25
19
  __all__ = ['Wigner']
26
20
 
@@ -29,10 +23,16 @@ __all__ = ['Wigner']
29
23
  # Wigner
30
24
  # ======
31
25
 
32
- class Wigner(object):
26
+ class Wigner(BaseDistribution):
33
27
  """
34
28
  Wigner semicircle distribution.
35
29
 
30
+ Parameters
31
+ ----------
32
+
33
+ r : float
34
+ Parameter :math:`r` of the distribution. See Notes.
35
+
36
36
  Methods
37
37
  -------
38
38
 
@@ -420,123 +420,6 @@ class Wigner(object):
420
420
 
421
421
  return m1, m2
422
422
 
423
- # ======
424
- # sample
425
- # ======
426
-
427
- def sample(self, size, x_min=None, x_max=None, method='qmc', seed=None,
428
- plot=False, latex=False, save=False):
429
- """
430
- Sample from distribution.
431
-
432
- Parameters
433
- ----------
434
-
435
- size : int
436
- Size of sample.
437
-
438
- x_min : float, default=None
439
- Minimum of sample values. If `None`, the left edge of the support
440
- is used.
441
-
442
- x_max : float, default=None
443
- Maximum of sample values. If `None`, the right edge of the support
444
- is used.
445
-
446
- method : {``'mc'``, ``'qmc'``}, default= ``'qmc'``
447
- Method of drawing samples from uniform distribution:
448
-
449
- * ``'mc'``: Monte Carlo
450
- * ``'qmc'``: Quasi Monte Carlo
451
-
452
- plot : bool, default=False
453
- If `True`, samples histogram is plotted.
454
-
455
- latex : bool, default=False
456
- If `True`, the plot is rendered using LaTeX. This option is
457
- relevant only if ``plot=True``.
458
-
459
- save : bool, default=False
460
- If not `False`, the plot is saved. If a string is given, it is
461
- assumed to the save filename (with the file extension). This option
462
- is relevant only if ``plot=True``.
463
-
464
- Returns
465
- -------
466
-
467
- s : numpy.ndarray
468
- Samples.
469
-
470
- Notes
471
- -----
472
-
473
- This method uses inverse transform sampling.
474
-
475
- Examples
476
- --------
477
-
478
- .. code-block::python
479
-
480
- >>> from freealg.distributions import Wigner
481
- >>> wg = Wigner(1)
482
- >>> s = wg.sample(2000)
483
-
484
- .. image:: ../_static/images/plots/wg_samples.png
485
- :align: center
486
- :class: custom-dark
487
- """
488
-
489
- if x_min is None:
490
- x_min = self.lam_m
491
-
492
- if x_max is None:
493
- x_max = self.lam_p
494
-
495
- # Grid and PDF
496
- xs = numpy.linspace(x_min, x_max, size)
497
- pdf = self.density(xs)
498
-
499
- # CDF (using cumulative trapezoidal rule)
500
- cdf = cumtrapz(pdf, xs, initial=0)
501
- cdf /= cdf[-1] # normalize CDF to 1
502
-
503
- # Inverse CDF interpolator
504
- inv_cdf = interp1d(cdf, xs, bounds_error=False,
505
- fill_value=(x_min, x_max))
506
-
507
- # Random generator
508
- rng = numpy.random.default_rng(seed)
509
-
510
- # Draw from uniform distribution
511
- if method == 'mc':
512
- u = rng.random(size)
513
-
514
- elif method == 'qmc':
515
- try:
516
- engine = qmc.Halton(d=1, scramble=True, rng=rng)
517
- except TypeError:
518
- # Older scipy versions
519
- engine = qmc.Halton(d=1, scramble=True, seed=rng)
520
- u = engine.random(size).ravel()
521
-
522
- else:
523
- raise NotImplementedError('"method" is invalid.')
524
-
525
- # Draw from distribution by mapping from inverse CDF
526
- samples = inv_cdf(u).ravel()
527
-
528
- if plot:
529
- radius = 0.5 * (self.lam_p - self.lam_m)
530
- center = 0.5 * (self.lam_p + self.lam_m)
531
- scale = 1.25
532
- x_min = numpy.floor(center - radius * scale)
533
- x_max = numpy.ceil(center + radius * scale)
534
- x = numpy.linspace(x_min, x_max, 500)
535
- rho = self.density(x)
536
- plot_samples(x, rho, x_min, x_max, samples, latex=latex, save=save)
537
-
538
- return samples
539
-
540
423
  # ======
541
424
  # matrix
542
425
  # ======
@@ -6,7 +6,7 @@
6
6
  # under the terms of the license found in the LICENSE.txt file in the root
7
7
  # directory of this source tree.
8
8
 
9
- from ._rgb_hsv import rgb_hsv
9
+ from ._domain_coloring import domain_coloring
10
10
  from ._glue_util import glue_branches
11
11
 
12
- __all__ = ['rgb_hsv', 'glue_branches']
12
+ __all__ = ['domain_coloring', 'glue_branches']
@@ -14,54 +14,62 @@
14
14
  import numpy
15
15
  import matplotlib
16
16
 
17
- __all__ = ['rgb_hsv']
17
+ __all__ = ['domain_coloring']
18
18
 
19
19
 
20
- # =======
21
- # rgb hsv
22
- # =======
20
+ # ===============
21
+ # domain coloring
22
+ # ===============
23
23
 
24
- def rgb_hsv(c, shift=0.0, thresh=numpy.inf, n_mod=12.0, n_ph=12.0, vmin=0.35,
25
- vmax=1.0, tile_gamma=1.0, tile_mix=1.0):
24
+ def domain_coloring(c, shift=0.0, thresh=numpy.inf, n_mod=12.0, n_ph=12.0,
25
+ vmin=0.35, vmax=1.0, tile_gamma=1.0, tile_mix=0.0):
26
26
  """
27
27
  Convert complex field c to RGB via HSV domain coloring.
28
28
 
29
29
  Parameters
30
30
  ----------
31
+
31
32
  c : array_like of complex
32
33
  Complex field.
33
34
 
34
- shift : float, default 0.0
35
- Phase offset in turns (1.0 = full 2*pi rotation). Applied to hue.
35
+ shift : float, default=0.0
36
+ Phase offset in turns (1.0 = full :math:`2 \\pi` rotation). Applied to
37
+ hue.
36
38
 
37
- thresh : float, default numpy.inf
38
- Optional cap on |c| used for magnitude-related terms. Use to prevent
39
- very large magnitudes from dominating the encoding.
39
+ thresh : float, default=numpy.inf
40
+ Optional cap on :math:`\\vert c \\vert` used for magnitude-related
41
+ terms. Use to prevent very large magnitudes from dominating the
42
+ encoding.
40
43
 
41
- n_mod : float, default 12.0
42
- Number of modulus steps per 2*pi in log(|c|). Higher -> more concentric
43
- rings. Set to 0.0 to disable modulus stepping.
44
+ n_mod : float, default=12.0
45
+ Number of modulus steps per :math:`2 \\pi` in
46
+ :math:`\\log(\\vert c \\vert`). Higher means more concentric rings. Set
47
+ to 0.0 to disable modulus stepping.
44
48
 
45
- n_ph : float, default 12.0
46
- Number of phase steps per 2*pi in arg(c). Higher -> more angular
47
- sectors. Set to 0.0 to disable phase stepping.
49
+ n_ph : float, default=12.0
50
+ Number of phase steps per :math:`2 \\pi` in :math:`\\mathrm{arg}(c)`.
51
+ Higher means more angular sectors. Set to 0.0 to disable phase
52
+ stepping.
48
53
 
49
- vmin : float, default 0.35
54
+ vmin : float, default=0.35
50
55
  Minimum brightness for the tiling shading (darkest parts of tiles).
51
56
 
52
- vmax : float, default 1.0
57
+ vmax : float, default=1.0
53
58
  Maximum brightness for the tiling shading (brightest parts of tiles).
54
59
  Lowering vmax (e.g. 0.8-0.9) can reduce the "neon" look.
55
60
 
56
- tile_gamma : float, default 1.0
57
- Shapes the within-tile ramp. 1.0 = linear sawtooth. >1.0 makes tiles
58
- stay darker longer and brighten sharply near boundaries. <1.0 brightens
59
- earlier.
61
+ tile_gamma : float, default=1.0
62
+ Shapes the within-tile ramp. 1.0 = linear sawtooth. Larger than 1.0
63
+ makes tiles stay darker longer and brighten sharply near boundaries.
64
+ Smaller than 1.0 brightens earlier.
60
65
 
61
- tile_mix : float in [0, 1], default 1.0
66
+ tile_mix : float in [0, 1], default=0.0
62
67
  Mix between original magnitude brightness and tiling shading:
63
- 0.0 -> value = 1 - exp(-|c|) (your original, no tiling influence)
64
- 1.0 -> value = tiling shading only (Wegert-style tiling look)
68
+
69
+ * 0.0: value is :math:`1 - \\exp(- \\vert c \\vert)` (original
70
+ coloring, no tiling influence)
71
+ * 1.0: value is tiling shading only (Wegert-style tiling look)
72
+
65
73
  Intermediate values overlay tiling onto the original magnitude shading.
66
74
 
67
75
  Notes
@@ -72,9 +80,9 @@ def rgb_hsv(c, shift=0.0, thresh=numpy.inf, n_mod=12.0, n_ph=12.0, vmin=0.35,
72
80
  References
73
81
  ----------
74
82
 
75
- [1] Wegert, E. (2015) "Visual Complex Functions: An Introduction +with
76
- Phase Portraits", Springer.
77
- doi: https://doi.org/10.1007/978-3-0348-0180-5
83
+ .. [1] Wegert, E. (2015) "Visual Complex Functions: An Introduction +with
84
+ Phase Portraits", Springer.
85
+ doi: https://doi.org/10.1007/978-3-0348-0180-5
78
86
  """
79
87
 
80
88
  hue = (numpy.angle(c) + numpy.pi) / (2.0 * numpy.pi)