From 6c53d2e74aa8ca5621070901d35d2eb2a6782833 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 18 Oct 2026 12:33:07 +0000 Subject: [PATCH] test: fix flat uniform DDF masking and clarify harness labels Simulation.get_ddf() is flat (9*ny*nx); view it as (Q, cells) before applying the fluid mask, with a flat-DDF regression. Label A/E as runner-like force-read workloads (values discarded, no aggregation or validation; no macro/probe/CSV cost; not benchmark throughput) and split status lines into CONSTRUCTED and WARM_READY. Test/doc only. Co-Authored-By: Claude Opus 5.5 --- docs/validation/refined_dfg_timing.md | 11 ++++++--- tests/unit/test_time_refined_dfg.py | 16 +++++++++++++- tests/validation/time_refined_dfg.py | 32 +++++++++++++++++++++------ 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/docs/validation/refined_dfg_timing.md b/docs/validation/refined_dfg_timing.md index a052e3b..b424750 100644 --- a/docs/validation/refined_dfg_timing.md +++ b/docs/validation/refined_dfg_timing.md @@ -4,14 +4,19 @@ `run_refined_dfg.py` (same configuration, geometry and initial state functions). No numerical, physics-gate or production change; no force or accuracy result is produced. -| Variant | Loop | Force history | +| Variant | Loop | Force reads | |---|---|---| -| A | refined `step(1)` + `read_raw_exchange` per base step (as the runner) | valid | +| A | refined `step(1)` + `read_raw_exchange` per base step | runner-like force-read workload (values discarded) | | B | refined `step(1)` only, no host reads (`observe_raw_exchange` stays on) | timing-only | | C | refined single `step(N)` | timing-only; ledger keeps the final base interval only | -| E | uniform `sim.run(<=100)` + `read_force` (as the runner) | valid | +| E | uniform `sim.run(<=100)` + `read_force` | runner-like force-read workload (values discarded) | | E' | uniform single `sim.run(2N)` | timing-only; at most a whole-window average, different summation order | +- No variant retains a valid force history; A/E omit the runner's interval aggregation and + validation, and no variant includes macro/probe/CSV costs. Results are not full benchmark + throughput. +- Status lines: `CONSTRUCTED` (construction/JIT complete) and `WARM_READY` (first warm-up and + health check passed) per case. - Equal simulated duration: N refined base steps vs 2N uniform D80 steps. - Every repeat starts from the same fresh state (refined `initialize`, uniform `snapshot/restore`) and the same warm-up; construction/JIT, warm-up, downloads and parity checks are untimed. diff --git a/tests/unit/test_time_refined_dfg.py b/tests/unit/test_time_refined_dfg.py index 126b152..5227aac 100644 --- a/tests/unit/test_time_refined_dfg.py +++ b/tests/unit/test_time_refined_dfg.py @@ -24,7 +24,9 @@ class TimingHarnessContract(unittest.TestCase): self.assertFalse(t.VARIANTS[name]["force_history_valid"]) self.assertTrue(t.VARIANTS[name]["timing_only"]) for name in ("A", "E"): - self.assertTrue(t.VARIANTS[name]["force_history_valid"]) + self.assertFalse(t.VARIANTS[name]["force_history_valid"]) # reads discarded + self.assertTrue(t.VARIANTS[name]["force_reads"]) + self.assertIn("runner-like", t.VARIANTS[name]["force_note"]) self.assertEqual({v["case"] for v in t.VARIANTS.values()}, {"refined", "uniform"}) self.assertIn("final base interval", t.VARIANTS["C"]["force_note"]) self.assertIn("whole-window", t.VARIANTS["E'"]["force_note"]) @@ -47,6 +49,18 @@ class TimingHarnessContract(unittest.TestCase): self.assertIn("infinite", t.same_state([inf], [inf.copy()])) # matching inf still fails self.assertIn("infinite", t.same_state([a], [inf])) + def test_flat_uniform_ddf(self): + fluid = np.array([[True, False, True], [True, True, False]]) + flat = np.ones(9 * fluid.size, np.float32) # Simulation.get_ddf() layout + self.assertTrue(t.uniform_populations_finite(flat, fluid)) + flat[1 * fluid.size + 1] = np.nan # q=1, solid cell 1: ignored + self.assertTrue(t.uniform_populations_finite(flat, fluid)) + flat[4 * fluid.size + 0] = np.nan # q=4, fluid cell 0: detected + self.assertFalse(t.uniform_populations_finite(flat, fluid)) + self.assertTrue(t.uniform_populations_finite(np.ones((9,) + fluid.shape), fluid)) + with self.assertRaises(RuntimeError): + t.uniform_populations_finite(np.ones(9 * fluid.size + 1), fluid) + def test_physical_health_limits(self): ok = (np.array([1., 1.01]), np.array([.01, .02]), np.array([0., .01])) health = t.physical_health([ok]) diff --git a/tests/validation/time_refined_dfg.py b/tests/validation/time_refined_dfg.py index 7d1a055..5dd7a8a 100644 --- a/tests/validation/time_refined_dfg.py +++ b/tests/validation/time_refined_dfg.py @@ -1,13 +1,17 @@ """Measurement-only wall timing for the matched MRT refined DFG case. No numerical edits. Variants over EQUAL simulated duration (one refined base step = two uniform D80 steps): - A refined: step(1) + read_raw_exchange per base step (as run_refined_dfg) + A refined: step(1) + read_raw_exchange per base step -- runner-like force-read workload B refined: step(1) only, no host reads -- timing-only, no force history C refined: one step(N) call -- timing-only; ledger keeps final base interval only - E uniform: sim.run(<=100) + read_force (as run_refined_dfg) + E uniform: sim.run(<=100) + read_force -- runner-like force-read workload E' uniform: one sim.run(2N) call -- timing-only; at most a whole-window force average (different summation order), no history +A/E read forces but discard them: no retained force history, no interval aggregation/validation, +and no macro/probe/CSV cost, so they are not full benchmark throughput. observe_raw_exchange stays True for A/B/C: B/C omit host reads only. +Status lines: CONSTRUCTED = backend/simulation built (JIT done); WARM_READY = first warm-up and +health check passed for that case. Parity compares A/B/C with each other and E/E' with each other, never uniform with refined. A-B and B-C are measured comparative differences, not exact causal decompositions. Each repeat starts from the same fresh initial state with the same warm-up; construction, @@ -34,12 +38,14 @@ sys.path.insert(0, str(HERE)) import run_refined_dfg as r # noqa: E402 (published runner: same setup functions) VARIANTS = { - "A": dict(case="refined", force_history_valid=True), + "A": dict(case="refined", force_history_valid=False, force_reads=True, + force_note="runner-like force-read workload; values discarded, no aggregation"), "B": dict(case="refined", force_history_valid=False, timing_only=True, force_note="no host reads"), "C": dict(case="refined", force_history_valid=False, timing_only=True, force_note="raw ledger retains only the final base interval"), - "E": dict(case="uniform", force_history_valid=True), + "E": dict(case="uniform", force_history_valid=False, force_reads=True, + force_note="runner-like force-read workload; values discarded, no aggregation"), "E'": dict(case="uniform", force_history_valid=False, timing_only=True, force_note="at most a whole-window accumulated average; different summation order"), } @@ -80,6 +86,14 @@ def same_state(reference, values): return None +def uniform_populations_finite(ddf, fluid): + """Simulation.get_ddf() may be flat (9*ny*nx); view it as (Q, cells) before masking.""" + ddf, fluid = np.asarray(ddf), np.asarray(fluid, bool).ravel() + if fluid.size == 0 or ddf.size % fluid.size: + raise RuntimeError(f"DDF size {ddf.size} incompatible with {fluid.size} cells") + return bool(np.isfinite(ddf.reshape(ddf.size // fluid.size, fluid.size)[:, fluid]).all()) + + def physical_health(fields): """fields: (rho, ux, uy) arrays already restricted to physical leaves/fluid.""" if not fields or any(not np.isfinite(v).all() or v.size == 0 for f in fields for v in f): @@ -165,13 +179,15 @@ def time_refined(a, h, sched): (pair.fine_kind == ACTIVE) & ((host.flags.reshape(pair.fine_shape) & SOLID) == 0)] fresh = (r.initial_state(pair.coarse_shape, (0.0, 0.0), 1.0, root=True), r.initial_state(pair.fine_shape, pair.fine_origin, 0.5)) - print(json.dumps(dict(status="READY", case="refined")), flush=True) + print(json.dumps(dict(status="CONSTRUCTED", case="refined")), flush=True) for repeat in range(a.repeats): for variant in ("A", "B", "C"): check_deadline(a.deadline) backend.initialize(*fresh) # resets step count; same fresh state every time refined_loop(backend, variant, warm, a.deadline) warm_health = refined_health(backend, masks) # untimed + if repeat == 0 and variant == "A": + print(json.dumps(dict(status="WARM_READY", case="refined")), flush=True) sync_refined(backend) start = time.perf_counter() refined_loop(backend, variant, n, a.deadline) @@ -212,7 +228,7 @@ def time_uniform(a, h, sched): fluid = (sim.get_flags() & FLUID) != 0 ny, nx = params["ny"], params["nx"] fluid = fluid.reshape(ny, nx) - print(json.dumps(dict(status="READY", case="uniform")), flush=True) + print(json.dumps(dict(status="CONSTRUCTED", case="uniform")), flush=True) for repeat in range(a.repeats): for variant in ("E", "E'"): check_deadline(a.deadline) @@ -221,6 +237,8 @@ def time_uniform(a, h, sched): raise RuntimeError("uniform restore parity changed between variants") uniform_loop(sim, variant, warm, a.deadline) warm_health = uniform_health(sim, fluid) # untimed + if repeat == 0 and variant == "E": + print(json.dumps(dict(status="WARM_READY", case="uniform")), flush=True) sync_uniform(sim) start = time.perf_counter() uniform_loop(sim, variant, n, a.deadline) @@ -228,7 +246,7 @@ def time_uniform(a, h, sched): seconds = time.perf_counter() - start end_health = uniform_health(sim, fluid) # untimed values = [sim.get_ddf()] - if not np.isfinite(values[0].reshape(values[0].shape[0], -1)[:, fluid.ravel()]).all(): + if not uniform_populations_finite(values[0], fluid): raise RuntimeError(f"uniform {variant} repeat {repeat}: nonfinite fluid populations") mismatch = None if repeat == 0 and variant == "E":