From 12c4789c61ac843dcd00e2c71e5388d362298b1a Mon Sep 17 00:00:00 2001 From: DaysSky <88261516+DaysSky@users.noreply.github.com> Date: Tue, 13 Oct 2026 10:57:20 +0000 Subject: [PATCH] Classify the covers of E7 by hyperplane flats No new kappa. Exhaustive and exact (ranks mod 2^31-1, equal to rational ranks by Hadamard): - the 315 covering triples are exactly the D6 triples of the D4 frames through t; the 3780 4A1 frames miss at least 8 lines; - the 378 near-covers (62 of 63) are exactly E6(A)+E6(B)+D6(m) for the A3 subsystems through t, missing m; - two rank-5 subflats never cover a D6 (28 of 30) but do cover its 16 private lines, and a 2+2+2 rank-5 cover of E7 exists, so the cover count alone does not force 3 registers per D6 pool. Agrees with main's D1 census (8821 flats, best pair 52, cover number 3). --- .gitattributes | 1 + .../e7-flat-cover-classification.yml | 37 +++ research/e7-flat-cover-classification/LICENSE | 201 ++++++++++++ .../e7-flat-cover-classification/NOTICE.md | 8 + .../e7-flat-cover-classification/README.md | 88 ++++++ .../cover_check.py | 299 ++++++++++++++++++ 6 files changed, 634 insertions(+) create mode 100644 .github/workflows/e7-flat-cover-classification.yml create mode 100644 research/e7-flat-cover-classification/LICENSE create mode 100644 research/e7-flat-cover-classification/NOTICE.md create mode 100644 research/e7-flat-cover-classification/README.md create mode 100644 research/e7-flat-cover-classification/cover_check.py diff --git a/.gitattributes b/.gitattributes index 6b648c37d1..b63132a1c7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -119,3 +119,4 @@ research/tintagel-source-lookup/** -text -whitespace research/trace-curvature-preload/** -text -whitespace research/witness-spec-tools/** -text -whitespace research/community-family588-audit/** -text -whitespace +research/e7-flat-cover-classification/** -text -whitespace diff --git a/.github/workflows/e7-flat-cover-classification.yml b/.github/workflows/e7-flat-cover-classification.yml new file mode 100644 index 0000000000..7e8213a831 --- /dev/null +++ b/.github/workflows/e7-flat-cover-classification.yml @@ -0,0 +1,37 @@ +name: Check the E7 flat-cover classification + +on: + push: + paths: + - 'research/e7-flat-cover-classification/**' + - 'research/format-limits/scripts/d1_cover_numbers.py' + - '.github/workflows/e7-flat-cover-classification.yml' + pull_request: + paths: + - 'research/e7-flat-cover-classification/**' + - 'research/format-limits/scripts/d1_cover_numbers.py' + - '.github/workflows/e7-flat-cover-classification.yml' + workflow_dispatch: + +permissions: + contents: read + +jobs: + check: + runs-on: ubuntu-24.04 + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + python-version: ['3.11', '3.14'] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7 + with: + python-version: ${{ matrix.python-version }} + - name: Classify covers and near-covers of E7 by hyperplane flats + run: python3 -B research/e7-flat-cover-classification/cover_check.py + - name: Require committed files to remain unchanged + run: git diff --exit-code diff --git a/research/e7-flat-cover-classification/LICENSE b/research/e7-flat-cover-classification/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/research/e7-flat-cover-classification/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/research/e7-flat-cover-classification/NOTICE.md b/research/e7-flat-cover-classification/NOTICE.md new file mode 100644 index 0000000000..a4951f838e --- /dev/null +++ b/research/e7-flat-cover-classification/NOTICE.md @@ -0,0 +1,8 @@ +# Notice + +This note and `cover_check.py` were prepared by DaysSky, with assistance from Claude. They are released under the +Apache-2.0 license in `LICENSE`. + +The checker reads `research/format-limits/scripts/d1_cover_numbers.py` (#595) as text to compare pinned values, without +modifying or importing it. That file keeps its own authors, notices and license; see the repository's `NOTICE`, +`CONTRIBUTORS.md` and the `format-limits` package. diff --git a/research/e7-flat-cover-classification/README.md b/research/e7-flat-cover-classification/README.md new file mode 100644 index 0000000000..30fcbe6854 --- /dev/null +++ b/research/e7-flat-cover-classification/README.md @@ -0,0 +1,88 @@ +# Covers of E7 by hyperplane flats: the D4-frame triples are the only covers + +**No new κ is claimed.** Main's design-free cover numbers (`research/format-limits` §D, +`scripts/d1_cover_numbers.py`) establish that the 63 readers of a bit source need three hyperplane sections. The +readers are the lines of E7 = t⊥. Two flats cover at most 52 lines, and some three D6 flats cover all 63. This note +classifies the covers exactly. + +1. **The covering triples are exactly the D4 frames through t.** + - Three hyperplane flats of E7 cover all 63 lines if and only if they are E7 ∩ a⊥, E7 ∩ b⊥, E7 ∩ c⊥, where + {t, a, b, c} is an orthogonal frame spanning a D4 subsystem. + - There are 315 such triples, one per D4 through t. + - The other 3780 orthogonal frames through t span only 4A1. Each of their triples leaves at least 8 lines + uncovered. +2. **The near-covers are exactly the A3 subsystems through t.** + - A near-cover is a triple that covers exactly 62 of the 63 lines. + - Every near-cover is E6(A) + E6(B) + D6(m) for an A3 through t. Here A and B are the A3's two A2 subsystems + through t, m is its one line orthogonal to t, and m is the missed line. + - There are 378 = 63 × 6 of them, and no other type occurs. +3. **A cover count alone does not force 3 registers per D6 at rank 5.** + - In a covering triple, each D6 has 16 private lines, covered by it alone. They span the D6. + - Two rank-5 subflats never cover a whole D6: at most 28 of its 30 lines. + - But two of them do cover the 16 private lines (75 such pairs per D6), and six rank-5 flats, two per D6, cover + all of E7. + - So "two 5-dim subflats cover ≤ 28 of 30" does not by itself force a third register in each D6 pool. A + 3-per-pool count needs a further argument about the shared lines. + +**Consequences for bit skeletons:** + +- The D4 skeletons of #493, #510 and #543 read each target through the three D6 frames {t, e}⊥, where e runs over + the other lines of t's 4-frame. By (1), every top layer made of three hyperplane sections has this form. +- The only near-alternative is (2), with one line read separately. +- (3) corrects a counting step that has been proposed for a floor of 540 = 180 × 3 bit registers in this paradigm. + +```sh +python3 -B research/e7-flat-cover-classification/cover_check.py +``` + +The check uses the standard library only and takes about 6 minutes. It ends with +`PASS_E7_FLAT_COVER_CLASSIFICATION (21 checks, ...)`. + +## Method + +- **Lines and flats.** + - The E8 lines are rebuilt in Construction-A coordinates from the [8, 4, 4] Hamming code. + - t is one fixed line. All lines are equivalent under W(E8), so one choice suffices. + - The closed flats of E7 are enumerated by rank. The rank-(r+1) flats over a rank-r flat F are the classes of the + remaining lines, grouped by direction modulo span(F). +- **Exact ranks.** All ranks are computed mod p = 2³¹ − 1. By Hadamard's inequality, a minor of at most 8 rows of + squared norm 4 has |det| ≤ 2⁸, so ranks mod p equal rational ranks. No floating point is used. +- **Exhaustive searches.** Every search in the table below is exhaustive. + +| Step | Check | Result | +|---|---|---| +| Flats | flats of E7 by rank 1–6 | 63 / 1281 / 10395 / 33411 / 36435 / 8821 | +| Hyperplane flats | by size | 5040 × 10, 2016 × 13, 1008 × 16, 666 × 21, 63 × 30 (D6), 28 × 36 (E6) | +| Agreement with main | `d1_cover_numbers.py` pins 8821 flats, the size histogram, best pair 52 and cover number 3 | identical | +| Identification | D6 flats = E7 ∩ a⊥ (63); E6 flats = E7 ∩ A⊥ for the 28 A2 subsystems through t | exact set equality | +| Pairs | best union of two hyperplane flats | 52; a larger union needs two flats of size ≥ 21, and all 757 such flats are tried | +| Covering triples | all triples, members in size order | 315, all D6 + D6 + D6 | +| Frames | orthogonal triples {a, b, c} ⊂ E7: span of {t, a, b, c} | 315 span a D4 (12 lines), 3780 span 4A1 (4 lines) | +| Classification | covering triples = D4-frame triples; each 4A1 triple misses ≥ 8 lines; each D4 through t has one frame through t | exact | +| Near-covers | for each of the 63 lines m, all triples covering E7 − {m} and avoiding m | 378 = 63 × 6, all E6 + E6 + D6 | +| A3 | the 378 A3 subsystems through t and their E6(A) + E6(B) + D6(m) triples | equal to the near-covers, with the same missed line | +| Inside a cover | private lines per D6; shared lines | 16 per D6, rank 6; 15 shared, 12 of them in all three | +| Rank-5 subflats of a D6 | count and sizes | 268: 120 × 8, 80 × 9, 30 × 13, 32 × 15, 6 × 20 | +| Pool step | best pair of rank-5 subflats on a D6; pairs covering the 16 private lines; a 2 + 2 + 2 cover of E7 | 28 of 30; 75 per D6; exists | + +## Scope + +- These are statements about covers by flats, which is the model behind main's §D cover numbers. +- (1) and (2) say which covers exist. They do not price a skeleton. +- (3) shows only that one counting step does not follow from coverage. It does not show that a design with 2 + registers per D6 pool exists: frame nesting, the readers' frames and restoration are not modelled. + +## Related work + +- Main: `research/format-limits/README.md` §D and `scripts/d1_cover_numbers.py` (#595, DreamingOfClouds). These give + the census of 8821 flats, the best pair 52, and the existence of a three-D6 cover. The classification of all covers + and near-covers is new here. +- #463 (DreamingOfClouds): the carrier bound, that two hyperplane sections cannot cover the 4-design s⊥. +- #493, #510, #543 (eumemic, DreamingOfClouds): the D4-skeleton bit words that use the D6 triples. +- Duplicates were checked against main at `f567884a` and against the titles and bodies of all hub PRs through #883. + +## Credits + +- DreamingOfClouds, for #595's cover-number census and #463's carrier bound. +- eumemic, for the D4 skeleton of #493 and #543. +- Prepared by DaysSky, with assistance from Claude. diff --git a/research/e7-flat-cover-classification/cover_check.py b/research/e7-flat-cover-classification/cover_check.py new file mode 100644 index 0000000000..3ff7f977bf --- /dev/null +++ b/research/e7-flat-cover-classification/cover_check.py @@ -0,0 +1,299 @@ +"""Covers of E7 by hyperplane flats: the exact classification behind README.md (no kappa claim). + +Run from the repository root: python3 -B research/e7-flat-cover-classification/cover_check.py +Standard library only, about two minutes. + +E8 lines are in Construction-A coordinates (doubled, every line has squared norm 4). t is one line and E7 = the 63 +lines orthogonal to t; every line of E8 is equivalent to t under W(E8), so the choice of t does not matter. + +Exactness. All rank and span questions are decided over F_p with p = 2^31 - 1. A minor of r <= 8 rows of squared norm 4 +has |det| <= 2^r <= 256 (Hadamard), so a minor vanishes mod p exactly when it vanishes over Q, and every rank below +equals the rational rank.""" +import collections +import itertools +import os +import re +import sys +import time + +HERE = os.path.dirname(os.path.abspath(__file__)) +ROOT = os.path.dirname(os.path.dirname(HERE)) +P = 2 ** 31 - 1 +N_CHECKS = 0 +T0 = time.time() + + +def check(name, ok, detail=''): + global N_CHECKS + N_CHECKS += 1 + print('%-4s %-52s %s' % ('ok' if ok else 'FAIL', name, detail), flush=True) + if not ok: + sys.exit(1) + + +# --------------------------------------------------------------------------------------------------------------- +# E8 lines and exact spans +# --------------------------------------------------------------------------------------------------------------- +def e8_lines(): + g = [(1, 1, 1, 1, 0, 0, 0, 0), (1, 1, 0, 0, 1, 1, 0, 0), (1, 0, 1, 0, 1, 0, 1, 0), (0, 1, 1, 0, 1, 0, 0, 1)] + words = {tuple(sum(a[k] * g[k][i] for k in range(4)) % 2 for i in range(8)) + for a in itertools.product((0, 1), repeat=4)} + out = [tuple(2 * (k == i) for k in range(8)) for i in range(8)] + for w in sorted(words): + if sum(w) != 4: + continue + idx = [i for i in range(8) if w[i]] + for sg in itertools.product((1, -1), repeat=3): # first nonzero coordinate positive + v = [0] * 8 + v[idx[0]] = 1 + for i, s in zip(idx[1:], sg): + v[i] = s + out.append(tuple(v)) + return out + + +L = e8_lines() +V = len(L) +DOT = [[sum(a * b for a, b in zip(x, y)) for y in L] for x in L] +SUPP = [[(i, x[i]) for i in range(8) if x[i]] for x in L] +check('E8 lines', V == 120 and all(DOT[i][i] == 4 for i in range(V)) + and all(abs(DOT[i][j]) in (0, 2) for i in range(V) for j in range(V) if i != j), + '120 lines, ||/2 in {0, 1} for distinct lines') +ORTH = [sum(1 << j for j in range(V) if DOT[i][j] == 0) for i in range(V)] +check('63 orthogonal lines per line', all(m.bit_count() == 63 for m in ORTH), '') + + +def bits(m): + out = [] + while m: + b = m & -m + out.append(b.bit_length() - 1) + m ^= b + return out + + +def kernel(rows): + """basis mod P of {n : n.r = 0 for every row r}, and the rank of the rows""" + A = [list(r) for r in rows] + piv = [] + r = 0 + for c in range(8): + k = next((i for i in range(r, len(A)) if A[i][c] % P), None) + if k is None: + continue + A[r], A[k] = A[k], A[r] + inv = pow(A[r][c], P - 2, P) + A[r] = [x * inv % P for x in A[r]] + for i in range(len(A)): + if i != r and A[i][c] % P: + f = A[i][c] + A[i] = [(x - f * y) % P for x, y in zip(A[i], A[r])] + piv.append(c) + r += 1 + basis = [] + for f in (c for c in range(8) if c not in piv): + n = [0] * 8 + n[f] = 1 + for i, c in enumerate(piv): + n[c] = (-A[i][f]) % P + basis.append(n) + return basis, r + + +def closure(lines): + """(mask of all E8 lines in the rational span of the given lines, rank)""" + K, r = kernel([L[s] for s in lines]) + return sum(1 << s for s in range(V) if all(sum(n[i] * c for i, c in SUPP[s]) % P == 0 for n in K)), r + + +def extensions(F, universe, basis): + """the flats of rank r+1 inside 'universe' that contain the rank-r flat F (spanned by 'basis'): the lines outside F + fall into classes by the direction of their image in Q^8 / span(F); each class together with F is one flat""" + K, _ = kernel([L[s] for s in basis]) + groups = {} + for s in bits(universe & ~F): + v = [sum(n[i] * c for i, c in SUPP[s]) % P for n in K] + j = next(i for i, a in enumerate(v) if a) + inv = pow(v[j], P - 2, P) + key = tuple(a * inv % P for a in v) + g = groups.get(key) + if g is None: + groups[key] = [1 << s, s] + else: + g[0] |= 1 << s + return [(F | m, basis + [s]) for m, s in groups.values()] + + +def flats_by_rank(universe, top): + level = {1 << s: [s] for s in bits(universe)} + out = {1: dict(level)} + for k in range(2, top + 1): + nxt = {} + for F, b in level.items(): + for G, bb in extensions(F, universe, b): + nxt.setdefault(G, bb) + out[k] = nxt + level = nxt + return out + + +# --------------------------------------------------------------------------------------------------------------- +# 1. the hyperplane flats of E7 (reproduces main's D1 census) +# --------------------------------------------------------------------------------------------------------------- +t = 0 +E7 = ORTH[t] +FL = flats_by_rank(E7, 6) +counts = {k: len(v) for k, v in FL.items()} +check('flats of E7 by rank', counts == {1: 63, 2: 1281, 3: 10395, 4: 33411, 5: 36435, 6: 8821}, str(counts)) +H = sorted(FL[6], key=lambda m: (-m.bit_count(), m)) +n = len(H) +pc = [m.bit_count() for m in H] +hist = dict(sorted(collections.Counter(pc).items())) +check('hyperplane flats by size', hist == {10: 5040, 13: 2016, 16: 1008, 21: 666, 30: 63, 36: 28}, str(hist)) +check('every hyperplane flat is closed of rank 6', all(closure(FL[6][F]) == (F, 6) for F in H[:28] + H[-28:]), + 'spot check of the 56 extreme members; closure is exact by construction') +d1 = open(os.path.join(ROOT, 'research', 'format-limits', 'scripts', 'd1_cover_numbers.py')).read() +pins = ['bit_flats=8821,', 'bit_flats_hist={10: 5040, 13: 2016, 16: 1008, 21: 666, 30: 63, 36: 28},', + 'bit_union2=52,', 'bit_cover_number=3,'] +check("agrees with main's D1 census (format-limits)", all(p in d1 for p in pins), ', '.join(p.rstrip(',') for p in pins)) + +# the D6 and E6 flats, by their root-system description +D6 = {E7 & ORTH[a]: a for a in bits(E7)} +check('D6 flats are E7 ∩ a⊥ (a in E7)', len(D6) == 63 and set(D6) == {F for F in H if F.bit_count() == 30}, '63 flats of 30 lines') +A2 = {} +for a in range(V): + if a != t and DOT[t][a]: + A2[closure([t, a])[0]] = None +E6 = {} +for S in A2: + perp = E7 + for x in bits(S): + perp &= ORTH[x] + E6[perp] = S +check('E6 flats are E7 ∩ A⊥ (A an A2 through t)', len(A2) == 28 and all(S.bit_count() == 3 for S in A2) + and set(E6) == {F for F in H if F.bit_count() == 36}, '28 A2 subsystems through t, 28 flats of 36 lines') + +# --------------------------------------------------------------------------------------------------------------- +# 2. two flats never cover; covering triples +# --------------------------------------------------------------------------------------------------------------- +big = [i for i in range(n) if pc[i] >= 21] +best2 = max((H[i] | H[j]).bit_count() for a, i in enumerate(big) for j in big[a + 1:]) +check('two hyperplane flats cover at most 52 of 63', best2 == 52, + 'a pair with union > 52 needs |A| + |B| > 52, so both are among the %d flats of size >= 21' % len(big)) +FL_OF = {s: 0 for s in bits(E7)} +for k, F in enumerate(H): + for s in bits(F): + FL_OF[s] |= 1 << k + + +def triples_covering(target, avoid): + """all unordered triples of hyperplane flats disjoint from 'avoid' whose union contains 'target'. + Members are taken in size order |A| >= |B| >= |C|. Since 3 * 16 < 62, the largest member has size >= 21.""" + assert target.bit_count() > 48 + allowed = 0 + for i in range(n): + if not H[i] & avoid: + allowed |= 1 << i + out = set() + for i in bits(allowed): + if pc[i] < 21: + break + A = H[i] + for j in bits(allowed >> (i + 1)): + j += i + 1 + R = target & ~(A | H[j]) + if R.bit_count() > pc[j]: + continue # C would have to be larger than B + m = allowed >> (j + 1) + for s in bits(R): + m &= FL_OF[s] >> (j + 1) + if not m: + break + for k in bits(m): + out.add((i, j, k + j + 1)) + return out + + +TRI = triples_covering(E7, 0) +types = collections.Counter(tuple(pc[x] for x in tr) for tr in TRI) +check('covering triples', len(TRI) == 315 and types == {(30, 30, 30): 315}, '315, all D6 + D6 + D6') +frames = [(a, b, c) for a, b, c in itertools.combinations(bits(E7), 3) if not (DOT[a][b] or DOT[a][c] or DOT[b][c])] +span_size = {f: closure([t, *f])[0].bit_count() for f in frames} +check('orthogonal 4-frames {t, a, b, c}', len(frames) == 4095 + and collections.Counter(span_size.values()) == {12: 315, 4: 3780}, + '315 span a D4 (12 lines), 3780 span only 4A1 (4 lines)') +d4_triples = {frozenset(E7 & ORTH[x] for x in f) for f in frames if span_size[f] == 12} +a1_triples = {frozenset(E7 & ORTH[x] for x in f) for f in frames if span_size[f] == 4} +covers = {frozenset(H[x] for x in tr) for tr in TRI} +check('covering triples = D4 frames through t', covers == d4_triples, + 'exactly the {E7∩a⊥, E7∩b⊥, E7∩c⊥} for {t,a,b,c} a frame of a D4 subsystem') +worst = min(63 - (A | B | C).bit_count() for A, B, C in map(tuple, a1_triples)) +check('4A1 frames do not cover', len(a1_triples) == 3780 and worst > 0, 'each leaves >= %d lines uncovered' % worst) +D4 = collections.Counter(closure([t, *f])[0] for f in frames if span_size[f] == 12) +check('D4 subsystems through t', len(D4) == 315 and set(D4.values()) == {1}, + '315, each with exactly one orthogonal frame through t: covering triples <-> D4 subsystems through t') + +# --------------------------------------------------------------------------------------------------------------- +# 3. near-covers: triples covering exactly 62 of the 63 lines, for every missing line +# --------------------------------------------------------------------------------------------------------------- +near = {} +for m in bits(E7): + for tr in triples_covering(E7 & ~(1 << m), 1 << m): + near[frozenset(H[x] for x in tr)] = m +types = collections.Counter(tuple(sorted(F.bit_count() for F in tr)) for tr in near) +per_m = collections.Counter(near.values()) +check('near-covers (exactly one line missed)', len(near) == 378 and types == {(30, 36, 36): 378} + and set(per_m.values()) == {6}, '378 = 63 x 6, all E6 + E6 + D6') +A3 = {} +for a in range(V): + for b in range(a + 1, V): + if t in (a, b) or not (DOT[t][a] or DOT[t][b]): + continue + S, r = closure([t, a, b]) + if r == 3 and S.bit_count() == 6: + A3[S] = None +A3_near = {} +for S in A3: + m = [x for x in bits(S) if x != t and DOT[t][x] == 0] + sub = [A for A in A2 if A & S == A] + perps = [] + for A in sub: + p = E7 + for x in bits(A): + p &= ORTH[x] + perps.append(p) + A3_near[frozenset(perps + [E7 & ORTH[m[0]]])] = (len(m), len(sub), m[0]) +ok = (len(A3) == 378 and all(v[:2] == (1, 2) for v in A3_near.values()) + and set(A3_near) == set(near) and all(near[k] == v[2] for k, v in A3_near.items())) +check('near-covers = A3 subsystems through t', ok, + 'E6(A)+E6(B)+D6(m) misses exactly m: A, B the two A2s of the A3 through t, m its line orthogonal to t') + +# --------------------------------------------------------------------------------------------------------------- +# 4. inside a covering triple: what a cover argument says about one D6 "pool" +# --------------------------------------------------------------------------------------------------------------- +A, B, C = sorted(next(iter(covers))) +priv = [X & ~(Y | Z) for X, Y, Z in ((A, B, C), (B, A, C), (C, A, B))] +shared = (A & B) | (A & C) | (B & C) +check('a covering triple', [X.bit_count() for X in priv] == [16] * 3 and (A & B & C).bit_count() == 12 + and shared.bit_count() == 15 and all(closure(bits(X))[1] == 6 for X in priv), + 'each D6 has 16 lines covered once (spanning the D6); 15 lines are shared, 12 by all three') +F5 = {} +for X in (A, B, C): + F5[X] = list(flats_by_rank(X, 5)[5]) +sizes = dict(sorted(collections.Counter(F.bit_count() for F in F5[A]).items())) +check('rank-5 subflats of a D6', len(F5[A]) == 268 and sizes == {8: 120, 9: 80, 13: 30, 15: 32, 20: 6}, str(sizes)) +best = max((F5[A][i] | F5[A][j]).bit_count() for i in range(268) for j in range(i + 1, 268)) +check('two rank-5 subflats cover at most 28 of a D6', best == 28, 'so a D6 is never covered by two of them') +pairs = {} +for X, Y in zip((A, B, C), priv): + pairs[X] = [(F5[X][i], F5[X][j]) for i in range(268) for j in range(i, 268) if Y & ~(F5[X][i] | F5[X][j]) == 0] +check('two rank-5 subflats do cover the 16 private lines', all(len(p) > 0 for p in pairs.values()), + '%s admissible pairs per D6' % [len(p) for p in pairs.values()]) +sh = bits(shared) +pos = {s: k for k, s in enumerate(sh)} +pat = {X: {sum(1 << pos[s] for s in bits((F | G) & shared)) for F, G in pairs[X]} for X in (A, B, C)} +full = (1 << len(sh)) - 1 +six = next(((a, b, c) for a in pat[A] for b in pat[B] for c in pat[C] if a | b | c == full), None) +check('six rank-5 flats, two per D6, cover E7', six is not None, + 'a cover count alone forces only 2 registers per D6 at rank 5, not 3') +print('PASS_E7_FLAT_COVER_CLASSIFICATION (%d checks, %.0f s)' % (N_CHECKS, time.time() - T0))