Option 2 (direct transversal) clean form is dead too
transversal.py: a STRONG transversal (n-2 faces whose Boolean assignment single-valuedly and injectively determines the boundary) would give a constructive proof. It exists in 0/2948 disks with k>=1 -- once there is any interior vertex, fixing n-2 faces leaves boundary-visible completion freedom, so the boundary is never single-valued in them. Works only at k=0 (base case). Both elementary routes (reduction localization, direct transversal) now closed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,123 @@
|
|||||||
|
"""
|
||||||
|
Option 2: a direct "strong transversal" for |Phi(D)| >= 2^(n-2).
|
||||||
|
|
||||||
|
In the Boolean reformulation, feasible x in {0,1}^F satisfy |x|_w ≡ -deg(w) at
|
||||||
|
interior w, and the boundary sequence is (deg(v)+|x|_v mod 3)_{v in C}. A STRONG
|
||||||
|
TRANSVERSAL is a set A of n-2 faces such that
|
||||||
|
(i) every assignment x_A in {0,1}^A extends to a feasible x,
|
||||||
|
(ii) the boundary sequence is single-valued in x_A (all feasible completions of
|
||||||
|
a given x_A give the same boundary), and
|
||||||
|
(iii) the map x_A -> boundary is injective.
|
||||||
|
If such A exists, the 2^(n-2) assignments give 2^(n-2) distinct boundary sequences,
|
||||||
|
proving the bound CONSTRUCTIVELY. We test whether a strong transversal exists.
|
||||||
|
|
||||||
|
Heuristic worry: over GF(3) the internal completion freedom (dim k) exceeds the
|
||||||
|
boundary-invisible freedom (dim k-1), so (ii) may fail. Test settles it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from collections import defaultdict
|
||||||
|
from itertools import combinations, product
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from scipy.spatial import Delaunay
|
||||||
|
|
||||||
|
np.seterr(all="ignore")
|
||||||
|
|
||||||
|
|
||||||
|
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)]
|
||||||
|
if k:
|
||||||
|
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)]])
|
||||||
|
else:
|
||||||
|
pts = bpts
|
||||||
|
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
|
||||||
|
from collections import Counter
|
||||||
|
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 feasible_table(faces, n):
|
||||||
|
"""Return list of (x tuple, boundary tuple) over feasible x in {0,1}^F."""
|
||||||
|
interior = sorted(set(v for f in faces for v in f if v >= n))
|
||||||
|
F = len(faces)
|
||||||
|
if F > 14:
|
||||||
|
return None
|
||||||
|
Bint = np.zeros((len(interior), F), dtype=np.int64)
|
||||||
|
Cinc = np.zeros((n, F), dtype=np.int64)
|
||||||
|
deg = np.zeros(n, dtype=np.int64)
|
||||||
|
iidx = {w: r for r, w in enumerate(interior)}
|
||||||
|
degw = np.zeros(len(interior), dtype=np.int64)
|
||||||
|
for j, (a, b, c) in enumerate(faces):
|
||||||
|
for v in (a, b, c):
|
||||||
|
if v >= n:
|
||||||
|
Bint[iidx[v], j] = 1; degw[iidx[v]] += 1
|
||||||
|
else:
|
||||||
|
Cinc[v, j] = 1; deg[v] += 1
|
||||||
|
xs = np.array(list(product((0, 1), repeat=F)), dtype=np.int64)
|
||||||
|
if len(interior):
|
||||||
|
ok = np.all((xs @ Bint.T - (-degw)) % 3 == 0, axis=1)
|
||||||
|
xs = xs[ok]
|
||||||
|
if xs.shape[0] == 0:
|
||||||
|
return []
|
||||||
|
bnd = (deg + xs @ Cinc.T) % 3
|
||||||
|
return list(zip(map(tuple, xs.tolist()), map(tuple, bnd.tolist())))
|
||||||
|
|
||||||
|
|
||||||
|
def has_strong_transversal(table, F, n):
|
||||||
|
target = 2 ** (n - 2)
|
||||||
|
for A in combinations(range(F), n - 2):
|
||||||
|
groups = defaultdict(set)
|
||||||
|
for x, b in table:
|
||||||
|
groups[tuple(x[i] for i in A)].add(b)
|
||||||
|
if len(groups) != target:
|
||||||
|
continue # not every x_A feasible
|
||||||
|
if any(len(bs) != 1 for bs in groups.values()):
|
||||||
|
continue # not single-valued (cond ii)
|
||||||
|
reps = [next(iter(bs)) for bs in groups.values()]
|
||||||
|
if len(set(reps)) == target: # injective (cond iii)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
seed = int(sys.argv[1]) if len(sys.argv) > 1 else 0
|
||||||
|
rng = np.random.default_rng(seed)
|
||||||
|
tested = 0; have = 0; fails = []
|
||||||
|
for _ in range(3000):
|
||||||
|
n = int(rng.integers(4, 6)); k = int(rng.integers(1, 3))
|
||||||
|
faces = disk(n, k, rng)
|
||||||
|
if not valid(faces, n, k) or len(faces) > 12:
|
||||||
|
continue
|
||||||
|
tbl = feasible_table(faces, n)
|
||||||
|
if not tbl:
|
||||||
|
continue
|
||||||
|
tested += 1
|
||||||
|
if has_strong_transversal(tbl, len(faces), n):
|
||||||
|
have += 1
|
||||||
|
elif len(fails) < 5:
|
||||||
|
fails.append((n, k, len(faces)))
|
||||||
|
print(f"disks tested (k>=1): {tested}")
|
||||||
|
print(f" have a STRONG transversal (size n-2, single-valued, injective): "
|
||||||
|
f"{have}/{tested} ({100*have/max(tested,1):.1f}%)")
|
||||||
|
if fails:
|
||||||
|
print(f" failures (n,k,F): {fails}")
|
||||||
|
if have == tested and tested:
|
||||||
|
print(" => strong transversals always exist: constructive proof viable.")
|
||||||
|
elif have == 0:
|
||||||
|
print(" => strong transversals NEVER exist: this clean form of option 2 is dead.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user