260 lines
13 KiB
Python
260 lines
13 KiB
Python
#!/usr/bin/env python3
|
|
"""Exercise checker acceptance and failure paths with synthetic probe records."""
|
|
|
|
import csv
|
|
import json
|
|
from pathlib import Path
|
|
import tempfile
|
|
import unittest
|
|
|
|
from check_numerical_strategies import assess
|
|
|
|
|
|
def write_rows(folder, name, rows, fields=None):
|
|
fields = fields or list(rows[0])
|
|
with (folder / name).open("w", newline="") as stream:
|
|
writer = csv.DictWriter(stream, fieldnames=fields)
|
|
writer.writeheader()
|
|
writer.writerows(rows)
|
|
|
|
|
|
def write_metrics(folder, name, values):
|
|
write_rows(folder, name, [{"metric": key, "value": value} for key, value in values.items()])
|
|
|
|
|
|
def gravity_fixture(folder):
|
|
summary = {"accepted_state_change": 0, "accepted_residual_change": 0, "accepted_physical_change": 0,
|
|
"maximum_original_restoration_error": 0, "gravity_completion_tolerance": 1e-11,
|
|
"reduced_base_completed": 1, "reduced_action_norm": 2,
|
|
"lifted_gravity_action_norm": 1e-13, "lifted_retained_action_difference": 1e-13}
|
|
inner = []
|
|
curvature = []
|
|
for alpha in (1., .1, .01, .001):
|
|
rhs = .1 * alpha**2
|
|
threshold = max(1e-13, 1e-9 * rhs)
|
|
residual = threshold * .1
|
|
inner.append({"kind": "curvature", "alpha": alpha, "index": 0, "status": 0, "converged": 1,
|
|
"right_hand_side_norm": rhs, "true_residual_norm": residual,
|
|
"relative_true_residual_norm": residual / rhs, "threshold": threshold})
|
|
curvature.append({"alpha": alpha, "prepared": 1, "inner_converged": 1, "corrected_prepared": 1,
|
|
"base_residual_norm": 1, "raw_residual_norm": 1, "corrected_residual_norm": .99,
|
|
"linear_prediction_norm": .99, "raw_gravity_remainder": rhs,
|
|
"corrected_gravity_remainder": residual, "gravity_correction_norm": .2 * alpha**2,
|
|
"correction_over_alpha_squared": .2, "retained_state_change": 0})
|
|
for kind in ("reduced_action", "reduced_lift"):
|
|
inner.append({"kind": kind, "alpha": 0, "index": 0, "status": 0, "converged": 1,
|
|
"right_hand_side_norm": 1, "true_residual_norm": 1e-13,
|
|
"relative_true_residual_norm": 1e-13, "threshold": 1e-9})
|
|
completions = [{"kind": "reduced_base", "alpha": 0, "completed": 1,
|
|
"final_gravity_norm": 5e-14, "retained_state_change": 0}]
|
|
differences = []
|
|
for alpha in (.01, .001, .0001):
|
|
for kind in ("reduced_plus", "reduced_minus"):
|
|
completions.append({"kind": kind, "alpha": alpha, "completed": 1,
|
|
"final_gravity_norm": 5e-14, "retained_state_change": 0})
|
|
differences.append({"alpha": alpha, "plus_completed": 1, "minus_completed": 1,
|
|
"relative_error": .25 * alpha**2, "difference_quotient_error": .5 * alpha**2,
|
|
"plus_gravity_norm": 5e-14, "minus_gravity_norm": 5e-14,
|
|
"residual_subtraction_roundoff_scale": 1e-14 / alpha})
|
|
write_metrics(folder, "numerical_strategy_summary.csv", summary)
|
|
write_rows(folder, "numerical_strategy_inner.csv", inner)
|
|
write_rows(folder, "numerical_strategy_curvature.csv", curvature)
|
|
write_rows(folder, "numerical_strategy_completions.csv", completions)
|
|
write_rows(folder, "numerical_strategy_reduced_derivative.csv", differences)
|
|
return summary, inner, curvature, completions, differences
|
|
|
|
|
|
def polynomial_fixture(folder):
|
|
certificates = [{"state": name, "status": status, "witness_element": 459 if status == "negative" else -1,
|
|
"x": .5, "y": .5, "z": .5}
|
|
for name, status in (("frozen_base", "negative"), ("context_seed_anchor", "certified_nonnegative"),
|
|
("original_full_candidate", "negative"))]
|
|
repair = [{"status": "invalid_base", "minimum_safe_fraction": 1, "base_status": "negative"}]
|
|
trials = [{"fraction": 0, "alpha": 1, "certificate": "negative", "prepared": 1, "merit_slope": -.1}]
|
|
write_rows(folder, "polynomial_certificates.csv", certificates)
|
|
write_rows(folder, "polynomial_repair.csv", repair)
|
|
write_rows(folder, "polynomial_repair_trials.csv", trials)
|
|
write_metrics(folder, "polynomial_restoration.csv", {
|
|
"accepted_physical_difference": 0, "accepted_normalized_difference": 0, "accepted_residual_difference": 0,
|
|
"restored_correction_difference": 0, "restored_residual_difference": 0})
|
|
return certificates, repair, trials
|
|
|
|
|
|
def application_fixture(folder):
|
|
rows = [{"direction": index, "compact_operator": 1, "compact_inverse": 1,
|
|
"operator_norm": 5.0, "operator_error": 5e-15, "operator_relative_error": 1e-15,
|
|
"compact_operator_seconds": .001, "root_operator_seconds": .2,
|
|
"inverse_norm": 0.25, "inverse_error": 2.5e-16, "inverse_relative_error": 1e-15,
|
|
"compact_inverse_seconds": .004, "root_inverse_seconds": .01}
|
|
for index in range(3)]
|
|
write_rows(folder, "gravity_applications.csv", rows)
|
|
return rows
|
|
|
|
|
|
class NumericalStrategyChecks(unittest.TestCase):
|
|
def setUp(self):
|
|
self.temporary = tempfile.TemporaryDirectory()
|
|
self.folder = Path(self.temporary.name)
|
|
|
|
def tearDown(self):
|
|
self.temporary.cleanup()
|
|
|
|
def test_application_evidence_is_discovered_and_passes(self):
|
|
application_fixture(self.folder)
|
|
report, code = assess(self.folder)
|
|
self.assertEqual(code, 0, report)
|
|
self.assertEqual(report["outcomes"]["gravity_applications"]["recorded_directions"], 3)
|
|
self.assertEqual(report["outcomes"]["gravity_applications"]["compact_operator_directions"], 3)
|
|
|
|
def test_application_fallback_is_a_valid_outcome(self):
|
|
rows = application_fixture(self.folder)
|
|
for row in rows:
|
|
row["compact_operator"], row["compact_inverse"] = 0, 0
|
|
write_rows(self.folder, "gravity_applications.csv", rows)
|
|
report, code = assess(self.folder, required=("applications",))
|
|
self.assertEqual(code, 0, report)
|
|
outcome = report["outcomes"]["gravity_applications"]
|
|
self.assertEqual(outcome["compact_operator_directions"], 0)
|
|
self.assertEqual(outcome["compact_inverse_directions"], 0)
|
|
self.assertEqual(outcome["measurements"][0]["operator_path"], "root_restriction")
|
|
|
|
def test_wrong_operator_or_default_inverse_application_fails(self):
|
|
for kind in ("operator", "inverse"):
|
|
with self.subTest(kind=kind):
|
|
rows = application_fixture(self.folder)
|
|
rows[0][f"{kind}_error"] = 1e-5
|
|
rows[0][f"{kind}_relative_error"] = 1e-5 / rows[0][f"{kind}_norm"]
|
|
write_rows(self.folder, "gravity_applications.csv", rows)
|
|
report, code = assess(self.folder)
|
|
self.assertEqual(code, 3, report)
|
|
self.assertIn(f"application_0_{kind}_same_action",
|
|
[check["name"] for check in report["checks"] if check["status"] == "fail"])
|
|
|
|
def test_application_nan_timing_and_flags_cannot_pass(self):
|
|
for field, value in (("operator_error", float("nan")), ("inverse_relative_error", float("nan")),
|
|
("root_operator_seconds", float("inf")), ("compact_inverse_seconds", -1),
|
|
("compact_operator", "true")):
|
|
with self.subTest(field=field):
|
|
rows = application_fixture(self.folder)
|
|
rows[0][field] = value
|
|
write_rows(self.folder, "gravity_applications.csv", rows)
|
|
report, code = assess(self.folder)
|
|
self.assertEqual(code, 3, report)
|
|
json.dumps(report, allow_nan=False)
|
|
|
|
def test_application_relative_error_must_match_absolute_measurement(self):
|
|
rows = application_fixture(self.folder)
|
|
rows[0]["operator_relative_error"] = 1e-6
|
|
write_rows(self.folder, "gravity_applications.csv", rows)
|
|
report, code = assess(self.folder)
|
|
self.assertEqual(code, 3, report)
|
|
|
|
def test_required_application_missing_or_empty_is_incomplete(self):
|
|
self.assertEqual(assess(self.folder, required=("applications",))[1], 2)
|
|
rows = application_fixture(self.folder)
|
|
write_rows(self.folder, "gravity_applications.csv", [], fields=list(rows[0]))
|
|
self.assertEqual(assess(self.folder, required=("applications",))[1], 2)
|
|
|
|
def test_application_absolute_floor_handles_small_actions(self):
|
|
rows = application_fixture(self.folder)
|
|
for row in rows:
|
|
row["operator_norm"] = 1e-8
|
|
row["operator_error"] = 1e-13
|
|
row["operator_relative_error"] = 1e-5
|
|
write_rows(self.folder, "gravity_applications.csv", rows)
|
|
report, code = assess(self.folder)
|
|
self.assertEqual(code, 0, report)
|
|
|
|
def test_complete_gravity_evidence_passes(self):
|
|
gravity_fixture(self.folder)
|
|
report, code = assess(self.folder, required=("gravity",))
|
|
self.assertEqual(code, 0, report)
|
|
|
|
def test_negative_late_base_is_an_expected_guard_success(self):
|
|
polynomial_fixture(self.folder)
|
|
report, code = assess(self.folder, expect_negative=True)
|
|
self.assertEqual(code, 0, report)
|
|
|
|
def test_negative_base_cannot_be_repaired_silently(self):
|
|
_, repair, _ = polynomial_fixture(self.folder)
|
|
repair[0]["status"] = "feasible"
|
|
write_rows(self.folder, "polynomial_repair.csv", repair)
|
|
report, code = assess(self.folder, expect_negative=True)
|
|
self.assertEqual(code, 3, report)
|
|
|
|
def test_false_convergence_report_fails(self):
|
|
_, inner, _, _, _ = gravity_fixture(self.folder)
|
|
inner[0]["true_residual_norm"] = 1.0
|
|
write_rows(self.folder, "numerical_strategy_inner.csv", inner)
|
|
report, code = assess(self.folder)
|
|
self.assertEqual(code, 3, report)
|
|
|
|
def test_changed_retained_state_fails(self):
|
|
_, _, curvature, _, _ = gravity_fixture(self.folder)
|
|
curvature[0]["retained_state_change"] = 1e-8
|
|
write_rows(self.folder, "numerical_strategy_curvature.csv", curvature)
|
|
report, code = assess(self.folder)
|
|
self.assertEqual(code, 3, report)
|
|
|
|
def test_failed_numerical_probe_is_incomplete_not_a_false_pass(self):
|
|
summary, inner, curvature, completions, _ = gravity_fixture(self.folder)
|
|
summary["reduced_base_completed"] = 0
|
|
for row in inner:
|
|
row["status"], row["converged"] = 1, 0
|
|
for row in curvature:
|
|
row["inner_converged"], row["corrected_prepared"] = 0, 0
|
|
for row in completions:
|
|
row["completed"] = 0
|
|
write_metrics(self.folder, "numerical_strategy_summary.csv", summary)
|
|
write_rows(self.folder, "numerical_strategy_inner.csv", inner)
|
|
write_rows(self.folder, "numerical_strategy_curvature.csv", curvature)
|
|
write_rows(self.folder, "numerical_strategy_completions.csv", completions)
|
|
report, code = assess(self.folder)
|
|
self.assertEqual(code, 2, report)
|
|
self.assertEqual(report["outcomes"]["gravity_inner"]["failed_calls"], 6)
|
|
|
|
def test_missing_probe_is_incomplete(self):
|
|
report, code = assess(self.folder, required=("gravity",))
|
|
self.assertEqual(code, 2, report)
|
|
|
|
def test_null_reduced_action_uses_absolute_arithmetic_floor(self):
|
|
summary, _, _, _, differences = gravity_fixture(self.folder)
|
|
summary["reduced_action_norm"] = 0.0
|
|
summary["lifted_retained_action_difference"] = 0.0
|
|
for row in differences:
|
|
row["difference_quotient_error"] = row["residual_subtraction_roundoff_scale"] * .1
|
|
row["relative_error"] = float("inf")
|
|
write_metrics(self.folder, "numerical_strategy_summary.csv", summary)
|
|
write_rows(self.folder, "numerical_strategy_reduced_derivative.csv", differences)
|
|
report, code = assess(self.folder)
|
|
self.assertEqual(code, 0, report)
|
|
|
|
def test_unfinished_restoration_record_is_incomplete(self):
|
|
summary, _, _, _, _ = gravity_fixture(self.folder)
|
|
del summary["accepted_state_change"]
|
|
write_metrics(self.folder, "numerical_strategy_summary.csv", summary)
|
|
report, code = assess(self.folder)
|
|
self.assertEqual(code, 2, report)
|
|
|
|
def test_nonfinite_restoration_fails_and_serializes_standard_json(self):
|
|
summary, _, _, _, _ = gravity_fixture(self.folder)
|
|
summary["accepted_state_change"] = float("nan")
|
|
write_metrics(self.folder, "numerical_strategy_summary.csv", summary)
|
|
report, code = assess(self.folder)
|
|
self.assertEqual(code, 3, report)
|
|
json.dumps(report, allow_nan=False)
|
|
|
|
def test_only_restoration_not_accepted_state_may_use_optional_tolerance(self):
|
|
summary, _, _, _, _ = gravity_fixture(self.folder)
|
|
summary["maximum_original_restoration_error"] = 1e-13
|
|
write_metrics(self.folder, "numerical_strategy_summary.csv", summary)
|
|
self.assertEqual(assess(self.folder)[1], 3)
|
|
self.assertEqual(assess(self.folder, restoration_tolerance=1e-12)[1], 0)
|
|
summary["accepted_state_change"] = 1e-13
|
|
write_metrics(self.folder, "numerical_strategy_summary.csv", summary)
|
|
self.assertEqual(assess(self.folder, restoration_tolerance=1e-12)[1], 3)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|