diff --git a/research/connector-depth-two-large-c/CERTIFICATE.json b/research/connector-depth-two-large-c/CERTIFICATE.json new file mode 100644 index 0000000000..18550500ca --- /dev/null +++ b/research/connector-depth-two-large-c/CERTIFICATE.json @@ -0,0 +1,432 @@ +{ + "schema_version": 2, + "interface": "PR #4231 unsigned dirty connector; PR #4248 prefix criterion over Z/c", + "depth": 2, + "rule": "A template (k, u, walk, cut) has each of k sources u times in walk. For every c >= u-1, replace the (cut[j]+1)-th event of source j by a run of c-u+1 copies of j (deleted at c=u-1).", + "templates": [ + { + "name": "six", + "sources": 6, + "base_multiplicity": 9, + "min_c": 8, + "walk": [ + 4, + 2, + 0, + 1, + 5, + 4, + 3, + 2, + 1, + 0, + 3, + 2, + 5, + 4, + 1, + 3, + 0, + 5, + 4, + 1, + 3, + 2, + 5, + 2, + 5, + 0, + 1, + 4, + 0, + 0, + 5, + 3, + 3, + 2, + 1, + 4, + 0, + 5, + 3, + 4, + 2, + 1, + 5, + 0, + 3, + 1, + 5, + 3, + 2, + 4, + 1, + 2, + 0, + 4 + ], + "cut": [ + 5, + 4, + 4, + 4, + 4, + 5 + ], + "search": "local simulated annealing, seed 9, 395,124 iterations, 28 s" + }, + { + "name": "seven", + "sources": 7, + "base_multiplicity": 13, + "min_c": 12, + "walk": [ + 3, + 1, + 0, + 2, + 4, + 3, + 6, + 2, + 5, + 5, + 4, + 6, + 2, + 1, + 5, + 0, + 4, + 6, + 1, + 0, + 3, + 4, + 5, + 0, + 3, + 2, + 1, + 4, + 5, + 0, + 6, + 2, + 5, + 3, + 1, + 0, + 3, + 2, + 6, + 4, + 1, + 6, + 3, + 0, + 1, + 5, + 6, + 1, + 6, + 4, + 6, + 2, + 4, + 2, + 1, + 3, + 5, + 0, + 6, + 3, + 0, + 2, + 4, + 1, + 5, + 3, + 0, + 2, + 5, + 4, + 6, + 1, + 3, + 0, + 2, + 5, + 4, + 0, + 1, + 4, + 3, + 6, + 5, + 2, + 6, + 5, + 0, + 4, + 2, + 1, + 3 + ], + "cut": [ + 6, + 7, + 7, + 6, + 7, + 6, + 6 + ], + "search": "local simulated annealing, one of two runs (seeds 131, 132), 962,992 iterations, 189.2 s" + }, + { + "name": "eight", + "sources": 8, + "base_multiplicity": 28, + "min_c": 27, + "walk": [ + 5, + 4, + 3, + 0, + 1, + 6, + 7, + 2, + 5, + 3, + 6, + 4, + 5, + 2, + 0, + 7, + 1, + 2, + 6, + 3, + 6, + 4, + 0, + 4, + 1, + 2, + 6, + 3, + 7, + 0, + 5, + 7, + 4, + 2, + 7, + 1, + 5, + 2, + 3, + 0, + 1, + 1, + 7, + 3, + 0, + 6, + 7, + 4, + 6, + 5, + 3, + 2, + 4, + 5, + 0, + 6, + 4, + 5, + 1, + 6, + 0, + 2, + 7, + 1, + 5, + 3, + 1, + 6, + 7, + 0, + 1, + 3, + 4, + 3, + 2, + 1, + 3, + 2, + 1, + 6, + 0, + 7, + 0, + 5, + 3, + 6, + 0, + 7, + 2, + 6, + 5, + 4, + 1, + 5, + 0, + 4, + 3, + 7, + 7, + 3, + 2, + 7, + 7, + 5, + 2, + 3, + 7, + 6, + 4, + 2, + 7, + 1, + 0, + 1, + 2, + 0, + 2, + 4, + 6, + 4, + 5, + 5, + 5, + 4, + 4, + 1, + 2, + 4, + 4, + 0, + 3, + 6, + 4, + 5, + 5, + 0, + 2, + 3, + 1, + 7, + 6, + 5, + 0, + 2, + 6, + 3, + 0, + 7, + 4, + 0, + 1, + 2, + 3, + 6, + 1, + 3, + 7, + 4, + 3, + 7, + 5, + 0, + 1, + 1, + 2, + 6, + 1, + 2, + 5, + 0, + 6, + 7, + 5, + 4, + 3, + 5, + 6, + 5, + 4, + 6, + 0, + 1, + 3, + 2, + 7, + 1, + 0, + 6, + 3, + 1, + 7, + 2, + 5, + 4, + 3, + 0, + 7, + 7, + 2, + 4, + 7, + 3, + 1, + 0, + 2, + 4, + 1, + 6, + 0, + 6, + 5, + 3, + 2, + 4, + 1, + 6, + 7, + 5, + 4, + 2, + 6, + 5, + 0, + 3 + ], + "cut": [ + 12, + 15, + 12, + 12, + 11, + 11, + 14, + 16 + ], + "search": "local simulated annealing, seed 28, 248,102 iterations, 229.2 s" + } + ], + "note": "The searches found the templates; they are not part of the proof. verify.py checks each template's integer identity, which is the only finite step the proof needs." +} diff --git a/research/connector-depth-two-large-c/README.md b/research/connector-depth-two-large-c/README.md new file mode 100644 index 0000000000..3c6877f3a7 --- /dev/null +++ b/research/connector-depth-two-large-c/README.md @@ -0,0 +1,212 @@ +# Unsigned connector: depth-two blocks on six, seven and eight sources for large c + +Take the unsigned dirty connector of +[#4231](https://github.com/CrocSwap/integer-mult-bounds/pull/4231) over a ring +of characteristic c, with k immutable sources and all 2^k − 1 nonzero +binary-mask outputs. Every legal word needs at least c(k + 2^k − 1) complete +calls, and N(c) is the largest k at which that floor is attained. +[#4248](https://github.com/CrocSwap/integer-mult-bounds/pull/4248) proved +N(c) ≥ 2c. Nick Petalas's +[#6035](https://github.com/CrocSwap/integer-mult-bounds/pull/6035) +(`research/connector-five-halves-growth`) gave a five-source depth-two block +in every c ≥ 5, so N(c) ≥ ⌊5c/2⌋. Its open question 1 asks whether any +characteristic has a depth-two block on six or more sources, valid for all +large c. + +This package answers it for large c: + +- **Theorem S.** There is a depth-two block on six sources in every + characteristic c ≥ 8, on seven sources in every c ≥ 12, and on eight + sources in every c ≥ 27. +- **Corollary.** N(c) ≥ k⌊c/2⌋ + 2(c mod 2) with k = 6 for c ≥ 8, k = 7 for + c ≥ 12 and k = 8 for c ≥ 27. + +So N(c) ≥ 3c for even c ≥ 8, N(c) ≥ 7c/2 for even c ≥ 12, and N(c) ≥ 4c for +even c ≥ 28. + +The claims are a scoped proof with a finite core, checked by a stdlib +verifier. There is no new κ, no consumer, no selected-frontier change and no +multiplication theorem. For c = 5, 6, 7 the six-source question is still open +(search notes below). Characteristic four is untouched: #4271 excludes +five-source depth-two blocks there. + +| c | #4248: 2c | #6035: ⌊5c/2⌋ | this package | +|---:|---:|---:|---:| +| 8 | 16 | 20 | **24** | +| 9 | 18 | 22 | **26** | +| 12 | 24 | 30 | **42** | +| 13 | 26 | 32 | **44** | +| 14 | 28 | 35 | **49** | +| 27 | 54 | 67 | **106** | +| 28 | 56 | 70 | **112** | + +Every value satisfies #4248's counting condition C(ck + c − 1, c) ≥ 2^k − 1; +the verifier checks this for 8 ≤ c ≤ 128. + +## 1. Interface and depth + +These are #4248's, as restated in #6035. A floor word has a source walk w of +length ck that uses each source exactly c times. Let q_t ∈ (Z/c)^k count +source events modulo c after t steps. The word is correct exactly when every +nonzero mask m has readout boundaries t_1 ≤ … ≤ t_c with +q_(t_1) + … + q_(t_c) = m in (Z/c)^k. A walk has **depth d** if every nonzero +mask is a sum of at most d prefixes. #4248's concatenation lemma joins walks +on disjoint source sets whose depths sum to at most c into a floor walk; +spare readouts go to boundary 0. Its deletion lemma makes the attaining set +of k an initial segment. + +## 2. Lifted templates with base multiplicity u + +#6035 uses a base walk with each source six times. The same argument works +with any base multiplicity u. A **template** (k, u, W, a) is a walk W on k +sources, each used u times, with cut positions 0 ≤ a_j < u. Let n_t(j) be the +number of events of source j among the first t events of W. The lifted prefix +L_t ∈ Z^k has L_t(j) = n_t(j) if n_t(j) ≤ a_j, and n_t(j) − u otherwise. + +**Template identity** (finite check). For every nonzero m ∈ {0,1}^k there are +base boundaries t_1 ≤ t_2 with L_(t_1) + L_(t_2) = m as integer vectors. + +**Expansion.** For c ≥ u − 1, form W_c by replacing the (a_j + 1)-th event of +each source j with a run of c − u + 1 copies of j. At c = u − 1 that event is +deleted. Each source then occurs (u − 1) + (c − u + 1) = c times. + +**Lemma.** If a template satisfies the identity, W_c has depth two on k +sources for every c ≥ u − 1. + +*Proof* (#6035's, with 6 replaced by u). Let τ(t) be the boundary of W_c that +follows the first t events of W, after the whole run if event t was +expanded. If n_t(j) ≤ a_j, the count of source j at τ(t) is n_t(j) = L_t(j). +Otherwise it is n_t(j) − 1 + (c − u + 1) = n_t(j) + c − u, which is L_t(j) +modulo c. So q_(τ(t)) ≡ L_t (mod c), and t_1 ≤ t_2 gives τ(t_1) ≤ τ(t_2). +For a mask with L_(t_1) + L_(t_2) = m in Z^k, reduction modulo c gives +q_(τ(t_1)) + q_(τ(t_2)) = m. ∎ + +**Theorem S** follows from the three templates in +[CERTIFICATE.json](CERTIFICATE.json): + +- k = 6, u = 9, a = (5, 4, 4, 4, 4, 5), a 54-event walk. Valid for c ≥ 8. +- k = 7, u = 13, a = (6, 7, 7, 6, 7, 6, 6), a 91-event walk. Valid for c ≥ 12. +- k = 8, u = 28, a = (12, 15, 12, 12, 11, 11, 14, 16), a 224-event walk. + Valid for c ≥ 27. + +The verifier checks the three identities (63, 127 and 255 masks) with integer +arithmetic. That is the only finite step the proof needs. + +**Corollary.** Concatenate ⌊c/2⌋ copies of the k-source block on disjoint +source sets. For odd c, append #4248's depth-one block a b a^(c−1) b^(c−1) on +two more sources. The depths sum to at most c, so the concatenation lemma +gives a floor walk on k⌊c/2⌋ + 2(c mod 2) sources, and the deletion lemma +covers every smaller k. + +## 3. What the verifier checks + +[verify.py](verify.py) uses only the standard library, imports no +predecessor code and runs in about 3 s. + +1. The three template identities, with integer arithmetic. +2. For every u − 1 ≤ c ≤ 64 (six and seven sources) and 27 ≤ c ≤ 40 (eight + sources): W_c uses each source c times, + every nonzero mask is a sum of two prefixes modulo c by direct search, and + each lifted readout pair maps through τ to a correct readout. This is a + control on the lemma, not part of the proof. +3. Eight literal floor words, simulated with generic coefficients over Z/c + as in #4248: one and two six-source blocks at c = 8 (6 and 12 sources), + two six-source blocks plus the pair block at c = 9 (14 sources), one and + two seven-source blocks at c = 12 (7 and 14 sources, up to 196,764 calls), + one seven-source block with the pair block at c = 13 (9 sources), and one + eight-source block alone and with the pair block at c = 27 (8 and 10 + sources). Every output must equal its mask, the connector must return to + its dirty value and every operator must be called exactly c times. The + full-size corollary words (24 sources at c = 8, for instance, with + 2^24 − 1 outputs) are not simulated; they rest on the cited concatenation + lemma, as in #6035. +4. The corollary table above, and #4248's counting condition for every + 8 ≤ c ≤ 128 (a consistency control). +5. Nine mutation controls must be rejected: the unexpanded six-source base + walk read in characteristic 10, the c = 8 block read in characteristic 7, + the c = 12 seven-source block read in characteristic 11 (83 of 127 masks), + every cut moved one event later (all three templates), the six-source walk + with base events 2 and 3 exchanged, five six-source blocks at c = 8 + (depth 10 > 8), and a floor word with one readout call dropped. The receipt + is a fingerprint for comparing runs, not a pinned integrity check. + +Expected marker: +`PASS_CONNECTOR_DEPTH_TWO_6_7_8 k6_every_c>=8 k7_every_c>=12 k8_every_c>=27 …`. +It also prints a receipt hash bound to all six package files. + +## 4. Search notes (local only, not proofs) + +The templates came from simulated annealing over base walks and cut vectors +under the integer criterion (score: number of covered masks). The search +programs and logs are not committed. On 8 cores, with 240–360 s per run: + +- Positive control: k = 5, u = 6 is found in under 1 s in each of four runs, + matching #6035. k = 5, u = 5 peaks at 28 of 31, matching #6035's report and + the c = 4 obstruction of #4271. +- k = 6: found at u = 9, 10 and 12. Not found at u = 6 (52/63), 7 (59/63) or + 8 (62/63, four runs). +- k = 6 directly modulo c, each source c times: not found at c = 5 (52/63), + 6 (58/63) or 7 (62/63), two runs each. +- k = 7: found at u = 13 (twice), 14 and 16. Not found at u = 10 (115/127), + 11 (121/127) or 12 (124/127). +- k = 8: found at u = 28, 32 and 40. Not found at u = 20 (252/255) or + 24 (254/255). + +These are search failures, not exclusions. + +## 5. Reproduction + +From the repository root, with CPython 3.12: + +```sh +python3.12 -W error -B research/connector-depth-two-large-c/verify.py +python3.12 -O -W error -B research/connector-depth-two-large-c/verify.py +python3.12 -B scripts/research_package.py --package research/connector-depth-two-large-c +python3.12 -B scripts/check_research_commit.py --package research/connector-depth-two-large-c --check-source-history +``` + +## 6. Limitations + +The result covers only the unsigned, immutable-source, complete-call interface +of #4231. It relies on #4248's prefix criterion, concatenation lemma and +deletion lemma, which are cited and not re-derived. Theorem S is proved for +every c ≥ 8 (six sources), c ≥ 12 (seven) and c ≥ 27 (eight). The direct +block check runs for c ≤ 64 (c ≤ 40 for eight sources), and literal floor +words only for the eight small cases above. +Fixed call prices must include their full implementation. Input admission, +coefficient preparation, dispatch and physical costs are additional and +unknown. No consumer is instantiated. Proof-kernel checks and independent +human review are not claimed. + +## Open next questions + +These are recorded with first steps in [TASK.json](TASK.json). + +1. Do six-source depth-two blocks exist for c = 5, 6, 7, seven-source ones + for 8 ≤ c ≤ 11, and eight-source ones for 12 ≤ c ≤ 26? Local annealing + reached 62 of 63 masks at c = 7. +2. Is there a k-source depth-two block for every k once c is large? The + minimum characteristic found so far grows quickly (8, 12, 27 for + k = 6, 7, 8). Depth-two counting allows k up to about 2 log₂(kc). A family + with k growing like a log c would give N(c) ≥ (a/2) c log c, matching the + O(c log c) counting bound up to a constant and answering #6035's question 3 + (is N(c)/c unbounded?). A first step is k = 9 at larger base multiplicity, + then an explicit recursive template. +3. Is there a depth-three block on more than 3k/2 sources, where k is the best + depth-two size at the same c? This is #6035's question 2 in the new regime. +4. Does any concrete consumer use a characteristic-c batch at a favorable + complete invoice? The abstract call counts change no supplier or κ. + +## Credit + +The lifted-template criterion, the expansion, the Theorem T proof that the +lemma above generalizes, and the open question are Nick Petalas's #6035. The +interface and lower bound are from #4231. The prefix criterion, depth notion, +concatenation and deletion lemmas, N(c) ≥ 2c, the depth-one pair block and the +generic simulator are from #4248 (with the deletion lemma of +[#4232](https://github.com/CrocSwap/integer-mult-bounds/pull/4232)). The c = 4 +obstruction is #4271's. The verifier's word builder and simulator are adapted +from `research/connector-five-halves-growth/verify.py`. New work: the two +templates, the base-multiplicity generalization and the corollary, produced by +Claude Opus 5.5 (Anthropic) in an unattended session for JosieElliston. +Apache-2.0. diff --git a/research/connector-depth-two-large-c/SOURCES.json b/research/connector-depth-two-large-c/SOURCES.json new file mode 100644 index 0000000000..6bf0e83e86 --- /dev/null +++ b/research/connector-depth-two-large-c/SOURCES.json @@ -0,0 +1,36 @@ +{ + "schema_version": 1, + "base_commit": "721c03822c421b7f7fcbb2598993b947c4d88419", + "files": [ + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "d59b5035e7b4cbaa9d688a1d32dd0d6eb79c466a", + "sha256": "9b8d0eea95b3bf0dfcb7938a732a6439b87a2685dec2a5ab9e525b3b34debbfa" + }, + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "3404fbdd5e7529a0674eef26114b5071e4586cec", + "sha256": "ead6cdc9d0af6d58e8a49744d8ec8c7c15e13d2ba93c276c434bcf9b51b93a81" + }, + { + "path": "research/connector-five-halves-growth/README.md", + "usage": "provenance", + "git_blob": "ede2725b4b49c8fe587f077d731432437a3fdb3d", + "sha256": "623f08f27f74ed050d19d5fb518c842512ac6eb54c07701aa94d018eda01cb6f" + }, + { + "path": "research/connector-five-halves-growth/CERTIFICATE.json", + "usage": "provenance", + "git_blob": "75bf7f0666ab2ccecd15ad6a8f8a0578b36cd3f0", + "sha256": "21efc7e9f2167250a9fdc1589dac8964cfe3a71115d38b9df362b01807f82c2a" + }, + { + "path": "research/connector-depth-blocks/README.md", + "usage": "provenance", + "git_blob": "5d5b4a5b96e05f3818ff454d4dfdc5dc2959f6b4", + "sha256": "0ce59767f249b24d65d7d14b466115858d82c0bbfaaa8eab46b7406f4e975331" + } + ] +} diff --git a/research/connector-depth-two-large-c/TASK.json b/research/connector-depth-two-large-c/TASK.json new file mode 100644 index 0000000000..e2667a3a7c --- /dev/null +++ b/research/connector-depth-two-large-c/TASK.json @@ -0,0 +1,91 @@ +{ + "schema_version": 1, + "task_id": "connector-alphabet-change", + "priority_revision": 8, + "base_commit": "721c03822c421b7f7fcbb2598993b947c4d88419", + "original_card": { + "id": "connector-alphabet-change", + "question": "Does one explicit extension of the connector alphabet offer a favorable completed budget?", + "starting_points": [ + "docs/research/research-family-status.md", + "research/universal-connector-boundary/README.md", + "certificates/selected-result.json" + ], + "methods": [ + "Construct and charge a legal extra operation on a minimal instance.", + "Prove a target-specific bound after adding one specified operation family." + ], + "acceptance_gate": "State which fixed-alphabet premise changes and charge its implementation; do not declare it free. A scoped local result may be retained without a complete supplier. Expanding it into further construction rounds requires the family-level budget and obligation gate in research-family-status.md; an optimistic passing relaxation alone is not acceptance.", + "first_step": { + "command": [ + "python3", + "-B", + "research/universal-connector-boundary/verify.py" + ], + "expected": "PASS_UNIVERSAL_CONNECTOR_BOUNDARY", + "inspect": "Reproduce the 945-pairing control, then read Exact interface to list the allowed calls.", + "scope": "Positive control / source-bound orientation only; this is not a new construction or full cold replay." + }, + "first_experiment": "Add exactly one legally priced operation and test a tiny dirty-input instance before enumerating larger cases.", + "bottleneck_link": "A new legal connector operation could change recursive interface cost; a larger census in the same alphabet is a separate side result.", + "allowed_variations": [ + "Choose one additional operation and a small source count for its first counterexample." + ], + "scope_change_triggers": [ + "Keeping the alphabet and only increasing the source count; record this as a changed assignment.", + "Extending a source-count census without naming a supplier/interface decision it could change; audit #2973 pruning concerns before relying on the affected predecessor exclusions." + ], + "overlap_terms": [ + "universal connector", + "source-toggle", + "connector alphabet" + ] + }, + "scope_status": "changed", + "actual_scope": "For the unsigned dirty connector of PR4231 over a ring of characteristic c, answer open question 1 of PR6035 (research/connector-five-halves-growth) for large c: generalize PR6035's lifted integer criterion to any base multiplicity u (valid for c>=u-1), give depth-two templates on six sources (u=9, every c>=8), seven sources (u=13, every c>=12) and eight sources (u=28, every c>=27), and conclude N(c)>=k*floor(c/2)+2*(c mod 2) with k=6,7,8 in those ranges via PR4248's concatenation and deletion lemmas.", + "scope_change_reason": "Same scope change as PR6035: the PR4231 alphabet is kept and the source count grows, a scope-change trigger on the card. This answers the predecessor's recorded open question 1 directly (a six-source depth-two block valid for all large c).", + "bottleneck_link": "Side result on the complete-call interface floor: it raises the batch size at which a characteristic-c connector consumer can pay exactly c calls per operator. No physical consumer, admission or transfer is supplied, so no kappa change follows.", + "budget_minutes": 60, + "stop_rule": "Stop after uniform six-, seven- and eight-source depth-two templates with an all-large-c proof, direct block checks over a finite range of c and literal floor words for small cases. Report other searches only as local search notes.", + "outcome": "completed", + "evidence": "CERTIFICATE.json gives three base walks with per-source cuts. verify.py checks each integer two-prefix identity (63, 127 and 255 masks, the finite core of the proof), checks each expanded block directly modulo c and through the lifted readouts for u-1<=c<=64 (six and seven sources) and 27<=c<=40 (eight), simulates eight literal floor words (up to 196,764 calls) with generic coefficients, checks the corollary table against PR4248's counting condition for 8<=c<=128, and rejects nine mutation controls.", + "author": "Claude (Anthropic) session for JosieElliston", + "ai_assistance": "Produced by Claude Opus 5.5 in an unattended session. Independent human and formal proof-kernel review are unclaimed.", + "open_questions": [ + { + "question": "Do six-source depth-two blocks exist for c=5,6,7, seven-source ones for 8<=c<=11, and eight-source ones for 12<=c<=26?", + "why_it_matters": "It fixes the best depth-two density at small characteristics, where the five-source bound of PR6035 still applies.", + "first_step": "Exhaust or SAT-encode the mod-c criterion at c=7 for six sources; local annealing reached 62 of 63 masks there.", + "blocked_by": "Only local annealing was run (best 52/63 at c=5, 58/63 at c=6, 62/63 at c=7; lifted u=8 also 62/63)." + }, + { + "question": "Is there a depth-two block on k sources for every k once c is large enough?", + "why_it_matters": "Depth-two counting allows k up to about 2*log2(kc). A family with k ~ a*log c would give N(c) >= (a/2) c log c, matching the O(c log c) counting bound up to a constant and answering PR6035 open question 3 (N(c)/c unbounded).", + "first_step": "Run the lifted criterion for k=9 at larger base multiplicity, then look for an explicit recursive template (e.g. a product of two smaller lifted walks). Minimum characteristics found so far: 8, 12, 27 for k=6, 7, 8.", + "blocked_by": "Templates are found by search only; no general construction is known." + }, + { + "question": "Is there a depth-three block on more than 3k/2 sources, where k is the best depth-two block size at the same c?", + "why_it_matters": "Only such a block would beat concatenated depth-two blocks; PR6035's 8/3 > 5/2 threshold is superseded by the 3, 7/2 and 4 densities here.", + "first_step": "Search lifted base walks under the integer three-prefix criterion at the base multiplicities used here.", + "blocked_by": "PR4248 reports a 125-of-127 search failure for seven sources at depth three in characteristic four only; no large-c depth-three search is recorded." + }, + { + "question": "Does any concrete consumer use a characteristic-c batch at a favorable complete invoice?", + "why_it_matters": "The abstract call counts change no recursive supplier or kappa by themselves.", + "first_step": "Identify an immutable-source, unobserved-output caller with coefficients of characteristic c and price every primitive, admission and dispatch.", + "blocked_by": "No selected-supplier consumer is instantiated." + } + ], + "predecessor_handoff": { + "pr": "https://github.com/CrocSwap/integer-mult-bounds/pull/6035", + "author": "Nick Petalas", + "usage": "Lifted integer template criterion, expansion and Theorem T proof (generalized here from base multiplicity 6 to any u), open question 1; PR4248 prefix criterion, concatenation and deletion lemmas; word builder and generic simulation adapted from research/connector-five-halves-growth/verify.py. No executable dependency." + }, + "coordination": { + "claim": "https://github.com/CrocSwap/integer-mult-bounds/discussions/1166#discussioncomment-19232907", + "upstream_commit": "721c03822c421b7f7fcbb2598993b947c4d88419", + "overlap_scope": "Merged README grep for six-source / depth-two statements across research/connector-*; open PR search for connector depth blocks; handoff thread 1166 grep for six-source, N(c) and #6035. Related packages: connector-five-halves-growth (PR6035), connector-depth-blocks (PR4248), connector-char4-floor-bounds (PR4255), connector-char4-floor-obstructions (PR4271).", + "family_decision": "Local interface result; stop. No construction round is justified without a consumer." + } +} diff --git a/research/connector-depth-two-large-c/VERIFY.json b/research/connector-depth-two-large-c/VERIFY.json new file mode 100644 index 0000000000..f0a79660f1 --- /dev/null +++ b/research/connector-depth-two-large-c/VERIFY.json @@ -0,0 +1,32 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [], + "commands": [ + { + "argv": [ + "{python}", + "-W", + "error", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 60, + "checks": "Integer two-prefix template identities for the six- (u=9), seven- (u=13) and eight-source (u=28) templates; expanded depth-two blocks directly modulo c and through the lifted readouts (u-1<=c<=64; eight sources 27<=c<=40); eight literal floor words with generic coefficients; corollary table and PR4248 counting consistency for 8<=c<=128; nine rejection controls." + }, + { + "argv": [ + "{python}", + "-O", + "-W", + "error", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 60, + "checks": "Repeat every check under optimized Python; checks use explicit exceptions." + } + ] +} diff --git a/research/connector-depth-two-large-c/verify.py b/research/connector-depth-two-large-c/verify.py new file mode 100644 index 0000000000..cb664f0470 --- /dev/null +++ b/research/connector-depth-two-large-c/verify.py @@ -0,0 +1,339 @@ +"""Verify six-, seven- and eight-source depth-two unsigned-connector blocks for every large c. + +Stdlib only. Checks use explicit exceptions so they stay active under -O. +The lifted-template criterion is Nick Petalas's (research/connector-five-halves-growth, +PR #6035, merged at 119de1d7f), generalized from base multiplicity 6 to any +base multiplicity u. The prefix criterion, concatenation lemma, word builder +and generic simulation follow research/connector-depth-blocks (PR #4248). +No predecessor code is imported. +""" +import hashlib +import json +import pathlib +import sys + +HERE = pathlib.Path(__file__).resolve().parent +PACKAGE_FILES = ("README.md", "TASK.json", "SOURCES.json", "VERIFY.json", + "CERTIFICATE.json", "verify.py") +BLOCK_MAX_C = {"six": 64, "seven": 64, "eight": 40} +# (c, template name, number of depth-two blocks, append a depth-one pair block) +WORD_CASES = ((8, "six", 1, False), (8, "six", 2, False), (9, "six", 2, True), + (12, "seven", 1, False), (13, "seven", 1, True), (12, "seven", 2, False), + (27, "eight", 1, False), (27, "eight", 1, True)) + + +class CheckError(Exception): + pass + + +def require(cond, message): + if not cond: + raise CheckError(message) + + +def mask_vector(m, k): + return tuple((m >> j) & 1 for j in range(k)) + + +def prefixes(path, k, c): + q = [0] * k + out = [tuple(q)] + for j in path: + q[j] = (q[j] + 1) % c + out.append(tuple(q)) + return out + + +def counts_ok(path, k, c): + return all(path.count(j) == c for j in range(k)) and len(path) == c * k + + +def depth_two_readouts(path, k, c): + """Map each nonzero mask to the first boundary pair whose prefixes sum to it mod c.""" + qs = prefixes(path, k, c) + found = {} + for t1 in range(len(qs)): + for t2 in range(t1, len(qs)): + s = tuple((a + b) % c for a, b in zip(qs[t1], qs[t2])) + if max(s) <= 1 and any(s): + found.setdefault(sum(bit << i for i, bit in enumerate(s)), (t1, t2)) + return found + + +def lifted_prefixes(base, cut, k, u): + """Integer prefix vectors of the base walk: count n, minus u once n > cut.""" + cnt = [0] * k + out = [tuple(cnt)] + for j in base: + cnt[j] += 1 + out.append(tuple(x if x <= cut[i] else x - u for i, x in enumerate(cnt))) + return out + + +def check_template(base, cut, k, u): + """Every nonzero mask is an integer sum of two lifted prefixes (finite proof core).""" + require(counts_ok(base, k, u), "base walk counts") + require(len(cut) == k and all(0 <= a < u for a in cut), "cut out of range") + lp = lifted_prefixes(base, cut, k, u) + require(lp[-1] == (0,) * k, "lifted walk does not return to zero") + pairs = {} + for t1 in range(len(lp)): + for t2 in range(t1, len(lp)): + s = tuple(a + b for a, b in zip(lp[t1], lp[t2])) + if all(x in (0, 1) for x in s) and any(s): + pairs.setdefault(sum(bit << i for i, bit in enumerate(s)), (t1, t2)) + require(set(pairs) == set(range(1, 2 ** k)), f"template covers {len(pairs)} of {2 ** k - 1}") + return pairs + + +def expand(base, cut, u, c): + """Replace the (cut_j+1)-th event of source j by a run of c-u+1 copies (none at c=u-1).""" + require(c >= u - 1, "expansion needs c >= u-1") + seen = [0] * len(cut) + path = [] + for j in base: + seen[j] += 1 + path += [j] * (c - u + 1) if seen[j] == cut[j] + 1 else [j] + return path + + +def expanded_boundary(base, cut, u, c, t): + """Boundary of the expanded walk that follows base event t.""" + seen = [0] * len(cut) + pos = 0 + for j in base[:t]: + seen[j] += 1 + pos += c - u + 1 if seen[j] == cut[j] + 1 else 1 + return pos + + +def unpack(tpl): + return tpl["walk"], tpl["cut"], tpl["sources"], tpl["base_multiplicity"] + + +def check_blocks(tpl, pairs): + base, cut, k, u = unpack(tpl) + require(tpl["min_c"] == u - 1, "declared minimum characteristic") + for c in range(u - 1, BLOCK_MAX_C[tpl["name"]] + 1): + path = expand(base, cut, u, c) + require(counts_ok(path, k, c), f"c={c} block counts") + found = depth_two_readouts(path, k, c) + require(set(found) == set(range(1, 2 ** k)), f"c={c} block covers {len(found)}") + qs = prefixes(path, k, c) + for m, (t1, t2) in pairs.items(): + u1 = expanded_boundary(base, cut, u, c, t1) + u2 = expanded_boundary(base, cut, u, c, t2) + s = tuple((a + b) % c for a, b in zip(qs[u1], qs[u2])) + require(s == mask_vector(m, k), f"c={c} lifted readout fails for {m}") + return BLOCK_MAX_C[tpl["name"]] - u + 2 + + +def concat_walk(tpl, c, nblocks, pair): + """Concatenate depth-two blocks on disjoint sources and optionally a b a^(c-1) b^(c-1).""" + base, cut, k, u = unpack(tpl) + block = expand(base, cut, u, c) + hits = depth_two_readouts(block, k, c) + path, blocks = [], [] + src = 0 + for _ in range(nblocks): + start = len(path) + path += [src + j for j in block] + blocks.append((tuple(range(src, src + k)), + {mask_vector(m, k): (start + t1, start + t2) + for m, (t1, t2) in hits.items()}, 2)) + src += k + if pair: + a, b = src, src + 1 + start = len(path) + path += [a, b] + [a] * (c - 1) + [b] * (c - 1) + blocks.append(((a, b), {(1, 0): (start + 1,), (1, 1): (start + 2,), + (0, 1): (start + c + 1,)}, 1)) + src += 2 + return path, blocks, src + + +def floor_readouts(path, blocks, k, c): + require(sum(d for _, _, d in blocks) <= c, "block depths exceed c") + readouts = {} + for m in range(1, 2 ** k): + bits = mask_vector(m, k) + ts = [] + for srcs, hit, _ in blocks: + key = tuple(bits[j] for j in srcs) + if any(key): + ts += hit[key] + require(len(ts) <= c, f"mask {m} needs {len(ts)} readouts") + readouts[m] = tuple(ts) + (0,) * (c - len(ts)) + return readouts + + +def build_word(path, readouts): + at = {} + for m, ts in readouts.items(): + for t in ts: + at.setdefault(t, []).append(m) + word = [] + for t in range(len(path) + 1): + word.extend(("A", m) for m in sorted(at.get(t, []))) + if t < len(path): + word.append(("B", path[t])) + return word + + +def check_word(word, k, c): + """Generic simulation over Z/c (PR #4248): z as coefficients of (z0, B_j x_j).""" + z = [1] + [0] * k + outs = {} + for kind, idx in word: + if kind == "B": + z[1 + idx] = (z[1 + idx] + 1) % c + else: + acc = outs.setdefault(idx, [0] * (k + 1)) + for i in range(k + 1): + acc[i] += z[i] + require(z == [1] + [0] * k, "connector not restored") + require(set(outs) == set(range(1, 2 ** k)), "output set mismatch") + for m, acc in outs.items(): + acc = [x % c for x in acc] + require(acc[0] == 0, f"connector dirt left in output {m}") + require(tuple(acc[1:]) == mask_vector(m, k), f"wrong row for output {m}") + counts = {} + for call in word: + counts[call] = counts.get(call, 0) + 1 + require(set(counts.values()) == {c}, "some operator not called exactly c times") + require(len(counts) == k + 2 ** k - 1, "operator set mismatch") + require(len(word) == c * (k + 2 ** k - 1), "length differs from the floor") + + +def check_floor_words(tpls): + out = [] + for c, name, nblocks, pair in WORD_CASES: + tpl = tpls[name] + path, blocks, k = concat_walk(tpl, c, nblocks, pair) + require(k == tpl["sources"] * nblocks + 2 * pair, f"c={c} source count {k}") + require(counts_ok(path, k, c), f"c={c} floor walk counts") + word = build_word(path, floor_readouts(path, blocks, k, c)) + check_word(word, k, c) + out.append((c, k, len(word))) + return out + + +SWAP_INDEX = 2 # base events 2 and 3 of the six-source walk (sources 0 and 1) + + +def swapped(base, i): + """The base walk with events i and i+1 (distinct sources) exchanged.""" + w = list(base) + require(w[i] != w[i + 1], "swap of equal sources") + w[i], w[i + 1] = w[i + 1], w[i] + return w + + +def check_controls(tpls): + six = tpls["six"] + base, cut, k, u = unpack(six) + + def five_blocks(): + path, blocks, kk = concat_walk(six, 8, 5, False) + floor_readouts(path, blocks, kk, 8) + + def dropped_readout(): + path, blocks, kk = concat_walk(six, 8, 1, False) + word = build_word(path, floor_readouts(path, blocks, kk, 8)) + word.remove(("A", 2 ** kk - 1)) + check_word(word, kk, 8) + + sb, sc, sk, su = unpack(tpls["seven"]) + trials = [ + # The unexpanded six-source base walk (a c=9 walk) read in characteristic ten. + lambda: require(len(depth_two_readouts(base, k, 10)) == 2 ** k - 1, "c9 block mod 10"), + # The c=8 block read in characteristic seven (it is not a c=7 walk). + lambda: require(len(depth_two_readouts(expand(base, cut, u, 8), k, 7)) == 2 ** k - 1, + "c8 block mod 7"), + # The c=12 seven-source block read in characteristic 11 (83 of 127 masks). + lambda: require(len(depth_two_readouts(expand(sb, sc, su, 12), sk, 11)) == 2 ** sk - 1, + "c12 seven block mod 11"), + # Moving every cut one event later breaks the integer criterion. + lambda: check_template(base, [a + 1 for a in cut], k, u), + lambda: check_template(sb, [a + 1 for a in sc], sk, su), + lambda: check_template(*_eight_shifted(tpls["eight"])), + # One adjacent transposition of the base walk breaks the criterion. + lambda: check_template(swapped(base, SWAP_INDEX), cut, k, u), + # Five six-source depth-two blocks exceed the eight readouts at c=8. + five_blocks, + # A floor word with one readout call dropped. + dropped_readout, + ] + rejected = 0 + for trial in trials: + try: + trial() + except CheckError: + rejected += 1 + require(rejected == len(trials), f"only {rejected} of {len(trials)} controls rejected") + return rejected + + +def _eight_shifted(tpl): + base, cut, k, u = unpack(tpl) + return base, [a + 1 for a in cut], k, u + + +def corollary_k(tpls, c): + """Largest k*floor(c/2)+2(c%2) over templates valid at c (PR6035's bound if none).""" + best = 5 * c // 2 if c >= 5 else 2 * c + for tpl in tpls.values(): + if c >= tpl["base_multiplicity"] - 1: + best = max(best, tpl["sources"] * (c // 2) + 2 * (c % 2)) + return best + + +def check_counting(tpls): + """Consistency: every corollary value satisfies PR4248's counting necessary condition.""" + from math import comb + for c in range(8, 129): + k = corollary_k(tpls, c) + require(comb(c * k + c - 1, c) >= 2 ** k - 1, f"corollary k={k} at c={c} violates counting") + return [(c, corollary_k(tpls, c)) for c in (8, 9, 12, 13, 14, 27, 28)] + + +def receipt(): + h = hashlib.sha256() + for name in PACKAGE_FILES: + data = (HERE / name).read_bytes() + h.update(name.encode() + b"\0" + hashlib.sha256(data).hexdigest().encode() + b"\n") + return h.hexdigest() + + +def main(): + cert = json.loads((HERE / "CERTIFICATE.json").read_text()) + tpls = {t["name"]: t for t in cert["templates"]} + require(set(tpls) == {"six", "seven", "eight"}, "template set") + require([tpls[n]["sources"] for n in ("six", "seven", "eight")] == [6, 7, 8], "template sizes") + lines = [] + for name in ("six", "seven", "eight"): + tpl = tpls[name] + base, cut, k, u = unpack(tpl) + pairs = check_template(base, cut, k, u) + nblocks = check_blocks(tpl, pairs) + lines.append(f"k{k}:u{u}:integer_masks={len(pairs)}:blocks_c{u - 1}..{BLOCK_MAX_C[name]}={nblocks}") + words = check_floor_words(tpls) + controls = check_controls(tpls) + table = check_counting(tpls) + require(table == [(8, 24), (9, 26), (12, 42), (13, 44), (14, 49), (27, 106), (28, 112)], + "README corollary table") + print("templates", " ".join(lines)) + print("corollary", " ".join(f"N({c})>={k}" for c, k in table), "counting_consistent_c8..128") + print("floor_words", " ".join(f"c{c}:k{k}:calls{n}" for c, k, n in words)) + print(f"controls={controls}") + print("receipt_sha256", receipt()) + print("PASS_CONNECTOR_DEPTH_TWO_6_7_8 k6_every_c>=8 k7_every_c>=12 k8_every_c>=27 " + "N(c)>=k*floor(c/2)+2(c%2)") + + +if __name__ == "__main__": + try: + main() + except CheckError as exc: + print("FAIL", exc) + sys.exit(1)