haskell-fsrs-7.0.0: reference/check_golden.py
"""Check that the committed golden vectors still match the Python reference.
Regenerates the vectors in memory and compares them, token by token, against
``test/Test/FSRS/GoldenData.hs``.
Numbers are compared with a tolerance rather than textually. ``exp`` and
``pow`` are not required by IEEE-754 to be correctly rounded, so the last bit
of a literal can legitimately differ between the machine that generated the
file and the machine checking it — a plain ``git diff`` would go red for
reasons that have nothing to do with the model. Everything else — structure,
identifiers, how many vectors there are — must match exactly.
Run from the repository root:
python3 reference/check_golden.py
"""
import os
import re
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import gen_golden # noqa: E402
# Relative tolerance. Several orders of magnitude looser than the last-bit
# noise we are trying to ignore, and several orders tighter than any change
# a real edit to the model would produce.
RTOL = 1e-9
ATOL = 1e-12
MAX_REPORTED = 5
_SPLIT = re.compile(r"([,()\[\]])|\s+")
def tokens(text):
return [tok for tok in _SPLIT.split(text) if tok and tok.strip()]
def as_float(token):
try:
return float(token)
except ValueError:
return None
def close(a, b):
return abs(a - b) <= ATOL + RTOL * max(abs(a), abs(b))
def main():
expected = tokens(gen_golden.render())
with open(gen_golden.OUT) as fh:
actual = tokens(fh.read())
if len(expected) != len(actual):
print(
f"{gen_golden.OUT} has {len(actual)} tokens, the reference "
f"produces {len(expected)}: the two have diverged structurally."
)
return 1
drifted = []
nudged = 0
for index, (want, got) in enumerate(zip(expected, actual)):
if want == got:
continue
want_f, got_f = as_float(want), as_float(got)
if want_f is not None and got_f is not None and close(want_f, got_f):
nudged += 1
continue
drifted.append((index, want, got))
if drifted:
print(f"{len(drifted)} of {len(expected)} tokens have drifted:")
for index, want, got in drifted[:MAX_REPORTED]:
print(f" token {index}: committed {got!r}, reference says {want!r}")
if len(drifted) > MAX_REPORTED:
print(f" ... and {len(drifted) - MAX_REPORTED} more")
print("Run 'python3 reference/gen_golden.py' and commit the result.")
return 1
print(
f"{len(expected)} tokens checked, all in agreement"
+ (f" ({nudged} within tolerance but not bit-identical)" if nudged else "")
)
return 0
if __name__ == "__main__":
sys.exit(main())