docs/experiments/EXP-3D-RGBD-DEPTHSPLAT-JEPA-ARKIT-OVERLAP-V1/exploratory_posthoc/gating_explore.py
"""EXPLORATORY (post hoc, in-sample, after the locked analysis of EXP-3D-RGBD-DEPTHSPLAT-JEPA-ARKIT-OVERLAP-V1): can
agreement gating make learned completion consistent on ARKit overlap queries? Learned completion lowered the mean FARH
AbsRel by ~25 % but improved only ~54 % of the scenes. Every variant falls back to the harmonic fill H3:
JO, HJO, G1N, HGN as in the locked analysis (reference)
JO_SEED<t> JO where at least two JO seeds cover and their ray depths agree ((max - min) / mean <= t)
JOG1_AGREE<t> (JO + G1N) / 2 where JO covers, G1N is confident (some seed opacity >= 0.5) and the two
agree (|JO - G1N| / mean <= t)
HJOG JO covered: (H3 + JO + G1N) / 3, else (H3 + G1N) / 2
JOG1_AVG JO covered: (JO + G1N) / 2, else G1N
Contrasts H3 - X on FARH with the V2 labels, plus the share of FARH pixels where X differs from H3. Uses only sealed
predictions (sha-checked) and the query depth already scored. In-sample: a promising variant needs a fresh test.
Run through cv_host_run.py from the repository root (CUDA hidden): python gating_explore.py ROOT
"""
import hashlib
import json
import sys
from collections import defaultdict
from pathlib import Path
import numpy as np
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "code"))
from overlap_score import ALPHA_MIN, COHORT, ds_seal, load, ray_cosine # noqa: E402
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "EXP-3D-RGBD-DEPTHSPLAT-JEPA-TTT-V1" / "code"))
from score_analyze import contrast, write # noqa: E402
SEEDS = ("JO1", "JO2", "JO3")
def sha(path):
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
def main(root):
lock = json.loads((root / "frame_role_lock.json").read_text())["cohorts"][COHORT]
records = {r["scene_id"]: r for r in json.loads(Path(lock["manifest"]).read_text())["scenes"]}
keys = [f"{e['scene_id']}/{e['role']}/{q}" for e in lock["episodes"] for q in e["queries"]]
arms = json.loads((root / f"raw/eval/{COHORT}/prediction_seal.json").read_text())
seals = {s: ds_seal(root, s, keys) for s in SEEDS}
grouped = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
for e in lock["episodes"]:
record = records[e["scene_id"]]
frames = {f["frame_id"]: f for f in record["frames"]}
for qid in e["queries"]:
key = f"{e['scene_id']}/{e['role']}/{qid}"
p = load(arms["predictions"][f"{COHORT}/{key}"])
near = p["near"].astype(bool)
if not near.any():
continue
h3 = p["REPROJ_HARMONIC"]
opac = np.array([p[f"OPACITY_G1_{s}"].astype(np.float64) for s in arms["seeds"]])
g1_conf = (opac >= 0.5).any(axis=0)
g1n = np.mean([np.where(p[f"OPACITY_G1_{s}"] >= 0.5,
p[f"G1_{s}"] / np.maximum(p[f"OPACITY_G1_{s}"].astype(np.float64), 1e-6), h3)
for s in arms["seeds"]], axis=0)
cosine = ray_cosine(record, qid)
arrays = [load(seals[s][key]) for s in SEEDS]
covers = np.array([a["CTX_alpha"].astype(np.float64) >= ALPHA_MIN for a in arrays])
ray = np.array([a["CTX_depth_z"].astype(np.float64) / np.maximum(a["CTX_alpha"].astype(np.float64), 1e-12)
for a in arrays]) / cosine
count = covers.sum(axis=0)
covered = count >= 2
jo_value = np.where(covers, ray, 0.0).sum(axis=0) / np.maximum(count, 1)
jo = np.where(covered, jo_value, h3)
hi = np.where(covers, ray, -np.inf).max(axis=0)
lo = np.where(covers, ray, np.inf).min(axis=0)
spread = np.where(covered, (hi - lo) / np.maximum(jo_value, 1e-6), np.inf)
pair = np.abs(jo - g1n) / np.maximum((jo + g1n) / 2, 1e-6)
variants = {"H3": h3, "JO": jo, "HJO": np.where(covered, (h3 + jo) / 2, h3), "G1N": g1n,
"HGN": (h3 + g1n) / 2, "HJOG": np.where(covered, (h3 + jo + g1n) / 3, (h3 + g1n) / 2),
"JOG1_AVG": np.where(covered, (jo + g1n) / 2, g1n)}
for t in (0.05, 0.10, 0.20):
variants[f"JO_SEED{t:.2f}"] = np.where(covered & (spread <= t), jo, h3)
for t in (0.10, 0.20, 0.30):
variants[f"JOG1_AGREE{t:.2f}"] = np.where(covered & g1_conf & (pair <= t), (jo + g1n) / 2, h3)
gt = np.load(frames[qid]["depth"]).squeeze().astype(np.float64)
farh = np.isfinite(gt) & (gt > 0) & ~near
if not farh.any():
continue
for name, x in variants.items():
grouped[f"{name}|FARH"][e["scene_id"]][e["role"]].append(
float(np.mean(np.abs(x[farh] - gt[farh]) / gt[farh])))
grouped[f"{name}|USED"][e["scene_id"]][e["role"]].append(float(np.mean(x[farh] != h3[farh])))
table = {n: {s: float(np.mean([np.mean(v) for v in r.values()])) for s, r in sc.items()} for n, sc in grouped.items()}
names = sorted({k.split("|")[0] for k in table} - {"H3"})
result = {}
print(f"{'variant':16s} {'FARH':>7s} {'used':>6s} H3 - X")
for name in names:
s = contrast(table, "H3|FARH", f"{name}|FARH")
result[name] = {"mean_farh": float(np.mean(list(table[f"{name}|FARH"].values()))),
"used_share": float(np.mean(list(table[f"{name}|USED"].values()))), "contrast": s}
print(f"{name:16s} {result[name]['mean_farh']:7.4f} {result[name]['used_share']:6.3f} "
f"{s['mean']:+.4f} [{s['ci95'][0]:+.4f}, {s['ci95'][1]:+.4f}] {s['positive']}/{s['tied']}/{s['negative']} "
f"median {s['median']:+.4f} {s['status']}")
print("H3 FARH", round(float(np.mean(list(table["H3|FARH"].values()))), 4), "scenes", len(table["H3|FARH"]))
write(root / "exploratory_posthoc/gating_explore.json", {"note": "exploratory, in-sample", "results": result})
if __name__ == "__main__":
main(Path(sys.argv[1]).resolve())