Download cli.py from zeechimp/numerical-provenance: direct link, hf CLI and curl.
- Browser
- Download file 4.6 kB
-
https://huggingface.co/zeechimp/numerical-provenance/resolve/main/cli.py
- Command line
-
hf download hf://zeechimp/numerical-provenance/cli.py
-
curl -L -o cli.py https://huggingface.co/zeechimp/numerical-provenance/resolve/main/cli.py
4.6 kB
| """ | |
| 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", "<refused" in r)) | |
| # 5. report accepts converged | |
| r = report(conv) | |
| checks.append(("report accepts converged", "[ok:" in r)) | |
| # 6. unwrap refuses without allow | |
| try: | |
| short.unwrap() | |
| checks.append(("unwrap refuses unconverged", False)) | |
| except UnconvergedError: | |
| checks.append(("unwrap refuses unconverged", True)) | |
| # 7. unwrap allows with opt-in | |
| try: | |
| short.unwrap(allow_unconverged=True) | |
| checks.append(("unwrap allows with opt-in", True)) | |
| except Exception: | |
| checks.append(("unwrap allows with opt-in", False)) | |
| # 8. cross_check on two converged agrees | |
| result = cross_check([jacobi_converged, jacobi_adaptive], A, tol=1e-6) | |
| checks.append(("cross_check agrees on two converged", | |
| isinstance(result, PValue))) | |
| # 9. cross_check on mixed returns Disagreement | |
| result = cross_check([jacobi_short, jacobi_converged], A, tol=1e-6) | |
| checks.append(("cross_check disagrees on mixed", | |
| isinstance(result, Disagreement))) | |
| # 10. outlier identifies the unconverged solver | |
| if isinstance(result, Disagreement): | |
| _, name, dist = result.outlier() | |
| checks.append(("outlier is jacobi_short", name == "jacobi_short")) | |
| else: | |
| checks.append(("outlier is jacobi_short", False)) | |
| # 11. cross_check on tolerance-mismatched pair | |
| result = cross_check([jacobi_converged, jacobi_loose], A, tol=1e-9) | |
| if isinstance(result, Disagreement): | |
| _, name, _ = result.outlier() | |
| checks.append(("outlier is jacobi_loose", name == "jacobi_loose")) | |
| else: | |
| checks.append(("outlier is jacobi_loose", False)) | |
| # 12. assert_converged raises on unconverged | |
| try: | |
| assert_converged(short, "test") | |
| checks.append(("assert_converged raises", False)) | |
| except AssertionError: | |
| checks.append(("assert_converged raises", True)) | |
| passed = sum(1 for _, ok in checks if ok) | |
| if verbose: | |
| print() | |
| print("=" * 74) | |
| print("SELF-TEST") | |
| print("=" * 74) | |
| for name, ok in checks: | |
| print(f" [{'PASS' if ok else 'FAIL'}] {name}") | |
| print() | |
| print(f" {passed}/{len(checks)} correct") | |
| return passed, len(checks) | |
| def main(argv=None) -> 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()) |