Track odd-size universal trend; the n=12 failure is sporadic, not a trend
Add kempe_universal_trend_probe.py (|D[m]| per size across n). Across n=6..13 and all sizes, the ONLY empty per-size universal is (n=12, m=7): at n=13 size 7 is back to |D|=2 with more boundaries (579), so the vanishing is sporadic, not monotone. The lone n=12 breaker is the outer rim of word=UUUDUDUDUDUD bite=(3,11) (most- alternating 7-up word, antipodal bite), realising 9/10 size-7 necklaces and missing only 0001112. Correct the earlier "doomed at scale" reading in the findings note: the uniform shortcut almost always works (near-total coverage) but is fragile to a single exceptional tile; pairwise gluability still always holds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+51
-14
@@ -56,23 +56,60 @@ cycle `σ_m` glues any tree with no pigeonhole.
|
||||
|
||||
Per-size universal domain sizes at n=12: `3:1 4:1 5:1 6:2 7:0 8:4 9:1`.
|
||||
|
||||
## Finding 3 — interpretation
|
||||
## Finding 3 — the failure is SPORADIC, not a monotone trend
|
||||
|
||||
Universals vanish as the tile population grows (more boundaries of a given size → more
|
||||
sets to intersect → empty), so the "paint every seam identically" shortcut is doomed
|
||||
at scale; the per-interface pigeonhole choice is genuinely necessary. **But this is
|
||||
not an obstruction to gluing** — pairwise overlap still always holds, so chains still
|
||||
glue by choosing states per interface. We have *located why the conjecture is hard*:
|
||||
the difficulty lives in the non-uniform, branch-coupled selection across the tree,
|
||||
exactly where the paper's pigeonhole sits — not in any single seam or a uniform
|
||||
assignment.
|
||||
`kempe_universal_trend_probe.py` tracks `|D[m]|` (universal count) per size across
|
||||
`n = 6..13`. Legend `|D[m]| (best_coverage / num_boundaries)`; `*` = odd size:
|
||||
|
||||
```
|
||||
n= 6: m3*=1(6/6) m4=2(2/2) m6=4(1/1)
|
||||
n= 7: m3*=1(10/10) m4=1(8/8) m5*=1(2/2) m7*=3(1/1)
|
||||
n= 8: m3*=1(28/28) m4=2(21/21) m5*=1(10/10) m6=2(3/3) m8=8(1/1)
|
||||
n= 9: m3*=1(49/49) m4=1(52/52) m5*=1(28/28) m6=1(14/14) m7*=2(3/3) m9*=8(1/1)
|
||||
n=10: m3*=1(118) m4=2(106) m5*=1(86) m6=2(46) m7*=1(16/16) m8=4(4/4) m10=18(1/1)
|
||||
n=11: m3*=1(310) m4=1(263) m5*=1(188) m6=1(139) m7*=2(60/60) m8=2(20/20) m9*=3(4/4) m11*=21(1/1)
|
||||
n=12: m3*=1(849) m4=1(691) m5*=1(534) m6=2(353) m7*=0(210/211) m8=3(88) m9*=1(24/24) m10=6(5/5) m12=48(1/1)
|
||||
n=13: m3*=1(2457) m4=1(1805) m5*=1(1386) m6=1(1070) m7*=2(579/579) m8=1(315) m9*=2(110) m10=1(28) m11*=7(5) m13*=63(1/1)
|
||||
```
|
||||
|
||||
The earlier "universals vanish as the tile population grows" reading is **wrong**.
|
||||
Across all `n = 6..13` and all sizes, the **only** empty universal anywhere is
|
||||
`(n=12, m=7)`. Size 7 has *more* boundaries at n=13 (579) than n=12 (211), yet its
|
||||
universal is back (`|D|=2`). So the failure is **sporadic**, not monotone — a
|
||||
number-theoretic quirk of `n=12`, not a scaling law. Note also that best_coverage is
|
||||
always near-total: the most-shared necklace reaches all-but-rarely-one boundary, so
|
||||
the universal is "almost there" even when it fails.
|
||||
|
||||
### The single breaker (n=12, m=7)
|
||||
The lone size-7 boundary that kills the universal is the **outer rim** of
|
||||
|
||||
```
|
||||
word = UUUDUDUDUDUD bite = (3,11) (7 up teeth)
|
||||
```
|
||||
|
||||
— the most-alternating word with a near-full-span bite. Its outer rim realises 9 of
|
||||
the 10 admissible size-7 necklaces, missing exactly `0001112` (the balanced two-block
|
||||
`3+3+1` pattern); every other size-7 boundary realises `0001112`. One exceptional tile
|
||||
breaks the shortcut.
|
||||
|
||||
## Finding 4 — interpretation
|
||||
|
||||
The uniform "paint every seam the same" shortcut **almost always works** (universals
|
||||
non-empty with near-total coverage, even at thousands of boundaries), but is
|
||||
**fragile**: a single exceptional tile can empty a per-size universal, as at
|
||||
`(n=12, m=7)`. So the shortcut cannot be relied on in general — yet its failures are
|
||||
rare, not systematic. The per-interface pigeonhole choice is needed precisely to
|
||||
absorb these sporadic breakers. **This is not an obstruction to gluing** — pairwise
|
||||
overlap always holds, so chains still glue by choosing states per interface. The
|
||||
conjecture's difficulty is thus concentrated in rare exceptional tiles and the
|
||||
branch-coupled selection around them, not in any single seam or in a scaling trend.
|
||||
|
||||
## Open threads
|
||||
|
||||
- **Odd-size seams are the pressure point.** Uniformity first fails at size 7 (odd);
|
||||
small odd sizes 3, 5 kept unique universals. Does every large odd size lose its
|
||||
universal as `n` grows? (tracked below / in follow-up).
|
||||
- **The 210/211 near-miss.** A single tile blocks the size-7 universal — identifying
|
||||
the "universal-breaker" tiles may expose the combinatorial core.
|
||||
- **Why n=12 / why this tile?** The breaker is the most-alternating 7-up word with an
|
||||
antipodal bite. Is the sporadic failure tied to `n` even / specific bite spans?
|
||||
Worth checking n=14, 16 for size-7 (and other) re-failures.
|
||||
- **CSP at n=13.** With `|D[m]| > 0` for every size, the per-size obstruction is gone;
|
||||
whether the joint uniform-family CSP is feasible again at n=13 needs a run.
|
||||
- **Branch-tree composition.** n=12 has 175 true branching tiles; composing `R_T`
|
||||
along actual trees (not just per-size uniformity) is the conjecture proper.
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
"""Do per-size universal boundary states survive as n grows?
|
||||
|
||||
For each annular size n and each boundary size m, D[m] is the set of boundary
|
||||
necklaces realisable on EVERY size-m boundary (outer up-rim or inner >=3-singleton
|
||||
face) across all tiles. |D[m]| > 0 means a uniform state of size m exists; |D[m]|=0
|
||||
means no state threads every size-m seam (the uniform shortcut is dead at that size).
|
||||
|
||||
This tracks |D[m]| as a function of n, to see whether/when each size -- especially
|
||||
odd sizes -- loses its universal. Also reports, per (n,m), the best coverage
|
||||
(how many of the size-m boundaries the most-shared necklace reaches).
|
||||
|
||||
Run: python3 kempe_universal_trend_probe.py --min-n 6 --max-n 12
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import time
|
||||
from collections import defaultdict
|
||||
|
||||
from full_medial_tire_generator import generate, innermost_bite
|
||||
from kempe_valid_colorings import classify_colorings
|
||||
from kempe_transfer_relation_probe import necklace, admissible_necklaces
|
||||
|
||||
|
||||
def per_size_universals(n: int):
|
||||
"""size m -> (num boundaries, |D[m]|, best coverage count)."""
|
||||
boundaries: dict[int, list[set]] = defaultdict(list)
|
||||
for g in generate(n, min_up_teeth=3, dedup=True):
|
||||
valid = [c for c, v in classify_colorings(g, dedup_colors=True) if v.valid]
|
||||
if not valid:
|
||||
continue
|
||||
p = len(g.up_edges)
|
||||
if p >= 3:
|
||||
boundaries[p].append(
|
||||
{necklace(tuple(c[f"u{e}"] for e in g.up_edges)) for c in valid})
|
||||
faces = defaultdict(list)
|
||||
for e in g.singleton_down_edges:
|
||||
faces[innermost_bite(e, g.bites)].append(e)
|
||||
for es in faces.values():
|
||||
if len(es) >= 3:
|
||||
es = sorted(es)
|
||||
boundaries[len(es)].append(
|
||||
{necklace(tuple(c[f"d{e}"] for e in es)) for c in valid})
|
||||
out = {}
|
||||
for m, sets in boundaries.items():
|
||||
inter = set.intersection(*sets)
|
||||
cnt: dict = defaultdict(int)
|
||||
for s in sets:
|
||||
for x in s:
|
||||
cnt[x] += 1
|
||||
best = max(cnt.values()) if cnt else 0
|
||||
out[m] = (len(sets), len(inter), best)
|
||||
return out
|
||||
|
||||
|
||||
def run(args):
|
||||
print("|D[m]| = number of universal boundary necklaces of size m "
|
||||
"(0 => uniform shortcut dead at that size)\n")
|
||||
print("legend per cell: |D[m]| (best_coverage/num_boundaries)\n")
|
||||
for n in range(args.min_n, args.max_n + 1):
|
||||
t0 = time.time()
|
||||
res = per_size_universals(n)
|
||||
dt = time.time() - t0
|
||||
cells = []
|
||||
for m in sorted(res):
|
||||
nb, dsz, best = res[m]
|
||||
tag = "*" if (m % 2 == 1) else " "
|
||||
cells.append(f"m{m}{tag}={dsz}({best}/{nb})")
|
||||
print(f"n={n:>2} [{dt:>4.0f}s]: " + " ".join(cells))
|
||||
sys.stdout.flush()
|
||||
print("\n(* = odd size)")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--min-n", type=int, default=6)
|
||||
parser.add_argument("--max-n", type=int, default=12)
|
||||
run(parser.parse_args())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user