Show Code
import os
import sys
sys.path.append("..")
sys.path.append("../..")
import checks
import report_utils as ru
from IPython.display import display, HTML, Markdown
display(HTML(f"<div style='margin-bottom: 20px;'>{ru.nav_bar('abc')}</div>"))Does pypomp’s ABC-MCMC sample the right ABC posterior at each tolerance?
import os
import sys
sys.path.append("..")
sys.path.append("../..")
import checks
import report_utils as ru
from IPython.display import display, HTML, Markdown
display(HTML(f"<div style='margin-bottom: 20px;'>{ru.nav_bar('abc')}</div>"))Tests Pomp._abc at each tolerance in the ladder ε = 10⁶, 4, 2.5, 1.5 against the exact ABC posterior from rejection sampling (reference/run.py) and against R pomp::abc. Data: 208 weeks simulated from pomp::sir at known parameters. Free parameters beta1 and rho have a flat prior on model.PRIOR_BOX, and all others are fixed at truth. Probes: mean reports in each quarter of the year.
Verdicts use z = difference / Monte Carlo SE, with SEs from bulk ESS: PASS |z| < 3, CHECK 3 ≤ |z| < 5, FAIL |z| ≥ 5. Draws are pooled over chains after discarding the first half of each chain.
import glob
import re
import numpy as np
import pandas as pd
from plotnine import (
aes,
geom_density,
geom_line,
geom_point,
geom_vline,
ggplot,
labs,
scale_x_log10,
)
os.environ["JAX_PLATFORMS"] = "cpu"
import model
GPU = os.path.join("results", "gpu")
R_DIR = os.path.join("results", "R")
REF_DIR = os.path.join("..", "reference", "results", "gpu")
PARAMS = list(model.FREE)
OTHER = {"beta1": "rho", "rho": "beta1"}
BURN_FRAC = 0.5
PRIOR_EPS = max(model.ABC_EPS_LADDER)
truth = model.true_theta()
sweeps = {}
for path in sorted(glob.glob(os.path.join(GPU, "eps*"))):
m = re.search(r"eps([0-9.e+-]+)$", path)
tr = ru.load_mcmc_traces(os.path.join(path, "traces.csv.gz"), "pypomp")
if m and tr is not None:
sweeps[float(m.group(1))] = {
"traces": tr,
"post": ru.drop_burnin(tr, BURN_FRAC),
"acceptance": ru.read_if_exists(os.path.join(path, "acceptance.csv")),
"meta": ru.load_json(os.path.join(path, "latest.json")),
}
r_traces = ru.load_mcmc_traces(os.path.join(R_DIR, "traces.csv.gz"), "R pomp")
r_meta = ru.load_json(os.path.join(R_DIR, "latest.json"))
r_acc = ru.read_if_exists(os.path.join(R_DIR, "acceptance.csv"))
r_sweeps = {}
if r_traces is not None:
for eps, tr in r_traces.groupby("epsilon"):
r_sweeps[float(eps)] = {"traces": tr, "post": ru.drop_burnin(tr, BURN_FRAC)}
rejection = ru.read_if_exists(os.path.join(REF_DIR, "abc_rejection.csv.gz"))
ref_meta = ru.load_json(os.path.join(REF_DIR, "latest.json"))
ref_cfg = ref_meta.get("run_config", {}) if ref_meta else {}
grid = ru.read_if_exists(os.path.join(REF_DIR, "grid_posterior.csv"))
have_py = len(sweeps) > 0
have_r = len(r_sweeps) > 0
have_ref = rejection is not Nonescorecard = []
def ref_moments(eps):
if eps > ref_cfg.get("EPS_KEEP", np.inf):
return {p: ru.uniform_moments(*model.PRIOR_BOX[p]) for p in PARAMS}
acc = rejection[rejection["distance"] < eps**2]
return {p: ru.iid_moments(acc[p]) for p in PARAMS}
def comparison(a, b, la, lb):
return pd.DataFrame([r for p in PARAMS for r in ru.compare(a[p], b[p], p, la, lb)])
def score(frames, check, question):
df = pd.concat(frames, ignore_index=True)
worst = ru.worst_row(df, "z")
if worst is None:
detail = "no standard errors (run level too low)"
else:
eps_txt = f" at ε={worst['epsilon']:g}" if "epsilon" in df.columns else ""
detail = f"largest gap: {worst['statistic']} {worst['parameter']}{eps_txt}, {worst['z']:+.1f} SE"
scorecard.append({
"check": check, "question": question,
"verdict": ru.worst_verdict(df["verdict"]), "detail": detail,
})
py_probes = ru.read_if_exists(os.path.join(GPU, "probe_values.csv"))
r_probes = ru.read_if_exists(os.path.join(R_DIR, "probe_values.csv"))
probe_cmp = None
if py_probes is not None and r_probes is not None:
probe_cmp = py_probes.merge(r_probes, on="probe", suffixes=(" pypomp", " R"))
probe_cmp["relative difference"] = (
(probe_cmp["value pypomp"] - probe_cmp["value R"]).abs() / probe_cmp["value R"].abs()
)
worst = probe_cmp["relative difference"].max()
scorecard.append({
"check": "1. Same probes",
"question": "Do pypomp and R compute the same summary statistics on the data?",
"verdict": "PASS" if worst < 1e-6 else "FAIL",
"detail": f"largest relative difference {worst:.1e}",
})
py_m = {e: {p: ru.mcmc_moments(s["post"], p) for p in PARAMS} for e, s in sweeps.items()}
r_m = {e: {p: ru.mcmc_moments(s["post"], p) for p in PARAMS} for e, s in r_sweeps.items()}
vs_ref = {}
if have_py and have_ref:
for eps in sorted(sweeps, reverse=True):
vs_ref[eps] = comparison(py_m[eps], ref_moments(eps), "pypomp", "exact").assign(epsilon=eps)
tight = [vs_ref[e] for e in vs_ref if e != PRIOR_EPS]
if tight:
score(tight, "2. Right ABC posterior",
"At each finite ε, does pypomp match rejection sampling?")
vs_R = {}
for eps in sorted(set(sweeps) & set(r_sweeps), reverse=True):
vs_R[eps] = comparison(py_m[eps], r_m[eps], "pypomp", "R pomp").assign(epsilon=eps)
if vs_R:
score(list(vs_R.values()), "3. Agrees with R", "At each ε, does pypomp match R pomp's abc?")
prior_cmp = None
if PRIOR_EPS in sweeps:
prior_cmp = comparison(
py_m[PRIOR_EPS], {p: ru.uniform_moments(*model.PRIOR_BOX[p]) for p in PARAMS},
"pypomp", "prior"
).assign(epsilon=PRIOR_EPS)
score([prior_cmp], "4. Huge ε gives the prior",
f"At ε={PRIOR_EPS:g}, where every move is accepted, is the answer the flat prior?")
stuck_rows = []
for label, acc in [("pypomp", s["acceptance"].assign(epsilon=e)) for e, s in sweeps.items()
if s["acceptance"] is not None] + ([("R pomp", r_acc)] if r_acc is not None else []):
for eps, g in acc.groupby("epsilon"):
stuck_rows.append({"source": label, "epsilon": float(eps), "chains": len(g),
"mean acceptance": g["acceptance_rate"].mean(),
"chains that never moved": int((g["acceptance_rate"] == 0).sum())})
stuck = pd.DataFrame(stuck_rows)
if len(stuck):
stuck = stuck.sort_values(["source", "epsilon"], ascending=[True, False])
frac = stuck["chains that never moved"].sum() / stuck["chains"].sum()
scorecard.append({
"check": "5. No stuck chains",
"question": "Did every chain accept at least one move at every ε?",
"verdict": "PASS" if frac == 0 else ("CHECK" if frac < 0.01 else "FAIL"),
"detail": f"{int(stuck['chains that never moved'].sum())} of {int(stuck['chains'].sum())} chain-runs never moved",
})
conv_rows = []
for label, arms in (("pypomp", sweeps), ("R pomp", r_sweeps)):
for eps, s in sorted(arms.items(), reverse=True):
for p in PARAMS:
arr = ru.chains_array(s["post"], p)
conv_rows.append({"source": label, "epsilon": eps, "parameter": p,
"chains": arr.shape[0], "draws per chain": arr.shape[1],
"split R-hat": ru.split_rhat(arr), "bulk ESS": ru.bulk_ess(arr)})
conv = pd.DataFrame(conv_rows)
row = ru.ess_check(conv, "6. Enough draws")
if row:
scorecard.append(row)for label, ok, path in (
("pypomp ABC runs", have_py, os.path.join(GPU, "eps*")),
("R pomp traces", have_r, R_DIR),
("Rejection reference", have_ref, os.path.join(REF_DIR, "abc_rejection.csv.gz")),
):
if not ok:
display(HTML(ru.missing_note(label, path)))
if scorecard:
display(HTML(ru.scorecard_html(scorecard)))
py_meta = sweeps[min(sweeps)]["meta"] if have_py else {}
checks.save(
[{"check": r["check"], "compared": r["question"], "result": r["detail"], "verdict": r["verdict"]}
for r in scorecard],
(py_meta.get("run_config") or {}).get("RUN_LEVEL"),
pypomp_version=py_meta.get("pypomp_version"),
)| check | question | verdict | detail |
|---|---|---|---|
| 1. Same probes | Do pypomp and R compute the same summary statistics on the data? | PASS | largest relative difference 3.6e-08 |
| 2. Right ABC posterior | At each finite ε, does pypomp match rejection sampling? | PASS | largest gap: mean beta1 at ε=4, +1.2 SE |
| 3. Agrees with R | At each ε, does pypomp match R pomp's abc? | PASS | largest gap: mean rho at ε=2.5, -2.2 SE |
| 4. Huge ε gives the prior | At ε=1e+06, where every move is accepted, is the answer the flat prior? | PASS | largest gap: sd beta1 at ε=1e+06, +0.6 SE |
| 5. No stuck chains | Did every chain accept at least one move at every ε? | PASS | 0 of 4240 chain-runs never moved |
| 6. Enough draws | Does every run have at least 400 effective independent draws? | PASS | smallest bulk ESS 4,870 (R pomp, ε=1.5, beta1); split R-hat up to 1.136, see diagnostics |
pomp curves of the same color should coincide.The ladder runs loosest first. ε = 10⁶ starts from the prior. Each tighter ε starts from points drawn from the previous run whose single simulation already falls within the new ε (ABC-SMC selection), so chains do not start where they can never move.
Probes from model.py and model.R on the data must agree to 1e-6 relative error.
if probe_cmp is not None:
display(HTML(ru.table_html(probe_cmp, fmt="%.6g")))
else:
display(Markdown("_Needs both run.py and run.R results._"))| probe | value pypomp | value R | relative difference |
|---|---|---|---|
| qtr1 | 352.5 | 352.5 | 0 |
| qtr2 | 700.981 | 700.981 | 6.69778e-09 |
| qtr3 | 542.519 | 542.519 | 8.65409e-09 |
| qtr4 | 194.846 | 194.846 | 3.6144e-08 |
pypomp vs rejection sampling at each finite ε.
if have_py and have_ref:
eps_finite = [e for e in sorted(sweeps, reverse=True) if e != PRIOR_EPS]
for param in PARAMS:
frames = []
for eps in eps_finite:
frames.append(ru.thin_for_plot(sweeps[eps]["post"][[param]]).assign(
epsilon=f"{eps:g}", source="pypomp ABC-MCMC"))
acc = rejection[rejection["distance"] < eps**2]
frames.append(ru.thin_for_plot(acc[[param]]).assign(
epsilon=f"{eps:g}", source="exact (rejection)"))
stacked = pd.concat(frames)
display(
ggplot(stacked, aes(x=param, color="epsilon", linetype="source"))
+ geom_density(size=0.9)
+ geom_vline(xintercept=truth[param], color=ru.color_palette["truth"], linetype="dotted")
+ labs(title=f"ABC-MCMC against the exact ABC posterior: {param}",
subtitle="Solid and dashed curves of the same color should coincide")
+ ru.theme_premium
)
display(HTML(ru.table_html(pd.concat([vs_ref[e] for e in eps_finite], ignore_index=True))))| parameter | statistic | pypomp | exact | difference | SE | z | verdict | epsilon |
|---|---|---|---|---|---|---|---|---|
| beta1 | mean | 394.8691 | 394.6441 | 0.2250 | 0.1918 | 1.1728 | PASS | 4.0000 |
| beta1 | sd | 35.7421 | 35.7578 | -0.0157 | 0.1357 | -0.1160 | PASS | 4.0000 |
| rho | mean | 0.6242 | 0.6243 | -0.0000 | 0.0003 | -0.1484 | PASS | 4.0000 |
| rho | sd | 0.0571 | 0.0569 | 0.0002 | 0.0002 | 0.8638 | PASS | 4.0000 |
| beta1 | mean | 393.2944 | 393.1643 | 0.1302 | 0.2056 | 0.6331 | PASS | 2.5000 |
| beta1 | sd | 27.3432 | 27.1981 | 0.1452 | 0.1454 | 0.9986 | PASS | 2.5000 |
| rho | mean | 0.6276 | 0.6280 | -0.0003 | 0.0003 | -1.0392 | PASS | 2.5000 |
| rho | sd | 0.0406 | 0.0404 | 0.0002 | 0.0002 | 0.8493 | PASS | 2.5000 |
| beta1 | mean | 392.3623 | 392.1115 | 0.2509 | 0.3254 | 0.7710 | PASS | 1.5000 |
| beta1 | sd | 23.1945 | 23.2883 | -0.0938 | 0.2301 | -0.4076 | PASS | 1.5000 |
| rho | mean | 0.6305 | 0.6303 | 0.0002 | 0.0004 | 0.4367 | PASS | 1.5000 |
| rho | sd | 0.0323 | 0.0322 | 0.0001 | 0.0003 | 0.2929 | PASS | 1.5000 |
pypomp vs R pomp::abc with the same probes, scales, tolerances, prior and data. pomp’s random walk is on the natural scale, and pypomp’s is on log and logit scales, so acceptance rates are not comparable. The posteriors should match.
if vs_R:
eps_shared = [e for e in vs_R if e != PRIOR_EPS]
for param in PARAMS:
frames = []
for eps in eps_shared:
frames.append(ru.thin_for_plot(sweeps[eps]["post"][[param]]).assign(epsilon=f"{eps:g}", source="pypomp"))
frames.append(ru.thin_for_plot(r_sweeps[eps]["post"][[param]]).assign(epsilon=f"{eps:g}", source="R pomp"))
display(
ggplot(pd.concat(frames), aes(x=param, color="epsilon", linetype="source"))
+ geom_density(size=0.9)
+ geom_vline(xintercept=truth[param], color=ru.color_palette["truth"], linetype="dotted")
+ labs(title=f"pypomp against R pomp: {param}",
subtitle="Solid and dashed curves of the same color should coincide")
+ ru.theme_premium
)
display(HTML(ru.table_html(pd.concat(list(vs_R.values()), ignore_index=True))))
else:
display(Markdown("_Needs both run.py and run.R results._"))| parameter | statistic | pypomp | R pomp | difference | SE | z | verdict | epsilon |
|---|---|---|---|---|---|---|---|---|
| beta1 | mean | 399.9755 | 399.5035 | 0.4720 | 0.5819 | 0.8111 | PASS | 1000000.0000 |
| beta1 | sd | 57.9278 | 57.6501 | 0.2776 | 0.4115 | 0.6747 | PASS | 1000000.0000 |
| rho | mean | 0.6252 | 0.6253 | -0.0001 | 0.0013 | -0.0403 | PASS | 1000000.0000 |
| rho | sd | 0.1007 | 0.1009 | -0.0001 | 0.0009 | -0.1492 | PASS | 1000000.0000 |
| beta1 | mean | 394.8691 | 394.8728 | -0.0037 | 0.3173 | -0.0116 | PASS | 4.0000 |
| beta1 | sd | 35.7421 | 35.8644 | -0.1223 | 0.2243 | -0.5452 | PASS | 4.0000 |
| rho | mean | 0.6242 | 0.6244 | -0.0002 | 0.0005 | -0.3061 | PASS | 4.0000 |
| rho | sd | 0.0571 | 0.0573 | -0.0002 | 0.0004 | -0.6023 | PASS | 4.0000 |
| beta1 | mean | 393.2944 | 392.7693 | 0.5251 | 0.2993 | 1.7544 | PASS | 2.5000 |
| beta1 | sd | 27.3432 | 26.8933 | 0.4500 | 0.2116 | 2.1260 | PASS | 2.5000 |
| rho | mean | 0.6276 | 0.6286 | -0.0010 | 0.0005 | -2.1996 | PASS | 2.5000 |
| rho | sd | 0.0406 | 0.0404 | 0.0002 | 0.0003 | 0.6589 | PASS | 2.5000 |
| beta1 | mean | 392.3623 | 392.1509 | 0.2114 | 0.4580 | 0.4616 | PASS | 1.5000 |
| beta1 | sd | 23.1945 | 22.7306 | 0.4639 | 0.3238 | 1.4325 | PASS | 1.5000 |
| rho | mean | 0.6305 | 0.6306 | -0.0002 | 0.0006 | -0.3058 | PASS | 1.5000 |
| rho | sd | 0.0323 | 0.0320 | 0.0003 | 0.0004 | 0.8024 | PASS | 1.5000 |
At ε = 10⁶, every move is accepted, so draws must be uniform on the prior box.
if prior_cmp is not None:
display(HTML(ru.table_html(prior_cmp)))| parameter | statistic | pypomp | prior | difference | SE | z | verdict | epsilon |
|---|---|---|---|---|---|---|---|---|
| beta1 | mean | 399.9755 | 400.0000 | -0.0245 | 0.4293 | -0.0570 | PASS | 1000000.0000 |
| beta1 | sd | 57.9278 | 57.7350 | 0.1927 | 0.3036 | 0.6349 | PASS | 1000000.0000 |
| rho | mean | 0.6252 | 0.6250 | 0.0002 | 0.0010 | 0.1935 | PASS | 1000000.0000 |
| rho | sd | 0.1007 | 0.1010 | -0.0003 | 0.0007 | -0.3907 | PASS | 1000000.0000 |
Acceptance and posterior sd by ε. The last row is the full posterior from the grid. Not scored.
if have_py:
rows = []
for eps, s in sorted(sweeps.items(), reverse=True):
acc = s["acceptance"]
row = {"epsilon": eps,
"acceptance (pypomp)": acc["acceptance_rate"].mean() if acc is not None else np.nan}
for p in PARAMS:
row[f"sd {p} (pypomp)"] = py_m[eps][p]["sd"]
if have_ref:
row[f"sd {p} (exact)"] = ref_moments(eps)[p]["sd"]
rows.append(row)
if grid is not None:
row = {"epsilon": 0.0}
for p in PARAMS:
row[f"sd {p} (exact)"] = ru.grid_moments(grid, p, OTHER[p])["sd"]
rows.append(row)
width = pd.DataFrame(rows)
shown = width.copy()
shown["epsilon"] = shown["epsilon"].map(lambda e: "full posterior (grid)" if e == 0 else f"{e:g}")
display(HTML(ru.table_html(shown, fmt="%.4g")))
finite = width[(width["epsilon"] > 0) & (width["epsilon"] < PRIOR_EPS)]
if len(finite) > 1:
display(
ggplot(finite, aes(x="epsilon", y="acceptance (pypomp)"))
+ geom_line(color=ru.color_palette["pypomp"], size=1)
+ geom_point(color=ru.color_palette["pypomp"], size=2)
+ scale_x_log10()
+ labs(title="ABC-MCMC acceptance rate against tolerance",
subtitle="Tighter tolerance: sharper answer, more rejected moves",
x="epsilon (log scale)", y="acceptance rate")
+ ru.theme_premium
)| epsilon | acceptance (pypomp) | sd beta1 (pypomp) | sd beta1 (exact) | sd rho (pypomp) | sd rho (exact) |
|---|---|---|---|---|---|
| 1e+06 | 0.8156 | 57.93 | 57.74 | 0.1007 | 0.101 |
| 4 | 0.4988 | 35.74 | 35.76 | 0.05711 | 0.05691 |
| 2.5 | 0.2422 | 27.34 | 27.2 | 0.04059 | 0.0404 |
| 1.5 | 0.06201 | 23.19 | 23.29 | 0.03231 | 0.03221 |
| full posterior (grid) | — | — | 9.885 | — | 0.01938 |
The first table counts chains that never accepted a move. The second requires bulk ESS ≥ 400 per run. Split R-hat is for information only.
if len(stuck):
display(HTML(ru.table_html(stuck, fmt="%.3g")))| source | epsilon | chains | mean acceptance | chains that never moved |
|---|---|---|---|---|
| R pomp | 1e+06 | 36 | 0.83 | 0 |
| R pomp | 4 | 36 | 0.508 | 0 |
| R pomp | 2.5 | 36 | 0.245 | 0 |
| R pomp | 1.5 | 36 | 0.062 | 0 |
| pypomp | 1e+06 | 1024 | 0.816 | 0 |
| pypomp | 4 | 1024 | 0.499 | 0 |
| pypomp | 2.5 | 1024 | 0.242 | 0 |
| pypomp | 1.5 | 1024 | 0.062 | 0 |
if len(conv):
display(HTML(ru.table_html(conv, fmt="%.3f")))| source | epsilon | parameter | chains | draws per chain | split R-hat | bulk ESS |
|---|---|---|---|---|---|---|
| pypomp | 1000000.000 | beta1 | 1024 | 50 | 1.047 | 18208.815 |
| pypomp | 1000000.000 | rho | 1024 | 50 | 1.079 | 9332.644 |
| pypomp | 4.000 | beta1 | 1024 | 100 | 1.023 | 34991.358 |
| pypomp | 4.000 | rho | 1024 | 100 | 1.028 | 30288.307 |
| pypomp | 2.500 | beta1 | 1024 | 100 | 1.042 | 17939.306 |
| pypomp | 2.500 | rho | 1024 | 100 | 1.041 | 17132.963 |
| pypomp | 1.500 | beta1 | 1024 | 100 | 1.136 | 5189.937 |
| pypomp | 1.500 | rho | 1024 | 100 | 1.130 | 5361.259 |
| R pomp | 1000000.000 | beta1 | 36 | 1000 | 1.001 | 21538.410 |
| R pomp | 1000000.000 | rho | 36 | 1000 | 1.001 | 16905.574 |
| R pomp | 4.000 | beta1 | 36 | 1000 | 1.000 | 20054.242 |
| R pomp | 4.000 | rho | 36 | 1000 | 1.001 | 19333.220 |
| R pomp | 2.500 | beta1 | 36 | 1000 | 1.001 | 15094.724 |
| R pomp | 2.500 | rho | 36 | 1000 | 1.001 | 14331.295 |
| R pomp | 1.500 | beta1 | 36 | 1000 | 1.006 | 4869.868 |
| R pomp | 1.500 | rho | 36 | 1000 | 1.004 | 5844.363 |
if have_py:
eps = min(sweeps)
tr = sweeps[eps]["traces"]
shown = tr[tr["chain"] < 16]
for param in PARAMS:
display(
ggplot(shown, aes(x="iter", y=param, group="chain", color="factor(chain)"))
+ geom_line(alpha=0.7, size=0.4)
+ geom_vline(xintercept=tr["iter"].max() * BURN_FRAC, linetype="dotted", color="#7f8c8d")
+ labs(title=f"First 16 chains at ε={eps:g}: {param}",
subtitle="Left of the dotted line is discarded as burn-in",
x="iteration", color="chain")
+ ru.theme_premium
)if have_py:
display(Markdown("**pypomp run**\n\n" + ru.format_metadata(py_meta)))
if have_r:
display(Markdown("**R pomp run**\n\n" + ru.format_r_metadata(r_meta)))
if ref_meta:
display(Markdown("**Rejection reference run**\n\n" + ru.format_metadata(ref_meta)))pypomp run
c6ac80ca36kind=abc, model=sir, RUN_LEVEL=4, USE_CPU=False, MAIN_SEED=3141593, NCHAINS=1024, M=2000, epsilon=1.5, rung=3, probes=[‘qtr1’, ‘qtr2’, ‘qtr3’, ‘qtr4’], probe_scale={‘qtr1’: 25.4946033314898, ‘qtr2’: 42.5390499244671, ‘qtr3’: 42.4112568674804, ‘qtr4’: 24.9736557636163}, free_params=[‘beta1’, ‘rho’], rw_sd_estimation_scale={‘beta1’: 0.06, ‘rho’: 0.15}, prior_box={‘beta1’: [300.0, 500.0], ‘rho’: [0.45, 0.8]}, execution_time=357.2224667072296, platform=gpu, trace_thin=10R pomp run
f4bad06939kind=abc, model=sir, RUN_LEVEL=4, NCHAINS=36, Nabc=40000, epsilon_ladder=[1000000, 4, 2.5, 1.5], trace_thin=20, probes=[‘qtr1’, ‘qtr2’, ‘qtr3’, ‘qtr4’], probe_scale={‘qtr1’: 25.4946, ‘qtr2’: 42.539, ‘qtr3’: 42.4113, ‘qtr4’: 24.9737}, free_params=[‘beta1’, ‘rho’], rw_sd_natural_scale={‘beta1’: 24, ‘rho’: 0.036}, execution_time=572.717Rejection reference run
c6ac80ca36kind=reference, model=sir, RUN_LEVEL=4, USE_CPU=False, MAIN_SEED=3141593, GRID_N=60, NP_REF=5000, NREPS_REF=3, CHUNK=200, N_REJ=20000000, EPS_KEEP=4.0, free_params=[‘beta1’, ‘rho’], prior_box={‘beta1’: [300.0, 500.0], ‘rho’: [0.45, 0.8]}, grid_time=145.90228652954102, rejection_time=75.43277430534363, execution_time=221.33506083488464, platform=gpu