Add Even Level Graph Generators paper + extend Level Switching reachability
- New paper papers/even_level_graph_generators/: defines Even Level Graph (every level cycle even), derived level graphs, intertwining trees, and the disjunction conjecture (every maximal planar graph is a derived level graph or intertwining tree). Empirically tested through n=11: every iso class is at least an intertwining tree, so the disjunction holds trivially in this range. The intertwining tree disjunct fails at the Tutte graph dual (n=25), so the disjunction becomes non-trivial past some unknown threshold. - Level Switching paper: adds Section 4 (Reachability via edge switches) with the two-step argument (Sleator-Tarjan-Thurston for Case 1; face-merges for Case 2) and Theorem 4.1 (O(n) edge switches suffice to reach all-depth-0). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
"""Test the disjunction: every maximal planar graph is a valid derived
|
||||
level graph, an intertwining tree, or both. Iterates n=6..12, stops if
|
||||
a counterexample is found."""
|
||||
import sys
|
||||
import os
|
||||
sys.path.insert(0, '/Users/didericis/Code/math-research/papers/'
|
||||
'level_resolutions_of_maximal_planar_graphs/experiments')
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
import time
|
||||
import itertools
|
||||
import networkx as nx
|
||||
from triangulation_gen import enumerate_all_triangulations
|
||||
from test_conjecture import (
|
||||
canonical_sig, bfs_levels, get_level_sources,
|
||||
is_even_level_graph, bfs_orbit
|
||||
)
|
||||
|
||||
|
||||
def is_intertwining_tree(G):
|
||||
"""Search for a 2-partition (A, B) such that G[A] and G[B] are trees."""
|
||||
nodes = list(G.nodes())
|
||||
n = len(nodes)
|
||||
# Try all 2^(n-1) partitions (fix node 0 in A by convention)
|
||||
for mask in range(1, 2 ** (n - 1)):
|
||||
A = [nodes[0]] + [nodes[i + 1] for i in range(n - 1) if (mask >> i) & 1]
|
||||
B = [nodes[i + 1] for i in range(n - 1) if not ((mask >> i) & 1)]
|
||||
if not A or not B:
|
||||
continue
|
||||
GA = G.subgraph(A)
|
||||
GB = G.subgraph(B)
|
||||
if nx.is_tree(GA) and nx.is_tree(GB):
|
||||
return True, (tuple(A), tuple(B))
|
||||
return False, None
|
||||
|
||||
|
||||
def derived_level_graph_iso_classes(tris):
|
||||
"""Compute the set of iso class signatures that are derived level
|
||||
graphs of some Even Level Graph."""
|
||||
iso_class_sigs = {canonical_sig(T) for T in tris}
|
||||
derived = set()
|
||||
for G in tris:
|
||||
if len(derived) == len(iso_class_sigs):
|
||||
break
|
||||
for source in get_level_sources(G):
|
||||
is_elg, levels = is_even_level_graph(G, source)
|
||||
if not is_elg:
|
||||
continue
|
||||
reached, _, _ = bfs_orbit(G, levels)
|
||||
derived.update(reached)
|
||||
return derived
|
||||
|
||||
|
||||
def test_n(n):
|
||||
t0 = time.time()
|
||||
tris = enumerate_all_triangulations(n)
|
||||
iso_sigs = [canonical_sig(T) for T in tris]
|
||||
derived = derived_level_graph_iso_classes(tris)
|
||||
n_derived = sum(1 for s in iso_sigs if s in derived)
|
||||
|
||||
# For iso classes that are NOT derived, check intertwining tree
|
||||
counterexamples = []
|
||||
n_intertwining_only = 0
|
||||
n_both = 0
|
||||
for i, G in enumerate(tris):
|
||||
is_derived = iso_sigs[i] in derived
|
||||
is_inter, partition = is_intertwining_tree(G)
|
||||
if is_derived and is_inter:
|
||||
n_both += 1
|
||||
elif is_derived:
|
||||
pass # only derived
|
||||
elif is_inter:
|
||||
n_intertwining_only += 1
|
||||
else:
|
||||
counterexamples.append((i, G))
|
||||
|
||||
n_total = len(tris)
|
||||
n_only_derived = n_derived - n_both
|
||||
elapsed = time.time() - t0
|
||||
return {
|
||||
'n': n,
|
||||
'total': n_total,
|
||||
'derived': n_derived,
|
||||
'intertwining_only': n_intertwining_only,
|
||||
'both': n_both,
|
||||
'only_derived': n_only_derived,
|
||||
'counterexamples': counterexamples,
|
||||
'elapsed': elapsed,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
results = []
|
||||
for n in [6, 7, 8, 9, 10, 11, 12]:
|
||||
print(f'\n=== n = {n} ===')
|
||||
r = test_n(n)
|
||||
results.append(r)
|
||||
print(f' total iso classes: {r["total"]}')
|
||||
print(f' derived only: {r["only_derived"]}')
|
||||
print(f' intertwining only: {r["intertwining_only"]}')
|
||||
print(f' both: {r["both"]}')
|
||||
print(f' counterexamples: {len(r["counterexamples"])}')
|
||||
print(f' elapsed: {r["elapsed"]:.1f}s')
|
||||
if r['counterexamples']:
|
||||
print(f' COUNTEREXAMPLE FOUND. Stopping.')
|
||||
for i, G in r['counterexamples'][:3]:
|
||||
print(f' iso[{i}] degree seq = '
|
||||
f'{sorted([G.degree(v) for v in G.nodes()], reverse=True)}')
|
||||
break
|
||||
|
||||
print('\n=== Final summary ===')
|
||||
print(f'{"n":>3} {"total":>6} {"deriv":>6} {"inter":>6} {"both":>6} {"missing":>8}')
|
||||
for r in results:
|
||||
cov = r['only_derived'] + r['intertwining_only'] + r['both']
|
||||
missing = r['total'] - cov
|
||||
print(f'{r["n"]:>3} {r["total"]:>6} {r["only_derived"]:>6} '
|
||||
f'{r["intertwining_only"]:>6} {r["both"]:>6} {missing:>8}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user