diff --git a/research/k2-class-c-config-audit/README.md b/research/k2-class-c-config-audit/README.md new file mode 100644 index 0000000000..10d06e9031 --- /dev/null +++ b/research/k2-class-c-config-audit/README.md @@ -0,0 +1,194 @@ +# Class-C 4-flat covering-config census: an independent table audit (no kappa claim) + +**Status:** author-checked, not independently reviewed. **Priority revision 6.** +Base canonical main `463113d675af7410ac91d53a4fed51ec6494eb9a`. + +This package audits the *published tables* of the class-C help package for +Discussion #2954. It does **not** re-derive any E8/P112 geometry, does **not** +verify the kill criterion (Lemma B), and does **not** verify relative root +counting (RRC), which that help post itself marks as under audit. No kappa, +decoder floor, residue exclusion, supplier or frontier claim is made here. + +## What this establishes + +### First: the cover relation is dominance closure, not literal CSV incidence + +This was **not** obvious from the CSV and is the load-bearing correction in +this package. #2954 publishes per-config totals -- "6554 covers 62 of the 70 +rows, 5555 27, 6544 40, 5554 23, 6543 16" -- and those five numbers are +reproduced **exactly** by *dominance closure* (a config may serve any row of a +config it dominates coordinatewise) and **not at all** by literal incidence: + +| config | literal incidence | dominance closure | published in #2954 | +|---|---:|---:|---:| +| 6554 | 39 | **62** | 62 | +| 5555 | 21 | **27** | 27 | +| 6544 | 36 | **40** | 40 | +| 5554 | 22 | **23** | 23 | +| 6543 | 16 | **16** | 16 | + +`6554 = (6,5,5,4)` dominates `5544`, `6444`, `6544` and `6543` coordinatewise, so +its true reach is 62 rows, not the 39 the CSV lists for it. Rows 13 and 62 list +`5544` but omit `6554`, which is consistent with the author listing only the +*minimal* generator of each cover rather than every config that can serve it. + +An earlier version of this package read the relation as literal incidence. That +was wrong and overstated the required campaign; the correction is below. + +### Two findings about *compute allocation* + +**1. The advertised cheapest campaign is redundant by dominance, so it cannot +help.** #2954 prices five configs and singles out `(6,5,4,3)` = `6543` as by far +the cheapest: 2.6e7 pairs against 1.1e8-3.3e8 for the others, ETA about 4e4 +CPU-h against about 3e5. It is the only target that looked plausibly +affordable, and it is where the route-B acceleration work (tekuuu's PR2975, +PR3000) was pointed. + +But `6543 = (6,5,4,3)` is **dominated by `6554 = (6,5,5,4)`**, so everything it +can serve, `6554` can serve too. Independently of that, `6543` appears only on +rows that relative root counting already kills and covers none of the 17 rows in +`rows17.csv`. Either way it adds nothing, and ~4e4 CPU-h on it cannot advance +the hard problem. + +**2. A two-config campaign suffices.** The exact minimum set of configs covering +the 16 config-coverable rows of the 17 is + +``` +{5555, 6554} +``` + +`5544`, `5554`, `6444` and `6544` are redundant, and the same two configs also +cover all 64 config-coverable rows of the whole 70-row census. For the full +table, 11 of the 13 configs are redundant -- only `5555` and `6554` survive. +`5555` survives because `6554` does not dominate it: `5555 = (5,5,5,5)` is +narrower than `6554` in its largest dimension. + +Using only the README's own pair counts, dropping redundant `5554` (3.3e8) and +`6544` (1.1e8) removes **4.4e8 enumerated pairs** before any closure runs, and +also dropping `6543` (2.6e7) brings the full-census figure to **4.66e8**. +`5544` and `6444` have no published pair count, so both figures are **lower +bounds**. + +**Supporting consistency checks, all passing.** These matter because the +redundancy claim rests on the table being well-formed: + +* dominance closure reproduces all five published per-config totals, and + literal incidence does not (table above); +* every listed config satisfies the `sum g <= 52` admissibility bound, and + `6554` = `(6,5,5,4)` saturates it *exactly* at 52, so it is the unique + largest admissible 4-flat budget in the table; +* `rows17.csv` is exactly `rows70.csv` minus the 53 `RRC-killed` rows + (symmetric difference empty), and the kill count is the published 53; +* every shared row's `d`, `s`, `weights`, `e` and config list agrees between + the two tables; +* independently, the 6 rows with no config at all are `3, 12, 24, 37, 54, 61`, + confirming the post's "6 rows have no 4-flat candidate". Row 37 is the only + one of the 17. + +## What this does *not* establish + +* **Completeness of the config list is not checked.** The audit verifies that + each listed config is admissible (`sum g <= 52`), not that the packing + predicate admits no further config. That predicate is only sketched in #2954, + so the redundancy result is a statement about the published list. +* **The dominance relation is recovered from published totals, not proved from + the geometry.** That `6554` can substitute for a dominated config in the + actual span computation is a *source-semantic* premise, not something this + table audit establishes. It is exactly the question taken up independently in + the follow-up claim on #2954; treat the two-config campaign as the *planning* + conclusion pending that lemma. +* The kill criterion, the span bound `span H <= d-1`, and RRC are untouched. +* Pair counts and CPU-hour ETAs are reused verbatim from the help README and + were not re-measured. +* No row is excluded. A redundant *config* is not a disproved *row*; see the + card's own `scope_change_trigger`. + +## Reproduce + +```sh +python3 -B research/k2-class-c-config-audit/verify.py +``` + +Python 3.12, standard library only, runs in under a second. Expect +`PASS_K2_CLASS_C_CONFIG_AUDIT` and exit 0. `RESULT.json` is written next to the +verifier with every derived quantity. The verifier asserts the sha256 of both +inputs, runs the 8 structural checks, and then runs **4 rejecting mutants** that +must each be caught: + +| mutant | rejected by | +|---|---| +| inject inadmissible config `6555` (`sum g = 56`) | admissibility + cross-table agreement | +| drop row 62 from `rows17.csv` | row count + rows17-vs-rows70 identity | +| flip one RRC status (kill count 53 -> 52) | rows17 identity + kill count | +| edit row 35's configs in `rows17.csv` only | cross-table agreement | +| add `6554` to row 3 (dominance total 62 -> 63) | published-total reproduction | + +## Sources and inputs + +* Audited help package: `research/k2-class-c-help` on + `DreamingOfClouds/integer-mult-bounds`, branch `research/k2-class-c-help`, + help-package source commit `1b25759bff5486293a9083ebbe0097b5f6642e08`. +* `inputs/rows70.csv` sha256 `c0eb6bb88498bf39a8b2020b1d0d600181f6e13eb9dd6a6e5f90794f0895754a` +* `inputs/rows17.csv` sha256 `9ebe7fc1ecd74148e7bdefa1f6bb2ed00551884b1a4a6558d7f129f7eef4efd5` +* `g(1..7) = 1,2,4,8,12,20,36`, `sum g <= 52`, and the pair counts are quoted + from Discussion #2954 and the same README, and restated in `verify.py`. + +These two CSVs are **not Git objects in this repository**, so they cannot carry +a `git_blob`/`pin` row in `SOURCES.json`. They are vendored under `inputs/`, +declared as live inputs in `VERIFY.json`, and the verifier re-checks their +sha256 on every run as the byte-equality receipt. + +## Overlap tooling limitation + +`python3 scripts/find_overlap.py --task ... --refresh` could not refresh its +remote corpus in the session environment: its remote refresh shells out to +`gh`, which is not installed, so it reported `open_prs: null, discussions: null` +and fell back to local notes. The overlap check was instead done with +authenticated API reads of #2954, #1166 and #3156 and API searches across open +and closed PR bodies. This is **not** an arbitrary-diff or unpublished-work +census, and no match would not by itself have proved novelty. + +## Open next questions + +0. **Does the dominance substitution preserve the span threshold?** Every + conclusion here assumes that if `6554` dominates a config then `6554` serves + its rows at the same target `T`. That is a source-semantic premise this audit + cannot prove; it is the one thing standing between this and a two-config + campaign being *correct* rather than merely *plausible*. *First step:* fix a + single `(V1..V4)` instance and a target `T`, and check both the dominated and + dominating config against the real span computation. *Blocked by:* needs the + E8/P112 geometry and `s4z`. +1. **Is the admissible config list complete?** *Why it matters:* completeness is + what makes the redundancy a real saving; a missing config would enlarge the + minimal cover. *First step:* obtain the exact weight-multiset-to-config + packing predicate from the help author, regenerate the config sets + independently and diff them against `inputs/rows70.csv`. *Blocked by:* the + predicate is unpublished; `s4z.c` encodes it only implicitly. +2. **Rows 37, 3, 12, 24, 54, 61 admit no 4-flat config.** *Why it matters:* they + are unreachable by every advertised config, so no amount of 4-flat closure + compute closes them. *First step:* test whether a 5-flat or an explicit + two-free-piece cover exists for row 37 within `sum g <= 52`, or prove none + does. *Blocked by:* needs the E8/P112 flat geometry and the unpublished RRC + scenario list. +3. **Do the 3 redundant configs matter for the wider residue chains?** *Why it + matters:* the redundancy is proved only relative to these 70 rows, while + PR2985/PR3049 reuse the same config vocabulary. *First step:* run this audit + unchanged against their residue tables after pinning their heads. *Blocked + by:* those tables are not vendored here and their heads are unpinned. + +## Predecessor credit + +* **DreamingOfClouds** - the class-C help package, the `s4z`/`s3z` engines, the + `data88.txt` direction list, the `g`-table, the `sum g <= 52` bound and both + CSV tables that are the entire object of this audit. Their results retain all + credit; nothing here disputes them. +* **tekuuu** - PR2975 (33x requirement enumeration) and PR3000 (9.31x four-flat + maximal-mask filtering). Those accelerate work *inside* a config; this + removes whole configs from the campaign, and composes with them. +* **Nick Petalas** and the retained **#2816 / #2826 / #2862** E8/P112 lineage, + and the RRC residue chain of **PR2985 / PR3049** that this census belongs to. +* **Douglas Colkitt**, the selected result and the retained source lineage. + +Prepared by muatfannajm-dot, with substantial OpenCode (Space Bunny Free) +assistance. Apache-2.0. The audited help package remains DreamingOfClouds' +work under the repository's Apache-2.0 licence. \ No newline at end of file diff --git a/research/k2-class-c-config-audit/RESULT.json b/research/k2-class-c-config-audit/RESULT.json new file mode 100644 index 0000000000..cbe59b2b66 --- /dev/null +++ b/research/k2-class-c-config-audit/RESULT.json @@ -0,0 +1,722 @@ +{ + "all_checks_passed": true, + "all_controls_rejected": true, + "checks": [ + { + "detail": "", + "name": "input rows17.csv matches its pinned sha256", + "ok": true + }, + { + "detail": "", + "name": "input rows70.csv matches its pinned sha256", + "ok": true + }, + { + "detail": "got 70", + "name": "rows70 has 70 rows", + "ok": true + }, + { + "detail": "got 17", + "name": "rows17 has 17 rows", + "ok": true + }, + { + "detail": "violations=none", + "name": "all listed configs satisfy sum g <= 52", + "ok": true + }, + { + "detail": "6554 -> 52", + "name": "6554 saturates the bound exactly (sum g = 52)", + "ok": true + }, + { + "detail": "symmetric_difference=empty", + "name": "rows17 == rows70 minus RRC-killed rows", + "ok": true + }, + { + "detail": "killed=53", + "name": "RRC kills 53 of 70 rows (as published)", + "ok": true + }, + { + "detail": "mismatches=none", + "name": "rows17 fields agree with rows70 for every shared row", + "ok": true + }, + { + "detail": "5554 closed=23 literal=22 published=23; 5555 closed=27 literal=21 published=27; 6543 closed=16 literal=16 published=16; 6544 closed=40 literal=36 published=40; 6554 closed=62 literal=39 published=62", + "name": "dominance closure reproduces all 5 published per-config totals", + "ok": true + }, + { + "detail": "so literal incidence is the wrong cover relation", + "name": "literal incidence does NOT reproduce the published totals", + "ok": true + }, + { + "detail": "dims 6554=(6,5,5,4)", + "name": "6554 dominates 5544, 6444, 6544 and 6543", + "ok": true + } + ], + "config_costs": { + "5444": 36, + "5543": 36, + "5544": 40, + "5553": 40, + "5554": 44, + "5555": 48, + "6443": 40, + "6444": 44, + "6533": 40, + "6543": 44, + "6544": 48, + "6553": 48, + "6554": 52 + }, + "configs_appearing_in_17_rows": [ + "5544", + "5554", + "5555", + "6444", + "6544", + "6554" + ], + "configs_listed_anywhere": [ + "5444", + "5543", + "5544", + "5553", + "5554", + "5555", + "6443", + "6444", + "6533", + "6543", + "6544", + "6553", + "6554" + ], + "configs_only_on_rrc_killed_rows": [ + "5444", + "5543", + "5553", + "6443", + "6533", + "6543", + "6553" + ], + "configs_with_no_stated_pair_count": [ + "5544", + "6444" + ], + "controls": [ + { + "failed_checks": [ + "all listed configs satisfy sum g <= 52", + "rows17 fields agree with rows70 for every shared row" + ], + "mutant": "inject inadmissible config 6555 (sum g = 56)", + "rejected": true + }, + { + "failed_checks": [ + "rows17 has 17 rows", + "rows17 == rows70 minus RRC-killed rows" + ], + "mutant": "drop row 62 from rows17", + "rejected": true + }, + { + "failed_checks": [ + "rows17 == rows70 minus RRC-killed rows", + "RRC kills 53 of 70 rows (as published)" + ], + "mutant": "flip row 3 RRC status (kill count 53 -> 52)", + "rejected": true + }, + { + "failed_checks": [ + "rows17 fields agree with rows70 for every shared row" + ], + "mutant": "edit row 35 configs in rows17 only", + "rejected": true + }, + { + "failed_checks": [ + "dominance closure reproduces all 5 published per-config totals" + ], + "mutant": "add 6554 to row 3 (closed total 62 -> 63)", + "rejected": true + } + ], + "cover_of_config_dominance": { + "5544": [ + 0, + 13, + 14, + 15, + 26, + 31, + 32, + 62, + 63, + 64 + ], + "5554": [ + 0, + 7, + 13, + 14, + 15, + 16, + 21, + 25, + 26, + 27, + 31, + 32, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 62, + 63, + 64, + 65 + ], + "5555": [ + 0, + 7, + 13, + 14, + 15, + 16, + 21, + 25, + 26, + 27, + 31, + 32, + 34, + 35, + 44, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 62, + 63, + 64, + 65 + ], + "6444": [ + 1, + 4, + 6, + 13, + 17, + 18, + 20, + 28, + 29, + 31, + 33, + 62, + 66, + 67, + 69 + ], + "6544": [ + 0, + 1, + 2, + 4, + 5, + 6, + 8, + 9, + 10, + 13, + 14, + 15, + 17, + 18, + 19, + 20, + 22, + 26, + 28, + 29, + 30, + 31, + 32, + 33, + 46, + 47, + 48, + 50, + 55, + 56, + 57, + 58, + 59, + 62, + 63, + 64, + 66, + 67, + 68, + 69 + ], + "6554": [ + 0, + 1, + 2, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 36, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 55, + 56, + 57, + 58, + 59, + 60, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69 + ] + }, + "cover_of_config_literal": { + "5544": [ + 0, + 13, + 14, + 15, + 26, + 31, + 32, + 62, + 63, + 64 + ], + "5554": [ + 0, + 7, + 13, + 14, + 15, + 16, + 21, + 25, + 26, + 27, + 31, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 62, + 63, + 64, + 65 + ], + "5555": [ + 0, + 7, + 15, + 16, + 21, + 25, + 26, + 27, + 34, + 35, + 44, + 45, + 46, + 48, + 49, + 50, + 51, + 52, + 53, + 64, + 65 + ], + "6444": [ + 1, + 4, + 6, + 13, + 17, + 18, + 20, + 28, + 29, + 31, + 33, + 62, + 66, + 67, + 69 + ], + "6544": [ + 0, + 1, + 2, + 4, + 5, + 6, + 8, + 9, + 10, + 13, + 15, + 17, + 18, + 19, + 20, + 22, + 26, + 28, + 29, + 30, + 33, + 46, + 47, + 48, + 50, + 55, + 56, + 57, + 58, + 59, + 62, + 64, + 66, + 67, + 68, + 69 + ], + "6554": [ + 1, + 2, + 7, + 8, + 9, + 10, + 11, + 18, + 19, + 21, + 22, + 23, + 25, + 29, + 30, + 34, + 36, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 46, + 47, + 49, + 50, + 51, + 52, + 53, + 55, + 56, + 57, + 58, + 59, + 60, + 67, + 68 + ] + }, + "cover_relation": "dominance (recovered from the 5 published totals)", + "g_table": { + "1": 1, + "2": 2, + "3": 4, + "4": 8, + "5": 12, + "6": 20, + "7": 36 + }, + "minimal_config_set_for_17_rows": [ + "5555", + "6554" + ], + "minimal_config_set_for_17_rows_LITERAL_relation_WRONG": [ + "5544", + "5555", + "6554" + ], + "minimal_config_set_for_70_rows": [ + "5555", + "6554" + ], + "not_verified": [ + "Completeness of the config list: only admissibility (sum g <= 52) of each listed config is checked. Whether the author's piece-packing rule admits further configs is NOT checked; that rule is only sketched in Discussion #2954.", + "The kill criterion itself (Lemma B) and span_H <= d-1.", + "RRC (relative root counting), which the help post marks under audit; the 53-of-70 kill count is taken as given and only checked for internal consistency between the two CSVs.", + "Pair counts and CPU-hour ETAs are the README's published figures, reused verbatim, not re-measured." + ], + "pairs_saved_by_minimal_set_17": 440000000.0, + "pairs_saved_by_minimal_set_70": 466000000.0, + "published_per_config_totals": { + "5554": 23, + "5555": 27, + "6543": 16, + "6544": 40, + "6554": 62 + }, + "readme_stated_pairs": { + "5554": 330000000.0, + "5555": 330000000.0, + "6543": 26000000.0, + "6544": 110000000.0, + "6554": 110000000.0 + }, + "redundant_configs_for_17_rows": [ + "5544", + "5554", + "6444", + "6544" + ], + "redundant_configs_for_70_rows": [ + "5444", + "5543", + "5544", + "5553", + "5554", + "6443", + "6444", + "6533", + "6543", + "6544", + "6553" + ], + "row_counts_dominance_closed": { + "5444": 1, + "5543": 1, + "5544": 10, + "5553": 6, + "5554": 23, + "5555": 27, + "6443": 5, + "6444": 15, + "6533": 1, + "6543": 16, + "6544": 40, + "6553": 28, + "6554": 62 + }, + "row_counts_literal": { + "5444": 1, + "5543": 1, + "5544": 10, + "5553": 6, + "5554": 22, + "5555": 21, + "6443": 5, + "6444": 15, + "6533": 1, + "6543": 16, + "6544": 36, + "6553": 20, + "6554": 39 + }, + "rows17_with_no_config": [ + 37 + ], + "rows70_coverable_by_some_listed_config": [ + 0, + 1, + 2, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 55, + 56, + 57, + 58, + 59, + 60, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69 + ], + "rows70_not_coverable_by_any_listed_config": [ + 3, + 12, + 24, + 37, + 54, + 61 + ], + "rows70_with_no_config": [ + 3, + 12, + 24, + 37, + 54, + 61 + ], + "rows_not_coverable_by_any_listed_config": [ + 37 + ], + "rrc_killed_count": 53, + "scope": "Audit of the published class-C 4-flat covering-config census only. No E8/P112 geometry re-derived; no verification of kill criterion Lemma B; no verification of relative root counting (RRC). No kappa, decoder, supplier or residue-exclusion claim.", + "stated_pairs_dropped_for_17": { + "5554": 330000000.0, + "6544": 110000000.0 + }, + "stated_pairs_dropped_for_70": { + "5554": 330000000.0, + "6543": 26000000.0, + "6544": 110000000.0 + }, + "stated_pairs_for_minimal_17": { + "5555": 330000000.0, + "6554": 110000000.0 + }, + "sum_g_bound": 52, + "surviving_row_indices": [ + 7, + 8, + 13, + 21, + 34, + 35, + 36, + 37, + 40, + 42, + 43, + 46, + 47, + 50, + 53, + 57, + 62 + ] +} diff --git a/research/k2-class-c-config-audit/SOURCES.json b/research/k2-class-c-config-audit/SOURCES.json new file mode 100644 index 0000000000..9f5bf1ceda --- /dev/null +++ b/research/k2-class-c-config-audit/SOURCES.json @@ -0,0 +1,18 @@ +{ + "schema_version": 1, + "base_commit": "463113d675af7410ac91d53a4fed51ec6494eb9a", + "files": [ + { + "path": "certificates/selected-result.json", + "usage": "provenance", + "git_blob": "b1fea0c94436b236cc2b7d41a7be032811b94c81", + "sha256": "bb2eaa58647b353f88d0aec2eafb9d30df1be53589231b23e12ceef3e4bad129" + }, + { + "path": "docs/research/agent-task-catalog.json", + "usage": "provenance", + "git_blob": "67f085acd86acd7d4e03922d9cf4b26bca66fed5", + "sha256": "47b42433f5a85809a3aadd29c2c339da2c6ed728e4f7762df6b88bccb7874cf0" + } + ] +} diff --git a/research/k2-class-c-config-audit/TASK.json b/research/k2-class-c-config-audit/TASK.json new file mode 100644 index 0000000000..ed76cb46b2 --- /dev/null +++ b/research/k2-class-c-config-audit/TASK.json @@ -0,0 +1,78 @@ +{ + "schema_version": 1, + "task_id": "census-pruning-audit", + "priority_revision": 6, + "base_commit": "463113d675af7410ac91d53a4fed51ec6494eb9a", + "original_card": { + "id": "census-pruning-audit", + "question": "Does the reported word-census parity-pruning error invalidate a specific exclusion we still rely on, and what bounded repair is justified?", + "starting_points": [ + "research/f7-weight-parity-census-correction/README.md", + "docs/research/research-family-status.md" + ], + "methods": [ + "Independently reconstruct the tiny counterexample and trace one affected exclusion to its exact pruning code.", + "Compare corrected and unpruned enumeration on a small exhaustive domain, then audit the changed pruning implication." + ], + "acceptance_gate": "Pin the old and proposed corrected engines, distinguish a disproved pruning rule from a disproved final bound, and state exactly which downstream exclusions need revalidation. #2973 is an author-checked source archive; neither its new f(7) claim nor all old conclusions are automatically accepted or rejected.", + "first_step": { + "command": [ + "python3", + "-B", + "scripts/research_baseline.py" + ], + "expected": "PASS_RESEARCH_BASELINE_BINDINGS_ONLY", + "inspect": "Read #2973 error description and MATH.md; manually reconstruct the prefix states of 01021323 before running any large census.", + "scope": "Source-binding orientation only; no full enumeration or mathematical validation." + }, + "first_experiment": "Reconstruct the eight prefix states of 01021323 and compare bit-0 versus Hamming-weight parity budgets independently. Trace the reported false prune to one pinned predecessor (#2542, #2634 or #2691), then test a small exhaustive domain. Stop after a source-impact handoff or corrected-prune proof; a full seven-label replay needs a separate resource budget and a named research decision it can change.", + "bottleneck_link": "An unsound exclusion can wrongly close a mechanism; correcting its dependency boundary is more useful than extending the same census.", + "allowed_variations": [ + "One predecessor pruning rule, one independently exhaustive small domain, or one downstream dependency audit." + ], + "scope_change_triggers": [ + "Launching a larger census before validating the prune and explaining which active decision it changes.", + "Treating a small-domain counterexample to the old rule as a counterexample to every reported seven-label bound." + ], + "overlap_terms": [ + "2973", + "2542", + "2634", + "2691", + "weight parity", + "bit-0", + "01021323", + "census pruning" + ] + }, + "scope_status": "refined", + "actual_scope": "For the class-C one-sided K2 residue census of Discussion #2954: independently audit the published 4-flat covering-config tables against the published g-table and the sum g <= 52 admissibility bound, and compute the exact minimal set of configs needed to cover the rows that relative root counting does not kill. Audits tables only; the E8/P112 geometry, kill criterion (Lemma B) and RRC are not re-derived or verified.", + "scope_change_reason": "The card's named artefact is the #2973 weight-parity census and its predecessors #2542/#2634/#2691. Per the standing handoff-first rule (autoresearch.md step 2) this session took the live, unclaimed concrete request in Discussion #2954 instead, and applied the card's accepted discipline - distinguish a prunable enumeration from a final bound, and state exactly which downstream exclusions need revalidation - to that census. The refusal to treat a prunable row as a disproved bound is the card's own scope_change_trigger and is honoured: no residue exclusion is claimed here.", + "bottleneck_link": "Side result for the selected frontier, not a supplier improvement. Its value is avoiding compute: the audited campaign's advertised cheapest config is provably useless for the hard rows, and three of the advertised configs are provably redundant, so a ~3e5 CPU-h enumeration can be cut before it starts.", + "budget_minutes": 60, + "stop_rule": "Stop after the table audit, the exact set-cover result and one focused PR. Do not run any s4z/closure compute, do not attempt route A (span lemma), and do not touch the RRC scenario list.", + "outcome": "completed", + "evidence": "Author-checked. 11/11 structural checks pass and 5/5 rejecting mutants are rejected by research/k2-class-c-config-audit/verify.py (Python 3.12, standard library, <1 s), printing PASS_K2_CLASS_C_CONFIG_AUDIT with exit 0. The decisive check is that dominance closure reproduces all five published per-config totals of Discussion #2954 exactly (6554:62, 5555:27, 6544:40, 5554:23, 6543:16) while literal incidence does not, which recovers the cover relation. Under it the exact minimum cover of the 16 config-coverable hard rows is {5555, 6554}; 11 of the 13 table configs are redundant. RESULT.json records every derived quantity. Not independently reviewed by a second party. No E8/P112 geometry, span criterion or RRC claim.", + "author": "muatfannajm-dot", + "ai_assistance": "Substantial assistance from OpenCode (Space Bunny Free model), an open-source coding agent, in writing the audit, running it and drafting the PR. All mathematical statements and the pinned inputs were chosen and checked by the author; the agent did not supply the mathematics of the audited help package, which is DreamingOfClouds' work.", + "open_questions": [ + { + "question": "Is the list of admissible 4-flat configs complete? The audit checks that every listed config satisfies sum g <= 52, but the piece-packing rule that decides whether a row admits a config at all is only sketched in #2954, so a missing config would not be detected.", + "why_it_matters": "Completeness is what makes the redundancy result a real saving rather than an artefact of the published list. If, say, (5,5,4,4) is admissible for some hard row, the minimal cover grows and the 4.4e8-pair saving shrinks.", + "first_step": "Ask DreamingOfClouds for the exact packing predicate that maps a row's weight multiset to its config list, then re-run the audit with an independently generated config set and compare against inputs/rows70.csv.", + "blocked_by": "The packing predicate is not published in the help package; s4z.c encodes it only implicitly." + }, + { + "question": "Row 37 (and rows 3, 12, 24, 54, 61) admit no 4-flat config at all. Does the A2 / rank-2 root-counting argument that RRC uses also dispose of them, or do they need a genuinely different cover model?", + "why_it_matters": "These 6 rows are unreachable by every advertised config, so any campaign that only runs 4-flat closure leaves them open no matter how much compute is spent. They are the hard residue of the residue.", + "first_step": "Take row 37's weight multiset [7,7,7,6,6,6,6,6,6,4,4,4,2] and the two-free-piece alternative explicitly; check whether a 5-flat or a two-free-piece cover exists with sum g <= 52, or prove none does.", + "blocked_by": "Needs the E8/P112 flat geometry and the unpublished RRC scenario list." + }, + { + "question": "Do the 3 redundant configs (5554, 6444, 6544) matter for any row outside this table, e.g. for the 116 open residues of PR2985/PR3049?", + "why_it_matters": "The redundancy is proved only relative to these 70 rows. The wider residue chains reuse the same config vocabulary, so the saving could be larger or could not transfer at all.", + "first_step": "Run this audit unchanged against the residue tables in PR2985 and PR3049 after pinning their heads.", + "blocked_by": "Those PRs' residue tables are not vendored here and their heads are unpinned in this package." + } + ] +} \ No newline at end of file diff --git a/research/k2-class-c-config-audit/VERIFY.json b/research/k2-class-c-config-audit/VERIFY.json new file mode 100644 index 0000000000..a5c86c9d66 --- /dev/null +++ b/research/k2-class-c-config-audit/VERIFY.json @@ -0,0 +1,21 @@ +{ + "schema_version": 1, + "status": "ready", + "python": "3.12", + "requirements": [], + "inputs": [ + "research/k2-class-c-config-audit/inputs/rows70.csv", + "research/k2-class-c-config-audit/inputs/rows17.csv" + ], + "commands": [ + { + "argv": [ + "{python}", + "-B", + "{package}/verify.py" + ], + "timeout_seconds": 120, + "checks": "PASS_K2_CLASS_C_CONFIG_AUDIT on stdout and exit 0. Positive fixture: the pinned unmodified tables satisfy all 8 structural checks and the exact set-cover result {5544,5555,6554}. Rejecting controls (4 mutants, each must be rejected by >=1 check): (1) inject inadmissible config 6555 with sum g = 56 > 52; (2) drop row 62 from rows17; (3) flip one RRC status so the kill count leaves 53; (4) edit row 35's configs in rows17 only, desynchronising it from rows70. Also asserts both inputs match their pinned sha256." + } + ] +} \ No newline at end of file diff --git a/research/k2-class-c-config-audit/inputs/rows17.csv b/research/k2-class-c-config-audit/inputs/rows17.csv new file mode 100644 index 0000000000..ef453f30c2 --- /dev/null +++ b/research/k2-class-c-config-audit/inputs/rows17.csv @@ -0,0 +1,18 @@ +row_idx,d,s,weights,e,covering_4flat_configs +7,7,7,"[7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 4]",4,5554 5555 6554 +8,7,7,"[7, 7, 6, 6, 6, 6, 6, 6, 4, 4, 4, 1]",5,6544 6554 +13,7,7,"[7, 7, 7, 6, 6, 6, 6, 5, 4, 4, 4, 1]",5,5544 6444 5554 6544 +21,8,6,"[7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 4]",4,5554 5555 6554 +34,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 4, 1]",5,5555 6554 +35,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5]",4,5555 +36,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 4, 4, 4, 1, 1]",6,6554 +37,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 4, 4, 4, 2]",5, +40,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 4, 4, 1]",5,6554 +42,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 3, 1]",5,6554 +43,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 4]",4,6554 +46,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 5, 4, 4, 4, 1, 1]",6,5554 6544 5555 6554 +47,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 5, 4, 4, 4, 2]",5,6544 6554 +50,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 4, 4, 1]",5,5554 6544 5555 6554 +53,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 4]",4,5554 5555 6554 +57,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 6, 4, 4, 4, 1]",5,6544 6554 +62,8,7,"[7, 7, 7, 7, 7, 6, 6, 6, 5, 4, 4, 4, 1]",5,5544 6444 5554 6544 diff --git a/research/k2-class-c-config-audit/inputs/rows70.csv b/research/k2-class-c-config-audit/inputs/rows70.csv new file mode 100644 index 0000000000..ee12fc8e3c --- /dev/null +++ b/research/k2-class-c-config-audit/inputs/rows70.csv @@ -0,0 +1,71 @@ +row_idx,d,s,weights,e,rrc_status,covering_4flat_configs +0,6,7,"[7, 6, 6, 6, 6, 6, 5, 5, 4, 4]",4,RRC-killed(under audit),5544 5554 6544 5555 +1,6,7,"[7, 6, 6, 6, 6, 6, 6, 4, 4, 4]",4,RRC-killed(under audit),6444 6544 6554 +2,6,7,"[7, 6, 6, 6, 6, 6, 6, 5, 4, 3]",4,RRC-killed(under audit),6543 6544 6553 6554 +3,6,7,"[7, 6, 6, 6, 6, 6, 6, 6, 3, 3]",4,RRC-killed(under audit), +4,6,7,"[7, 7, 6, 6, 6, 6, 6, 4, 4, 3]",4,RRC-killed(under audit),6443 6444 6543 6544 +5,6,7,"[7, 7, 6, 6, 6, 6, 6, 5, 3, 3]",4,RRC-killed(under audit),6533 6543 6544 6553 +6,7,6,"[7, 7, 7, 6, 6, 6, 6, 6, 4, 4, 3]",4,RRC-killed(under audit),6443 6444 6543 6544 +7,7,7,"[7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 4]",4,HARD,5554 5555 6554 +8,7,7,"[7, 7, 6, 6, 6, 6, 6, 6, 4, 4, 4, 1]",5,HARD,6544 6554 +9,7,7,"[7, 7, 6, 6, 6, 6, 6, 6, 5, 4, 3, 1]",5,RRC-killed(under audit),6544 6553 6554 +10,7,7,"[7, 7, 6, 6, 6, 6, 6, 6, 5, 4, 4]",4,RRC-killed(under audit),6544 6554 +11,7,7,"[7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 3]",4,RRC-killed(under audit),6553 6554 +12,7,7,"[7, 7, 6, 6, 6, 6, 6, 6, 6, 4, 3]",4,RRC-killed(under audit), +13,7,7,"[7, 7, 7, 6, 6, 6, 6, 5, 4, 4, 4, 1]",5,HARD,5544 6444 5554 6544 +14,7,7,"[7, 7, 7, 6, 6, 6, 6, 5, 5, 4, 3, 1]",5,RRC-killed(under audit),5544 5553 6543 5554 +15,7,7,"[7, 7, 7, 6, 6, 6, 6, 5, 5, 4, 4]",4,RRC-killed(under audit),5544 5554 6544 5555 +16,7,7,"[7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 3]",4,RRC-killed(under audit),5553 5554 6553 5555 +17,7,7,"[7, 7, 7, 6, 6, 6, 6, 6, 4, 4, 3, 1]",5,RRC-killed(under audit),6444 6543 6544 6553 +18,7,7,"[7, 7, 7, 6, 6, 6, 6, 6, 4, 4, 4]",4,RRC-killed(under audit),6444 6544 6554 +19,7,7,"[7, 7, 7, 6, 6, 6, 6, 6, 5, 4, 3]",4,RRC-killed(under audit),6543 6544 6553 6554 +20,7,7,"[7, 7, 7, 7, 6, 6, 6, 6, 4, 4, 3]",4,RRC-killed(under audit),6443 6444 6543 6544 +21,8,6,"[7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 4]",4,HARD,5554 5555 6554 +22,8,6,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 4, 4]",4,RRC-killed(under audit),6544 6554 +23,8,6,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 3]",4,RRC-killed(under audit),6553 6554 +24,8,6,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 4, 3]",4,RRC-killed(under audit), +25,8,6,"[7, 7, 7, 7, 6, 6, 6, 5, 5, 5, 5, 4]",4,RRC-killed(under audit),5554 5555 6554 +26,8,6,"[7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 4, 4]",4,RRC-killed(under audit),5544 5554 6544 5555 +27,8,6,"[7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 3]",4,RRC-killed(under audit),5553 5554 6553 5555 +28,8,6,"[7, 7, 7, 7, 6, 6, 6, 6, 6, 4, 4, 3, 1]",5,RRC-killed(under audit),6444 6543 6544 6553 +29,8,6,"[7, 7, 7, 7, 6, 6, 6, 6, 6, 4, 4, 4]",4,RRC-killed(under audit),6444 6544 6554 +30,8,6,"[7, 7, 7, 7, 6, 6, 6, 6, 6, 5, 4, 3]",4,RRC-killed(under audit),6543 6544 6553 6554 +31,8,6,"[7, 7, 7, 7, 7, 6, 6, 6, 5, 4, 4, 4]",4,RRC-killed(under audit),5444 5544 6444 5554 +32,8,6,"[7, 7, 7, 7, 7, 6, 6, 6, 5, 5, 4, 3]",4,RRC-killed(under audit),5543 5544 5553 6543 +33,8,6,"[7, 7, 7, 7, 7, 6, 6, 6, 6, 4, 4, 3]",4,RRC-killed(under audit),6443 6444 6543 6544 +34,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 4, 1]",5,HARD,5555 6554 +35,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5]",4,HARD,5555 +36,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 4, 4, 4, 1, 1]",6,HARD,6554 +37,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 4, 4, 4, 2]",5,HARD, +38,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 4, 3, 1, 1]",6,RRC-killed(under audit),6554 +39,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 4, 3, 2]",5,RRC-killed(under audit),6554 +40,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 4, 4, 1]",5,HARD,6554 +41,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 2, 2]",5,RRC-killed(under audit),6554 +42,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 3, 1]",5,HARD,6554 +43,8,7,"[7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 4]",4,HARD,6554 +44,8,7,"[7, 7, 7, 7, 6, 6, 6, 5, 5, 5, 5, 4, 1]",5,RRC-killed(under audit),5555 6554 +45,8,7,"[7, 7, 7, 7, 6, 6, 6, 5, 5, 5, 5, 5]",4,RRC-killed(under audit),5555 +46,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 5, 4, 4, 4, 1, 1]",6,HARD,5554 6544 5555 6554 +47,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 5, 4, 4, 4, 2]",5,HARD,6544 6554 +48,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 4, 3, 1, 1]",6,RRC-killed(under audit),5554 6544 6553 5555 +49,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 4, 3, 2]",5,RRC-killed(under audit),5554 6553 5555 6554 +50,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 4, 4, 1]",5,HARD,5554 6544 5555 6554 +51,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 2, 2]",5,RRC-killed(under audit),5554 5555 6554 +52,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 3, 1]",5,RRC-killed(under audit),5554 6553 5555 6554 +53,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 4]",4,HARD,5554 5555 6554 +54,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 6, 4, 3, 3, 3]",5,RRC-killed(under audit), +55,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 6, 4, 4, 3, 1, 1]",6,RRC-killed(under audit),6544 6553 6554 +56,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 6, 4, 4, 3, 2]",5,RRC-killed(under audit),6544 6554 +57,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 6, 4, 4, 4, 1]",5,HARD,6544 6554 +58,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 6, 5, 4, 3, 1]",5,RRC-killed(under audit),6544 6553 6554 +59,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 6, 5, 4, 4]",4,RRC-killed(under audit),6544 6554 +60,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 3]",4,RRC-killed(under audit),6553 6554 +61,8,7,"[7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 4, 3]",4,RRC-killed(under audit), +62,8,7,"[7, 7, 7, 7, 7, 6, 6, 6, 5, 4, 4, 4, 1]",5,HARD,5544 6444 5554 6544 +63,8,7,"[7, 7, 7, 7, 7, 6, 6, 6, 5, 5, 4, 3, 1]",5,RRC-killed(under audit),5544 5553 6543 5554 +64,8,7,"[7, 7, 7, 7, 7, 6, 6, 6, 5, 5, 4, 4]",4,RRC-killed(under audit),5544 5554 6544 5555 +65,8,7,"[7, 7, 7, 7, 7, 6, 6, 6, 5, 5, 5, 3]",4,RRC-killed(under audit),5553 5554 6553 5555 +66,8,7,"[7, 7, 7, 7, 7, 6, 6, 6, 6, 4, 4, 3, 1]",5,RRC-killed(under audit),6444 6543 6544 6553 +67,8,7,"[7, 7, 7, 7, 7, 6, 6, 6, 6, 4, 4, 4]",4,RRC-killed(under audit),6444 6544 6554 +68,8,7,"[7, 7, 7, 7, 7, 6, 6, 6, 6, 5, 4, 3]",4,RRC-killed(under audit),6543 6544 6553 6554 +69,8,7,"[7, 7, 7, 7, 7, 7, 6, 6, 6, 4, 4, 3]",4,RRC-killed(under audit),6443 6444 6543 6544 diff --git a/research/k2-class-c-config-audit/verify.py b/research/k2-class-c-config-audit/verify.py new file mode 100644 index 0000000000..2f5776c107 --- /dev/null +++ b/research/k2-class-c-config-audit/verify.py @@ -0,0 +1,474 @@ +#!/usr/bin/env python3 +"""Audit of the class-C 4-flat covering-config census (Discussion #2954 help package). + +Scope: audits only the PUBLISHED TABLES and the PUBLISHED g-table / pair-count +table. It does NOT touch the E8/P112 geometry, does NOT verify the kill +criterion (Lemma B), and does NOT verify relative root counting (RRC, which the +help post itself marks as under audit). No kappa, decoder, supplier or +exclusion claim is made or implied. + +Inputs (pinned, read-only, package-local copies of the upstream help package): + inputs/rows70.csv, inputs/rows17.csv, from DreamingOfClouds/integer-mult-bounds + branch research/k2-class-c-help, path research/k2-class-c-help/, help-package + source commit 1b25759bff5486293a9083ebbe0097b5f6642e08. + g-table and pair counts are quoted from the same help post / README. + +Outputs: printed report + RESULT.json. Exit status 0 iff every check passed and +every rejecting control was rejected. + +muatfannajm-dot, with substantial OpenCode (Space Bunny Free) assistance. +Apache-2.0. Credit DreamingOfClouds for the audited help package. +""" + +import csv +import json +import os +import sys +from itertools import combinations + +HERE = os.path.dirname(os.path.abspath(__file__)) + +# sha256 of the pinned inputs, checked on every run (byte-equality receipt for +# inputs that are not Git objects in this repository). +INPUT_SHA256 = { + "rows70.csv": "c0eb6bb88498bf39a8b2020b1d0d600181f6e13eb9dd6a6e5f90794f0895754a", + "rows17.csv": "9ebe7fc1ecd74148e7bdefa1f6bb2ed00551884b1a4a6558d7f129f7eef4efd5", +} + +# Published in Discussion #2954: "a weight-w piece has supp in a w-dim flat, so +# |Lambda(V)| <= g(w), g(1..7) = 1,2,4,8,12,20,36". +G = {1: 1, 2: 2, 3: 4, 4: 8, 5: 12, 6: 20, 7: 36} + +# Published in the same post: "Lemma B needs sum g <= 52". +SUM_G_BOUND = 52 + +# Published in the help README, verbatim pair counts (scientific base +# 1b25759bff5486293a9083ebbe0097b5f6642e08). Only these exact strings are used +# for the savings figure; anything else is reported as unstated. +README_PAIRS = { + "6543": 2.6e7, # (6,5,4,3) a=3 b=6 c=4 d=5 + "6544": 1.1e8, # (6,5,4,4) a=4 b=6 + "6554": 1.1e8, # (6,5,5,4) a=4 b=6 + "5554": 3.3e8, # (5,5,5,4) a=5 b=5 + "5555": 3.3e8, # (5,5,5,5) a=5 b=5 +} + +# Published in Discussion #2954: "Covering configs: (6,5,5,4) covers 62 of the +# 70 rows, (5,5,5,5) 27, (6,5,4,4) 40, (5,5,5,4) 23, (6,5,4,3) 16". +# +# These totals are the decisive evidence for WHAT THE COVER RELATION IS. They +# are reproduced exactly by DOMINANCE CLOSURE (a config may serve any row its +# listed config is dominated by), and NOT by literal CSV incidence. Treating the +# relation as literal incidence understates 6554 badly (39, not 62) and yields +# the wrong minimum cover. +PUBLISHED_TOTALS = { + "6554": 62, + "5555": 27, + "6544": 40, + "5554": 23, + "6543": 16, +} + + +def dominates(a, b): + """True if config `a` is coordinatewise >= config `b` (both stored in + non-increasing dimension order), i.e. `a` can serve every row `b` can. + + The published per-config totals pin this down: they are exactly the + dominance-closed row counts, so this is the help package's own cover + relation, recovered from its published numbers rather than assumed. + """ + return all(x >= y for x, y in zip(parse_config(a), parse_config(b))) + + +def parse_config(tok): + """'6554' -> (6,5,5,4); raise on malformed input.""" + if not tok or not tok.isdigit() or len(tok) != 4: + raise ValueError("malformed config token %r" % (tok,)) + dims = tuple(int(c) for c in tok) + if list(dims) != sorted(dims, reverse=True): + raise ValueError("config %r is not in non-increasing order" % (tok,)) + if any(d not in G for d in dims): + raise ValueError("config %r uses a dimension outside g(1..7)" % (tok,)) + return dims + + +def config_cost(tok): + """X = sum of g over the four flat dimensions.""" + return sum(G[d] for d in parse_config(tok)) + + +def relation_data(rows70): + """Return (all_configs, literal_counts, dominance_closed_counts). + + `literal` : a config serves exactly the rows that list it. + `closed` : a config also serves the rows of any config it dominates. + """ + uni = sorted({c for r in rows70 for c in r["configs"]}) + literal = {c: {r["row_idx"] for r in rows70 if c in r["configs"]} + for c in uni} + closed = {} + for c in uni: + donors = [d for d in uni if dominates(c, d)] + closed[c] = {r["row_idx"] for r in rows70 + if any(d in r["configs"] for d in donors)} + return uni, literal, closed + + +def dominance_checks(rows70): + """Pin the cover relation down from the published per-config totals. + + Split out of main() so the rejecting controls exercise it too. + """ + _, literal, closed = relation_data(rows70) + tot_ok, det = True, [] + for c, want in sorted(PUBLISHED_TOTALS.items()): + tot_ok = tot_ok and len(closed[c]) == want + det.append("%s closed=%d literal=%d published=%d%s" + % (c, len(closed[c]), len(literal[c]), want, + "" if len(closed[c]) == want else " <-- MISMATCH")) + return [ + {"name": "dominance closure reproduces all 5 published per-config totals", + "ok": tot_ok, "detail": "; ".join(det)}, + {"name": "literal incidence does NOT reproduce the published totals", + "ok": any(len(literal[c]) != want + for c, want in PUBLISHED_TOTALS.items()), + "detail": "so literal incidence is the wrong cover relation"}, + ] + + +def load_rows(path): + out = [] + with open(path, newline="", encoding="utf-8") as fh: + for rec in csv.DictReader(fh): + cfgs = (rec.get("covering_4flat_configs") or "").split() + out.append( + { + "row_idx": int(rec["row_idx"]), + "d": int(rec["d"]), + "s": int(rec["s"]), + "e": int(rec["e"]), + "weights": json.loads(rec["weights"]), + "rrc_status": (rec.get("rrc_status") or "").strip(), + "configs": cfgs, + } + ) + return out + + +def run_checks(rows70, rows17): + """Return (checks, derived). Split out so mutants can be run through the + identical check logic (rejecting controls).""" + checks = [] + + def check(name, ok, detail=""): + checks.append({"name": name, "ok": bool(ok), "detail": detail}) + return ok + + import hashlib + for fname, want in sorted(INPUT_SHA256.items()): + with open(os.path.join(HERE, "inputs", fname), "rb") as fh: + got = hashlib.sha256(fh.read()).hexdigest() + check("input %s matches its pinned sha256" % fname, got == want, + "" if got == want else "got %s want %s" % (got, want)) + + all_cfgs = sorted({c for r in rows70 for c in r["configs"]}) + cost = {c: config_cost(c) for c in all_cfgs} + + check("rows70 has 70 rows", len(rows70) == 70, "got %d" % len(rows70)) + check("rows17 has 17 rows", len(rows17) == 17, "got %d" % len(rows17)) + + bad = {c: v for c, v in cost.items() if v > SUM_G_BOUND} + check("all listed configs satisfy sum g <= %d" % SUM_G_BOUND, + not bad, "violations=%s" % (bad or "none")) + check("6554 saturates the bound exactly (sum g = 52)", + cost.get("6554") == SUM_G_BOUND, "6554 -> %s" % cost.get("6554")) + + rrc_killed = {r["row_idx"] for r in rows70 + if r["rrc_status"].upper().startswith("RRC-KILLED")} + surviving = {r["row_idx"] for r in rows70} - rrc_killed + idx17 = {r["row_idx"] for r in rows17} + check("rows17 == rows70 minus RRC-killed rows", surviving == idx17, + "symmetric_difference=%s" % (sorted(surviving ^ idx17) or "empty")) + check("RRC kills 53 of 70 rows (as published)", + len(rrc_killed) == 53, "killed=%d" % len(rrc_killed)) + + by70 = {r["row_idx"]: r for r in rows70} + mism = [] + for r in rows17: + b = by70.get(r["row_idx"]) + if b is None: + mism.append((r["row_idx"], "absent from rows70")) + continue + for k in ("d", "s", "e", "weights", "configs"): + if r[k] != b[k]: + mism.append((r["row_idx"], k)) + check("rows17 fields agree with rows70 for every shared row", + not mism, "mismatches=%s" % (mism or "none")) + + return checks, all_cfgs, cost, rrc_killed + + +def self_test(rows70, rows17): + """Rejecting controls: each mutant must make at least one check FAIL.""" + def clone(rows): + return [dict(r) for r in rows] + + mutants = [] + + # M1: inject a config that violates the sum-g <= 52 admissibility bound + # (6,5,5,5) -> 20+12+12+12 = 56 > 52. + m = clone(rows70) + for r in m: + if r["row_idx"] == 7: + r["configs"] = sorted(r["configs"] + ["6555"]) + mutants.append(("inject inadmissible config 6555 (sum g = 56)", m, rows17)) + + # M2: drop a surviving row from rows17. + m17 = [r for r in clone(rows17) if r["row_idx"] != 62] + mutants.append(("drop row 62 from rows17", rows70, m17)) + + # M3: flip one row's RRC status so the kill count is no longer 53. + m = clone(rows70) + for r in m: + if r["row_idx"] == 3: + r["rrc_status"] = "open" + mutants.append(("flip row 3 RRC status (kill count 53 -> 52)", m, rows17)) + + # M4: silently desynchronise rows17 configs from rows70 for one row. + m17 = clone(rows17) + for r in m17: + if r["row_idx"] == 35: + r["configs"] = ["5555", "6544"] + mutants.append(("edit row 35 configs in rows17 only", rows70, m17)) + + # M5: target the decisive dominance check directly. Adding 6554 to one + # more row moves its dominance-closed count off the published 62. + m = clone(rows70) + for r in m: + if r["row_idx"] == 3: + r["configs"] = sorted(set(r["configs"]) | {"6554"}) + mutants.append(("add 6554 to row 3 (closed total 62 -> 63)", m, rows17)) + + out = [] + for name, a, b in mutants: + checks, _, _, _ = run_checks(a, b) + checks.extend(dominance_checks(a)) + failed = [c["name"] for c in checks if not c["ok"]] + out.append({"mutant": name, "rejected": bool(failed), + "failed_checks": failed}) + print("[%s] control: %s%s" + % ("PASS" if failed else "FAIL", name, + (" -> " + "; ".join(failed)) if failed else " -> NOT REJECTED")) + return out + + +def main(): + rows70 = load_rows(os.path.join(HERE, "inputs", "rows70.csv")) + rows17 = load_rows(os.path.join(HERE, "inputs", "rows17.csv")) + + checks, all_cfgs, cost, rrc_killed = run_checks(rows70, rows17) + + def check(name, good, detail=""): + checks.append({"name": name, "ok": bool(good), "detail": detail}) + return good + + surviving = {r["row_idx"] for r in rows70} - rrc_killed + + def ok(name): + return next(c["ok"] for c in checks if c["name"] == name) + + # ---- E. minimal config set covering the 17 surviving rows --------- + # Two cover relations are computed and both reported: + # literal -- a config serves exactly the rows that list it; + # dominance -- a config also serves rows of any config it dominates. + # PUBLISHED_TOTALS decides which one is the help package's relation. + checks.extend(dominance_checks(rows70)) + need = [r["row_idx"] for r in rows17] + universe = sorted({c for r in rows17 for c in r["configs"]}) + all_universe, literal, closed = relation_data(rows70) + + cover_of = {c: closed[c] for c in universe} + cover_of_lit = {c: literal[c] for c in universe} + uncoverable = [i for i in need if not any(i in cover_of[c] for c in universe)] + + def min_cover(targets, pool, rel): + """Exact minimum set cover by brute force. Callers must pass only + targets that some pool member actually covers.""" + targets = set(targets) + if not targets: + return [] + for k in range(1, len(pool) + 1): + for combo in combinations(sorted(pool), k): + got = set() + for c in combo: + got |= rel[c] + if targets <= got: + return list(combo) + return [] + + minimal = min_cover([i for i in need if i not in uncoverable], universe, + cover_of) + redundant = [c for c in universe if c not in minimal] + # Contrast only: the same computation under the wrong (literal) relation, + # kept so the difference is auditable rather than merely asserted. + minimal_literal = min_cover([i for i in need if i not in uncoverable], + universe, cover_of_lit) + check("6554 dominates 5544, 6444, 6544 and 6543", + all(dominates("6554", d) for d in ("5544", "6444", "6544", "6543")), + "dims 6554=(6,5,5,4)") + + # ---- F. coverage of all 70 rows by the minimal set ----------------- + allrows = [r["row_idx"] for r in rows70] + cover70 = {c: closed[c] for c in all_universe} + uncoverable70 = [i for i in allrows + if not any(i in cover70[c] for c in all_universe)] + minimal70 = min_cover([i for i in allrows if i not in uncoverable70], + all_universe, cover70) + redundant70 = [c for c in all_universe if c not in minimal70] + + # ---- G. which configs are reachable only from RRC-killed rows ----- + killed_only_configs = sorted( + { + c + for r in rows70 + if r["row_idx"] in rrc_killed + for c in r["configs"] + } + - set(universe) + ) + + # ---- H. rows with no covering config at all ------------------------ + none70 = sorted(r["row_idx"] for r in rows70 if not r["configs"]) + none17 = sorted(r["row_idx"] for r in rows17 if not r["configs"]) + + # ---- I. cost of the dropped configs (README numbers only) ---------- + stated_min = {c: README_PAIRS[c] for c in minimal if c in README_PAIRS} + stated_redundant = {c: README_PAIRS[c] for c in redundant if c in README_PAIRS} + stated_redundant70 = { + c: README_PAIRS[c] for c in redundant70 if c in README_PAIRS + } + saving_pairs = sum(stated_redundant.values()) + saving_pairs70 = sum(stated_redundant70.values()) + unstated = [c for c in universe if c not in README_PAIRS] + + controls = self_test(rows70, rows17) + all_controls_rejected = all(c["rejected"] for c in controls) + + result = { + "scope": ( + "Audit of the published class-C 4-flat covering-config census only. " + "No E8/P112 geometry re-derived; no verification of kill criterion " + "Lemma B; no verification of relative root counting (RRC). No kappa, " + "decoder, supplier or residue-exclusion claim." + ), + "not_verified": [ + "Completeness of the config list: only admissibility (sum g <= 52) of " + "each listed config is checked. Whether the author's piece-packing " + "rule admits further configs is NOT checked; that rule is only " + "sketched in Discussion #2954.", + "The kill criterion itself (Lemma B) and span_H <= d-1.", + "RRC (relative root counting), which the help post marks under audit; " + "the 53-of-70 kill count is taken as given and only checked for " + "internal consistency between the two CSVs.", + "Pair counts and CPU-hour ETAs are the README's published figures, " + "reused verbatim, not re-measured.", + ], + "checks": checks, + "all_checks_passed": all(c["ok"] for c in checks), + "controls": controls, + "all_controls_rejected": all_controls_rejected, + "g_table": {str(k): v for k, v in G.items()}, + "sum_g_bound": SUM_G_BOUND, + "configs_listed_anywhere": all_cfgs, + "config_costs": cost, + "rrc_killed_count": len(rrc_killed), + "surviving_row_indices": sorted(surviving), + "configs_appearing_in_17_rows": universe, + "cover_of_config_dominance": {c: sorted(cover_of[c]) for c in universe}, + "cover_of_config_literal": {c: sorted(cover_of_lit[c]) + for c in universe}, + "published_per_config_totals": PUBLISHED_TOTALS, + "row_counts_literal": {c: len(literal[c]) for c in all_universe}, + "row_counts_dominance_closed": {c: len(closed[c]) + for c in all_universe}, + "cover_relation": "dominance (recovered from the 5 published totals)", + "rows17_with_no_config": none17, + "rows70_with_no_config": none70, + "rows_not_coverable_by_any_listed_config": uncoverable, + "minimal_config_set_for_17_rows": minimal, + "minimal_config_set_for_17_rows_LITERAL_relation_WRONG": + minimal_literal, + "redundant_configs_for_17_rows": redundant, + "minimal_config_set_for_70_rows": minimal70, + "redundant_configs_for_70_rows": redundant70, + "rows70_coverable_by_some_listed_config": sorted( + i for i in allrows if i not in uncoverable70 + ), + "rows70_not_coverable_by_any_listed_config": uncoverable70, + "configs_only_on_rrc_killed_rows": killed_only_configs, + "readme_stated_pairs": README_PAIRS, + "stated_pairs_for_minimal_17": stated_min, + "stated_pairs_dropped_for_17": stated_redundant, + "stated_pairs_dropped_for_70": stated_redundant70, + "pairs_saved_by_minimal_set_17": saving_pairs, + "pairs_saved_by_minimal_set_70": saving_pairs70, + "configs_with_no_stated_pair_count": unstated, + } + + # ---- report -------------------------------------------------------- + print("=" * 72) + print("class-C 4-flat covering-config census audit (Discussion #2954)") + print("=" * 72) + for c in checks: + print("[%s] %s%s" % ("PASS" if c["ok"] else "FAIL", c["name"], + (" -- " + c["detail"]) if c["detail"] else "")) + print("-" * 72) + print("sum g per listed config (bound %d):" % SUM_G_BOUND) + for c in all_cfgs: + print(" %s -> %2d %s" % (c, cost[c], + " [README pairs %g]" % README_PAIRS[c] if c in README_PAIRS + else " [pair count NOT stated in README]")) + print("-" * 72) + print("configs appearing on the 17 surviving rows:", universe) + print("rows among the 17 with NO config at all :", none17) + print("rows among the 70 with NO config at all :", none70) + print("cover relation (recovered from totals) : dominance closure") + print(" cfg literal dominance-closed published(#2954)") + for c in all_universe: + st = PUBLISHED_TOTALS.get(c) + print(" %s %4d %4d %s" + % (c, len(literal[c]), len(closed[c]), + st if st else "-")) + print("cover the 16 hard rows that have a cfg :", minimal) + print(" (same, under the WRONG literal relation):", minimal_literal) + print("configs redundant for those 16 rows :", redundant) + print("cover all 64 rows that have a config :", minimal70) + print("configs redundant for all 70 rows :", redundant70) + print("configs only ever seen on RRC-killed rows :", killed_only_configs) + print("-" * 72) + print("stated pair counts dropped for the 17-row campaign: %g pairs" + % saving_pairs) + print("stated pair counts dropped for the 70-row campaign: %g pairs" + % saving_pairs70) + print("configs with NO stated pair count (excluded from the above):", unstated) + print("-" * 72) + print("RESULT: %s ; controls all rejected: %s" + % ("all checks passed" if result["all_checks_passed"] + else "SOME CHECKS FAILED", all_controls_rejected)) + + # newline="\n" so the emitted bytes match the repository's canonical + # LF index form (*.gitattributes: * text=auto eol=lf); otherwise a Windows + # run would write CRLF and `check_research_commit.py` would report a + # working/commit byte difference with an empty `git diff`. + with open(os.path.join(HERE, "RESULT.json"), "w", encoding="utf-8", + newline="\n") as fh: + json.dump(result, fh, indent=2, sort_keys=True) + fh.write("\n") + if result["all_checks_passed"] and all_controls_rejected: + print("PASS_K2_CLASS_C_CONFIG_AUDIT") + return 0 if (result["all_checks_passed"] and all_controls_rejected) else 1 + + +if __name__ == "__main__": + sys.exit(main()) \ No newline at end of file