Test monotonicity lemma: degree-3 exact, but lemma is false at degree-4

monotonicity_test.py inserts interior vertices and checks |Phi|. Degree-3
stacks preserve Phi exactly (confirms un-stacking, 100%), but degree-4
insertions can SHRINK Phi (6->5, 30->28) and Phi(D') subset Phi(D) fails
~13% -- so the reduce-to-base-case proof of the 2^(n-2) floor via
monotonicity does not work. Violations stay above the floor, so the floor
is protected by something stronger; redirect to a direct n-2 toggle
construction.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-17 19:58:59 -04:00
parent 1d981b4d01
commit 9f6328788c
@@ -0,0 +1,170 @@
"""
Test the MONOTONICITY LEMMA behind the 2^(n-2) lower bound:
adding an interior vertex never DECREASES |Phi|
(equivalently Phi(D') subset Phi(D) when D = D' + one interior vertex).
If true, every disk reduces to the k=0 base case without increasing Phi, so
|Phi(D)| >= |Phi(D_0)| = 2^(n-2). A single insertion that shrinks Phi (or breaks
the inclusion) would refute the proof strategy.
We build a validated base disk D' (Delaunay, convex non-cocircular boundary), then
insert a vertex two ways:
* degree-3 stack into a face (proved: should give equality)
* degree-4 open of an internal edge (a,b)|(c,d) (the first genuinely open case)
and compare Phi(D') to Phi(D).
"""
import sys
from collections import Counter, defaultdict
from itertools import product
import numpy as np
from scipy.spatial import Delaunay
np.seterr(all="ignore")
def base_disk(n, k, rng):
ang = 2 * np.pi * np.arange(n) / n
rad = 1.0 + 0.15 * rng.random(n)
bpts = np.c_[rad * np.cos(ang), rad * np.sin(ang)]
if k:
r = 0.7 * 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)]])
else:
pts = bpts
faces = [tuple(int(x) for x in s) for s in Delaunay(pts).simplices]
return faces
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(faces, n):
verts = set(v for f in faces for v in f)
interior = sorted(v for v in verts 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 set()
return set(map(tuple, np.unique((labs @ Cinc.T) % 3, axis=0)))
def insert_deg3(faces, fi, v):
a, b, c = faces[fi]
out = [f for i, f in enumerate(faces) if i != fi]
out += [(a, b, v), (b, c, v), (a, c, v)]
return out
def insert_deg4(faces, n):
"""Open an internal edge (a,b) shared by faces (a,b,c),(a,b,d): replace those
two faces with the 4-star of a new center over the quad a-c-b-d."""
ef = defaultdict(list)
for i, (a, b, c) in enumerate(faces):
for e in ((a, b), (b, c), (a, c)):
ef[frozenset(e)].append(i)
for e, fl in ef.items():
if len(fl) != 2:
continue
a, b = tuple(e)
if (a < n and b < n and (b - a) % n in (1, n - 1)):
continue # boundary edge
f1, f2 = faces[fl[0]], faces[fl[1]]
c = next(x for x in f1 if x not in (a, b))
d = next(x for x in f2 if x not in (a, b))
if c == d:
continue
v = max(max(f) for f in faces) + 1
out = [f for i, f in enumerate(faces) if i not in fl]
out += [(a, c, v), (c, b, v), (b, d, v), (d, a, v)]
return out, v
return None, None
def main():
seed = int(sys.argv[1]) if len(sys.argv) > 1 else 0
rng = np.random.default_rng(seed)
viol_size = 0 # |Phi(D)| < |Phi(D')| (monotonicity broken)
viol_incl = 0 # Phi(D') not subset Phi(D)
tested = 0
deg3_equal = 0; deg3_tot = 0
deg4_strict = 0; deg4_tot = 0
examples = []
for _ in range(500):
n = int(rng.integers(4, 7)); k = int(rng.integers(0, 4))
faces = base_disk(n, k, rng)
if not valid(faces, n, k) or len(faces) > 14:
continue
Pp = phi(faces, n)
if Pp is None:
continue
# degree-3 insertions: every face
for fi in range(len(faces)):
D = insert_deg3(faces, fi, max(max(f) for f in faces) + 1)
P = phi(D, n)
if P is None:
continue
tested += 1; deg3_tot += 1
if not Pp <= P:
viol_incl += 1
if len(P) < len(Pp):
viol_size += 1
if len(examples) < 5:
examples.append(("deg3", n, len(Pp), len(P)))
if len(P) == len(Pp):
deg3_equal += 1
# one degree-4 insertion
D4, v = insert_deg4(faces, n)
if D4 is not None:
P = phi(D4, n)
if P is not None:
tested += 1; deg4_tot += 1
if not Pp <= P:
viol_incl += 1
if len(P) < len(Pp):
viol_size += 1
if len(examples) < 5:
examples.append(("deg4", n, len(Pp), len(P)))
if len(P) > len(Pp):
deg4_strict += 1
print(f"insertions tested: {tested}")
print(f" monotonicity violations (|Phi(D)| < |Phi(D')|): {viol_size}")
print(f" inclusion violations (Phi(D') not subset Phi(D)): {viol_incl}")
print(f" degree-3: {deg3_equal}/{deg3_tot} gave EXACT equality "
f"(proved un-stacking => should be all)")
print(f" degree-4: {deg4_strict}/{deg4_tot} strictly ENLARGED Phi")
if examples:
print(" VIOLATION examples (type,n,|Phi(D')|,|Phi(D)|):")
for e in examples:
print(f" {e}")
else:
print(" no violation: every insertion preserved or enlarged Phi, "
"and Phi(D') subset Phi(D) throughout.")
if __name__ == "__main__":
main()