Test-only opt-in. New shear_twin.py: same two L0->L1 boxes as shear_nested, no L2; leaves [7936,33792], hops [2048,4096], work 154664960. Four fresh cases U128/U256/constant R128 d2/projected R128 d2; physics is the unchanged depth-2/2N shear_wave.assess. run_case: --diagnostic twin_shear_n128 with shear_twin.py+shear_nested.py pins, no snapshot. assess_shear_wave: nested contract made preset-generic (PRESETS) with nested behaviour unchanged. Labels: twin vs nested = effect of adding this nested refinement (not abstract depth). shear_wave.py, shear_nested.py and oracle.py byte-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
337 lines
17 KiB
Python
337 lines
17 KiB
Python
"""Fixed four-case shear-wave contracts.
|
|
|
|
Default: N128 (U128, U256, constant R128, projected R128). Opt-in
|
|
--diagnostic scaled_shear_n256: N256 (U256, U512, constant R256, projected
|
|
R256), same physical rectangle, t* schedule, nu = U N / 100, eps(N), limits
|
|
and floors, plus a descriptive comparison with the hash-pinned N128 receipts.
|
|
|
|
Shared provenance, build, workload and sample-time checks are reused from
|
|
assess_projected_pairs (same cases, source pins and geometry); only the
|
|
Taylor-Green-specific checks are replaced by shear-wave metadata and physics.
|
|
"""
|
|
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import math
|
|
from pathlib import Path
|
|
|
|
import assess_projected_pairs as tg
|
|
import shear_wave as sw
|
|
import shear_nested as nested
|
|
import shear_twin as twin
|
|
from run_case import (NESTED_SHEAR, SCALED_DIAGNOSTIC, SCALED_SHEAR, SHEAR_NESTED_SHA256,
|
|
SHEAR_TWIN_SHA256, SHEAR_WAVE_SHA256, TWIN_SHEAR, sample_steps)
|
|
|
|
# Audited de5b0cc N128 receipts (evidence commit cba6bca, shear-wave-de5b0cc zip).
|
|
REFERENCE_REVISION = "de5b0cc080794d0ce44d37f845aa8e8dbf8c2016"
|
|
REFERENCE_RECEIPTS = {
|
|
"uniform128": "d4a60fb806d04bfa8098a862cceba51e00b49979a6a250fef17a5fc8e3ea3255",
|
|
"uniform256": "e0b58e734724be5f82ee5d6df84395e3181b4e96e4246dd5a574ea23a8d12386",
|
|
"constant128": "c70d7cd14b1257a01cc49f8edfcc7685d430e5301e2f2d60ed426936f8b96c51",
|
|
"projected128": "980161458b9463af09a8e3178063fea0f4bbeb465329e1d3becdb0f224537b54",
|
|
}
|
|
ROLES = ("uniform_root", "uniform_fine", "constant", "projected_linear")
|
|
|
|
SHARED = ("complete_matrix", "no_extra_cases", "no_duplicate_cases", "finite_receipts",
|
|
"same_source_and_harness", "clean_a135252_numerical_source",
|
|
"same_recorded_runtime", "same_explicit_device", "same_early_sampling")
|
|
PER_CASE = ("complete_times", "scales", "actual_builds", "reference", "runtime_source",
|
|
"patch", "workload")
|
|
|
|
|
|
METADATA_ULPS = 4
|
|
|
|
|
|
def close_ulps(recorded, expected, ulps=METADATA_ULPS):
|
|
"""Portable check for recomputed float metadata only (e.g. eps = |k|^2).
|
|
|
|
The recorded value comes from another runtime/libm, so exact equality can
|
|
fail by one ULP (observed: 0.012047856934923534 Horsea vs ...532 here).
|
|
A few ULPs is far below any meaningful change; hashes, case identity and
|
|
scientific thresholds stay exact.
|
|
"""
|
|
return (isinstance(recorded, float) and math.isfinite(recorded)
|
|
and abs(recorded - expected) <= ulps * math.ulp(max(abs(recorded), abs(expected))))
|
|
|
|
|
|
def metadata_ok(record, n):
|
|
return (record.get("flow") == "shear_wave" and record.get("mode") == list(sw.MODE)
|
|
and record.get("polarization") == sw.E.tolist()
|
|
and record.get("angle_deg") == sw.ANGLE_DEG and record.get("phase") == sw.PHI
|
|
and close_ulps(record.get("eps"), sw.eps(n))
|
|
and record.get("numerics") == tg.NUMERICS
|
|
and record.get("initialization") == sw.INITIALIZATION
|
|
and record.get("limits") == sw.LIMITS
|
|
and record.get("early_pressure") == dict(enabled=False, rows=[],
|
|
sampled_max_pressure_l2=None)
|
|
and (record.get("source") or {}).get("shear_wave_sha256") == SHEAR_WAVE_SHA256)
|
|
|
|
|
|
def cases_for(scaled):
|
|
factor = 2 if scaled else 1
|
|
return tuple((re, n * factor, depth, scheme) for re, n, depth, scheme in tg.CASES)
|
|
|
|
|
|
def assess(records, expected_revision=None, *, scaled=False):
|
|
if not isinstance(records, list) or not all(isinstance(r, dict) for r in records):
|
|
raise ValueError("records must be a list of receipt objects")
|
|
# The scaled TG assessor supplies N256/512 cases, builds and workload; its
|
|
# TG-only diagnostic identity and early-sampling checks are not used here.
|
|
base_checks = tg.assess(records, expected_revision,
|
|
diagnostic=SCALED_DIAGNOSTIC if scaled else None)["checks"]
|
|
checks = {name: base_checks.get(name, False) for name in SHARED}
|
|
checks["shear_diagnostic_identity"] = all(
|
|
r.get("diagnostic") == (SCALED_SHEAR if scaled else None) for r in records)
|
|
cases = cases_for(scaled)
|
|
indexed = {}
|
|
for r in records:
|
|
indexed.setdefault(tuple(r.get(k) for k in ("re_L", "n", "depth", "explosion")), r)
|
|
for key in cases:
|
|
_, n, depth, scheme = key
|
|
label = f"{n}/{depth}/{scheme}"
|
|
for name in PER_CASE:
|
|
checks[f"{label} {name}"] = base_checks.get(f"{label} {name}", False)
|
|
checks[f"{label} shear_metadata"] = key in indexed and metadata_ok(indexed[key], n)
|
|
contract_valid = all(checks.values())
|
|
result = dict(checks=checks, contract_valid=contract_valid,
|
|
cases=[list(k) for k in cases], expected_revision=expected_revision,
|
|
diagnostic=SCALED_SHEAR if scaled else None,
|
|
scope="2D periodic Re100 oblique (2,1) shear wave; one phase and one "
|
|
"rectangle; no placement robustness or convergence order")
|
|
if not contract_valid:
|
|
result.update(status="INVALID_SET", passed=False)
|
|
return result
|
|
try:
|
|
physics = sw.assess(indexed[cases[0]], indexed[cases[1]],
|
|
[indexed[cases[2]], indexed[cases[3]]])
|
|
except (KeyError, ValueError) as error:
|
|
result.update(status="INVALID_SET", passed=False, reason=str(error))
|
|
return result
|
|
result.update(physics=physics, status=physics["status"],
|
|
passed=physics["status"] == "PASS")
|
|
try:
|
|
result["signed"] = signed_summary([indexed[k] for k in cases])
|
|
except (KeyError, TypeError, ValueError) as error:
|
|
result["signed_unavailable"] = str(error)
|
|
return result
|
|
|
|
|
|
CASE_AGNOSTIC = ("finite_receipts", "same_source_and_harness", "clean_a135252_numerical_source",
|
|
"same_recorded_runtime", "same_explicit_device", "same_early_sampling")
|
|
|
|
|
|
# Fixed multi-box presets sharing one contract; only geometry, controls, pins differ.
|
|
PRESETS = {
|
|
NESTED_SHEAR: dict(
|
|
module=nested, physics=nested.assess, snapshot=True,
|
|
pins={"shear_nested_sha256": SHEAR_NESTED_SHA256},
|
|
finest_control="uniform 4N (U512)",
|
|
scope="2D periodic Re100 oblique (2,1) shear wave; fixed three-level/two-region "
|
|
"placement; changes placement and refined volume as well as depth, so no "
|
|
"isolated-level cost or resolution trend"),
|
|
TWIN_SHEAR: dict(
|
|
module=twin, physics=sw.assess, snapshot=False,
|
|
pins={"shear_nested_sha256": SHEAR_NESTED_SHA256,
|
|
"shear_twin_sha256": SHEAR_TWIN_SHA256},
|
|
finest_control="uniform 2N (U256)",
|
|
scope="2D periodic Re100 oblique (2,1) shear wave; depth-2 twin of the nested "
|
|
"preset (same two L0->L1 boxes, no L2). Twin vs nested is the effect of adding "
|
|
"this nested refinement; it also changes finest spacing and refined volume, so it "
|
|
"does not isolate abstract depth"),
|
|
}
|
|
|
|
|
|
def _nested_case_ok(r, n, depth, diagnostic=NESTED_SHEAR):
|
|
"""Per-case identity of a fixed multi-box preset (scales, builds, patch, work, pins)."""
|
|
preset = PRESETS[diagnostic]
|
|
geometry = preset["module"]
|
|
runtime = r.get("runtime_source", {})
|
|
package = Path(runtime.get("checkout", "")) / "src/CelerisLab"
|
|
cells = [n * n] if depth == 1 else geometry.LEAVES
|
|
hops = [16 * n * 2**level for level in range(depth)]
|
|
work = r.get("workload", {})
|
|
snapshot = r.get("final_snapshot")
|
|
expected_patch = [] if depth == 1 else geometry.REFINEMENTS
|
|
return {
|
|
"complete_times": r.get("completed") is True and tg.at_steps(
|
|
r.get("rows", []), sample_steps(n)[0], n),
|
|
"scales": (r.get("U") == sw.U and tg.finite(r.get("viscosity"))
|
|
and abs(r["viscosity"] - sw.U * n / 100) < 1e-15
|
|
and r.get("tau_by_level") == [0.5 + 3 * sw.U * n / 100 * 2**l
|
|
for l in range(depth)]
|
|
and r.get("mach") == sw.U * math.sqrt(3)),
|
|
"actual_builds": tg.valid_builds(r, n, depth),
|
|
"reference": (r.get("numerical_revision") == tg.NUMERICAL_REVISION
|
|
and r.get("reference_harness") == tg.REFERENCE_HARNESS),
|
|
"runtime_source": bool(runtime.get("checkout")) and all(
|
|
runtime.get(k) == str(package / tail) for k, tail in
|
|
(("module", "__init__.py"), ("compiler", "cuda/compiler_v2.py"),
|
|
("kernel_root", "lbm/kernels"))),
|
|
"patch": json.dumps(r.get("refinements")) == json.dumps(expected_patch),
|
|
"workload": (work.get("active_cells_by_level") == cells and work.get("level_hops") == hops
|
|
and work.get("root_intervals") == 16 * n
|
|
and work.get("active_collision_updates_by_level") == [
|
|
c * h for c, h in zip(cells, hops)]
|
|
and work.get("active_collision_updates") == sum(
|
|
c * h for c, h in zip(cells, hops))),
|
|
"shear_metadata": metadata_ok(r, n),
|
|
"nested_module_pin": all((r.get("source") or {}).get(key) == pin
|
|
for key, pin in preset["pins"].items()),
|
|
# Optional, nested projected depth-3 only; bounded and hashed when present.
|
|
"snapshot": snapshot is None or (
|
|
preset["snapshot"] and depth == nested.DEPTH and r.get("explosion") == "projected_linear"
|
|
and snapshot.get("kept") is True and isinstance(snapshot.get("sha256"), str)
|
|
and len(snapshot["sha256"]) == 64
|
|
and 0 < snapshot.get("bytes", 0) <= nested.SNAPSHOT_MAX_BYTES
|
|
and snapshot.get("leaf_counts") == nested.LEAVES
|
|
and snapshot.get("step") == sample_steps(n)[0][-1]),
|
|
}
|
|
|
|
|
|
def assess_nested(records, expected_revision=None, diagnostic=NESTED_SHEAR):
|
|
"""Fixed four-case preset contract: nested_shear_n128 (U128, U512, constant/projected
|
|
R128 depth 3) or twin_shear_n128 (U128, U256, constant/projected R128 depth 2)."""
|
|
preset = PRESETS[diagnostic]
|
|
geometry = preset["module"]
|
|
if not isinstance(records, list) or not all(isinstance(r, dict) for r in records):
|
|
raise ValueError("records must be a list of receipt objects")
|
|
base_checks = tg.assess(records, expected_revision)["checks"]
|
|
checks = {name: base_checks.get(name, False) for name in CASE_AGNOSTIC}
|
|
indexed, duplicates = {}, []
|
|
for r in records:
|
|
key = tuple(r.get(k) for k in ("re_L", "n", "depth", "explosion"))
|
|
(duplicates.append(key) if key in indexed else indexed.__setitem__(key, r))
|
|
checks.update(complete_matrix=all(k in indexed for k in geometry.CASES),
|
|
no_extra_cases=set(indexed) <= set(geometry.CASES),
|
|
no_duplicate_cases=not duplicates,
|
|
shear_diagnostic_identity=all(r.get("diagnostic") == diagnostic
|
|
for r in records))
|
|
for key in geometry.CASES:
|
|
_, n, depth, scheme = key
|
|
label = f"{n}/{depth}/{scheme}"
|
|
case = _nested_case_ok(indexed[key], n, depth, diagnostic) if key in indexed else {}
|
|
for name in ("complete_times", "scales", "actual_builds", "reference", "runtime_source",
|
|
"patch", "workload", "shear_metadata", "nested_module_pin", "snapshot"):
|
|
checks[f"{label} {name}"] = bool(case.get(name, False))
|
|
contract_valid = all(checks.values())
|
|
result = dict(checks=checks, contract_valid=contract_valid, diagnostic=diagnostic,
|
|
cases=[list(k) for k in geometry.CASES], expected_revision=expected_revision,
|
|
finest_control=preset["finest_control"], scope=preset["scope"])
|
|
if not contract_valid:
|
|
result.update(status="INVALID_SET", passed=False)
|
|
return result
|
|
try:
|
|
cases = geometry.CASES
|
|
physics = preset["physics"](indexed[cases[0]], indexed[cases[1]],
|
|
[indexed[cases[2]], indexed[cases[3]]])
|
|
except (KeyError, ValueError) as error:
|
|
result.update(status="INVALID_SET", passed=False, reason=str(error))
|
|
return result
|
|
result.update(physics=physics, status=physics["status"], passed=physics["status"] == "PASS")
|
|
try:
|
|
# Role "uniform_fine" is the preset's finest control (4N nested, 2N twin).
|
|
result["signed"] = signed_summary([indexed[k] for k in geometry.CASES])
|
|
except (KeyError, TypeError, ValueError) as error:
|
|
result["signed_unavailable"] = str(error)
|
|
return result
|
|
|
|
|
|
def _signed(record):
|
|
"""Raw signed quantities of one valid record (None when the fit is unavailable)."""
|
|
s = sw.summarize(record)
|
|
bias = None if not s["rate_fit_valid"] else s["rate"] / s["exact_rate"] - 1
|
|
return dict(n=record["n"], depth=record["depth"], explosion=record["explosion"],
|
|
rate_fit_valid=s["rate_fit_valid"], signed_rate_bias=bias,
|
|
rate_tstar=s["rate_tstar"], exact_rate_tstar=s["exact_rate_tstar"],
|
|
interval_rate_errors=s["interval_rate_errors"],
|
|
residual_l2=s["residual_l2"], spurious_pressure_scaled=s["spurious_pressure_scaled"],
|
|
spurious_pressure_rms=s["spurious_pressure_rms"],
|
|
final_amplitude_error=record["rows"][-1]["amplitude_error"])
|
|
|
|
|
|
def signed_summary(records):
|
|
"""Signed bias per case and refined excess over each uniform control."""
|
|
rows = dict(zip(ROLES, (_signed(r) for r in records)))
|
|
|
|
def minus(a, b):
|
|
return None if a is None or b is None else a - b
|
|
|
|
for role in ("constant", "projected_linear"):
|
|
for control in ("uniform_root", "uniform_fine"):
|
|
rows[role][f"excess_over_{control}"] = {
|
|
key: minus(rows[role][key], rows[control][key])
|
|
for key in ("signed_rate_bias", "residual_l2", "spurious_pressure_rms")}
|
|
return rows
|
|
|
|
|
|
def load_reference(paths):
|
|
"""The four audited N128 receipts verbatim; never relabelled as fresh controls."""
|
|
blobs = [Path(path).read_bytes() for path in paths]
|
|
hashes = {hashlib.sha256(blob).hexdigest() for blob in blobs}
|
|
if len(blobs) != 4 or hashes != set(REFERENCE_RECEIPTS.values()):
|
|
raise ValueError("N128 receipt hashes differ from the audited de5b0cc evidence")
|
|
return [json.loads(blob) for blob in blobs]
|
|
|
|
|
|
def resolution_trend(new_result, reference, reference_revision=REFERENCE_REVISION):
|
|
"""Descriptive N128 -> N256 signed changes; never an acceptance gate or an order."""
|
|
old_result = assess(reference, reference_revision)
|
|
if "signed" not in old_result or "signed" not in new_result:
|
|
return dict(valid=False, reason="N128 reference or N256 set lacks a valid signed summary")
|
|
out = {}
|
|
for role in ROLES:
|
|
old, new = old_result["signed"][role], new_result["signed"][role]
|
|
out[role] = {}
|
|
for key in ("signed_rate_bias", "residual_l2", "spurious_pressure_rms",
|
|
*(f"excess_over_{c}" for c in ("uniform_root", "uniform_fine"))):
|
|
if key not in old:
|
|
continue
|
|
pairs = old[key].items() if isinstance(old[key], dict) else [(None, old[key])]
|
|
for sub, low in pairs:
|
|
high = new[key][sub] if sub else new[key]
|
|
ok = low is not None and high is not None
|
|
out[role][key if sub is None else f"{key}.{sub}"] = dict(
|
|
n128=low, n256=high, signed_change=high - low if ok else None,
|
|
n256_to_n128=high / low if ok and low else None)
|
|
return dict(valid=True, reference_revision=reference_revision,
|
|
reference_receipt_sha256=REFERENCE_RECEIPTS,
|
|
reference_status=old_result["status"], changes=out,
|
|
scope="same-placement two-resolution trend; not a convergence order, "
|
|
"placement robustness or redesign decision")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
p = argparse.ArgumentParser(description=__doc__)
|
|
p.add_argument("files", type=Path, nargs=4)
|
|
p.add_argument("--output", type=Path, required=True)
|
|
p.add_argument("--expected-revision", required=True)
|
|
p.add_argument("--diagnostic", choices=[SCALED_SHEAR, NESTED_SHEAR, TWIN_SHEAR])
|
|
p.add_argument("--reference-files", type=Path, nargs=4)
|
|
args = p.parse_args()
|
|
if args.output.exists():
|
|
p.error("Output already exists; choose a new path to retain prior evidence")
|
|
if args.diagnostic in PRESETS:
|
|
if args.reference_files:
|
|
p.error(f"{args.diagnostic} takes no reference files (no resolution trend)")
|
|
result = assess_nested([json.loads(path.read_text()) for path in args.files],
|
|
args.expected_revision, args.diagnostic)
|
|
text = json.dumps(result, indent=2, allow_nan=False) + "\n"
|
|
args.output.write_text(text)
|
|
print(text, end="")
|
|
raise SystemExit(0 if result["passed"] else 1)
|
|
if bool(args.diagnostic) != bool(args.reference_files):
|
|
p.error("--diagnostic scaled_shear_n256 requires --reference-files (N128 receipts)")
|
|
result = assess([json.loads(path.read_text()) for path in args.files], args.expected_revision,
|
|
scaled=bool(args.diagnostic))
|
|
if args.diagnostic:
|
|
try:
|
|
reference = load_reference(args.reference_files)
|
|
except ValueError as exc:
|
|
p.error(str(exc))
|
|
result["resolution_trend"] = resolution_trend(result, reference)
|
|
text = json.dumps(result, indent=2, allow_nan=False) + "\n"
|
|
args.output.write_text(text)
|
|
print(text, end="")
|
|
raise SystemExit(0 if result["passed"] else 1)
|