""" Command-line interface for numerical-provenance. Usage: numerical-provenance --demo # run the full demo numerical-provenance --selftest # run the regression checks numerical-provenance --strict --demo # abort on self-test failure """ from __future__ import annotations import argparse import sys from .model import ( jacobi_short, jacobi_converged, jacobi_adaptive, jacobi_loose, cross_check, PValue, Disagreement, report, assert_converged, UnconvergedError, _build_reference_matrix, _section, ) def _selftest(verbose: bool = True) -> tuple: """Verify the discipline holds. Returns (passed, total).""" checks = [] A = _build_reference_matrix(n=20) # 1. Converged solver converges conv = jacobi_converged(A) checks.append(("jacobi_converged converges", conv.converged)) # 2. Short solver does not short = jacobi_short(A) checks.append(("jacobi_short does not converge", not short.converged)) # 3. Arithmetic propagates taint mixed = (short + 5.0) / 2.0 checks.append(("arithmetic propagates taint", not mixed.converged)) # 4. report refuses unconverged r = report(short) checks.append(("report refuses unconverged", " int: p = argparse.ArgumentParser( prog="numerical-provenance", description="Every numeric output carries its convergence state.", ) p.add_argument("--demo", action="store_true", help="run the full demo") p.add_argument("--selftest", action="store_true", help="run the regression checks and exit") p.add_argument("--strict", action="store_true", help="abort with exit code 1 if the self-test fails") p.add_argument("--quiet", action="store_true", help="suppress the self-test banner") args = p.parse_args(argv) passed, total = _selftest(verbose=not args.quiet) if args.selftest: return 0 if passed == total else 1 if args.strict and passed < total: print("\n--strict: self-test failed; aborting.", file=sys.stderr) return 1 if args.demo: from .model import demo demo() return 0 p.print_help() return 0 if __name__ == "__main__": sys.exit(main())