diff --git a/research/eisenstein-rational-rank/BENCHMARK.json b/research/eisenstein-rational-rank/BENCHMARK.json new file mode 100644 index 0000000000..fc36af22a7 --- /dev/null +++ b/research/eisenstein-rational-rank/BENCHMARK.json @@ -0,0 +1,134 @@ +{ + "Q_call_digest": "e1b5b6b4838abef5fb576050015f4338c783820e9d232630056c5a8a9b7b90ed", + "Q_seconds": { + "baseline": [ + 0.1974230830091983, + 0.20564645796548575, + 0.19658200000412762, + 0.19378291605971754, + 0.24812508292961866, + 0.19987333298195153 + ], + "integer": [ + 0.04953145794570446, + 0.050143082975409925, + 0.049230208969675004, + 0.050073625054210424, + 0.04916433396283537, + 0.05532212497200817 + ] + }, + "Q_summary": { + "baseline": { + "max": 0.24812508292961866, + "median": 0.19864820799557492, + "min": 0.19378291605971754 + }, + "integer": { + "max": 0.05532212497200817, + "median": 0.04980254149995744, + "min": 0.04916433396283537 + } + }, + "adapter_sha256": { + "benchmark.py": "f842991ff721b5b677d453deca51163855c569f9203fda6cc0466e4d79f3840d", + "rational_rank.py": "e323bb0d9e6ff62df11754b12eba6204eb9edfe67b0fcffbc23d68c7e93358e8", + "replay.py": "d7e2abfdf482d04bb681c10ad8133194644c53a011927a904752885f54c9bb98", + "verify.py": "b293039a5eb42eae968721a9e5b90dd3b82870f90897f999a31bb35cf9e34587" + }, + "complete_stdout_sha256": "e42bb5dc19ea186704cf18ec7707973d974d954afd70147c576c23599e01238c", + "discarded_warmup_pairs": 1, + "errors": 0, + "full_seconds": { + "baseline": [ + 0.43367100006435066, + 0.4285935830557719, + 0.43997616693377495, + 0.43282008299138397, + 0.4980214589741081, + 0.496430917060934 + ], + "integer": [ + 0.2850769170327112, + 0.286506833974272, + 0.2787634580163285, + 0.2804110830184072, + 0.27929520804900676, + 0.3063662080094218 + ] + }, + "full_speed_ratio": 1.5449437776206578, + "full_summary": { + "baseline": { + "max": 0.4980214589741081, + "median": 0.4368235834990628, + "min": 0.4285935830557719 + }, + "integer": { + "max": 0.3063662080094218, + "median": 0.2827440000255592, + "min": 0.2787634580163285 + } + }, + "interpreter": "/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12", + "machine": "arm64", + "order": [ + [ + 1, + "integer" + ], + [ + 1, + "baseline" + ], + [ + 2, + "baseline" + ], + [ + 2, + "integer" + ], + [ + 3, + "integer" + ], + [ + 3, + "baseline" + ], + [ + 4, + "baseline" + ], + [ + 4, + "integer" + ], + [ + 5, + "integer" + ], + [ + 5, + "baseline" + ], + [ + 6, + "baseline" + ], + [ + 6, + "integer" + ] + ], + "pairs": 6, + "platform": "macOS-27.0.1-arm64-arm-64bit", + "python": "3.12.15", + "rank_calls_per_complete_run": { + "F4": 311, + "K": 359, + "Q": 209 + }, + "scope": "Same complete fixture and K adapter; only Q-rank changes. Fresh-process wall time includes imports and source authentication. Kernel samples execute all 209 actual matrices. Shared-host load is uncontrolled; no universal speed guarantee." +} diff --git a/research/eisenstein-rational-rank/README.md b/research/eisenstein-rational-rank/README.md new file mode 100644 index 0000000000..6cea3eb320 --- /dev/null +++ b/research/eisenstein-rational-rank/README.md @@ -0,0 +1,141 @@ +# Faster complete Eisenstein replay with integer rational rank + +The complete replay using ywz65's K-rank adapter takes a median +0.436824 seconds with the original Q-rank function and 0.282744 seconds +with this optional rational-rank adapter, a 35.27% reduction in wall time. +This is the first implementation tried; optimization stopped at that gain. +The measured ranges do not overlap. All 209 actual Q calls agree, and the +complete stdout is byte-identical, including the seven original rejection +controls. The 359 K calls keep ywz65's implementation and all 311 F4 calls +keep Jose Manuel's implementation. + +Claim type: finite exact equivalence certificate and local performance +measurement. The new result is faster execution of the same complete fixture. +It does not add to or independently review the cited Eisenstein cost theorem. +The adapter, verifier and benchmark were produced by Nick Petalas. Apache-2.0. + +## Method and exactness + +Clear every row's rational denominators by their positive lcm. For a nonzero +pivot p and an entry a below it, replace the lower row r by p*r-a*pivot_row, +then divide out its nonzero integer content. Multiplication by p is invertible +over Q. The pivot row stays unchanged, so this replacement is an invertible +row operation. Removing integer content also preserves row space. Previously +eliminated columns are zero, and every counted pivot is nonzero. Thus the +returned pivot count is the rational rank. Empty and zero-width matrices have +rank zero. These are standard elimination facts; no new rank theorem is claimed. + +The routine copies its input and caches no matrix or mathematical success. +It accepts rectangular lists or tuples containing exact integers or Fractions. +There are at most 96 rows and columns, input numerators and denominators have +at most 128 bits, and every initialized or updated integer row has at most +4096 bits per entry. Capacity exhaustion raises an error. The actual fixture +has dimensions at most 80 by 80 and input heights at most four bits. + +[replay.py](replay.py) authenticates all three executable source files by SHA256 +and Git blob ID before loading either predecessor module. Both comparison modes +use the same wrapper, imports, source authentication and K adapter. Only Q-rank +changes. No frozen source or production verifier is modified. + +## Evidence + +[BENCHMARK.json](BENCHMARK.json) is generated evidence with every observation, +execution order, environment, code hashes and ordered Q-call digest. Six pairs +alternate the order of baseline and integer execution, after an excluded warmup +pair. Complete fresh-process wall time includes imports and authentication. + +The original-Q mode ranges from 0.428594 to 0.498021 seconds. The integer-Q mode +ranges from 0.278763 to 0.306366 seconds. There are zero failed timed runs. +Every timed run executes all 879 rank calls and compares complete stdout bytes. +Separate timed executions of the 209 actual Q matrices have medians 0.198648 +and 0.049803 seconds. The original Q kernel is about 45% of the measured whole +replay, so its reduction explains the complete improvement. These separate +kernel timings do not include matrix capture or the correctness oracle. + +Measurements used CPython 3.12.15 on macOS arm64. The host has 18 logical CPUs; +the pre-run load averages were 5.67, 5.15 and 4.01. Other work was running and +was not stopped. Alternation controls drift, but timings remain observations +on this host, not a universal speed guarantee or multiplication speedup. +An untimed cProfile run identified Fraction multiplication/addition in Q-rank +as the main remaining cost after the K adapter. + +[verify.py](verify.py) compares every actual Q-call result and checks input +preservation. It compares the complete replay output, checks the original seven +controls are present, and rejects a zero-returning Q adapter through the original +checks. A separate Leibniz-determinant/minor oracle checks 1,798 rational matrices, +including complete small rectangular domains and 200 deterministic 3-by-3 +fixtures. Seven invalid-input/capacity controls remain active under `-O`. + +[integrity.py](integrity.py) runs both complete modes in a Git-free private copy, +compares their output and all input hashes, and corrupts each of the three live +sources in turn. Each corruption must fail at authentication before import. +The private copies are removed. Default replay writes no artifacts. + +## Reproduce + +From the repository root, use Python 3.12 and the standard library: + +```sh +/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -W error -I -O -B research/eisenstein-rational-rank/replay.py +/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -W error -I -B research/eisenstein-rational-rank/verify.py +/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -B scripts/research_package.py --package research/eisenstein-rational-rank +/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -B scripts/check_research_commit.py --package research/eisenstein-rational-rank --check-source-history +``` + +Any CPython 3.12 path can replace the displayed interpreter. The standalone +marker is `PASS_EISENSTEIN_RATIONAL_RANK`; integrity prints +`PASS_EISENSTEIN_RATIONAL_INTEGRITY`. The registered commands run normal and +optimized correctness checks and the integrity check, each with a 60-second +limit. Timing is optional and is never a passing threshold: + +```sh +/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -W error -I -O -B research/eisenstein-rational-rank/benchmark.py --output /absolute/new/path/benchmark.json +``` + +The timing destination must be absent and outside the checkout. The default +uses six measured pairs plus one discarded warmup pair. + +## Sources and scope + +This answers Open next question 2 of ywz65's +[PR2627](https://github.com/CrocSwap/integer-mult-bounds/pull/2627), which supplies +the retained integer-pair K-rank implementation and leaves Q-rank unchanged. +Jose Manuel / jmbarrancoml's +[PR2017](https://github.com/CrocSwap/integer-mult-bounds/pull/2017) supplies the +original complete verifier and mathematical cost-40 proof. Geometry retains +Jonathan Lam / PR798 and Joel Pulikkan / GamingPuzzled / PR620's credit. +Primitive integer-row elimination is classical. All predecessor credit and +source bytes remain unchanged. + +[SOURCES.json](SOURCES.json) pins exact inputs and historical provenance at +canonical main `19fdb086ea96af9a9f87936a2b888e10af4ed810`, priority revision 8. +[TASK.json](TASK.json) refines the current replay-runtime card. +The [advance claim](https://github.com/CrocSwap/integer-mult-bounds/discussions/1166#discussioncomment-19220187) +preceded implementation. Live PRs, recent claims, account history and targeted +main/merged searches were checked. Cached overlap covered 324 open PRs and +5,496 Discussions with complete pagination. Sparse local coverage was partial; +targeted main searches supplement it. Unpublished work and arbitrary diffs are +not an exhaustive novelty guarantee. + +The retained cost theorem is a cited result, not this contribution's deliverable. +No pairing bound, native word, complete multiplication theorem, new kappa or +selected-frontier change is claimed. Physical access, restoration, precision, +compiler, stock and supplier admission are outside this package. Independent +human and formal proof-kernel review are unclaimed. Lean, Docker and the selected +supplier's cold replay are unrun. + +Python and the standard library allocate dynamically, a managed-runtime deviation +from fixed allocation. The stated dimensions and bit capacities bound the rank +routine's live arrays. Verifier fixtures, child counts and 30-second child +process timeouts are explicit; every function is below 60 physical lines. +Dynamic module loading and callback replacement have only the two authenticated +source targets and the local adapter. Warning-strict normal/optimized execution +and the package checks supply diagnostics. No broad shared-code change is made. + +## Open next questions + +Does the same Q-rank adapter improve another named complete replay with larger +ranks or coefficient heights? Capture that consumer's actual ordered matrix +census and run matched complete fresh-process measurements before proposing +adoption. Its coefficient bounds and full workload remain prerequisites. +No further field optimization or construction expansion is part of this result. diff --git a/research/eisenstein-rational-rank/SOURCES.json b/research/eisenstein-rational-rank/SOURCES.json new file mode 100644 index 0000000000..88d49bff17 --- /dev/null +++ b/research/eisenstein-rational-rank/SOURCES.json @@ -0,0 +1,42 @@ +{ + "schema_version": 1, + "base_commit": "19fdb086ea96af9a9f87936a2b888e10af4ed810", + "files": [ + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "581f8d87008354eb5b869f7ed9de1317ad837ce8", + "sha256": "2a0220e866417774606e0f991e41b9c1d26b1f43b97857238cf478dbc7d330b5" + }, + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "3404fbdd5e7529a0674eef26114b5071e4586cec", + "sha256": "ead6cdc9d0af6d58e8a49744d8ec8c7c15e13d2ba93c276c434bcf9b51b93a81" + }, + { + "path": "research/eisenstein-clique-copy-bound/geometry.py", + "usage": "input", + "git_blob": "a92c16295d6fcf2a7ffeb7d38444613f939db6cb", + "sha256": "248df3fb820b5165ca485ad4d43f0271043498c45a59ac1edc310a124073644c" + }, + { + "path": "research/eisenstein-integer-rank/README.md", + "usage": "provenance", + "git_blob": "12f520e1de8360929561f1a020e9912d20ddb391", + "sha256": "fbfb819c1650116591269878e2f46323eb238d67633fad1bcc7a0c8712613110" + }, + { + "path": "research/eisenstein-integer-rank/integer_rank.py", + "usage": "input", + "git_blob": "4e30d1e26d0dd6c1cf3833e19379be9bf2217e55", + "sha256": "03e11b1e05649d993f43e8d7f62366d41fb71406a47fb2a3e3b81fe2690c449d" + }, + { + "path": "research/eisenstein-reduction-copy-floor/verify.py", + "usage": "input", + "git_blob": "25e47be9a6fe4fe4a7c3c693565ceb33e2cf38bc", + "sha256": "a55f7400386821334d23417406dd105bdd854dbc5832ec015cfe2e1ff951a0ab" + } + ] +} diff --git a/research/eisenstein-rational-rank/TASK.json b/research/eisenstein-rational-rank/TASK.json new file mode 100644 index 0000000000..730c3e175a --- /dev/null +++ b/research/eisenstein-rational-rank/TASK.json @@ -0,0 +1,63 @@ +{ + "schema_version": 1, + "task_id": "replay-runtime", + "priority_revision": 8, + "base_commit": "19fdb086ea96af9a9f87936a2b888e10af4ed810", + "original_card": { + "id": "replay-runtime", + "question": "Can one measured replay bottleneck be sped up without dropping coverage?", + "starting_points": [ + "scripts/run_isolated_tests.py", + "scripts/verify_replay_coverage.py", + "certificates/selected-result.json" + ], + "methods": [ + "Profile one isolated replay and optimize the measured bottleneck.", + "Design source-bound reuse with explicit dependency invalidation and negative controls." + ], + "acceptance_gate": "Report before/after wall time on the same fixture, retained checks and invalidation behavior.", + "first_step": { + "command": [ + "python3", + "-B", + "scripts/research_selected_baseline.py" + ], + "expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY", + "inspect": "Resolve the current selected review, separate complex/ordinary BIT/admitted BIT/outer budgets, and compare the card against live handoffs before starting. Historical ceilings require exact source/model equivalence.", + "scope": "Source-binding orientation only; not a scientific replay or all-size proof. Materialize selected inputs if this checkout is sparse." + }, + "first_experiment": "Measure one unchanged fixture, preserve check coverage, and test one optimization with invalidation controls.", + "bottleneck_link": "Faster trustworthy replays increase review throughput and let mechanism candidates be checked sooner.", + "allowed_variations": [ + "Profile one stage or design one source-bound cache boundary." + ], + "scope_change_triggers": [ + "Skipping coverage or comparing different fixtures to claim speedup." + ], + "overlap_terms": [ + "replay runtime", + "cache invalidation", + "isolated tests" + ] + }, + "scope_status": "refined", + "actual_scope": "Answer Open next question 2 of ywz65 PR2627: accelerate the remaining 209 Q-rank calls in the complete PR2017 replay, retaining its K adapter, F4 calls and all original checks.", + "scope_change_reason": "The runtime card is refined to the explicit rational-arithmetic performance question in PR2627. This contributes a new optional adapter rather than auditing the predecessor theorem.", + "bottleneck_link": "An exact faster opt-in replay reduces the measured check latency. It adds no mathematics to the cited cost-40 theorem and changes no supplier or selected frontier.", + "budget_minutes": 60, + "stop_rule": "Stop at the first output-identical improvement exceeding observed timing noise, or a documented dead end. Do not optimize another field or extend a mathematical census.", + "outcome": "completed", + "evidence": "BENCHMARK.json: six alternating fresh-process pairs, no errors, full stdout byte equality; median 0.4368235835 to 0.2827440000 seconds. verify.py covers the 209 actual Q calls and 1798 minor-oracle matrices. integrity.py rejects three source corruptions before import.", + "author": "Nick Petalas", + "ai_assistance": "Independent human and formal proof-kernel review are unclaimed.", + "open_questions": [ + { + "question": "Does the same Q-rank adapter help another named complete replay with larger ranks or coefficient heights?", + "why_it_matters": "This measurement does not imply a general performance policy.", + "first_step": "Capture that actual ordered matrix census and compare complete matched fresh-process runs before proposing adoption.", + "blocked_by": "A separate concrete consumer, height bounds and full workload measurements." + } + ], + "claim_url": "https://github.com/CrocSwap/integer-mult-bounds/discussions/1166#discussioncomment-19220187", + "first_working_command": "/Users/nick/git/integer-mult-bounds/.venv/bin/python3.12 -B scripts/research_selected_baseline.py -> PASS_RESEARCH_BASELINE_BINDINGS_ONLY" +} diff --git a/research/eisenstein-rational-rank/VERIFY.json b/research/eisenstein-rational-rank/VERIFY.json new file mode 100644 index 0000000000..f585f976c4 --- /dev/null +++ b/research/eisenstein-rational-rank/VERIFY.json @@ -0,0 +1,50 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [ + "research/eisenstein-clique-copy-bound/geometry.py", + "research/eisenstein-integer-rank/integer_rank.py", + "research/eisenstein-reduction-copy-floor/verify.py" + ], + "commands": [ + { + "argv": [ + "{python}", + "-W", + "error", + "-I", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 60, + "checks": "All 209 actual Q-rank calls, unchanged full stdout and seven original controls, 1798 independent minor cases and eight arithmetic controls." + }, + { + "argv": [ + "{python}", + "-W", + "error", + "-I", + "-O", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 60, + "checks": "Same checks with optimized Python and explicit invariant failures." + }, + { + "argv": [ + "{python}", + "-W", + "error", + "-I", + "-B", + "{package}/integrity.py" + ], + "timeout_seconds": 60, + "checks": "Both complete modes in a Git-free copy, unchanged input hashes and three source corruptions rejected before import." + } + ] +} diff --git a/research/eisenstein-rational-rank/benchmark.py b/research/eisenstein-rational-rank/benchmark.py new file mode 100644 index 0000000000..b47b473cfb --- /dev/null +++ b/research/eisenstein-rational-rank/benchmark.py @@ -0,0 +1,95 @@ +"""Measure one complete, authenticated fixture; write only a new external file.""" + +import argparse +import hashlib +import json +from pathlib import Path +import platform +import statistics +import subprocess +import sys +import time + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +import replay +from rational_rank import rank, require +from verify import capture_fixture, fixture_digest + + +def full_sample(mode, expected): + command = [sys.executable, "-W", "error", "-I", "-O", "-B", str(HERE / "replay.py")] + if mode == "baseline": + command.append("--original") + start = time.perf_counter() + done = subprocess.run(command, capture_output=True, timeout=30, check=False) + elapsed = time.perf_counter() - start + require(done.returncode == 0 and not done.stderr, "timed replay failed") + require(done.stdout == expected, "timed complete output differs") + return elapsed + + +def kernel_sample(mode, matrices, expected, original): + start = time.perf_counter() + if mode == "baseline": + results = [original(matrix, "Q") for matrix in matrices] + else: + results = [rank(matrix) for matrix in matrices] + elapsed = time.perf_counter() - start + require(results == expected, "timed Q results differ") + return elapsed + + +def summarize(samples): + return {mode: {"median": statistics.median(values), "min": min(values), "max": max(values)} + for mode, values in samples.items()} + + +def measurements(pairs): + matrices, expected_ranks, output = capture_fixture() + original, _ = replay.load() + full = {"baseline": [], "integer": []} + kernels = {"baseline": [], "integer": []} + order = [] + for pair in range(pairs + 1): + modes = ("baseline", "integer") if pair % 2 == 0 else ("integer", "baseline") + for mode in modes: + elapsed = full_sample(mode, output.encode()) + kernel = kernel_sample(mode, matrices, expected_ranks, original.rank) + if pair: + full[mode].append(elapsed) + kernels[mode].append(kernel) + order.append([pair, mode]) + full_summary, kernel_summary = summarize(full), summarize(kernels) + ratio = full_summary["baseline"]["median"] / full_summary["integer"]["median"] + return {"full_seconds": full, "Q_seconds": kernels, "order": order, + "full_summary": full_summary, "Q_summary": kernel_summary, "full_speed_ratio": ratio, + "Q_call_digest": fixture_digest(matrices, expected_ranks), + "complete_stdout_sha256": hashlib.sha256(output.encode()).hexdigest(), + "rank_calls_per_complete_run": replay.EXPECTED_CALLS, "errors": 0, + "pairs": pairs, "discarded_warmup_pairs": 1} + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--output", type=Path, required=True) + parser.add_argument("--pairs", type=int, default=6) + args = parser.parse_args() + require(5 <= args.pairs <= 12, "use five through twelve timing pairs") + destination = args.output.resolve() + require(not destination.is_relative_to(replay.ROOT), "timing output must be outside checkout") + require(not destination.exists(), "timing output must be new") + result = measurements(args.pairs) + result.update({"python": platform.python_version(), "platform": platform.platform(), + "machine": platform.machine(), "interpreter": sys.executable, + "adapter_sha256": {name: hashlib.sha256((HERE / name).read_bytes()).hexdigest() + for name in ("rational_rank.py", "replay.py", "benchmark.py", "verify.py")}, + "scope": "Same complete fixture and K adapter; only Q-rank changes. Fresh-process wall time includes imports and source authentication. Kernel samples execute all 209 actual matrices. Shared-host load is uncontrolled; no universal speed guarantee."}) + with destination.open("x", encoding="utf-8") as handle: + handle.write(json.dumps(result, indent=2, sort_keys=True) + "\n") + print(json.dumps({"full": result["full_summary"], "Q": result["Q_summary"], + "ratio": result["full_speed_ratio"], "errors": result["errors"]}, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/research/eisenstein-rational-rank/integrity.py b/research/eisenstein-rational-rank/integrity.py new file mode 100644 index 0000000000..d784141765 --- /dev/null +++ b/research/eisenstein-rational-rank/integrity.py @@ -0,0 +1,61 @@ +"""Run both modes without Git and reject changed live sources before import.""" + +import hashlib +import json +from pathlib import Path +import shutil +import subprocess +import sys +import tempfile + +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[1] +PACKAGE = "research/eisenstein-rational-rank" +sys.path.insert(0, str(HERE)) +from rational_rank import require + + +def execute(root, original=False): + command = [sys.executable, "-W", "error", "-I", "-O", "-B", str(root / PACKAGE / "replay.py")] + if original: + command.append("--original") + return subprocess.run(command, cwd=root, capture_output=True, timeout=30, check=False) + + +def hashes(root, paths): + return {p: hashlib.sha256((root / p).read_bytes()).hexdigest() for p in paths} + + +def main(): + manifest = json.loads((HERE / "VERIFY.json").read_text()) + inputs = manifest["inputs"] + require(len(inputs) == 3, "complete three-file executable dependency set") + local = [PACKAGE + "/" + p.name for p in HERE.iterdir() if p.is_file()] + paths = sorted(local + inputs) + with tempfile.TemporaryDirectory(prefix="eisenstein-rational-integrity-") as directory: + root = Path(directory) + for name in paths: + destination = root / name + destination.parent.mkdir(parents=True, exist_ok=True) + shutil.copyfile(ROOT / name, destination) + before = hashes(root, paths) + baseline, changed = execute(root, True), execute(root) + require(baseline.returncode == changed.returncode == 0, "Git-free replay failed") + require(not baseline.stderr and not changed.stderr, "Git-free replay warning") + require(baseline.stdout == changed.stdout, "Git-free complete output differs") + require(hashes(root, paths) == before, "Git-free replay changed input files") + for name in inputs: + source = root / name + raw = source.read_bytes() + source.write_bytes(raw + b"\n# changed source\n") + failed = execute(root) + require(failed.returncode != 0, "changed source accepted") + require(("source SHA: " + name).encode() in failed.stderr, + "changed source was not rejected before import") + source.write_bytes(raw) + require(hashes(root, paths) == before, "source control did not restore private copy") + print("PASS_EISENSTEIN_RATIONAL_INTEGRITY git_free_modes=2 source_controls=3") + + +if __name__ == "__main__": + main() diff --git a/research/eisenstein-rational-rank/rational_rank.py b/research/eisenstein-rational-rank/rational_rank.py new file mode 100644 index 0000000000..20911923bd --- /dev/null +++ b/research/eisenstein-rational-rank/rational_rank.py @@ -0,0 +1,65 @@ +"""Exact rational rank using primitive integer rows. + +Produced by Nick Petalas. Apache-2.0. Row-content elimination is classical. +""" + +from fractions import Fraction +from math import gcd, lcm + +MAX_DIMENSION = 96 +MAX_INPUT_BITS = 128 +MAX_ROW_BITS = 4096 + + +def require(condition, message): + if not condition: + raise ValueError(message) + + +def primitive(row): + require(all(abs(x).bit_length() <= MAX_ROW_BITS for x in row), + "integer row exceeds bit capacity") + content = gcd(*row) + return [x // content for x in row] if content > 1 else row + + +def integer_rows(matrix): + require(isinstance(matrix, (list, tuple)), "matrix must be a sequence") + require(len(matrix) <= MAX_DIMENSION, "too many rows") + width = len(matrix[0]) if matrix else 0 + require(width <= MAX_DIMENSION, "too many columns") + rows = [] + for row in matrix: + require(isinstance(row, (list, tuple)) and len(row) == width, "ragged matrix") + denominator = 1 + for value in row: + require(type(value) in (int, Fraction), "entries must be exact rationals") + require(max(abs(value.numerator).bit_length(), value.denominator.bit_length()) + <= MAX_INPUT_BITS, "rational entry exceeds bit capacity") + denominator = lcm(denominator, value.denominator) + require(denominator.bit_length() <= MAX_ROW_BITS, "row denominator too large") + rows.append(primitive([x.numerator * (denominator // x.denominator) for x in row])) + return rows, width + + +def rank(matrix): + """Return Q-rank without changing the input; reject capacity exhaustion.""" + rows, width = integer_rows(matrix) + pivot = 0 + for column in range(width): + found = next((i for i in range(pivot, len(rows)) if rows[i][column]), None) + if found is None: + continue + rows[pivot], rows[found] = rows[found], rows[pivot] + leading = rows[pivot][column] + require(leading != 0, "zero pivot") + for i in range(pivot + 1, len(rows)): + factor = rows[i][column] + if factor: + tail = [leading * x - factor * y + for x, y in zip(rows[i][column + 1:], rows[pivot][column + 1:])] + rows[i] = [0] * (column + 1) + primitive(tail) + pivot += 1 + if pivot == len(rows): + break + return pivot diff --git a/research/eisenstein-rational-rank/replay.py b/research/eisenstein-rational-rank/replay.py new file mode 100644 index 0000000000..d6613af0f7 --- /dev/null +++ b/research/eisenstein-rational-rank/replay.py @@ -0,0 +1,75 @@ +"""Optional complete replay, keeping the predecessor K adapter in both modes.""" + +import argparse +import hashlib +import importlib.util +import json +from pathlib import Path +import sys + +HERE = Path(__file__).resolve().parent +ROOT = HERE.parents[1] +sys.path.insert(0, str(HERE)) +from rational_rank import rank, require + +SOURCE = "research/eisenstein-reduction-copy-floor/verify.py" +K_SOURCE = "research/eisenstein-integer-rank/integer_rank.py" +EXPECTED_CALLS = {"K": 359, "F4": 311, "Q": 209} + + +def authenticate(): + manifest = json.loads((HERE / "SOURCES.json").read_text()) + for row in manifest["files"]: + if row["usage"] == "input": + raw = (ROOT / row["path"]).read_bytes() + require(hashlib.sha256(raw).hexdigest() == row["sha256"], "source SHA: " + row["path"]) + blob = hashlib.sha1(b"blob " + str(len(raw)).encode() + b"\0" + raw).hexdigest() + require(blob == row["git_blob"], "source blob: " + row["path"]) + + +def load_module(name, path): + specification = importlib.util.spec_from_file_location(name, path) + require(specification is not None and specification.loader is not None, "missing loader") + module = importlib.util.module_from_spec(specification) + specification.loader.exec_module(module) + return module + + +def load(): + authenticate() + return load_module("original_floor", ROOT / SOURCE), load_module("integer_k_rank", ROOT / K_SOURCE) + + +def install(old, k_engine, original_mode=False): + original = old.rank + calls = dict.fromkeys(EXPECTED_CALLS, 0) + + def dispatch(matrix, field="K"): + require(field in calls, "unexpected coefficient field") + calls[field] += 1 + if field == "K": + return k_engine.rank(matrix) + if field == "Q" and not original_mode: + return rank(matrix) + return original(matrix, field) + + old.rank = dispatch + return calls + + +def execute(original_mode=False): + old, k_engine = load() + calls = install(old, k_engine, original_mode) + old.main() + require(calls == EXPECTED_CALLS, "complete rank-call coverage changed") + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--original", action="store_true", help="retain original Q-rank") + args = parser.parse_args() + execute(args.original) + + +if __name__ == "__main__": + main() diff --git a/research/eisenstein-rational-rank/verify.py b/research/eisenstein-rational-rank/verify.py new file mode 100644 index 0000000000..7dbd5f1b97 --- /dev/null +++ b/research/eisenstein-rational-rank/verify.py @@ -0,0 +1,156 @@ +"""Check the new arithmetic and unchanged complete replay, not the floor proof.""" + +from contextlib import redirect_stdout +from copy import deepcopy +from fractions import Fraction +import hashlib +from itertools import combinations, product, permutations +import io +import json +from pathlib import Path +from random import Random +import sys + +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) +import rational_rank +import replay +from rational_rank import require + + +def determinant(matrix): + """Independent Leibniz determinant for orders at most three.""" + size = len(matrix) + require(size <= 3, "minor oracle capacity") + answer = Fraction(0) + for order in permutations(range(size)): + inversions = sum(order[i] > order[j] for i in range(size) for j in range(i + 1, size)) + term = Fraction((-1) ** inversions) + for i in range(size): + term *= matrix[i][order[i]] + answer += term + return answer + + +def minor_rank(matrix): + height, width = len(matrix), len(matrix[0]) if matrix else 0 + require(max(height, width) <= 3, "small-minor oracle capacity") + for size in range(min(height, width), 0, -1): + for rows in combinations(range(height), size): + for cols in combinations(range(width), size): + if determinant([[matrix[i][j] for j in cols] for i in rows]): + return size + return 0 + + +def arithmetic_checks(): + count = 0 + alphabet = (Fraction(-1, 2), Fraction(0), Fraction(2, 3)) + shapes = ((0, 0), (2, 0), (1, 1), (1, 3), (3, 1), (2, 2), (2, 3), (3, 2)) + for height, width in shapes: + for values in product(alphabet, repeat=height * width): + matrix = [list(values[i * width:(i + 1) * width]) for i in range(height)] + original = deepcopy(matrix) + require(rational_rank.rank(matrix) == minor_rank(matrix), "independent minor rank") + require(matrix == original, "arithmetic input was modified") + count += 1 + rng = Random(2627) + for _ in range(200): + matrix = [[Fraction(rng.randrange(-9, 10), rng.randrange(1, 10)) for _ in range(3)] + for _ in range(3)] + require(rational_rank.rank(matrix) == minor_rank(matrix), "rational 3-by-3 minor rank") + count += 1 + return count + + +def rejection_checks(): + invalid = ([[1], [1, 2]], [[0.5]], [[True]], [[1 << 129]], [[0] * 97], [[0]] * 97) + count = 0 + for matrix in invalid: + try: + rational_rank.rank(matrix) + except ValueError: + count += 1 + else: + raise ValueError("invalid matrix accepted") + try: + rational_rank.primitive([1 << 4097]) + except ValueError: + count += 1 + else: + raise ValueError("integer row exhaustion accepted") + return count + + +def capture_fixture(): + old, k_engine = replay.load() + original = old.rank + calls = dict.fromkeys(replay.EXPECTED_CALLS, 0) + matrices, ranks = [], [] + + def capture(matrix, field="K"): + calls[field] += 1 + result = k_engine.rank(matrix) if field == "K" else original(matrix, field) + if field == "Q": + saved = deepcopy(matrix) + require(rational_rank.rank(matrix) == result, "actual rational rank differs") + require(saved == matrix, "actual input was modified") + matrices.append(saved) + ranks.append(result) + return result + + old.rank = capture + output = io.StringIO() + with redirect_stdout(output): + old.main() + require(calls == replay.EXPECTED_CALLS, "complete actual-call census") + return matrices, ranks, output.getvalue() + + +def fixture_digest(matrices, ranks): + census = [[[[str(value) for value in row] for row in matrix], result] + for matrix, result in zip(matrices, ranks)] + raw = json.dumps(census, separators=(",", ":"), sort_keys=True).encode() + return hashlib.sha256(raw).hexdigest() + + +def full_checks(expected): + output = io.StringIO() + with redirect_stdout(output): + replay.execute() + require(output.getvalue() == expected, "complete replay stdout differs") + marker = "PASS_EISENSTEIN_REDUCTION_COPY_FLOOR: sharp abstract scalar cost 40" + require(expected.endswith(marker + "\n"), "complete source marker missing") + receipt = json.loads(expected[:expected.rfind(marker)]) + require(len(receipt["negative_controls"]) == 7, "original rejection controls missing") + previous = replay.rank + replay.rank = lambda matrix: 0 + try: + output = io.StringIO() + try: + with redirect_stdout(output): + replay.execute() + except ValueError: + return 1 + raise ValueError("wrong rational-rank adapter survived the original checks") + finally: + replay.rank = previous + + +def main(): + arithmetic = arithmetic_checks() + rejected = rejection_checks() + matrices, ranks, expected = capture_fixture() + mutations = full_checks(expected) + report = {"arithmetic_cases": arithmetic, "invalid_input_controls": rejected, + "wrong_adapter_controls": mutations, "rank_calls": replay.EXPECTED_CALLS, + "Q_call_digest": fixture_digest(matrices, ranks), + "complete_stdout_sha256": hashlib.sha256(expected.encode()).hexdigest(), + "files": {p.name: hashlib.sha256(p.read_bytes()).hexdigest() + for p in sorted(HERE.iterdir()) if p.is_file()}} + print(json.dumps(report, indent=2, sort_keys=True)) + print("PASS_EISENSTEIN_RATIONAL_RANK") + + +if __name__ == "__main__": + main()