Files
Raptor/validation/raptor_validation/output_comparison.py
T
NiccoloN a77edafcbf
Validate Operations / validate-operations (push) Has been cancelled
even better more structured throughput scheduling
plot adjustments
validation adjustments
2026-10-27 17:46:46 +01:00

45 lines
2.1 KiB
Python

from dataclasses import dataclass
import math
import numpy as np
VALIDATION_POLICY = "pointwise-and-relative-l2-v1"
@dataclass(frozen=True)
class OutputComparison:
passed: bool
max_abs_diff: float
relative_l2_error: float | None
pointwise_passed: bool
def compare_output_arrays(actual, expected, *, atol, rtol):
"""Require pointwise tolerance and relative L2 tolerance for nonzero outputs."""
if any(not math.isfinite(value) or value < 0 for value in (atol, rtol)):
raise ValueError("output tolerances must be finite and non-negative")
actual, expected = np.asarray(actual), np.asarray(expected)
if actual.dtype.kind not in "biuf" or expected.dtype.kind not in "biuf":
raise ValueError("output comparison requires real numeric arrays")
if actual.shape != expected.shape:
raise ValueError(f"output shapes differ: {actual.shape} != {expected.shape}")
if not actual.size:
return OutputComparison(True, 0.0, None, True)
if not np.all(np.isfinite(actual)) or not np.all(np.isfinite(expected)):
return OutputComparison(False, math.inf, None, False)
if expected.dtype.kind in "biu":
difference = np.abs(actual.astype(object) - expected.astype(object))
passed = bool(np.array_equal(actual, expected))
return OutputComparison(passed, float(difference.max()), None, passed)
actual, expected = actual.astype(np.float64), expected.astype(np.float64)
with np.errstate(over="ignore", invalid="ignore", divide="ignore"):
difference = np.abs(actual - expected)
pointwise = bool(np.all(difference <= atol + rtol * np.abs(expected)))
scale = float(np.max(np.abs(expected)))
relative = (float(np.linalg.norm(difference / scale) /
np.linalg.norm(expected / scale)) if scale else None)
# A zero reference has no relative scale. rtol=0 explicitly requests absolute-only checks.
relative_passed = relative is None or rtol == 0 or relative <= rtol
return OutputComparison(pointwise and relative_passed, float(difference.max()), relative, pointwise)