Hyperiso 1.0.3
Modular flavour-physics calculations, Wilson coefficients and statistical inference
Loading...
Searching...
No Matches
example_plot_marginal.py
Go to the documentation of this file.
1from __future__ import annotations
2
3import os
4from dataclasses import dataclass
5from typing import Optional, List, Tuple
6
7import numpy as np
8import matplotlib.pyplot as plt
9
10
11from pyhyperiso.core.Statistic.MarginalDistribution import (
12 DistributionFactoryWrapper as DF,
13 MarginalKind,
14 GaussianMarginalConfig,
15 SplitGaussianMarginalConfig,
16 FlatMarginalConfig,
17 LikelihoodMarginalConfig,
18)
19
20
21def make_likelihood_cfg() -> LikelihoodMarginalConfig:
22 """Likelihood synthétique (mélange de 2 gaussiennes) sur une grille."""
23 xs = np.linspace(-5.0, 5.0, 401)
24 w = np.exp(-0.5 * ((xs - (-1.2)) / 0.7) ** 2) + 0.65 * np.exp(-0.5 * (xs - 1.6) / 1.1) ** 2
25 w = w / np.sum(w)
26 return LikelihoodMarginalConfig(values=xs.tolist(), weights=w.tolist())
27
28
29@dataclass(frozen=True)
31 name: str
32 kind: MarginalKind
33 cfg: object
34
35
36def _safe_float(x) -> float:
37 try:
38 return float(x)
39 except Exception:
40 return float("nan")
41
42
43def _grid_from_ppf(dist, lo=0.001, hi=0.999, n=600) -> np.ndarray:
44 """Grille x basée sur des quantiles (robuste et adapté à la distrib)."""
45 try:
46 x_lo = _safe_float(dist.ppf(lo))
47 x_hi = _safe_float(dist.ppf(hi))
48 if not (np.isfinite(x_lo) and np.isfinite(x_hi) and x_hi > x_lo):
49 raise ValueError("bad ppf range")
50 pad = 0.08 * (x_hi - x_lo)
51 return np.linspace(x_lo - pad, x_hi + pad, n)
52 except Exception:
53 return np.linspace(-6.0, 6.0, n)
54
55
56def _pdf(dist, xs: np.ndarray) -> np.ndarray:
57 logp = np.array([_safe_float(dist.logpdf(float(x))) for x in xs], dtype=float)
58 return np.exp(logp)
59
60
61def _cdf(dist, xs: np.ndarray) -> np.ndarray:
62 return np.array([_safe_float(dist.cdf(float(x))) for x in xs], dtype=float)
63
64
65def _ecdf(samples: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
66 s = np.sort(samples)
67 y = np.arange(1, len(s) + 1) / len(s)
68 return s, y
69
70
72 name: str, dist, xs: np.ndarray, samples: np.ndarray, outpath: Optional[str] = None
73) -> None:
74 pdf = _pdf(dist, xs)
75
76 plt.figure(figsize=(10.2, 5.7))
77 plt.hist(samples, bins=60, density=True, alpha=0.35, label="samples (density)")
78 plt.plot(xs, pdf, linewidth=2.3, label="pdf = exp(logpdf)")
79
80 try:
81 q16, q50, q84 = dist.ppf(0.16), dist.ppf(0.50), dist.ppf(0.84)
82 q16, q50, q84 = float(q16), float(q50), float(q84)
83 if all(map(np.isfinite, [q16, q50, q84])) and (q84 > q16):
84 plt.axvspan(q16, q84, alpha=0.12, label="68% interval [16%,84%]")
85 plt.axvline(q50, linestyle="--", linewidth=1.8, label="median (50%)")
86 except Exception:
87 pass
88
89 try:
90 mu = float(dist.mean())
91 if np.isfinite(mu):
92 plt.axvline(mu, linestyle=":", linewidth=1.8, label="mean")
93 except Exception:
94 pass
95
96 plt.title(f"{name} — PDF vs samples")
97 plt.xlabel("x")
98 plt.ylabel("density")
99 plt.grid(True, alpha=0.28)
100 plt.minorticks_on()
101 plt.legend(frameon=True)
102 plt.tight_layout()
103
104 if outpath:
105 plt.savefig(outpath, dpi=200)
106 plt.close()
107
108
110 name: str, dist, xs: np.ndarray, samples: np.ndarray, outpath: Optional[str] = None
111) -> None:
112 cdf_th = _cdf(dist, xs)
113 s, y = _ecdf(samples)
114
115 plt.figure(figsize=(10.2, 5.7))
116 plt.plot(xs, cdf_th, linewidth=2.4, label="theoretical CDF")
117 plt.step(s, y, where="post", linewidth=1.8, alpha=0.9, label="empirical CDF (ECDF)")
118
119 for p, ls in [(0.25, "--"), (0.50, "--"), (0.75, "--")]:
120 try:
121 q = float(dist.ppf(p))
122 if np.isfinite(q):
123 plt.axvline(q, linestyle=ls, linewidth=1.2)
124 except Exception:
125 pass
126
127 plt.title(f"{name} — CDF: theoretical vs empirical")
128 plt.xlabel("x")
129 plt.ylabel("CDF(x)")
130 plt.ylim(-0.02, 1.02)
131 plt.grid(True, alpha=0.28)
132 plt.minorticks_on()
133 plt.legend(frameon=True)
134 plt.tight_layout()
135
136 if outpath:
137 plt.savefig(outpath, dpi=200)
138 plt.close()
139
140
142 specs: List[DistSpec], seed: int, outpath: Optional[str] = None
143) -> None:
144 p = np.linspace(0.001, 0.999, 500)
145
146 plt.figure(figsize=(10.4, 5.8))
147 for sp in specs:
148 dist = DF.create(sp.kind, sp.cfg, seed=seed)
149 err = []
150 for pi in p:
151 try:
152 x = float(dist.ppf(float(pi)))
153 err.append(_safe_float(dist.cdf(x)) - float(pi))
154 except Exception:
155 err.append(float("nan"))
156 err = np.array(err, dtype=float)
157 plt.plot(p, err, linewidth=2.1, label=sp.name)
158
159 plt.plot([0, 1], [0, 0], linestyle="--", linewidth=1.8, label="0 (ideal)")
160 plt.title("Sanity check — CDF(PPF(p)) − p (should be near 0)")
161 plt.xlabel("p")
162 plt.ylabel("error")
163 plt.grid(True, alpha=0.28)
164 plt.minorticks_on()
165 plt.legend(frameon=True)
166 plt.tight_layout()
167
168 if outpath:
169 plt.savefig(outpath, dpi=200)
170 plt.close()
171
172
174 show: bool = True,
175 outdir: Optional[str] = "marginal_plots",
176 seed: int = 123,
177 n_samples: int = 3500,
178) -> None:
179 specs: List[DistSpec] = [
180 DistSpec("Gaussian", MarginalKind.GAUSSIAN, GaussianMarginalConfig(mu=0.6, sigma=1.15)),
181 DistSpec(
182 "SplitGaussian",
183 MarginalKind.HALF_GAUSSIAN,
184 SplitGaussianMarginalConfig(mu=0.0, sigma_p=0.75, sigma_m=1.55),
185 ),
186 DistSpec("Flat", MarginalKind.FLAT, FlatMarginalConfig(a=-2.5, b=3.2)),
187 ]
188
189 if outdir is not None:
190 os.makedirs(outdir, exist_ok=True)
191
192 for sp in specs:
193 dist = DF.create(sp.kind, sp.cfg, seed=seed)
194
195 xs = _grid_from_ppf(dist)
196 samples = np.array(dist.rvs(n_samples), dtype=float)
197
198 pdf_path = None if outdir is None else os.path.join(outdir, f"{sp.name}_pdf_samples.png")
199 cdf_path = None if outdir is None else os.path.join(outdir, f"{sp.name}_cdf_ecdf.png")
200
201 plot_pdf_vs_samples(sp.name, dist, xs, samples, outpath=pdf_path)
202 plot_cdf_theory_vs_empirical(sp.name, dist, xs, samples, outpath=cdf_path)
203
204 global_path = None if outdir is None else os.path.join(outdir, "global_cdf_ppf_consistency.png")
205 plot_global_cdf_ppf_consistency(specs, seed=seed, outpath=global_path)
206
207 if show:
208 plt.show()
209 else:
210 plt.close("all")
211
212
213if __name__ == "__main__":
214 main(show=True, outdir="marginal_plots", seed=123, n_samples=3500)
np.ndarray _pdf(dist, np.ndarray xs)
None plot_global_cdf_ppf_consistency(List[DistSpec] specs, int seed, Optional[str] outpath=None)
np.ndarray _grid_from_ppf(dist, lo=0.001, hi=0.999, n=600)
LikelihoodMarginalConfig make_likelihood_cfg()
None plot_pdf_vs_samples(str name, dist, np.ndarray xs, np.ndarray samples, Optional[str] outpath=None)
None plot_cdf_theory_vs_empirical(str name, dist, np.ndarray xs, np.ndarray samples, Optional[str] outpath=None)
Tuple[np.ndarray, np.ndarray] _ecdf(np.ndarray samples)
np.ndarray _cdf(dist, np.ndarray xs)