ynuozhang
Upload ScooBDoob code without binary caches
31d1d63
Raw History Blame Contribute Delete
2.44 kB
from __future__ import annotations
import numpy as np
from scoobdoob import _conditioning
from scoobdoob._conditioning import InfeasibleBridgeError as InfeasibleBridgeError
def doob_kernels(P, S_end, horizon, w=None):
"""Time-sliced Doob kernels {Ph[n]} for n = 0..horizon-1.
Backward recursion h[n] = P (w * h[n+1]), h[horizon] = uniform on S_end.
Doob kernel Ph[n]_ij = P_ij w_j h[n+1]_j / (P (w h[n+1]))_i.
"""
return _conditioning.build(P, w, S_end, horizon)[0]
def sample_bridge_paths(Ph, S_start, n_paths=200, seed=0):
"""Sample paths, rejecting any infeasible start rather than dropping it."""
return _conditioning.sample(Ph, S_start, n_paths, seed)
def sample_unconditional_paths(P, S_start, horizon, n_paths=200, seed=0):
"""Baseline: free MSM rollouts of length ``horizon`` from the start set."""
P = np.asarray(P, dtype=np.float64)
rng = np.random.default_rng(seed)
K = P.shape[0]
starts = np.asarray(list(S_start), dtype=int)
paths = []
for _ in range(n_paths):
i = int(rng.choice(starts))
path = [i]
for _ in range(horizon):
p = P[i]
s = p.sum()
p = p / s if s > 0 else np.full(K, 1.0 / K)
i = int(rng.choice(K, p=p))
path.append(i)
paths.append(np.asarray(path, dtype=int))
return paths
def reached(paths, S_end):
"""Boolean array: did each path's final state land in S_end?"""
end = set(int(s) for s in S_end)
return np.array([int(p[-1]) in end for p in paths], dtype=bool)
def bootstrap_ci(success_bool, n_boot=2000, alpha=0.05, seed=0):
"""Percentile bootstrap CI for the success rate of a boolean array."""
x = np.asarray(success_bool, dtype=float)
n = len(x)
rate = float(x.mean()) if n else float("nan")
if n == 0:
return rate, (float("nan"), float("nan"))
rng = np.random.default_rng(seed)
boot = x[rng.integers(0, n, size=(n_boot, n))].mean(axis=1)
lo, hi = np.percentile(boot, [100 * alpha / 2, 100 * (1 - alpha / 2)])
return rate, (float(lo), float(hi))
def success_with_ci(paths, S_end, n_boot=2000, alpha=0.05, seed=0):
"""Convenience: success rate + bootstrap CI for a set of sampled paths."""
s = reached(paths, S_end)
rate, ci = bootstrap_ci(s, n_boot=n_boot, alpha=alpha, seed=seed)
return {"rate": rate, "ci": ci, "n": len(paths), "n_success": int(s.sum())}