├── charts ├── dirichlet.png ├── unit_disc.svg ├── unit_circle.svg ├── exponential_exp1.svg ├── bernoulli.svg └── standard_normal.svg ├── requirements.txt ├── src ├── distributions │ ├── exponential_exp1.py │ ├── standard_normal.py │ ├── exponential.py │ ├── cauchy.py │ ├── normal.py │ ├── gumbel.py │ ├── pareto.py │ ├── student_t.py │ ├── log_normal.py │ ├── skew_normal.py │ ├── inverse_gaussian.py │ ├── standard_geometric.py │ ├── zeta.py │ ├── beta.py │ ├── chi_squared.py │ ├── zipf.py │ ├── gamma.py │ ├── fisher_f.py │ ├── normal_inverse_gaussian.py │ ├── poisson.py │ ├── binomial.py │ ├── triangular.py │ ├── frechet.py │ ├── weibull.py │ ├── hypergeometric.py │ ├── unit_disc.py │ ├── unit_circle.py │ ├── bernoulli.py │ ├── geometric.py │ ├── unit_sphere.py │ ├── unit_ball.py │ ├── pert.py │ └── dirichlet.py └── main.py ├── .gitignore └── LICENSE /charts/dirichlet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust-random/charts/main/charts/dirichlet.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy==1.26.4 2 | matplotlib==3.8.4 3 | scipy==1.13.0 4 | python-ternary==1.0.8 -------------------------------------------------------------------------------- /src/distributions/exponential_exp1.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import expon 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | # Fixed value for lambda 8 | lmbda = 1 9 | # Possible values for the distribution 10 | x = np.linspace(0, 5, 1000) 11 | 12 | # Creating the figure and the axis 13 | fig, ax = plt.subplots() 14 | 15 | # Plotting the PDF for each value of lambda 16 | ax.plot(x, expon.pdf(x, scale=1 / lmbda), label=f'λ = {lmbda}') 17 | 18 | # Adding title and labels 19 | ax.set_title('Exponential distribution') 20 | ax.set_xlabel('x') 21 | ax.set_ylabel('Probability density') 22 | 23 | # Adding a legend 24 | ax.legend() 25 | ax.grid() 26 | ax.margins(x=0, y=0) 27 | 28 | plt.savefig(f"{directory}/exponential_exp1.{extension}") 29 | plt.close() 30 | -------------------------------------------------------------------------------- /src/distributions/standard_normal.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import norm 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | # Possible values for the distribution 8 | x = np.linspace(-5, 5, 1000) 9 | 10 | # Creating the figure and the axis 11 | fig, ax = plt.subplots() 12 | 13 | # Plotting the PDF for the standard normal distribution 14 | ax.plot(x, norm.pdf(x), label=f'μ = 0, σ = 1') 15 | 16 | # Adding title and labels 17 | ax.set_title('Standard normal distribution') 18 | ax.set_xlabel('x') 19 | ax.set_ylabel('Probability density') 20 | 21 | # Adding a legend 22 | ax.legend() 23 | ax.grid() 24 | ax.margins(x=0, y=0) 25 | ymin, ymax = ax.get_ylim() 26 | ax.set_ylim(ymin, ymax * 1.05) 27 | 28 | plt.savefig(f"{directory}/standard_normal.{extension}") 29 | plt.close() 30 | -------------------------------------------------------------------------------- /src/distributions/exponential.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import expon 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | # Possible values of lambda for the distribution 8 | lambda_values = [1, 0.5, 2] 9 | # Possible values for the distribution 10 | x = np.linspace(0, 5, 1000) 11 | 12 | # Creating the figure and the axis 13 | fig, ax = plt.subplots() 14 | 15 | # Plotting the PDF for each value of lambda 16 | for lmbda in lambda_values: 17 | ax.plot(x, expon.pdf(x, scale=1 / lmbda), label=f'λ = {lmbda}') 18 | 19 | # Adding title and labels 20 | ax.set_title('Exponential distribution') 21 | ax.set_xlabel('x') 22 | ax.set_ylabel('Probability density') 23 | 24 | # Adding a legend 25 | ax.legend() 26 | ax.grid() 27 | ax.margins(x=0, y=0) 28 | 29 | plt.savefig(f"{directory}/exponential.{extension}") 30 | plt.close() 31 | -------------------------------------------------------------------------------- /src/distributions/cauchy.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | 5 | def save_to(directory: str, extension: str): 6 | # Possible values for the distribution 7 | x = np.linspace(-7, 7, 1000) 8 | 9 | # Creating the figure and the axis 10 | fig, ax = plt.subplots() 11 | 12 | inputs = [(0, 1), (0, 0.5), (0, 2), (-2, 1)] 13 | 14 | # Plotting the PDF for the Cauchy distribution 15 | for x0, gamma in inputs: 16 | ax.plot(x, 1 / (np.pi * gamma * (1 + ((x - x0) / gamma)**2)), label=f'x₀ = {x0}, γ = {gamma}') 17 | 18 | # Adding title and labels 19 | ax.set_title('Cauchy distribution') 20 | ax.set_xlabel('x') 21 | ax.set_ylabel('Probability density') 22 | 23 | # Adding a legend 24 | ax.legend() 25 | ax.grid() 26 | ax.margins(x=0, y=0) 27 | ymin, ymax = ax.get_ylim() 28 | ax.set_ylim(ymin, ymax * 1.05) 29 | 30 | plt.savefig(f"{directory}/cauchy.{extension}") 31 | plt.close() 32 | -------------------------------------------------------------------------------- /src/distributions/normal.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import norm 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | inputs = [(0, 1), (0, 0.5), (0, 2), (-2, 1)] 8 | # Possible values for the distribution 9 | x = np.linspace(-5, 5, 1000) 10 | 11 | # Creating the figure and the axis 12 | fig, ax = plt.subplots() 13 | 14 | # Plotting the PDF for each value of mu and sigma 15 | for mu, sigma in inputs: 16 | ax.plot(x, norm.pdf(x, loc=mu, scale=sigma), label=f'μ = {mu}, σ = {sigma}') 17 | 18 | # Adding title and labels 19 | ax.set_title('Normal distribution') 20 | ax.set_xlabel('x') 21 | ax.set_ylabel('Probability density') 22 | 23 | # Adding a legend 24 | ax.legend() 25 | ax.grid() 26 | ax.margins(x=0, y=0) 27 | ymin, ymax = ax.get_ylim() 28 | ax.set_ylim(ymin, ymax * 1.05) 29 | 30 | plt.savefig(f"{directory}/normal.{extension}") 31 | plt.close() 32 | -------------------------------------------------------------------------------- /src/distributions/gumbel.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import gumbel_r 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | inputs = [(0, 1), (0, 0.5), (0, 2), (-2, 1)] 8 | # Possible values for the distribution 9 | x = np.linspace(-5, 5, 1000) 10 | 11 | # Creating the figure and the axis 12 | fig, ax = plt.subplots() 13 | 14 | # Plotting the PDF for each value of mu and beta 15 | for mu, beta in inputs: 16 | ax.plot(x, gumbel_r.pdf(x, loc=mu, scale=beta), label=f'μ = {mu}, β = {beta}') 17 | 18 | # Adding title and labels 19 | ax.set_title('Gumbel distribution') 20 | ax.set_xlabel('x') 21 | ax.set_ylabel('Probability density') 22 | 23 | # Adding a legend 24 | ax.legend() 25 | ax.grid() 26 | ax.margins(x=0, y=0) 27 | ymin, ymax = ax.get_ylim() 28 | ax.set_ylim(ymin, ymax * 1.05) 29 | 30 | plt.savefig(f"{directory}/gumbel.{extension}") 31 | plt.close() 32 | -------------------------------------------------------------------------------- /src/distributions/pareto.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import pareto 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | inputs = [(1, 1), (1, 2), (1, 3), (2, 1)] 8 | # Possible values for the distribution 9 | x = np.linspace(0, 3, 1000) 10 | 11 | # Creating the figure and the axis 12 | fig, ax = plt.subplots() 13 | 14 | # Plotting the PDF for each value of alpha 15 | for scale, shape in inputs: 16 | ax.plot(x, pareto.pdf(x, shape, scale=scale), label=f'α = {shape}, x$_{{m}}$ = {scale}') 17 | 18 | # Adding title and labels 19 | ax.set_title('Pareto distribution') 20 | ax.set_xlabel('x') 21 | ax.set_ylabel('Probability density') 22 | 23 | # Adding a legend 24 | ax.legend() 25 | ax.grid() 26 | ax.margins(x=0, y=0) 27 | ymin, ymax = ax.get_ylim() 28 | ax.set_ylim(ymin, ymax * 1.05) 29 | 30 | plt.savefig(f"{directory}/pareto.{extension}") 31 | plt.close() 32 | -------------------------------------------------------------------------------- /src/distributions/student_t.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import t 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | # Degrees of freedom for the distribution 8 | df_values = [0.1, 0.5, 1, 2, 5, np.inf] 9 | # Possible values for the distribution 10 | x = np.linspace(-5, 5, 1000) 11 | 12 | # Creating the figure and the axis 13 | fig, ax = plt.subplots() 14 | 15 | # Plotting the PDF for each value of the degrees of freedom 16 | for df in df_values: 17 | ax.plot(x, t.pdf(x, df), label=f'nu = {df}') 18 | 19 | # Adding title and labels 20 | ax.set_title('T-distribution') 21 | ax.set_xlabel('x') 22 | ax.set_ylabel('Probability density') 23 | 24 | # Adding a legend 25 | ax.legend() 26 | ax.grid() 27 | ax.margins(x=0, y=0) 28 | ymin, ymax = ax.get_ylim() 29 | ax.set_ylim(ymin, ymax * 1.05) 30 | 31 | plt.savefig(f"{directory}/student_t.{extension}") 32 | plt.close() 33 | -------------------------------------------------------------------------------- /src/distributions/log_normal.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import lognorm 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | inputs = [(0, 1), (0, 0.5), (0, 2), (-0.5, 1), (1, 1)] 8 | # Possible values for the distribution 9 | x = np.linspace(0, 5, 1000) 10 | 11 | # Creating the figure and the axis 12 | fig, ax = plt.subplots() 13 | 14 | # Plotting the PDF for each value of mu and sigma 15 | for mu, sigma in inputs: 16 | ax.plot(x, lognorm.pdf(x, s=sigma, scale=np.exp(mu)), label=f'μ = {mu}, σ = {sigma}') 17 | 18 | # Adding title and labels 19 | ax.set_title('Log-normal distribution') 20 | ax.set_xlabel('x') 21 | ax.set_ylabel('Probability density') 22 | 23 | # Adding a legend 24 | ax.legend() 25 | ax.grid() 26 | ax.margins(x=0, y=0) 27 | ymin, ymax = ax.get_ylim() 28 | ax.set_ylim(ymin, ymax * 1.05) 29 | 30 | plt.savefig(f"{directory}/log_normal.{extension}") 31 | plt.close() 32 | -------------------------------------------------------------------------------- /src/distributions/skew_normal.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import skewnorm 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | inputs = [(0, 1, -5), (0, 1, -2), (0, 1, 0), (0, 1, 2), (0, 1, 5)] 8 | # Possible values for the distribution 9 | x = np.linspace(-5, 5, 1000) 10 | 11 | # Creating the figure and the axis 12 | fig, ax = plt.subplots() 13 | 14 | # Plotting the PDF for each value of alpha 15 | for loc, scale, shape in inputs: 16 | ax.plot(x, skewnorm.pdf(x, shape, loc, scale), label=f'shape = {shape}') 17 | 18 | # Adding title and labels 19 | ax.set_title('Skew Normal distribution') 20 | ax.set_xlabel('x') 21 | ax.set_ylabel('Probability density') 22 | 23 | # Adding a legend 24 | ax.legend() 25 | ax.grid() 26 | ax.margins(x=0, y=0) 27 | ymin, ymax = ax.get_ylim() 28 | ax.set_ylim(ymin, ymax * 1.05) 29 | 30 | plt.savefig(f"{directory}/skew_normal.{extension}") 31 | plt.close() 32 | -------------------------------------------------------------------------------- /src/distributions/inverse_gaussian.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import invgauss 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | # Possible values for the distribution 8 | x = np.linspace(0, 5, 1000) 9 | 10 | # Creating the figure and the axis 11 | fig, ax = plt.subplots() 12 | 13 | inputs = [(1, 1), (1, 2), (2, 1), (2, 2)] 14 | 15 | # Plotting the PDF for the Inverse Gaussian distribution 16 | for mu, lambda_ in inputs: 17 | ax.plot(x, invgauss.pdf(x, mu, scale=lambda_), label=f'μ = {mu}, λ = {lambda_}') 18 | 19 | # Adding title and labels 20 | ax.set_title('Inverse Gaussian distribution') 21 | ax.set_xlabel('x') 22 | ax.set_ylabel('Probability density') 23 | 24 | # Adding a legend 25 | ax.legend() 26 | ax.grid() 27 | ax.margins(x=0, y=0) 28 | ymin, ymax = ax.get_ylim() 29 | ax.set_ylim(ymin, ymax * 1.05) 30 | 31 | plt.savefig(f"{directory}/inverse_gaussian.{extension}") 32 | plt.close() 33 | -------------------------------------------------------------------------------- /src/distributions/standard_geometric.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import geom 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | # Possible outcomes for a Geometric distributed variable 8 | outcomes = np.arange(1, 11) 9 | 10 | # Creating the figure and the axis 11 | fig, ax = plt.subplots() 12 | 13 | # Plotting the PMF for the standard Geometric distribution 14 | ax.bar(outcomes, geom.pmf(outcomes, 0.5), label=f'p = 0.5') 15 | 16 | # Adding title and labels 17 | ax.set_title('Standard Geometric distribution') 18 | ax.set_xlabel('Number of trials until first success') 19 | ax.set_ylabel('Probability') 20 | ax.set_xticks(outcomes) # set the ticks to be the outcome values 21 | 22 | # Adding a legend 23 | ax.legend() 24 | ax.grid() 25 | ax.margins(x=0, y=0) 26 | ymin, ymax = ax.get_ylim() 27 | ax.set_ylim(ymin, ymax * 1.05) 28 | 29 | plt.savefig(f"{directory}/standard_geometric.{extension}") 30 | plt.close() 31 | -------------------------------------------------------------------------------- /src/distributions/zeta.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import zipf 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | inputs = [3, 2, 1.5, 1.1] # Different values of s 8 | outcomes = np.arange(1, 11) # Outcomes from 1 to 10 9 | 10 | # Creating the figure 11 | fig, ax = plt.subplots() 12 | width = 0.2 # Bar width 13 | 14 | # Plotting the Zeta Distribution for each value of s 15 | for i, s in enumerate(inputs): 16 | ax.bar(outcomes + i * width - width * 3 / 2, zipf.pmf(outcomes, s), width=width, label=f's = {s}') 17 | 18 | ax.set_title('Zeta Distribution') 19 | ax.set_xlabel('Outcome') 20 | ax.set_ylabel('Probability') 21 | ax.set_xticks(outcomes) # Adjusting x-ticks to center 22 | ax.legend() 23 | ax.grid() 24 | ax.margins(x=0, y=0) 25 | ymin, ymax = ax.get_ylim() 26 | ax.set_ylim(ymin, ymax * 1.05) 27 | 28 | # Save the plot to a file 29 | plt.savefig(f"{directory}/zeta.{extension}") 30 | plt.close() 31 | -------------------------------------------------------------------------------- /src/distributions/beta.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import beta 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | # Defining the Beta distribution PDF 8 | def y(a, b, x): 9 | y = beta.pdf(x, a, b) 10 | y[y > 4] = np.nan 11 | return y 12 | 13 | inputs = [(0.5, 0.5), (5, 1), (1, 3), (2, 2), (2, 5)] 14 | # Possible values for the distribution 15 | x = np.linspace(0, 1, 1000) 16 | 17 | # Creating the figure and the axis 18 | fig, ax = plt.subplots() 19 | 20 | # Plotting the PDF for each value of alpha and beta 21 | for a, b in inputs: 22 | ax.plot(x, y(a, b, x), label=f'α = {a}, β = {b}') 23 | 24 | # Adding title and labels 25 | ax.set_title('Beta distribution') 26 | ax.set_xlabel('x') 27 | ax.set_ylabel('Probability density') 28 | 29 | # Adding a legend 30 | ax.legend() 31 | ax.grid() 32 | ax.margins(x=0, y=0) 33 | 34 | plt.savefig(f"{directory}/beta.{extension}") 35 | plt.close() 36 | -------------------------------------------------------------------------------- /src/distributions/chi_squared.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import chi2 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | def y(x, df): 8 | y = chi2.pdf(x, df) 9 | y[y > 1.05] = np.nan 10 | return y 11 | # Degrees of freedom for the distribution 12 | df_values = [1, 2, 3, 5, 9] 13 | # Possible values for the distribution 14 | x = np.linspace(0, 10, 1000) 15 | 16 | # Creating the figure and the axis 17 | fig, ax = plt.subplots() 18 | 19 | # Plotting the PDF for each value of the degrees of freedom 20 | for df in df_values: 21 | ax.plot(x, y(x, df), label=f'k = {df}') 22 | 23 | # Adding title and labels 24 | ax.set_title('Chi-squared distribution') 25 | ax.set_xlabel('Chi-squared statistic') 26 | ax.set_ylabel('Probability density') 27 | 28 | # Adding a legend 29 | ax.legend() 30 | ax.grid() 31 | ax.margins(x=0, y=0) 32 | 33 | plt.savefig(f"{directory}/chi_squared.{extension}") 34 | plt.close() 35 | -------------------------------------------------------------------------------- /src/distributions/zipf.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import zipfian 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | inputs = [(2, 10), (1, 10), (0, 10)] # Different values of s and n 8 | outcomes = np.arange(1, 12) # Outcomes from 1 to 10 9 | 10 | # Creating the figure 11 | fig, ax = plt.subplots() 12 | width = 0.2 # Bar width 13 | 14 | # Plotting the Zipf Distribution for each value of s 15 | for i, (s, n) in enumerate(inputs): 16 | ax.bar(outcomes + i * width - width, zipfian.pmf(outcomes, s, n), width=width, label=f's = {s}, n = {n}') 17 | 18 | ax.set_title('Zipf Distribution') 19 | ax.set_xlabel('Outcome') 20 | ax.set_ylabel('Probability') 21 | ax.set_xticks(outcomes) # Adjusting x-ticks to center 22 | ax.legend() 23 | ax.grid() 24 | ax.margins(x=0, y=0) 25 | ymin, ymax = ax.get_ylim() 26 | ax.set_ylim(ymin, ymax * 1.05) 27 | 28 | # Save the plot to a file 29 | plt.savefig(f"{directory}/zipf.{extension}") 30 | plt.close() 31 | -------------------------------------------------------------------------------- /src/distributions/gamma.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import gamma 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | inputs = [(1, 1), (2, 1), (3, 1), (1, 2), (2, 2), (3, 2)] 8 | # Possible values for the distribution 9 | x = np.linspace(0, 7, 1000) 10 | 11 | # Creating the figure and the axis 12 | fig, ax = plt.subplots() 13 | colors = ["blue", "red", "green", "blue", "red", "green"] 14 | alphas = [1.0, 1.0, 1.0, 0.6, 0.6, 0.6] 15 | 16 | # Plotting the PDF for each value of alpha and beta 17 | for i, (k, theta) in enumerate(inputs): 18 | ax.plot(x, gamma.pdf(x, k, scale=theta), label=f'k = {k}, θ = {theta}', color=colors[i], alpha=alphas[i]) 19 | 20 | # Adding title and labels 21 | ax.set_title('Gamma distribution') 22 | ax.set_xlabel('x') 23 | ax.set_ylabel('Probability density') 24 | 25 | # Adding a legend 26 | ax.legend() 27 | ax.grid() 28 | ax.margins(x=0, y=0) 29 | 30 | plt.savefig(f"{directory}/gamma.{extension}") 31 | plt.close() 32 | -------------------------------------------------------------------------------- /src/distributions/fisher_f.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import f 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | def y(x, dfn, dfd): 8 | y = f.pdf(x, dfn, dfd) 9 | y[y > 2.3] = np.nan 10 | return y 11 | 12 | # Degrees of freedom for the distribution 13 | d1_d2 = [(1, 1), (2, 1), (3, 1), (10, 1), (10, 10), (100, 100)] 14 | # Possible values for the distribution 15 | x = np.linspace(0, 5, 1000) 16 | 17 | # Creating the figure and the axis 18 | fig, ax = plt.subplots() 19 | 20 | # Plotting the PDF for each value of the degrees of freedom 21 | for m, n in d1_d2: 22 | ax.plot(x, y(x, m, n), label=f'm = {m}, n = {n}') 23 | 24 | # Adding title and labels 25 | ax.set_title('F-distribution') 26 | ax.set_xlabel('F-statistic') 27 | ax.set_ylabel('Probability density') 28 | 29 | # Adding a legend 30 | ax.legend() 31 | ax.grid() 32 | ax.margins(x=0, y=0) 33 | 34 | plt.savefig(f"{directory}/fisher_f.{extension}") 35 | plt.close() 36 | -------------------------------------------------------------------------------- /src/distributions/normal_inverse_gaussian.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import norminvgauss 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | inputs = [(1, 0), (3, 0), (0.1, 0), (1, -0.99), (1, 0.99)] 8 | # Possible values for the distribution 9 | x = np.linspace(-5, 5, 1000) 10 | 11 | # Creating the figure and the axis 12 | fig, ax = plt.subplots(figsize=(8, 5)) 13 | 14 | # Plotting the PDF for the Normal Inverse Gaussian distribution 15 | for alpha, beta in inputs: 16 | ax.plot(x, norminvgauss.pdf(x, alpha, beta, 0, 1), label=f'α = {alpha}, β = {beta}') 17 | 18 | # Adding title and labels 19 | ax.set_title('Normal Inverse Gaussian distribution') 20 | ax.set_xlabel('x') 21 | ax.set_ylabel('Probability density') 22 | 23 | # Adding a legend 24 | ax.legend() 25 | ax.grid() 26 | ax.margins(x=0, y=0) 27 | ymin, ymax = ax.get_ylim() 28 | ax.set_ylim(ymin, ymax * 1.05) 29 | 30 | plt.savefig(f"{directory}/normal_inverse_gaussian.{extension}") 31 | plt.close() 32 | -------------------------------------------------------------------------------- /src/distributions/poisson.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import poisson 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | # Possible values of lambda for the distribution 8 | lambda_values = [0.5, 1, 2, 4, 10] 9 | # Possible outcomes for a Poisson distributed variable 10 | outcomes = np.arange(0, 15) 11 | 12 | # Creating the figure and the axis 13 | fig, ax = plt.subplots() 14 | 15 | # Plotting the PMF for each value of lambda 16 | for i, lmbda in enumerate(lambda_values): 17 | ax.plot(outcomes, poisson.pmf(outcomes, lmbda), 'o-', label=f'λ = {lmbda}') 18 | 19 | # Adding title and labels 20 | ax.set_title('Poisson distribution') 21 | ax.set_xlabel('Outcome') 22 | ax.set_ylabel('Probability') 23 | ax.set_xticks(outcomes) # set the ticks to be the outcome values 24 | 25 | # Adding a legend 26 | ax.legend() 27 | ax.grid() 28 | ax.margins(x=0, y=0) 29 | ymin, ymax = ax.get_ylim() 30 | ax.set_ylim(ymin, ymax * 1.05) 31 | 32 | plt.savefig(f"{directory}/poisson.{extension}") 33 | plt.close() 34 | -------------------------------------------------------------------------------- /src/distributions/binomial.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import binom 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | inputs = [(10, 0.2), (10, 0.6)] 8 | # Possible outcomes for a Binomial distributed variable 9 | outcomes = np.arange(0, 11) 10 | width = 0.5 11 | 12 | # Creating the figure and the axis 13 | fig, ax = plt.subplots() 14 | 15 | # Plotting the PMF for each value of n and p 16 | for i, (n, p) in enumerate(inputs): 17 | ax.bar(outcomes + i * width - width / 2, binom.pmf(outcomes, n, p), width=width, label=f'n = {n}, p = {p}') 18 | 19 | # Adding title and labels 20 | ax.set_title('Binomial distribution') 21 | ax.set_xlabel('k (number of successes)') 22 | ax.set_ylabel('Probability') 23 | ax.set_xticks(outcomes) # set the ticks to be the outcome values 24 | 25 | # Adding a legend 26 | ax.legend() 27 | ax.grid() 28 | ax.margins(x=0, y=0) 29 | ymin, ymax = ax.get_ylim() 30 | ax.set_ylim(ymin, ymax * 1.05) 31 | 32 | plt.savefig(f"{directory}/binomial.{extension}") 33 | plt.close() 34 | -------------------------------------------------------------------------------- /src/distributions/triangular.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import triang 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | # Defining the Triangular distribution PDF 8 | def y(a, b, c, x): 9 | return triang.pdf(x, c=(c - a) / (b - a), loc=a, scale=b - a) 10 | 11 | inputs = [(0, 1, 0.5), (0, 1, 0.25), (0, 1, 0.75), (-1, 1, 0)] 12 | # Possible values for the distribution 13 | x = np.linspace(-1, 1, 1000) 14 | 15 | # Creating the figure and the axis 16 | fig, ax = plt.subplots() 17 | 18 | # Plotting the PDF for each value of a, b, and c 19 | for a, b, c in inputs: 20 | ax.plot(x, y(a, b, c, x), label=f'a = {a}, b = {b}, c = {c}') 21 | 22 | # Adding title and labels 23 | ax.set_title('Triangular distribution') 24 | ax.set_xlabel('x') 25 | ax.set_ylabel('Probability density') 26 | 27 | # Adding a legend 28 | ax.legend() 29 | ax.grid() 30 | ax.margins(x=0, y=0) 31 | ymin, ymax = ax.get_ylim() 32 | ax.set_ylim(ymin, ymax * 1.05) 33 | 34 | plt.savefig(f"{directory}/triangular.{extension}") 35 | plt.close() 36 | -------------------------------------------------------------------------------- /src/distributions/frechet.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import invweibull 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | def y(x, shape, loc, scale): 8 | return invweibull.pdf(x, shape, loc=loc, scale=scale) 9 | # Inputs for the distribution 10 | inputs = [(0, 1, 1), (1, 1, 1), (0, 0.5, 1), (0, 2, 1), (0, 1, 0.35), (0, 1, 2)] 11 | # x values for the distribution 12 | x = np.linspace(0, 5, 1000) 13 | 14 | # Creating the figure and the axis 15 | fig, ax = plt.subplots() 16 | 17 | # Plotting the PDF for each value of a 18 | for loc, scale, shape in inputs: 19 | ax.plot(x, y(x, shape, loc, scale), label=f'μ = {loc}, σ = {scale}, α = {shape}') 20 | 21 | # Adding title and labels 22 | ax.set_title('Fréchet distribution') 23 | ax.set_xlabel('x') 24 | ax.set_ylabel('Probability density') 25 | 26 | # Adding a legend 27 | ax.legend() 28 | ax.grid() 29 | ax.margins(x=0, y=0) 30 | ymin, ymax = ax.get_ylim() 31 | ax.set_ylim(ymin, ymax * 1.05) 32 | 33 | plt.savefig(f"{directory}/frechet.{extension}") 34 | plt.close() 35 | -------------------------------------------------------------------------------- /src/distributions/weibull.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import weibull_min 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | def y(x, scale, shape): 8 | y = weibull_min.pdf(x, shape, scale=scale) 9 | y[y > 5] = np.nan 10 | return y 11 | # Possible values of alpha for the distribution 12 | inputs = [(1, 1), (2, 1), (3, 1), (1, 2), (1, 3), (2, 2)] 13 | # Possible values for the distribution 14 | x = np.linspace(0, 3, 1000) 15 | 16 | # Creating the figure and the axis 17 | fig, ax = plt.subplots() 18 | 19 | # Plotting the PDF for each value of alpha 20 | for scale, shape in inputs: 21 | ax.plot(x, y(x, scale, shape), label=f'λ = {scale}, k = {shape}') 22 | 23 | # Adding title and labels 24 | ax.set_title('Weibull distribution') 25 | ax.set_xlabel('x') 26 | ax.set_ylabel('Probability density') 27 | 28 | # Adding a legend 29 | ax.legend() 30 | ax.grid() 31 | ax.margins(x=0, y=0) 32 | ymin, ymax = ax.get_ylim() 33 | ax.set_ylim(ymin, ymax * 1.05) 34 | 35 | plt.savefig(f"{directory}/weibull.{extension}") 36 | plt.close() 37 | -------------------------------------------------------------------------------- /src/distributions/hypergeometric.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import hypergeom 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | inputs = [(50, 12, 10), (50, 35, 10)] 8 | # Possible outcomes for a Hypergeometric distributed variable 9 | outcomes = np.arange(0, 11) 10 | width = 0.5 11 | 12 | # Creating the figure and the axis 13 | fig, ax = plt.subplots() 14 | 15 | # Plotting the PMF for each value of N, K, and n 16 | for i, (N, K, n) in enumerate(inputs): 17 | ax.bar(outcomes + i * width - width / 2, hypergeom.pmf(outcomes, N, K, n), width=width, label=f'N = {N}, K = {K}, n = {n}') 18 | 19 | # Adding title and labels 20 | ax.set_title('Hypergeometric distribution') 21 | ax.set_xlabel('k (number of successes)') 22 | ax.set_ylabel('Probability') 23 | ax.set_xticks(outcomes) # set the ticks to be the outcome values 24 | 25 | # Adding a legend 26 | ax.legend() 27 | ax.grid() 28 | ax.margins(x=0, y=0) 29 | ymin, ymax = ax.get_ylim() 30 | ax.set_ylim(ymin, ymax * 1.05) 31 | 32 | plt.savefig(f"{directory}/hypergeometric.{extension}") 33 | plt.close() 34 | -------------------------------------------------------------------------------- /src/distributions/unit_disc.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | 5 | def save_to(directory: str, extension: str): 6 | # Create a circle 7 | def plot_circle(radius=1, num_divisions=100): 8 | theta = np.linspace(0, 2 * np.pi, num_divisions) 9 | x = radius * np.cos(theta) 10 | y = radius * np.sin(theta) 11 | 12 | return x, y 13 | 14 | # Plotting parameters 15 | radius = 1 16 | num_divisions = 100 # Increase this for a smoother circle 17 | 18 | x, y = plot_circle(radius, num_divisions) 19 | 20 | # Create a plot 21 | fig, ax = plt.subplots(figsize=(8, 8)) 22 | ax.fill(x, y, color='b', alpha=0.6) 23 | 24 | # Scaling the axes 25 | ax.set_xlim([-1, 1]) 26 | ax.set_ylim([-1, 1]) 27 | ax.set_aspect('equal') 28 | 29 | # Labels and title 30 | ax.set_xlabel('X') 31 | ax.set_ylabel('Y') 32 | ax.set_title('Unit Disc') 33 | ax.grid() 34 | ax.margins(x=0, y=0) 35 | ymin, ymax = ax.get_ylim() 36 | ax.set_ylim(ymin, ymax * 1.05) 37 | 38 | plt.tight_layout() 39 | 40 | # Save the figure 41 | plt.savefig(f"{directory}/unit_disc.{extension}") 42 | plt.close() 43 | -------------------------------------------------------------------------------- /src/distributions/unit_circle.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | 5 | def save_to(directory: str, extension: str): 6 | # Create a circle 7 | def plot_circle(radius=1, num_divisions=100): 8 | theta = np.linspace(0, 2 * np.pi, num_divisions) 9 | x = radius * np.cos(theta) 10 | y = radius * np.sin(theta) 11 | 12 | return x, y 13 | 14 | # Plotting parameters 15 | radius = 1 16 | num_divisions = 100 # Increase this for a smoother circle 17 | 18 | x, y = plot_circle(radius, num_divisions) 19 | 20 | # Create a plot 21 | fig, ax = plt.subplots(figsize=(8, 8)) 22 | ax.plot(x, y, color='b', alpha=0.6) 23 | 24 | # Scaling the axes 25 | ax.set_xlim([-1, 1]) 26 | ax.set_ylim([-1, 1]) 27 | ax.set_aspect('equal') 28 | 29 | # Labels and title 30 | ax.set_xlabel('X') 31 | ax.set_ylabel('Y') 32 | ax.set_title('Unit Circle') 33 | ax.grid() 34 | ax.margins(x=0, y=0) 35 | ymin, ymax = ax.get_ylim() 36 | ax.set_ylim(ymin, ymax * 1.05) 37 | 38 | plt.tight_layout() 39 | 40 | # Save the figure 41 | plt.savefig(f"{directory}/unit_circle.{extension}") 42 | plt.close() 43 | -------------------------------------------------------------------------------- /src/distributions/bernoulli.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import bernoulli 4 | 5 | 6 | # Bernoulli distribution 7 | def save_to(directory: str, extension: str): 8 | # Defining the Bernoulli distribution PMF 9 | def y(p): 10 | return np.array([1 - p, p]) 11 | 12 | # Possible values of p for the distribution 13 | p_values = [0.1, 0.5, 0.9] 14 | # Possible outcomes for a Bernoulli distributed variable 15 | outcomes = np.array([0, 1]) 16 | 17 | # Creating the figure and the axis 18 | fig, ax = plt.subplots() 19 | # Width of each bar 20 | width = 0.2 21 | 22 | # Plotting the PMF for each value of p 23 | for i, p in enumerate(p_values): 24 | ax.bar(outcomes - width / 2 + i * width - 0.1, y(p), width=width, label=f'p = {p}') 25 | 26 | # Adding title and labels 27 | ax.set_title('Bernoulli distribution') 28 | ax.set_xlabel('Outcome') 29 | ax.set_ylabel('Probability') 30 | ax.set_xticks(outcomes) # set the ticks to be the outcome values 31 | 32 | # Adding a legend 33 | ax.legend() 34 | ax.grid() 35 | ax.margins(x=0, y=0) 36 | ymin, ymax = ax.get_ylim() 37 | ax.set_ylim(ymin, 1) 38 | 39 | plt.savefig(f"{directory}/bernoulli.{extension}") 40 | plt.close() 41 | -------------------------------------------------------------------------------- /src/distributions/geometric.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import geom 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | # Possible values of p for the distribution 8 | p_values = [0.2, 0.5, 0.8] 9 | # Possible outcomes for a Geometric distributed variable 10 | outcomes = np.arange(0, 10) 11 | 12 | # Creating the figure and the axis 13 | fig, ax = plt.subplots() 14 | width = 0.2 15 | 16 | # Plotting the PMF for each value of p 17 | for i, p in enumerate(p_values): 18 | # Specify loc=-1 correct for the difference in the definition of the geometric distribution in scipy 19 | # and the definition in the rand crate 20 | ax.bar(outcomes + i * width - width, geom.pmf(outcomes, p, loc=-1), width=width, label=f'p = {p}') 21 | 22 | # Adding title and labels 23 | ax.set_title('Geometric distribution') 24 | ax.set_xlabel('Number of failures before first success') 25 | ax.set_ylabel('Probability') 26 | ax.set_xticks(outcomes) # set the ticks to be the outcome values 27 | 28 | # Adding a legend 29 | ax.legend() 30 | ax.grid() 31 | ax.margins(x=0, y=0) 32 | ymin, ymax = ax.get_ylim() 33 | ax.set_ylim(ymin, ymax * 1.05) 34 | 35 | plt.savefig(f"{directory}/geometric.{extension}") 36 | plt.close() 37 | -------------------------------------------------------------------------------- /src/distributions/unit_sphere.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | 5 | def save_to(directory: str, extension: str): 6 | # Create a sphere 7 | def plot_sphere(radius=1, num_divisions=50): 8 | phi = np.linspace(0, np.pi, num_divisions) # polar angle 9 | theta = np.linspace(0, 2 * np.pi, num_divisions) # azimuthal angle 10 | 11 | # Meshgrid 12 | phi, theta = np.meshgrid(phi, theta) 13 | x = radius * np.sin(phi) * np.cos(theta) 14 | y = radius * np.sin(phi) * np.sin(theta) 15 | z = radius * np.cos(phi) 16 | 17 | return x, y, z 18 | 19 | # Plotting parameters 20 | radius = 1 21 | num_divisions = 50 # Increase this for a smoother sphere 22 | 23 | x, y, z = plot_sphere(radius, num_divisions) 24 | 25 | # Create a plot 26 | fig = plt.figure(figsize=(8, 6)) 27 | ax = fig.add_subplot(111, projection='3d') 28 | ax.plot_wireframe(x, y, z, color='b', alpha=0.6, rstride=1, cstride=1) 29 | 30 | # Scaling the axes 31 | ax.set_xlim([-1, 1]) 32 | ax.set_ylim([-1, 1]) 33 | ax.set_zlim([-1, 1]) 34 | ax.set_aspect('auto') 35 | ax.set_box_aspect([1, 1, 1]) 36 | 37 | # Labels and title 38 | ax.set_xlabel('X') 39 | ax.set_ylabel('Y') 40 | ax.set_zlabel('Z') 41 | ax.set_title('Unit Sphere (shell)') 42 | ax.margins(x=0, y=0) 43 | ymin, ymax = ax.get_ylim() 44 | ax.set_ylim(ymin, ymax * 1.05) 45 | 46 | # Save the figure 47 | plt.savefig(f"{directory}/unit_sphere.{extension}") 48 | plt.close() 49 | -------------------------------------------------------------------------------- /src/distributions/unit_ball.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from mpl_toolkits.mplot3d import Axes3D 4 | from scipy.spatial import ConvexHull 5 | 6 | 7 | def save_to(directory: str, extension: str): 8 | # Create a sphere 9 | def plot_sphere(radius=1, num_divisions=50): 10 | phi = np.linspace(0, np.pi, num_divisions) # polar angle 11 | theta = np.linspace(0, 2 * np.pi, num_divisions) # azimuthal angle 12 | 13 | # Meshgrid 14 | phi, theta = np.meshgrid(phi, theta) 15 | x = radius * np.sin(phi) * np.cos(theta) 16 | y = radius * np.sin(phi) * np.sin(theta) 17 | z = radius * np.cos(phi) 18 | 19 | return x, y, z 20 | 21 | # Plotting parameters 22 | radius = 1 23 | num_divisions = 50 # Increase this for a smoother sphere 24 | 25 | x, y, z = plot_sphere(radius, num_divisions) 26 | 27 | # Create a plot 28 | fig = plt.figure(figsize=(8, 6)) 29 | ax = fig.add_subplot(111, projection='3d') 30 | ax.plot_surface(x, y, z, color='b', rstride=1, cstride=1, alpha=0.6, edgecolor='none') 31 | 32 | # Scaling the axes 33 | ax.set_xlim([-1, 1]) 34 | ax.set_ylim([-1, 1]) 35 | ax.set_zlim([-1, 1]) 36 | ax.set_aspect('auto') 37 | ax.set_box_aspect([1, 1, 1]) 38 | 39 | # Labels and title 40 | ax.set_xlabel('X') 41 | ax.set_ylabel('Y') 42 | ax.set_zlabel('Z') 43 | ax.set_title('Unit Ball (solid)') 44 | ax.margins(x=0, y=0) 45 | ymin, ymax = ax.get_ylim() 46 | ax.set_ylim(ymin, ymax * 1.05) 47 | 48 | # Save the figure 49 | plt.savefig(f"{directory}/unit_ball.{extension}") 50 | plt.close() 51 | -------------------------------------------------------------------------------- /src/distributions/pert.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | from scipy.stats import beta 4 | 5 | 6 | def save_to(directory: str, extension: str): 7 | def y(x, min_value, mode, max_value, shape): 8 | a = 1 + shape * (mode - min_value) / (max_value - min_value) 9 | b = 1 + shape * (max_value - mode) / (max_value - min_value) 10 | return beta.pdf(x, a, b, loc=min_value, scale=max_value - min_value) 11 | 12 | inputs = [(-1, 0, 1, 4), (-1, 0, 1, 1), (-1, 0, 1, 8), (-1, 0.5, 1, 4)] 13 | # Adjusting the range of x values to be more meaningful for the PERT distribution 14 | x = np.linspace(-1, 1, 1000) # max_value in inputs is 2, hence 3 is a reasonable upper bound 15 | 16 | # Creating the figure and the axis 17 | fig, ax = plt.subplots(figsize=(10, 5)) 18 | 19 | # Plotting the PDF for each value of min_value, mode, max_value, and shape 20 | for min_value, mode, max_value, shape in inputs: 21 | ax.plot(x, y(x, min_value, mode, max_value, shape), 22 | label=f'min = {min_value}, mode = {mode}, max = {max_value}, shape = {shape}') 23 | 24 | # Adding title and labels 25 | ax.set_title('PERT Distribution') 26 | ax.set_xlabel('x') 27 | ax.set_ylabel('Probability density') 28 | 29 | # Adding a legend 30 | box = ax.get_position() 31 | ax.set_position([box.x0, box.y0, box.width * 0.6, box.height]) 32 | ax.legend(loc='upper left', bbox_to_anchor=(1, 1)) 33 | ax.grid() 34 | ax.margins(x=0, y=0) 35 | ymin, ymax = ax.get_ylim() 36 | ax.set_ylim(ymin, ymax * 1.05) 37 | 38 | plt.savefig(f"{directory}/pert.{extension}") 39 | plt.close() 40 | -------------------------------------------------------------------------------- /src/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | from distributions import ( 3 | bernoulli, 4 | beta, 5 | binomial, 6 | cauchy, 7 | chi_squared, 8 | dirichlet, 9 | exponential, 10 | exponential_exp1, 11 | fisher_f, 12 | frechet, 13 | gamma, 14 | geometric, 15 | gumbel, 16 | hypergeometric, 17 | inverse_gaussian, 18 | log_normal, 19 | normal, 20 | normal_inverse_gaussian, 21 | pareto, 22 | pert, 23 | poisson, 24 | skew_normal, 25 | standard_geometric, 26 | standard_normal, 27 | student_t, 28 | triangular, 29 | unit_ball, 30 | unit_circle, 31 | unit_disc, 32 | unit_sphere, 33 | weibull, 34 | zeta, 35 | zipf, 36 | ) 37 | 38 | if __name__ == "__main__": 39 | out = "charts" 40 | ext = "svg" 41 | if not os.path.exists(out): 42 | os.makedirs(out) 43 | for distr in ( 44 | bernoulli, 45 | beta, 46 | binomial, 47 | cauchy, 48 | chi_squared, 49 | dirichlet, 50 | exponential, 51 | exponential_exp1, 52 | fisher_f, 53 | frechet, 54 | gamma, 55 | geometric, 56 | gumbel, 57 | hypergeometric, 58 | inverse_gaussian, 59 | log_normal, 60 | normal, 61 | normal_inverse_gaussian, 62 | pareto, 63 | pert, 64 | poisson, 65 | skew_normal, 66 | standard_geometric, 67 | standard_normal, 68 | student_t, 69 | triangular, 70 | unit_ball, 71 | unit_circle, 72 | unit_disc, 73 | unit_sphere, 74 | weibull, 75 | zeta, 76 | zipf, 77 | ): 78 | distr.save_to(out, ext) 79 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | -------------------------------------------------------------------------------- /src/distributions/dirichlet.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | # 3 | # Copyright (c) 2024 Developers of the Rand project 4 | # Copyright (c) 2014 Thomas Boggs 5 | # 6 | # Permission is hereby granted, free of charge, to any 7 | # person obtaining a copy of this software and associated 8 | # documentation files (the "Software"), to deal in the 9 | # Software without restriction, including without 10 | # limitation the rights to use, copy, modify, merge, 11 | # publish, distribute, sublicense, and/or sell copies of 12 | # the Software, and to permit persons to whom the Software 13 | # is furnished to do so, subject to the following 14 | # conditions: 15 | # 16 | # The above copyright notice and this permission notice 17 | # shall be included in all copies or substantial portions 18 | # of the Software. 19 | # 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 21 | # ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 22 | # TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 23 | # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 24 | # SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 25 | # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 26 | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 27 | # IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 28 | # DEALINGS IN THE SOFTWARE. 29 | import numpy as np 30 | import matplotlib.pyplot as plt 31 | import matplotlib.tri as tri 32 | from math import gamma 33 | import ternary 34 | 35 | 36 | # Code source: https://blog.bogatron.net/blog/2014/02/02/visualizing-dirichlet-distributions/ 37 | class Dirichlet(object): 38 | def __init__(self, alpha): 39 | self._alpha = np.array(alpha) 40 | self._coef = gamma(np.sum(self._alpha)) / np.multiply.reduce([gamma(a) for a in self._alpha]) 41 | 42 | def pdf(self, x): 43 | """Returns pdf value for `x`.""" 44 | return self._coef * np.multiply.reduce([xx ** (aa - 1) for (xx, aa) in zip(x, self._alpha)]) 45 | 46 | 47 | def save_to(directory: str, _: str): 48 | extension = "png" # Hardcode png output format. SVG file size for this distribution is ~100x larger. 49 | corners = np.array([[0, 0], [1, 0], [0.5, np.sqrt(0.75)]]) 50 | AREA = 0.5 * 1 * np.sqrt(0.75) 51 | triangle = tri.Triangulation(corners[:, 0], corners[:, 1]) 52 | 53 | pairs = [corners[np.roll(range(3), -i)[1:]] for i in range(3)] 54 | tri_area = lambda xy, pair: 0.5 * np.linalg.norm(np.cross(*(pair - xy))) 55 | 56 | def xy2bc(xy, tol=1.e-4): 57 | coords = np.array([tri_area(xy, p) for p in pairs]) / AREA 58 | return np.clip(coords, tol, 1.0 - tol) 59 | 60 | def draw_pdf_contours(ax, alphas, nlevels=200, subdiv=8): 61 | refiner = tri.UniformTriRefiner(triangle) 62 | trimesh = refiner.refine_triangulation(subdiv=subdiv) 63 | pvals = [Dirichlet(alphas).pdf(xy2bc(xy)) for xy in zip(trimesh.x, trimesh.y)] 64 | 65 | contour = ax.tricontourf(trimesh, pvals, nlevels, cmap='plasma') 66 | ternary.plt.colorbar(contour, ax=ax, orientation='vertical', fraction=0.05, pad=0.05) 67 | 68 | ax.axis('equal') 69 | ax.spines['top'].set_visible(False) 70 | ax.spines['right'].set_visible(False) 71 | ax.spines['bottom'].set_visible(False) 72 | ax.spines['left'].set_visible(False) 73 | 74 | tax = ternary.TernaryAxesSubplot(ax=ax, scale=1.0) 75 | 76 | tax.boundary(linewidth=1.0) 77 | 78 | tax.ticks(axis='lbr', linewidth=1, multiple=0.2, tick_formats="%.1f", offset=0.02) 79 | 80 | fontsize = 13 81 | tax.set_title(f"α = {alphas}", fontsize=fontsize, pad=20) 82 | tax.right_axis_label("$x_3$", fontsize=fontsize, offset=0.15) 83 | tax.left_axis_label("$x_1$", fontsize=fontsize, offset=0.15) 84 | tax.bottom_axis_label("$x_2$", fontsize=fontsize) 85 | tax._redraw_labels() # Won't do this automatically because of the way we are saving the plot 86 | 87 | tax.clear_matplotlib_ticks() 88 | 89 | inputs = [ 90 | [1.5, 1.5, 1.5], 91 | [5.0, 5.0, 5.0], 92 | [1.0, 2.0, 2.0], 93 | [2.0, 4.0, 8.0] 94 | ] 95 | 96 | fig, axes = plt.subplots(2, 2, figsize=(12, 10)) 97 | for ax, alphas in zip(axes.flatten(), inputs): 98 | draw_pdf_contours(ax, alphas) 99 | 100 | # Adding the main title and colorbar 101 | ternary.plt.suptitle('Dirichlet Distribution', fontsize=16) 102 | 103 | ternary.plt.savefig(f"{directory}/dirichlet.{extension}", bbox_inches='tight', pad_inches=0.5) 104 | plt.close() 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /charts/unit_disc.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 2024-05-03T20:15:47.944594 10 | image/svg+xml 11 | 12 | 13 | Matplotlib v3.8.4, https://matplotlib.org/ 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 143 | 144 | 145 | 146 | 147 | 150 | 151 | 152 | 153 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 172 | 186 | 193 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 248 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 487 | 488 | 489 | 490 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 705 | 706 | 707 | 710 | 711 | 712 | 715 | 716 | 717 | 720 | 721 | 722 | 723 | 724 | 725 | 742 | 761 | 774 | 795 | 796 | 815 | 846 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | -------------------------------------------------------------------------------- /charts/unit_circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 2024-05-03T20:15:47.527310 10 | image/svg+xml 11 | 12 | 13 | Matplotlib v3.8.4, https://matplotlib.org/ 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 68 | 82 | 89 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 144 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 383 | 384 | 385 | 386 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 699 | 700 | 701 | 704 | 705 | 706 | 709 | 710 | 711 | 714 | 715 | 716 | 719 | 720 | 721 | 722 | 723 | 724 | 741 | 760 | 773 | 794 | 795 | 816 | 833 | 854 | 861 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | -------------------------------------------------------------------------------- /charts/exponential_exp1.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 2024-05-03T20:19:54.595598 10 | image/svg+xml 11 | 12 | 13 | Matplotlib v3.8.4, https://matplotlib.org/ 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 331 | 332 | 333 | 334 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 538 | 555 | 576 | 602 | 635 | 648 | 655 | 676 | 693 | 694 | 720 | 745 | 764 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 873 | 874 | 875 | 878 | 879 | 880 | 883 | 884 | 885 | 888 | 889 | 890 | 893 | 894 | 895 | 896 | 897 | 898 | 913 | 939 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 1001 | 1002 | 1003 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1027 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | -------------------------------------------------------------------------------- /charts/bernoulli.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 2024-06-18T12:19:41.968684 10 | image/svg+xml 11 | 12 | 13 | Matplotlib v3.8.4, https://matplotlib.org/ 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 47 | 48 | 49 | 55 | 56 | 57 | 63 | 64 | 65 | 71 | 72 | 73 | 79 | 80 | 81 | 87 | 88 | 89 | 90 | 91 | 94 | 95 | 96 | 97 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 194 | 216 | 237 | 258 | 279 | 309 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 351 | 352 | 353 | 354 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 625 | 642 | 668 | 701 | 714 | 721 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 757 | 758 | 759 | 762 | 763 | 764 | 767 | 768 | 769 | 772 | 773 | 774 | 775 | 776 | 777 | 809 | 828 | 829 | 855 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 924 | 925 | 926 | 932 | 933 | 934 | 935 | 936 | 937 | 963 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 993 | 994 | 995 | 996 | 997 | 998 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | -------------------------------------------------------------------------------- /charts/standard_normal.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 2024-05-03T20:15:46.276187 10 | image/svg+xml 11 | 12 | 13 | Matplotlib v3.8.4, https://matplotlib.org/ 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 68 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 245 | 246 | 247 | 248 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 267 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 522 | 539 | 560 | 586 | 619 | 632 | 639 | 660 | 677 | 678 | 704 | 729 | 748 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 900 | 901 | 902 | 905 | 906 | 907 | 910 | 911 | 912 | 915 | 916 | 917 | 920 | 921 | 922 | 923 | 924 | 925 | 956 | 986 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1052 | 1053 | 1054 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1091 | 1104 | 1113 | 1136 | 1137 | 1138 | 1139 | 1140 | 1141 | 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 | 1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 | 1157 | 1158 | 1159 | 1160 | --------------------------------------------------------------------------------