diff --git a/certificates/disjoint-tensor-compression.json b/certificates/disjoint-tensor-compression.json index a24b0c9af4..36b0056f99 100644 --- a/certificates/disjoint-tensor-compression.json +++ b/certificates/disjoint-tensor-compression.json @@ -342,7 +342,7 @@ "scripts/binary_phase_frames.py": "4148cfa313cf050ed25296e8db36d35871520b8318fd086c7d1facf0c6af67d7", "scripts/complex_compression.py": "9b6f758a5985ba5d9fdd726fe6556b3d3b4bd9d98aaf8ba06a7bb58093c4c504", "scripts/exclusion_circuit.py": "f9fbcd6e85e442cbd0926ac0887414e20735b2dc923d2d5822c803ceb46726d3", - "scripts/experiments/disjoint_tensor.py": "085600fc922ae167b5981505e1a5caba4d1c1df15482f61d83d2c086fa89eac1" + "scripts/experiments/disjoint_tensor.py": "23763a4b6086fb3d19f9282fff5c118f53fa52e7a7f17da1bde990bd4cf8b6ac" }, "status": "IMPROVED FINITE COMPLEX NETWORK; NO NEW MULTIPLICATION KAPPA", "upstream_commit": "adc7f1241b42e322a6451854ab7e4b4c146bf78a" diff --git a/certificates/dyadic-central-factor.json b/certificates/dyadic-central-factor.json index 5bd4e583cd..d4cebc6a40 100644 --- a/certificates/dyadic-central-factor.json +++ b/certificates/dyadic-central-factor.json @@ -103,7 +103,7 @@ "scripts/complex_compression.py": "9b6f758a5985ba5d9fdd726fe6556b3d3b4bd9d98aaf8ba06a7bb58093c4c504", "scripts/exclusion_circuit.py": "f9fbcd6e85e442cbd0926ac0887414e20735b2dc923d2d5822c803ceb46726d3", "scripts/experiments/complex_centers.py": "3744396587d729253d80980f6310b56e7bf0ea21b165bd178d0d6d4c49faf2e2", - "scripts/experiments/disjoint_tensor.py": "085600fc922ae167b5981505e1a5caba4d1c1df15482f61d83d2c086fa89eac1", + "scripts/experiments/disjoint_tensor.py": "23763a4b6086fb3d19f9282fff5c118f53fa52e7a7f17da1bde990bd4cf8b6ac", "scripts/general_network_guard.py": "790a2064449afdbffd6dbd4adbcf4a28eaf41931ce7134e4a4e8766f3764270c" }, "status": "COMPLEX INTERFACE HEADROOM; RETAINED KAPPA 2^-31", diff --git a/certificates/parity-side.json b/certificates/parity-side.json index bcc1a78412..9bf31edd67 100644 --- a/certificates/parity-side.json +++ b/certificates/parity-side.json @@ -120,7 +120,7 @@ "docs/research/parity-side.md": "75de20f8dcd3d1a2e2d19bc087eda50a6cc77027651f48198868426a80cd12f2", "scripts/audit_parity_side.py": "7cbdd405ce11fa6f7ffcbef3811174f8685ad4640e9330176601d3b3d3e95390", "scripts/binary_phase_frames.py": "4148cfa313cf050ed25296e8db36d35871520b8318fd086c7d1facf0c6af67d7", - "scripts/experiments/disjoint_tensor.py": "085600fc922ae167b5981505e1a5caba4d1c1df15482f61d83d2c086fa89eac1", + "scripts/experiments/disjoint_tensor.py": "23763a4b6086fb3d19f9282fff5c118f53fa52e7a7f17da1bde990bd4cf8b6ac", "scripts/experiments/mixed_point_circuit.py": "f509362b5031976a22af351fd158ae0b4520fa4f286a5176ec37023d672a7ddc", "scripts/experiments/parity_phase_repair.py": "1f76f3b96ed556ed901835bd101d0e2588c997d2ed39bdfca097f0187aa86d40", "scripts/experiments/parity_side.py": "1363ebf82d4c39e458e7bede8253688271008374db70ed4284df84253c8d092b" diff --git a/certificates/ternary-side.json b/certificates/ternary-side.json index b2c1b793e7..314373fb7a 100644 --- a/certificates/ternary-side.json +++ b/certificates/ternary-side.json @@ -1564,7 +1564,7 @@ "scripts/audit_ternary_side.py": "5e86566eee32031e1829d26ea17a7372e4802e2f7d76a2caa3ae16de3ab072c1", "scripts/certify.py": "2348d95008276c5d5764f7e028c3918e484582cd589bd4d9b82919161745e53e", "scripts/exclusion_circuit.py": "f9fbcd6e85e442cbd0926ac0887414e20735b2dc923d2d5822c803ceb46726d3", - "scripts/experiments/disjoint_tensor.py": "085600fc922ae167b5981505e1a5caba4d1c1df15482f61d83d2c086fa89eac1", + "scripts/experiments/disjoint_tensor.py": "23763a4b6086fb3d19f9282fff5c118f53fa52e7a7f17da1bde990bd4cf8b6ac", "scripts/experiments/prime_core.py": "080a89a2c91505b509068698542843c9d7af3cdec01b5c88972107dc9c688c62", "scripts/experiments/rank_product_core.py": "7a91c1188c5d42e864a5d2e42397b09c435b526ae4f4210c44bf615de488708e", "scripts/experiments/shared_core.py": "d3c59b61229956cb54ae1ef9145ed213abdf1ae743929de145a77c43656f01a8", diff --git a/research/disjoint-tensor-frame-unions/NOTICE.md b/research/disjoint-tensor-frame-unions/NOTICE.md new file mode 100644 index 0000000000..863f741c2a --- /dev/null +++ b/research/disjoint-tensor-frame-unions/NOTICE.md @@ -0,0 +1,13 @@ +# Notice — disjoint-tensor frame unions + +Douglas R. Colkitt authored the disjoint-tensor compression screen, the +`DisjointTensor` recurrence, embedding and original `frame_data` / +`verify_frames` checkers consumed by this tooling package. + +Stephan Arrington’s `research/disjoint-frame-unions/` (#1044) proved the exact +target-union propagation algebra as an opt-in adapter with identical +historical-certificate bytes. This package promotes that algebra into the +default production `DisjointTensor.frame_data` path, with identical +`verify_frames` receipts and updated source pins only. + +Prepared by Wentao Li with substantial AI assistance, under Apache-2.0. diff --git a/research/disjoint-tensor-frame-unions/README.md b/research/disjoint-tensor-frame-unions/README.md new file mode 100644 index 0000000000..1e7401cd15 --- /dev/null +++ b/research/disjoint-tensor-frame-unions/README.md @@ -0,0 +1,112 @@ +# Faster DisjointTensor.frame_data with identical frame receipts + +**Tooling improvement; no new kappa.** At base +`0fdd7d82de03e43c9e5a1000dfbcd380d1b687d2`, merged +[CrocSwap/integer-mult-bounds#2001](https://github.com/CrocSwap/integer-mult-bounds/pull/2001) +left `DisjointTensor.verify_frames` / `frame_data` as an explicit next question +after shipping closed-form verify support masks. Profiling on the historical +full-size circuit (`h=26`, 60372 active nodes) shows about 1.8 of 2.2 seconds +of `verify_frames` inside the per-node reachable-target bit enumeration in +`frame_data`. + +[CrocSwap/integer-mult-bounds#1044](https://github.com/CrocSwap/integer-mult-bounds/pull/1044) +already proved exact target-union propagation as an **opt-in** adapter under +`research/disjoint-frame-unions/`. Production `scripts/experiments/disjoint_tensor.py` +still used the historical bit loop. This change promotes the same algebra into +the default path, keeps every descendant bitset, source union and rectangle +`require`, and leaves `verify_frames` receipts fieldwise identical. Only the +source pin for `scripts/experiments/disjoint_tensor.py` changes inside the four +certificates that bind that file. + +## Reproduce + +Python **3.12**, standard library only, from the repository root: + +```sh +python3.12 -I -B research/disjoint-tensor-frame-unions/verify.py +python3.12 -I -O -B research/disjoint-tensor-frame-unions/verify.py +python3.12 -B scripts/research_package.py --package research/disjoint-tensor-frame-unions +python3.12 -I -B research/disjoint-tensor-frame-unions/benchmark.py --rounds 5 +``` + +Expected: + +```text +PASS_DISJOINT_TENSOR_FRAME_UNIONS frame_cases=6 map_cases=6 certs=4 no_new_kappa +PASS_REGISTERED_RESEARCH_PACKAGE research/disjoint-tensor-frame-unions outcome=completed +PASS_IDENTICAL_DISJOINT_TENSOR_FRAME_UNION_RECEIPTS +``` + +Default verify is read-only. Full `make verify`, selected cold replay, Lean, and +multiplication-theorem obligations were not rerun for this isolated +historical-checker change. + +## Result + +On Linux / CPython 3.12.3 (Linux-6.12.94+-x86_64-with-glibc2.39), five +alternating fresh-process pairs timing only `DisjointTensor(26).verify_frames` +(construction excluded) gave median wall time **2.232 → 0.465 seconds (4.80×)**. +Timing is host-descriptive and is not a correctness gate; all samples and +environment pins are in [RESULT.json](RESULT.json). Every frame receipt matches +the baseline checker fieldwise (`distinct_nontrivial_transitions`, +`frame_types`, flags). + +## Equivalence + +For a node \(v\) let \(D(v)\) be its set of reachable output indices. If output +\(i\) has ground-coordinate mask \(T_i\), the historical loop computes + +```text +U(v) = OR_{i in D(v)} T_i +``` + +by walking bits of \(D(v)\). Define \(F(A)=\mathrm{OR}_{i\in A} T_i\). Then +\(F(\emptyset)=0\) and \(F(A\cup B)=F(A)\lor F(B)\). Initializing \(U\) at the +same output nodes as \(D\) and propagating \(U\) alongside \(D\) in the identical +reverse topological order yields \(U(v)=F(D(v))\) at every node. An XOR-of-mask +mutant cancels overlapping paths and is rejected by the package controls. +Rectangle checks still use `require`, so admission stays enforced under `-O`. + +## Open next questions + +1. **Question:** Should `DisjointTensor.verify`'s `dag_sha256` `json.dumps` path + get a hand-rolled formatter like the mixed-point / SharedPoint digests? + **Why it matters:** After support masks and frame_data, `json.dumps` remains a + secondary share of verify. + **First step:** Profile the post-mask verify residual and compare a + hand-rolled `[[i,args,str(support)]]` encoder against the committed digest. + **Blocked by:** Out of this session’s stop rule. + +2. **Question:** Can `research/disjoint-frame-unions` drop its opt-in monkeypatch + now that production `frame_data` matches the accelerator? + **Why it matters:** The adapter is redundant on main, but its + byte-for-byte historical certificate claim is a separate provenance object. + **First step:** Diff accelerator vs production and decide whether that + package becomes a pure historical replay fixture. + **Blocked by:** Do not reopen #1044’s certificate fixture in this PR. + +## Overlap and credit + +Closest priors (different objects or delivery): +[CrocSwap/integer-mult-bounds#756](https://github.com/CrocSwap/integer-mult-bounds/pull/756), +[CrocSwap/integer-mult-bounds#1044](https://github.com/CrocSwap/integer-mult-bounds/pull/1044) +(opt-in exact union propagation; this package promotes it to production), +[CrocSwap/integer-mult-bounds#1793](https://github.com/CrocSwap/integer-mult-bounds/pull/1793), +[CrocSwap/integer-mult-bounds#1861](https://github.com/CrocSwap/integer-mult-bounds/pull/1861), +[CrocSwap/integer-mult-bounds#1922](https://github.com/CrocSwap/integer-mult-bounds/pull/1922), +[CrocSwap/integer-mult-bounds#1984](https://github.com/CrocSwap/integer-mult-bounds/pull/1984), +[CrocSwap/integer-mult-bounds#1994](https://github.com/CrocSwap/integer-mult-bounds/pull/1994), +[CrocSwap/integer-mult-bounds#2001](https://github.com/CrocSwap/integer-mult-bounds/pull/2001) +(support masks + open `verify_frames` / `frame_data` question this answers). +Open [CrocSwap/integer-mult-bounds#2100](https://github.com/CrocSwap/integer-mult-bounds/pull/2100) +updates `ternary_side.py` inside `certificates/ternary-side.json`; this PR only +rewrites the `disjoint_tensor.py` pin in that shared JSON. +Open [CrocSwap/integer-mult-bounds#1861](https://github.com/CrocSwap/integer-mult-bounds/pull/1861) +updates `binary_phase_frames.py` inside `certificates/parity-side.json`; shared +JSON should carry both pins on merge. + +Douglas R. Colkitt authored the disjoint-tensor checkers. Stephan Arrington’s +#1044 supplied the opt-in union algebra. Prepared by Wentao Li +([VictorLiwentao](https://github.com/VictorLiwentao), +[@Is__Victor](https://x.com/Is__Victor)) with substantial AI assistance, under +Apache-2.0. diff --git a/research/disjoint-tensor-frame-unions/RESULT.json b/research/disjoint-tensor-frame-unions/RESULT.json new file mode 100644 index 0000000000..517da86c70 --- /dev/null +++ b/research/disjoint-tensor-frame-unions/RESULT.json @@ -0,0 +1,50 @@ +{ + "environment": { + "executable": "/usr/bin/python3.12", + "platform": "Linux-6.12.94+-x86_64-with-glibc2.39", + "python": "3.12.3 (main, Aug 31 2026, 10:18:26) [GCC 13.3.0]" + }, + "fixture": "DisjointTensor(26).verify_frames only (construction excluded)", + "median_baseline_seconds": 2.231777176000037, + "median_optimized_seconds": 0.4646116810000649, + "median_ratio": 4.8035322125267985, + "no_new_kappa": true, + "rounds": 5, + "samples": [ + { + "baseline_seconds": 2.132552615999998, + "optimized_seconds": 0.4646116810000649, + "ratio": 4.589967715425778, + "round": 0 + }, + { + "baseline_seconds": 2.1409860709999293, + "optimized_seconds": 0.44430533499996727, + "ratio": 4.818726903200671, + "round": 1 + }, + { + "baseline_seconds": 2.231777176000037, + "optimized_seconds": 0.44960231200002454, + "ratio": 4.9638916803433055, + "round": 2 + }, + { + "baseline_seconds": 2.450227195000025, + "optimized_seconds": 0.6052943949999872, + "ratio": 4.047992539233866, + "round": 3 + }, + { + "baseline_seconds": 2.325545840000018, + "optimized_seconds": 0.49189761000002363, + "ratio": 4.727703068124089, + "round": 4 + } + ], + "source_sha256": { + "baseline": "085600fc922ae167b5981505e1a5caba4d1c1df15482f61d83d2c086fa89eac1", + "production": "23763a4b6086fb3d19f9282fff5c118f53fa52e7a7f17da1bde990bd4cf8b6ac" + }, + "status": "PASS_IDENTICAL_DISJOINT_TENSOR_FRAME_UNION_RECEIPTS" +} diff --git a/research/disjoint-tensor-frame-unions/SOURCES.json b/research/disjoint-tensor-frame-unions/SOURCES.json new file mode 100644 index 0000000000..cbf168250b --- /dev/null +++ b/research/disjoint-tensor-frame-unions/SOURCES.json @@ -0,0 +1,84 @@ +{ + "schema_version": 1, + "base_commit": "0fdd7d82de03e43c9e5a1000dfbcd380d1b687d2", + "files": [ + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "e8870e5917057d59b730eb14721a778639eca050", + "sha256": "d46eb6d5b3e279428753d770653663fbdf1063e55c255ea073d768f344927ef7" + }, + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "ae6a99f28aa468649eb66a361e764d769363bf11", + "sha256": "10b9e340fd8e354a37a0c4813c90e5de1dd42044b5f6aca4a3fc5a42b685fa32" + }, + { + "path": "certificates/disjoint-tensor-compression.json", + "usage": "provenance", + "git_blob": "a24b0c9af473414fa87efa5a8d2b643d93e6fd01", + "sha256": "899950c322069ebf5a561a321c987906f8c11a592ca229143840901e4e370dd6" + }, + { + "path": "certificates/ternary-side.json", + "usage": "provenance", + "git_blob": "b2c1b793e7cb7e4d358b66bfd021d01c85371e19", + "sha256": "2ec667c52babb2a25820e8305538ef16399ab2ea12441d2e8130cc8e3fa13614" + }, + { + "path": "certificates/dyadic-central-factor.json", + "usage": "provenance", + "git_blob": "5bd4e583cd61b0e5183d74799e886afb57690960", + "sha256": "3f46000e645c338a583e0f2ab669a7c681980743d03335548eeb838072f1d458" + }, + { + "path": "certificates/parity-side.json", + "usage": "provenance", + "git_blob": "bcc1a78412d297424db1727f49636598206b9392", + "sha256": "44ab9d7b781a28228498aa0e73229c700eac4a3a3cf93ffe8f82f52f8c52226c" + }, + { + "path": "scripts/experiments/disjoint_tensor.py", + "usage": "provenance", + "git_blob": "b842d0a8d4f0f782a1f0bef171f5f2cd96878e58", + "sha256": "085600fc922ae167b5981505e1a5caba4d1c1df15482f61d83d2c086fa89eac1" + }, + { + "path": "scripts/audit_disjoint_tensor.py", + "usage": "provenance", + "git_blob": "08cb8184abcb7f81434395871152e4902df8cf84", + "sha256": "477db540e972b82751fac6a3a6d6e38fb4141e967261b1f9c260e2c686479a78" + }, + { + "path": "scripts/exclusion_circuit.py", + "usage": "provenance", + "git_blob": "b0e2f3e03d7de791ca936dfd92cee2134c7dd4f5", + "sha256": "f9fbcd6e85e442cbd0926ac0887414e20735b2dc923d2d5822c803ceb46726d3" + }, + { + "path": "scripts/binary_phase_frames.py", + "usage": "provenance", + "git_blob": "c8e4fa71fe60550324f9e43c1dd5ad6d9bf4e2f4", + "sha256": "4148cfa313cf050ed25296e8db36d35871520b8318fd086c7d1facf0c6af67d7" + }, + { + "path": "scripts/certify.py", + "usage": "provenance", + "git_blob": "a773311b726fd1ef98a056f6f76010e872d7908a", + "sha256": "2348d95008276c5d5764f7e028c3918e484582cd589bd4d9b82919161745e53e" + }, + { + "path": "research/disjoint-frame-unions/accelerator.py", + "usage": "provenance", + "git_blob": "e4bdd7e3aeb11b86e627b1227249188e4a1157ef", + "sha256": "4b90cdf10e864d6a477c43ded3b3025c38cdf82f6c819b0a055795c31ddd9a02" + }, + { + "path": "research/disjoint-tensor-support-masks/TASK.json", + "usage": "provenance", + "git_blob": "4c6d696123cbc21e08595d0b93ef4c97260d4cae", + "sha256": "5fe0c79417e7ac42b903db01774f788affff6f2f4b8f58dcbc55d1cda454665f" + } + ] +} diff --git a/research/disjoint-tensor-frame-unions/TASK.json b/research/disjoint-tensor-frame-unions/TASK.json new file mode 100644 index 0000000000..232f8628f3 --- /dev/null +++ b/research/disjoint-tensor-frame-unions/TASK.json @@ -0,0 +1,70 @@ +{ + "schema_version": 1, + "task_id": "replay-runtime", + "priority_revision": 3, + "base_commit": "0fdd7d82de03e43c9e5a1000dfbcd380d1b687d2", + "chooser_seed": "a4f19c82e6b0357d9148e2c0b5d67a31", + "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_baseline.py" + ], + "expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY", + "inspect": "Read the selected reproduction command and choose a single replay stage for profiling.", + "scope": "Positive control / source-bound orientation only; this is not a new construction or full cold replay." + }, + "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": "Can scripts/experiments/disjoint_tensor.py:DisjointTensor.frame_data replace its per-node reachable-target bit enumeration with equivalent exact target-union propagation (as proved opt-in in research/disjoint-frame-unions / #1044) so verify_frames receipts, descendant bitsets, source unions and rectangle require() checks stay fieldwise identical on the historical h=26 circuit?", + "scope_change_reason": "The catalogue card asks for one measured replay bottleneck with before/after wall time and retained checks. Expertise override selected verifier-engineering after merged #2001 left DisjointTensor.verify_frames / frame_data as an explicit open question; profiling named the historical bit-enumeration loop in frame_data (~1.8s of ~2.2s verify_frames on h=26) as the next unclaimed hot path. The #1044 opt-in adapter is not the default production path.", + "bottleneck_link": "Side result on review throughput: disjoint-tensor-compression, ternary-side, dyadic-central-factor and parity-side certificates call DisjointTensor.verify_frames. A faster identical frame_data does not change kappa or the binding complex supplier.", + "budget_minutes": 60, + "stop_rule": "Ship an equivalence-preserving production frame_data change with frozen baseline, identical verify_frames receipts on the historical h=26 circuit, updated source pins only on the four binding certificates, registered replay and a measured before/after median. Do not invent kappa, do not touch ternary_side.py / audit_joint_frames.py, and do not run the selected cold frontier replay.", + "outcome": "completed", + "evidence": "PASS_DISJOINT_TENSOR_FRAME_UNIONS via research/disjoint-tensor-frame-unions/verify.py (also under -O); PASS_IDENTICAL_DISJOINT_TENSOR_FRAME_UNION_RECEIPTS via benchmark.py; four certificates differ from base only in the scripts/experiments/disjoint_tensor.py source pin.", + "author": "Wentao Li", + "github": "VictorLiwentao", + "email": "wentaol4@illinois.edu", + "ai_assistance": "Substantial AI assistance for orientation, overlap search, profiling, implementation, packaging, benchmarking and writing. Not independent human peer review.", + "open_questions": [ + { + "question": "Should DisjointTensor.verify's dag_sha256 json.dumps path get a hand-rolled formatter like the mixed-point / SharedPoint digests?", + "why_it_matters": "After support masks and frame_data, json.dumps remains a secondary share of DisjointTensor.verify (~0.4s on h=26); a byte-identical encoder would be a different object.", + "first_step": "Profile the post-mask verify residual and compare a hand-rolled [[i,args,str(support)]] encoder against the committed dag_sha256.", + "blocked_by": "Out of this session's stop rule; frame_data / verify_frames was the measured bottleneck." + }, + { + "question": "Can research/disjoint-frame-unions drop its opt-in monkeypatch now that production frame_data matches the accelerator?", + "why_it_matters": "The historical complete-audit package still swaps DisjointTensor.frame_data at runtime; that adapter is redundant once main carries the same algebra, but its certificate byte-for-byte claim is a separate provenance object.", + "first_step": "Diff accelerator.frame_data against production and decide whether the opt-in package becomes a pure historical replay fixture.", + "blocked_by": "Out of this session's stop rule; do not reopen #1044's certificate fixture." + } + ] +} diff --git a/research/disjoint-tensor-frame-unions/VERIFY.json b/research/disjoint-tensor-frame-unions/VERIFY.json new file mode 100644 index 0000000000..609b99fa3c --- /dev/null +++ b/research/disjoint-tensor-frame-unions/VERIFY.json @@ -0,0 +1,58 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [ + "scripts/experiments/disjoint_tensor.py", + "scripts/audit_disjoint_tensor.py", + "scripts/exclusion_circuit.py", + "scripts/binary_phase_frames.py", + "scripts/certify.py", + "certificates/disjoint-tensor-compression.json", + "certificates/ternary-side.json", + "certificates/dyadic-central-factor.json", + "certificates/parity-side.json", + "tests/test_disjoint_tensor.py" + ], + "commands": [ + { + "argv": [ + "{python}", + "-I", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 300, + "checks": "Exact baseline copy of the base-commit disjoint_tensor.py; identical frame_data maps and verify_frames receipts on historical sizes through h=26; XOR target-union mutant rejected; rectangle require preserved; four certificates differ from base only in the disjoint_tensor.py source pin; no duplicate JSON keys." + }, + { + "argv": [ + "{python}", + "-I", + "-O", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 300, + "checks": "Same frame_data equivalence under -O. Rectangle and support gates use require and remain enforced; receipt identity remains the gate." + }, + { + "argv": [ + "{python}", + "-I", + "-B", + "-m", + "unittest", + "discover", + "-s", + "tests", + "-p", + "test_disjoint_tensor_frame_unions.py", + "-v" + ], + "timeout_seconds": 180, + "checks": "Focused disjoint-tensor frame-union package controls." + } + ] +} diff --git a/research/disjoint-tensor-frame-unions/baseline.py b/research/disjoint-tensor-frame-unions/baseline.py new file mode 100644 index 0000000000..b842d0a8d4 --- /dev/null +++ b/research/disjoint-tensor-frame-unions/baseline.py @@ -0,0 +1,256 @@ +"""Cancellation-free tensor contractions for disjoint-subset sums. + +The recurrence counts arithmetic DAG nodes, not rectangle memberships. +Expanded DAGs intern equal supports and are checked coefficient by coefficient. +""" +from functools import cache +from itertools import combinations +from math import comb +from hashlib import sha256 +import json + +from certify import require +from exclusion_circuit import ExclusionCircuit +from binary_phase_frames import nullspace, certify_chain + + +@cache +def plan(n, a, b): + require(0 <= a <= n and 0 <= b <= n, 'Invalid subset sizes') + if a+b > n: return (0, 'empty') + if not a: return (0, 'copy') + if not b: return (comb(n, a)-1, 'sum') + best = (comb(n, b)*(comb(n-b, a)-1), 'rows') + for left in range(1, n//2+1): + right = n-left; total = 0 + for j in range(max(0, b-right), min(left, b)+1): + parts = 0 + for i in range(max(0, a-right), min(left, a)+1): + if i+j > left or a-i+b-j > right: continue + A, B = plan(left, i, j)[0], plan(right, a-i, b-j)[0] + total += min(comb(right, a-i)*A+comb(left, j)*B, + comb(left, i)*B+comb(right, b-j)*A) + parts += 1 + if parts: total += comb(left, j)*comb(right, b-j)*(parts-1) + if total < best[0]: best = total, left + return best + + +@cache +def subsets(points, size): + return tuple(sum(1 << p for p in S) for S in combinations(points, size)) + + +class DisjointTensor(ExclusionCircuit): + def __init__(self, h, k=3, maximum_inputs=10000): + require(type(h) is int and type(k) is int and h >= 2*k and k >= 1, + 'Need a nonempty disjointness relation') + require(comb(h, k) <= maximum_inputs, 'Expansion budget exceeded') + self.h, self.k = h, k + self.inputs = list(subsets(tuple(range(h)), k)) + self.support = [0]+[1 << i for i in range(len(self.inputs))] + self.args = [None]*len(self.support) + self.lookup = {s:i for i, s in enumerate(self.support)} + self.variables = {S:i+1 for i, S in enumerate(self.inputs)} + self.outputs = self.transform(tuple(range(h)), k, k, self.variables) + self.active = set(); pending = list(self.outputs.values()) + while pending: + node = pending.pop() + if not node or node in self.active: continue + self.active.add(node) + if self.args[node]: pending.extend(self.args[node]) + self.additions = sum(self.args[node] is not None for node in self.active) + + def transform(self, points, a, b, values): + n = len(points); _, method = plan(n, a, b) + outputs = subsets(points, b) + if method == 'empty': return {T:0 for T in outputs} + if method == 'copy': return {T:values[0] for T in outputs} + if method == 'sum': return {0:self.total(list(values.values()))} + if method == 'rows': + return {T:self.total([values[S] for S in subsets(points, a) if not S&T]) + for T in outputs} + left, right = points[:method], points[method:] + l, r = len(left), len(right) + terms = {T:[] for T in outputs} + for j in range(max(0, b-r), min(l, b)+1): + for i in range(max(0, a-r), min(l, a)+1): + if i+j > l or a-i+b-j > r: continue + A, B = plan(l, i, j)[0], plan(r, a-i, b-j)[0] + if comb(r, a-i)*A+comb(l, j)*B <= comb(l, i)*B+comb(r, b-j)*A: + middle = {S:self.transform(left, i, j, + {R:values[R|S] for R in subsets(left, i)}) + for S in subsets(right, a-i)} + for T in subsets(left, j): + row = self.transform(right, a-i, b-j, {S:M[T] for S,M in middle.items()}) + for U, node in row.items(): terms[T|U].append(node) + else: + middle = {S:self.transform(right, a-i, b-j, + {R:values[R|S] for R in subsets(right, a-i)}) + for S in subsets(left, i)} + for T in subsets(right, b-j): + row = self.transform(left, i, j, {S:M[T] for S,M in middle.items()}) + for U, node in row.items(): terms[T|U].append(node) + return {T:self.total(nodes) for T,nodes in terms.items()} + + def verify(self): + for node in sorted(self.active): + if self.args[node]: + a, b = self.args[node] + require(a < node and b < node and not self.support[a]&self.support[b], + 'An addition uses cancellation or is not acyclic') + require(self.support[node] == self.support[a]|self.support[b], 'Wrong sum') + # Expected output support equals the full input mask with every input + # that meets T cleared. Equivalent to the historical genexpr + # sum(1< 6, 'The phase lemma here is for triples') + descendants, source_union, target_union = self.frame_data() + code = self.compile(); h = self.h; full = ('coordinate',(1 << h)-1) + empty = ('coordinate',0); checked = set(); types = {} + def space(frame): + kind, mask = frame + if kind == 'line': return (mask,) + if kind == 'complement': return nullspace((mask,),h) + return tuple(1 << i for i in range(h) if mask >> i & 1) + def transition(lower, upper): + if lower == upper: return + pair = lower, upper + if pair in checked: return + a,A = lower; b,B = upper + if a == 'coordinate' and b == 'coordinate': require(A&~B == 0,'Not nested coordinates') + elif a == 'line' and b == 'coordinate': require(A&~B == 0 and B&~A,'Missing residual unit') + elif a == 'coordinate' and b == 'line': require(A == 0,'Invalid line entry') + elif a == 'coordinate' and b == 'complement': + require(not A&B and ((1 << h)-1)&~(A|B),'Missing complement residual unit') + elif a == 'line' and b == 'complement': + require(not A&B and ((1 << h)-1)&~(A|B),'Missing two-line residual unit') + elif a == 'complement' and b == 'coordinate': require(B == (1 << h)-1,'Invalid complement exit') + else: require(False,'Unsupported phase transition') + if exact_bases: certify_chain((space(lower),space(upper))) + checked.add(pair) + for reverse in (False,True): + labels = {} + for node in sorted(self.active): + ns,nt = self.support[node].bit_count(),descendants[node].bit_count() + A,B = source_union[node],target_union[node] + if reverse: ns,nt,A,B = nt,ns,B,A + label = ('line',A) if ns == 1 else ('complement',B) if nt == 1 else ('coordinate',A) + labels[node] = label; types[label[0]] = types.get(label[0],0)+1 + physical = [empty]*code['roles'] + inputs = code['outputs'] if reverse else code['sources'] + outputs = code['sources'] if reverse else code['outputs'] + for S,slot in inputs.items(): + physical[slot] = ('line',S); transition(empty,physical[slot]) + gates = reversed(code['gates']) if reverse else code['gates'] + for node,ins,outs in gates: + label = labels[node] + for slot in set(ins+outs): transition(physical[slot],label); physical[slot] = label + for T,slot in outputs.items(): + target = ('complement',T); transition(physical[slot],target); physical[slot] = target + for old in physical: transition(old,full) + return dict(h=h,orientations=2,all_physical_transitions_checked=True, + distinct_nontrivial_transitions=len(checked),frame_types=types, + exact_residual_bases_constructed=exact_bases) + + +def complex_counts(h, disjoint_roles): + from fractions import Fraction as Q + require(h >= 8 and h%2 == 0 and disjoint_roles >= 0, 'Invalid complex ledger') + n = comb(h,3); N = n**3; m = h**3 + pair_roles = comb(h,2)*(4*(h-2)-6) + side = disjoint_roles+pair_roles; centers = h+1 + W = 2*N+2*n*n*(side+centers); L = 3*n*n*h*centers + delta = 2*N-2*L + return dict(h=h,v=n,N=N,m=m,disjoint_roles=disjoint_roles, + intersection_two_roles=pair_roles,side_roles=side,central_roles=centers, + W=W,L=L,s=W*m-delta,deficit=delta,eta=Q(delta,W*m)) + + +def scalar_program(circuit): + """Reuse the signed invocation interface with the new +1/2 side DAG.""" + from fractions import Fraction as Q + from complex_compression import LeaveOneCircuit + h = circuit.h + require(circuit.k == 3 and h >= 8 and h%2 == 0, 'Complex triple interface requires even h') + triples = list(combinations(range(h),3)) + index = {sum(1 << x for x in T):i for i,T in enumerate(triples)} + code = circuit.compile() + gates = [(ins,outs) for _,ins,outs in code['gates']] + sources = [(index[T],slot) for T,slot in code['sources'].items()] + outputs = [(index[T],slot,Q(1,2)) for T,slot in code['outputs'].items()] + offset = code['roles']; pair_code = LeaveOneCircuit(h-2).compile() + for pair in combinations(range(h),2): + rest = [i for i in range(h) if i not in pair] + def target(i): return index[sum(1 << x for x in (*pair,rest[i]))] + for _,ins,outs in pair_code['gates']: + gates.append((tuple(offset+i for i in ins),tuple(offset+i for i in outs))) + sources.extend((target(i),offset+slot) for i,slot in pair_code['sources'].items()) + outputs.extend((target(i),offset+slot,Q(-1,2)) for i,slot in pair_code['outputs'].items()) + offset += pair_code['roles'] + require(offset == complex_counts(h,code['roles'])['side_roles'], 'Wrong scalar role ledger') + return dict(h=h,triples=triples,gates=gates,sources=sources,outputs=outputs,roles=offset) diff --git a/research/disjoint-tensor-frame-unions/benchmark.py b/research/disjoint-tensor-frame-unions/benchmark.py new file mode 100644 index 0000000000..b7f81bca4f --- /dev/null +++ b/research/disjoint-tensor-frame-unions/benchmark.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 +"""Alternating fresh-process before/after timing for DisjointTensor.verify_frames. + +Timing is descriptive and never a correctness gate. Receipts must match +fieldwise between baseline and optimized workers. Circuit construction is +shared and excluded from the timed interval so the measurement isolates +frame_data / verify_frames. +""" +from __future__ import annotations + +import argparse +from hashlib import sha256 +import json +import os +from pathlib import Path +import platform +import statistics +import subprocess +import sys + +ROOT = Path(__file__).resolve().parents[2] +PACKAGE = Path(__file__).resolve().parent +sys.path.insert(0, str(ROOT / "scripts")) +from certify import require # noqa: E402 + +WORKER = r''' +import importlib.util +import json +import sys +import time +from pathlib import Path + +root = Path(sys.argv[1]) +mode = sys.argv[2] +sys.path.insert(0, str(root / "scripts")) + +if mode == "baseline": + spec = importlib.util.spec_from_file_location( + "baseline_dt", root / "research/disjoint-tensor-frame-unions/baseline.py" + ) + mod = importlib.util.module_from_spec(spec) + sys.modules["baseline_dt"] = mod + spec.loader.exec_module(mod) + DisjointTensor = mod.DisjointTensor +else: + from experiments.disjoint_tensor import DisjointTensor + +# Build the fixed historical full-size circuit outside the timed window. +circuit = DisjointTensor(26) + +t0 = time.perf_counter() +record = circuit.verify_frames() +elapsed = time.perf_counter() - t0 +print(json.dumps(dict(mode=mode, seconds=elapsed, record=record), sort_keys=True)) +''' + + +def run_worker(mode: str) -> dict: + env = dict(os.environ) + env.pop("PYTHONOPTIMIZE", None) + env["PYTHONDONTWRITEBYTECODE"] = "1" + proc = subprocess.run( + [sys.executable, "-I", "-B", "-c", WORKER, str(ROOT), mode], + cwd=ROOT, + env=env, + capture_output=True, + text=True, + check=False, + ) + require(proc.returncode == 0, f"worker {mode} failed: {proc.stderr[-2000:]}") + line = proc.stdout.strip().splitlines()[-1] + return json.loads(line) + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("--rounds", type=int, default=5) + parser.add_argument("--out", type=Path, default=PACKAGE / "RESULT.json") + args = parser.parse_args() + require(args.rounds >= 1, "rounds") + + samples = [] + for i in range(args.rounds): + order = ("optimized", "baseline") if i % 2 == 0 else ("baseline", "optimized") + pair = {} + for mode in order: + pair[mode] = run_worker(mode) + require( + pair["baseline"]["record"] == pair["optimized"]["record"], + f"receipt mismatch on round {i}", + ) + samples.append( + dict( + round=i, + baseline_seconds=pair["baseline"]["seconds"], + optimized_seconds=pair["optimized"]["seconds"], + ratio=pair["baseline"]["seconds"] / pair["optimized"]["seconds"], + ) + ) + print( + f"round {i}: baseline={pair['baseline']['seconds']:.3f}s " + f"optimized={pair['optimized']['seconds']:.3f}s " + f"ratio={samples[-1]['ratio']:.3f}", + flush=True, + ) + + base_med = statistics.median(s["baseline_seconds"] for s in samples) + opt_med = statistics.median(s["optimized_seconds"] for s in samples) + result = dict( + status="PASS_IDENTICAL_DISJOINT_TENSOR_FRAME_UNION_RECEIPTS", + fixture="DisjointTensor(26).verify_frames only (construction excluded)", + rounds=args.rounds, + median_baseline_seconds=base_med, + median_optimized_seconds=opt_med, + median_ratio=base_med / opt_med, + samples=samples, + environment=dict( + python=sys.version, + platform=platform.platform(), + executable=sys.executable, + ), + source_sha256=dict( + baseline=sha256((PACKAGE / "baseline.py").read_bytes()).hexdigest(), + production=sha256( + (ROOT / "scripts/experiments/disjoint_tensor.py").read_bytes() + ).hexdigest(), + ), + no_new_kappa=True, + ) + args.out.write_text(json.dumps(result, indent=2, sort_keys=True) + "\n") + print( + "PASS_IDENTICAL_DISJOINT_TENSOR_FRAME_UNION_RECEIPTS", + f"median {base_med:.3f} -> {opt_med:.3f} s ({base_med / opt_med:.2f}x)", + flush=True, + ) + + +if __name__ == "__main__": + main() diff --git a/research/disjoint-tensor-frame-unions/verify.py b/research/disjoint-tensor-frame-unions/verify.py new file mode 100644 index 0000000000..6d81d9c9f1 --- /dev/null +++ b/research/disjoint-tensor-frame-unions/verify.py @@ -0,0 +1,259 @@ +#!/usr/bin/env python3 +"""Equivalence, pin and mutation controls for DisjointTensor.frame_data. + +Read-only by default. Regenerates no certificate. Timing is not a pass gate; +see benchmark.py / RESULT.json. + +Promotes the exact target-union propagation proved as an opt-in adapter in +research/disjoint-frame-unions/ (#1044) into the default production path, with +identical verify_frames receipts. +""" +from __future__ import annotations + +import argparse +from copy import deepcopy +from hashlib import sha256 +import importlib.util +import json +from pathlib import Path +import subprocess +import sys + +ROOT = Path(__file__).resolve().parents[2] +PACKAGE = Path(__file__).resolve().parent +SCRIPTS = ROOT / "scripts" +sys.path.insert(0, str(SCRIPTS)) + +from certify import require # noqa: E402 +from experiments import disjoint_tensor as production # noqa: E402 + +BASE_COMMIT = "0fdd7d82de03e43c9e5a1000dfbcd380d1b687d2" +ORIGINAL_BLOB = "b842d0a8d4f0f782a1f0bef171f5f2cd96878e58" +ORIGINAL_SHA256 = "085600fc922ae167b5981505e1a5caba4d1c1df15482f61d83d2c086fa89eac1" +OPTIMIZED_SHA256 = "23763a4b6086fb3d19f9282fff5c118f53fa52e7a7f17da1bde990bd4cf8b6ac" + +PINNED_CERTIFICATES = ( + "certificates/disjoint-tensor-compression.json", + "certificates/ternary-side.json", + "certificates/dyadic-central-factor.json", + "certificates/parity-side.json", +) + +H26_FRAME_TYPES = {"line": 27430, "coordinate": 65884, "complement": 27430} +H26_TRANSITIONS = 195345 + + +def load_module(path: Path, name: str): + spec = importlib.util.spec_from_file_location(name, path) + require(spec is not None and spec.loader is not None, f"missing module {path}") + module = importlib.util.module_from_spec(spec) + sys.modules[name] = module + spec.loader.exec_module(module) + return module + + +def digest_file(path: Path) -> str: + return sha256(path.read_bytes()).hexdigest() + + +def git_show(path: str) -> bytes: + return subprocess.check_output(["git", "show", f"{BASE_COMMIT}:{path}"], cwd=ROOT) + + +def check_baseline_bytes() -> None: + baseline = PACKAGE / "baseline.py" + original = git_show("scripts/experiments/disjoint_tensor.py") + require(sha256(original).hexdigest() == ORIGINAL_SHA256, "base disjoint_tensor.py sha256 drift") + blob = ( + subprocess.check_output( + ["git", "rev-parse", f"{BASE_COMMIT}:scripts/experiments/disjoint_tensor.py"], + cwd=ROOT, + ) + .decode() + .strip() + ) + require(blob == ORIGINAL_BLOB, "base disjoint_tensor.py blob drift") + require(baseline.read_bytes() == original, "baseline.py must be an exact copy of the base commit source") + require( + digest_file(SCRIPTS / "experiments" / "disjoint_tensor.py") == OPTIMIZED_SHA256, + "production disjoint_tensor.py does not match the claimed optimized digest", + ) + + +def xor_mutant_target_unions(self): + """Deliberate mutant: XOR target unions instead of OR while propagating. + + Skips rectangle require so the foil can be compared even when XOR creates + empty or overlapping masks that the real checker would reject. + """ + descendants = {node: 0 for node in self.active} + target_union = {node: 0 for node in sorted(self.active)} + for i, T in enumerate(sorted(self.outputs)): + node = self.outputs[T] + descendants[node] |= 1 << i + target_union[node] ^= T # MUTATION + for node in sorted(self.active, reverse=True): + if self.args[node]: + for parent in self.args[node]: + descendants[parent] |= descendants[node] + target_union[parent] ^= target_union[node] # MUTATION + return descendants, target_union + + +def check_frame_equivalence(baseline, optimized) -> dict: + map_cases = 0 + frame_cases = 0 + records = [] + for h in (8, 10, 12, 16, 20, 26): + circuit = optimized.DisjointTensor(h) + old_maps = baseline.DisjointTensor.frame_data(circuit) + new_maps = circuit.frame_data() + require(old_maps == new_maps, f"frame_data maps mismatch on h={h}") + map_cases += 1 + old = baseline.DisjointTensor.verify_frames(circuit) + new = circuit.verify_frames() + require(old == new, f"verify_frames mismatch on h={h}") + frame_cases += 1 + records.append( + dict( + h=h, + distinct_nontrivial_transitions=new["distinct_nontrivial_transitions"], + frame_types=new["frame_types"], + exact_residual_bases_constructed=new["exact_residual_bases_constructed"], + ) + ) + require(records[-1]["distinct_nontrivial_transitions"] == H26_TRANSITIONS, "unexpected h=26 transitions") + require(records[-1]["frame_types"] == H26_FRAME_TYPES, "unexpected h=26 frame_types") + return {"map_cases": map_cases, "frame_cases": frame_cases, "records": records} + + +def check_xor_mutant_rejected(optimized) -> dict: + circuit = optimized.DisjointTensor(12) + descendants, _sources, targets = circuit.frame_data() + mutant_descendants, mutant_targets = xor_mutant_target_unions(circuit) + require(mutant_descendants == descendants, "xor-mutant must preserve descendant bitsets") + require(mutant_targets != targets, "xor-mutant target_union must differ on h=12") + return {"xor_mutant": "rejected", "h": 12} + + +def check_rectangle_rejection(baseline, optimized) -> dict: + circuit = optimized.DisjointTensor(10) + # Widen a leaf source mask so source_union meets its nonempty target_union. + leaf = min(n for n in circuit.active if circuit.args[n] is None) + circuit.inputs[leaf - 1] = (1 << circuit.h) - 1 + with _expect_value_error(): + optimized.DisjointTensor.frame_data(circuit) + with _expect_value_error(): + baseline.DisjointTensor.frame_data(circuit) + return {"rectangle_rejection": "preserved", "corrupted_h": 10} + + +class _expect_value_error: + def __enter__(self): + return self + + def __exit__(self, exc_type, exc, tb): + require(exc_type is ValueError, "expected ValueError from corrupted rectangle") + return True + + +def check_certificate_pin_discipline() -> dict: + """Certificates may update disjoint_tensor.py; companion pins stay as on base.""" + reports = {} + for rel in PINNED_CERTIFICATES: + base = json.loads(git_show(rel).decode()) + live = json.loads((ROOT / rel).read_text(encoding="utf-8")) + key = "scripts/experiments/disjoint_tensor.py" + base_pin = base["source_sha256"][key] + live_pin = live["source_sha256"][key] + require(base_pin == ORIGINAL_SHA256, f"{rel}: unexpected base pin") + require(live_pin == OPTIMIZED_SHA256, f"{rel}: optimized pin missing") + restored = deepcopy(live) + restored["source_sha256"][key] = ORIGINAL_SHA256 + require(restored == base, f"{rel}: changed fields beyond the disjoint_tensor.py source pin") + reports[rel] = { + "base_pin": base_pin, + "live_pin": live_pin, + "only_pin_changed": True, + } + return reports + + +def check_no_duplicate_json_keys() -> dict: + """Reject duplicate JSON object keys in live certificates (stdlib load keeps last).""" + import re + + key_re = re.compile(r'"([^\\"]*(?:\\.[^\\"]*)*)"\s*:') + checked = 0 + for rel in PINNED_CERTIFICATES: + text = (ROOT / rel).read_text(encoding="utf-8") + # Track keys per object nesting depth via a small scanner. + stack: list[set[str]] = [] + i = 0 + in_string = False + escape = False + while i < len(text): + ch = text[i] + if in_string: + if escape: + escape = False + elif ch == "\\": + escape = True + elif ch == '"': + in_string = False + i += 1 + continue + if ch == '"': + m = key_re.match(text, i) + if m and stack: + key = json.loads(f'"{m.group(1)}"') + require(key not in stack[-1], f"{rel}: duplicate JSON key {key!r}") + stack[-1].add(key) + i = m.end() + continue + in_string = True + i += 1 + continue + if ch == "{": + stack.append(set()) + elif ch == "}": + require(stack, f"{rel}: unbalanced }}") + stack.pop() + i += 1 + require(not stack, f"{rel}: unbalanced {{") + checked += 1 + return {"duplicate_key_files_checked": checked} + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("--write-certificate", action="store_true", help="unused; kept for API parity") + args = parser.parse_args() + require(not args.write_certificate, "this package does not rewrite certificate payloads") + + check_baseline_bytes() + baseline = load_module(PACKAGE / "baseline.py", "disjoint_tensor_frame_unions_baseline") + frames = check_frame_equivalence(baseline, production) + mutant = check_xor_mutant_rejected(production) + rejection = check_rectangle_rejection(baseline, production) + pins = check_certificate_pin_discipline() + keys = check_no_duplicate_json_keys() + print( + "PASS_DISJOINT_TENSOR_FRAME_UNIONS", + f"frame_cases={frames['frame_cases']}", + f"map_cases={frames['map_cases']}", + f"certs={len(pins)}", + "no_new_kappa", + ) + print( + "controls", + mutant["xor_mutant"], + rejection["rectangle_rejection"], + f"dup_key_files={keys['duplicate_key_files_checked']}", + f"h26_transitions={H26_TRANSITIONS}", + flush=True, + ) + + +if __name__ == "__main__": + main() diff --git a/research/disjoint-tensor-support-masks/verify.py b/research/disjoint-tensor-support-masks/verify.py index f5281b6822..5076b673b2 100644 --- a/research/disjoint-tensor-support-masks/verify.py +++ b/research/disjoint-tensor-support-masks/verify.py @@ -26,7 +26,7 @@ BASE_COMMIT = "0b1cccf86e2f5132ed286a26ef0a681a495740ea" ORIGINAL_BLOB = "dd196e67162c349d9b6f7aa27edbed2b1b0b601f" ORIGINAL_SHA256 = "102dd59bf96033f96ba0dab4c2aba77b3a7a73b67b0f96929ff8b20a98b91cd8" -OPTIMIZED_SHA256 = "085600fc922ae167b5981505e1a5caba4d1c1df15482f61d83d2c086fa89eac1" +OPTIMIZED_SHA256 = "23763a4b6086fb3d19f9282fff5c118f53fa52e7a7f17da1bde990bd4cf8b6ac" H26_DAG_SHA256 = "5da8011dadf51d6121d343416fa38b6b4bf524fd689e5b1b2def91324660f19b" PINNED_CERTIFICATES = ( diff --git a/research/exclusion-embedding-masks/verify.py b/research/exclusion-embedding-masks/verify.py index d280945bc5..20e45693f3 100644 --- a/research/exclusion-embedding-masks/verify.py +++ b/research/exclusion-embedding-masks/verify.py @@ -223,7 +223,7 @@ def check_certificate_pin_discipline() -> dict: """Certificates may update exclusion_circuit.py and companion disjoint_tensor.py pins.""" companion_key = "scripts/experiments/disjoint_tensor.py" companion_orig = "102dd59bf96033f96ba0dab4c2aba77b3a7a73b67b0f96929ff8b20a98b91cd8" - companion_opt = "085600fc922ae167b5981505e1a5caba4d1c1df15482f61d83d2c086fa89eac1" + companion_opt = "23763a4b6086fb3d19f9282fff5c118f53fa52e7a7f17da1bde990bd4cf8b6ac" reports = {} for rel in PINNED_CERTIFICATES: base = json.loads(git_show(rel).decode()) diff --git a/research/exclusion-support-masks/verify.py b/research/exclusion-support-masks/verify.py index 43b8396e11..c6b8d1f8c6 100644 --- a/research/exclusion-support-masks/verify.py +++ b/research/exclusion-support-masks/verify.py @@ -155,7 +155,7 @@ def check_certificate_pin_discipline() -> dict: """Certificates may update exclusion_circuit.py and companion disjoint_tensor.py pins.""" companion_key = "scripts/experiments/disjoint_tensor.py" companion_orig = "102dd59bf96033f96ba0dab4c2aba77b3a7a73b67b0f96929ff8b20a98b91cd8" - companion_opt = "085600fc922ae167b5981505e1a5caba4d1c1df15482f61d83d2c086fa89eac1" + companion_opt = "23763a4b6086fb3d19f9282fff5c118f53fa52e7a7f17da1bde990bd4cf8b6ac" reports = {} for rel in PINNED_CERTIFICATES: base = json.loads(git_show(rel).decode()) diff --git a/scripts/experiments/disjoint_tensor.py b/scripts/experiments/disjoint_tensor.py index b842d0a8d4..cc85de3024 100644 --- a/scripts/experiments/disjoint_tensor.py +++ b/scripts/experiments/disjoint_tensor.py @@ -142,23 +142,31 @@ def verify(self): dag_sha256=sha256(encoded).hexdigest()) def frame_data(self): - """Ancestor/reachable-target families and their ground-point unions.""" + """Ancestor/reachable-target families and their ground-point unions. + + Target ground-coordinate unions propagate alongside descendant bitsets + in the reverse topological pass. Union commutes with union, so the + mask at each node equals OR of target keys over exactly the same + reachable outputs as the historical bit-enumeration loop. Reachable + target bitsets, source unions and rectangle checks are unchanged. + """ descendants = {node:0 for node in self.active} - targets = sorted(self.outputs) - for i,T in enumerate(targets): descendants[self.outputs[T]] |= 1 << i + target_union = {node:0 for node in sorted(self.active)} + for i,T in enumerate(sorted(self.outputs)): + node = self.outputs[T] + descendants[node] |= 1 << i + target_union[node] |= T for node in sorted(self.active, reverse=True): if self.args[node]: - for parent in self.args[node]: descendants[parent] |= descendants[node] + for parent in self.args[node]: + descendants[parent] |= descendants[node] + target_union[parent] |= target_union[node] source_union = {} - target_union = {} for node in sorted(self.active): if self.args[node]: a,b = self.args[node]; source_union[node] = source_union[a]|source_union[b] else: source_union[node] = self.inputs[node-1] - bits = descendants[node]; union = 0 - while bits: - bit = bits&-bits; bits ^= bit; union |= targets[bit.bit_length()-1] - target_union[node] = union + union = target_union[node] require(union and not union&source_union[node], 'Node is not a disjoint rectangle') return descendants, source_union, target_union diff --git a/tests/test_disjoint_tensor_frame_unions.py b/tests/test_disjoint_tensor_frame_unions.py new file mode 100644 index 0000000000..607a50d0d7 --- /dev/null +++ b/tests/test_disjoint_tensor_frame_unions.py @@ -0,0 +1,58 @@ +"""Focused controls for production DisjointTensor.frame_data union propagation.""" +from __future__ import annotations + +import importlib.util +from pathlib import Path +import sys +import unittest + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT / "scripts")) + +from experiments.disjoint_tensor import DisjointTensor # noqa: E402 + + +def load_baseline(): + path = ROOT / "research/disjoint-tensor-frame-unions/baseline.py" + spec = importlib.util.spec_from_file_location("dt_frame_baseline", path) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod + + +class DisjointTensorFrameUnions(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.baseline = load_baseline() + + def test_frame_maps_and_receipts_match_baseline(self): + for h in (8, 10, 12, 16): + circuit = DisjointTensor(h) + self.assertEqual( + self.baseline.DisjointTensor.frame_data(circuit), + circuit.frame_data(), + ) + self.assertEqual( + self.baseline.DisjointTensor.verify_frames(circuit), + circuit.verify_frames(), + ) + + def test_h26_receipt_fields(self): + frames = DisjointTensor(26).verify_frames() + self.assertTrue(frames["all_physical_transitions_checked"]) + self.assertEqual(frames["distinct_nontrivial_transitions"], 195345) + self.assertEqual( + frames["frame_types"], + {"line": 27430, "coordinate": 65884, "complement": 27430}, + ) + + def test_corrupted_rectangle_rejected(self): + circuit = DisjointTensor(10) + leaf = min(n for n in circuit.active if circuit.args[n] is None) + circuit.inputs[leaf - 1] = (1 << circuit.h) - 1 + with self.assertRaises(ValueError): + circuit.frame_data() + + +if __name__ == "__main__": + unittest.main()