Pin the extremal irreducible disk (correcting the wheel claim)
wheel_extremal.py: |Phi(wheel_n)| = floor(2^n/3) exactly (ratio ->4/3), but the wheel is NOT the irreducible minimiser for n>=6. The extremal disk is a single MINIMAL-degree interior vertex (degree 4 or 5, both tie), giving |Phi| = (5/4)*2^(n-2) = 5*2^(n-4). The ratio rises monotonically with center degree, 5/4 -> 4/3, so minimal degree is extremal. Sharpens the irreducible lemma to |Phi| >= (5/4)*2^(n-2), tight at the degree-4/5 patch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,154 @@
|
|||||||
|
"""
|
||||||
|
Pin the extremal irreducible disk.
|
||||||
|
|
||||||
|
The wheel W_n: boundary n-cycle + one center, faces (i,i+1,c). The center is the
|
||||||
|
only interior vertex (degree n), constraint sum_i lambda_i ≡ 0 (mod 3), and the
|
||||||
|
boundary value is the cyclic adjacent sum sigma_i = lambda_{i-1}+lambda_i (mod 3).
|
||||||
|
So
|
||||||
|
|
||||||
|
|Phi(W_n)| = #{ (lambda_{i-1}+lambda_i)_i mod 3 : lambda in {+-1}^n, sum ≡ 0 } .
|
||||||
|
|
||||||
|
We (1) compute |Phi(W_n)| exactly for a range of n and look for a formula, and
|
||||||
|
(2) run a thorough irreducible-disk search to check whether the wheel is actually
|
||||||
|
the MINIMISER over irreducible disks (and dump the minimiser's structure).
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from collections import Counter
|
||||||
|
from itertools import product
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from scipy.spatial import Delaunay
|
||||||
|
|
||||||
|
np.seterr(all="ignore")
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------- exact wheel value ------------------------------------------
|
||||||
|
def wheel_phi_size(n):
|
||||||
|
S = set()
|
||||||
|
cnt = 0
|
||||||
|
for lam in product((1, -1), repeat=n):
|
||||||
|
if sum(lam) % 3 != 0:
|
||||||
|
continue
|
||||||
|
cnt += 1
|
||||||
|
sig = tuple((lam[i - 1] + lam[i]) % 3 for i in range(n))
|
||||||
|
S.add(sig)
|
||||||
|
return len(S), cnt # distinct boundary seqs, feasible labellings
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------- general disk Phi -------------------------------------------
|
||||||
|
def disk(n, k, rng):
|
||||||
|
ang = 2 * np.pi * np.arange(n) / n
|
||||||
|
rad = 1.0 + 0.18 * rng.random(n)
|
||||||
|
bpts = np.c_[rad * np.cos(ang), rad * np.sin(ang)]
|
||||||
|
r = 0.8 * np.sqrt(rng.random(k)); t = 2 * np.pi * rng.random(k)
|
||||||
|
pts = np.vstack([bpts, np.c_[r * np.cos(t), r * np.sin(t)]])
|
||||||
|
return [tuple(int(x) for x in s) for s in Delaunay(pts).simplices]
|
||||||
|
|
||||||
|
|
||||||
|
def valid(faces, n, k):
|
||||||
|
if len(faces) != 2 * k + n - 2:
|
||||||
|
return False
|
||||||
|
ec = Counter()
|
||||||
|
for a, b, c in faces:
|
||||||
|
for e in ((a, b), (b, c), (a, c)):
|
||||||
|
ec[frozenset(e)] += 1
|
||||||
|
return all(ec[frozenset((i, (i + 1) % n))] == 1 for i in range(n))
|
||||||
|
|
||||||
|
|
||||||
|
def phi_size(faces, n):
|
||||||
|
interior = sorted(set(v for f in faces for v in f if v >= n))
|
||||||
|
F = len(faces)
|
||||||
|
if F > 18:
|
||||||
|
return None
|
||||||
|
Bint = np.zeros((len(interior), F), dtype=np.int64)
|
||||||
|
Cinc = np.zeros((n, F), dtype=np.int64)
|
||||||
|
iidx = {w: r for r, w in enumerate(interior)}
|
||||||
|
for j, (a, b, c) in enumerate(faces):
|
||||||
|
for v in (a, b, c):
|
||||||
|
if v >= n:
|
||||||
|
Bint[iidx[v], j] = 1
|
||||||
|
else:
|
||||||
|
Cinc[v, j] = 1
|
||||||
|
labs = np.array(list(product((1, 2), repeat=F)), dtype=np.int64)
|
||||||
|
if interior:
|
||||||
|
labs = labs[np.all((labs @ Bint.T) % 3 == 0, axis=1)]
|
||||||
|
if labs.shape[0] == 0:
|
||||||
|
return 0
|
||||||
|
return len(set(map(tuple, np.unique((labs @ Cinc.T) % 3, axis=0))))
|
||||||
|
|
||||||
|
|
||||||
|
def min_degree_ok(faces, n, k):
|
||||||
|
deg = Counter()
|
||||||
|
for f in faces:
|
||||||
|
for v in f:
|
||||||
|
if v >= n:
|
||||||
|
deg[v] += 1
|
||||||
|
return len(deg) == k and all(deg[v] >= 4 for v in deg)
|
||||||
|
|
||||||
|
|
||||||
|
def single_deg_disk(n, d):
|
||||||
|
"""One interior vertex v=n of degree d: fan over boundary 0..d-1, the rest of
|
||||||
|
the n-gon polygon-triangulated from vertex 0 (so v stays degree d, k=1)."""
|
||||||
|
v = n
|
||||||
|
faces = [(i, i + 1, v) for i in range(d - 1)]
|
||||||
|
poly = [0] + list(range(n - 1, d - 2, -1)) + [v]
|
||||||
|
for j in range(1, len(poly) - 1):
|
||||||
|
faces.append((0, poly[j], poly[j + 1]))
|
||||||
|
return faces
|
||||||
|
|
||||||
|
|
||||||
|
def degree_sweep():
|
||||||
|
print("\n|Phi| of a single degree-d interior vertex (rest at the floor):\n")
|
||||||
|
print(" ratio |Phi|/2^(n-2) by center degree d -- MINIMUM marks the extremal disk")
|
||||||
|
for n in (6, 7, 8):
|
||||||
|
row = []
|
||||||
|
for d in range(4, n + 1):
|
||||||
|
f = single_deg_disk(n, d)
|
||||||
|
row.append(f"d={d}:{phi_size(f, n)/2**(n-2):.4f}")
|
||||||
|
print(f" n={n} (floor {2**(n-2)}): " + " ".join(row))
|
||||||
|
print(" => min ratio 5/4 at d=4,5 (extremal); rises with d to ~4/3 at the wheel.")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Exact |Phi(W_n)| and candidate formula:\n")
|
||||||
|
print(" n |Phi(W_n)| feasible-labellings ratio-to-2^(n-2)")
|
||||||
|
vals = {}
|
||||||
|
for n in range(3, 15):
|
||||||
|
s, cnt = wheel_phi_size(n)
|
||||||
|
vals[n] = s
|
||||||
|
print(f" {n:2d} {s:8d} {cnt:14d} {s / 2**(n-2):.4f}")
|
||||||
|
# differences / ratios to spot a pattern
|
||||||
|
print("\n consecutive ratios |Phi(W_{n+1})| / |Phi(W_n)|:")
|
||||||
|
for n in range(3, 14):
|
||||||
|
print(f" {n}->{n+1}: {vals[n+1]/vals[n]:.4f}")
|
||||||
|
|
||||||
|
print("\nThe actual irreducible minimiser (Delaunay search, dumping structure)\n")
|
||||||
|
rng = np.random.default_rng(0)
|
||||||
|
for n in (4, 5, 6, 7):
|
||||||
|
best = 10**9; bestdeg = None; bestk = None
|
||||||
|
for _ in range(12000):
|
||||||
|
k = int(rng.integers(1, 4))
|
||||||
|
faces = disk(n, k, rng)
|
||||||
|
if not valid(faces, n, k) or len(faces) > 16:
|
||||||
|
continue
|
||||||
|
if not min_degree_ok(faces, n, k):
|
||||||
|
continue
|
||||||
|
s = phi_size(faces, n)
|
||||||
|
if s and s < best:
|
||||||
|
best = s
|
||||||
|
deg = Counter()
|
||||||
|
for f in faces:
|
||||||
|
for v in f:
|
||||||
|
if v >= n:
|
||||||
|
deg[v] += 1
|
||||||
|
bestdeg = sorted(deg.values()); bestk = k
|
||||||
|
floor = 2 ** (n - 2)
|
||||||
|
print(f" n={n}: min irreducible |Phi|={best} (k={bestk}, interior degrees "
|
||||||
|
f"{bestdeg}) ratio to floor = {best/floor:.4f} "
|
||||||
|
f"5*2^(n-4)={5*2**(n-4)} wheel={vals[n]}")
|
||||||
|
degree_sweep()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user