even_level: add "Toward a characterization of bridge-derived graphs"

Record the partition sweep on the n=24 Fig 2.10 dual. New subsection +
experiments/bridge_partition_sweep.py.

Findings:
- A bridge switch is a constrained diagonal flip; bridge-derived via L
  means lying in an Even-Level-Graph component of the restricted flip
  graph. So the question is which flip-components contain an ELG.
- Identity: every 4-coloring of a triangulation has e_cross = 2n-4 (each
  face has one within-pair edge), so total parity-subgraph Betti =
  (c_A+c_B)-2; intertwining trees are the Betti-0 case.
- Of T's 333 valid partitions, total Betti splits 288/42/3 over 1/2/3;
  min is 1 (T not intertwining). All 27 partitions found bridge-derived
  (depth 2-3) have the minimum Betti 1 -> necessary.
- But not sufficient: only 27 of 288 Betti-1 partitions yield a witness;
  the rest have flip-orbits >1.5e5 with no ELG, and a 12x budget increase
  found none. The discriminator is flip-component structure (sharp
  orbit-size dichotomy), not a numerical invariant. Characterizing which
  Betti-minimal partitions sit in an ELG component is left open.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-22 17:41:13 -04:00
parent 435f055d82
commit 36ed7bac38
6 changed files with 168 additions and 24 deletions
@@ -0,0 +1,89 @@
"""Probe which valid parity partitions of the Fig. 2.10 dual T (24-vertex
5-connected triangulation) make it bridge-derived, and what distinguishes
them.
For every valid parity partition L of T we record:
- e_cross, e_A, e_B and the total first Betti number of the two parity
subgraphs (which equals (c_A + c_B) - 2, since e_A + e_B = n - 2 for
every 4-coloring of a triangulation: each triangle has exactly one
within-colour-pair edge, 2n-4 triangles, each such edge in 2 faces);
- whether L is the BFS-level parity of T from some source;
- the outcome of a backward bridge-orbit search (found / capped).
Finding: minimal total Betti (= 1 here, since T is not intertwining) is
necessary for the bridge-derived partitions we locate, but far from
sufficient -- the bridge-derivable partitions form a small, sharply
separated subset distinguished by tiny flip-orbit size, not by any simple
count. See the paper subsection "Toward a characterization of
bridge-derived graphs".
"""
import sys
import os
import time
from collections import defaultdict
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 networkx as nx
from sage.all import Graph # type: ignore
from tutte_dual_treecolor import dual_triangulation
from test_tutte_bridge import valid_parity_partitions_via_coloring, search_partition
from test_fig210_dual_bridge import sage_to_nx
from fast_bridge import EdgeCode
HERE = os.path.dirname(os.path.abspath(__file__))
def parity_stats(T, labels):
A = [v for v in T if labels[v] == 0]
B = [v for v in T if labels[v] == 1]
GA, GB = T.subgraph(A), T.subgraph(B)
cA = nx.number_connected_components(GA)
cB = nx.number_connected_components(GB)
bA = GA.number_of_edges() - len(A) + cA
bB = GB.number_of_edges() - len(B) + cB
ecross = T.number_of_edges() - GA.number_of_edges() - GB.number_of_edges()
realiz = any(
all((nx.single_source_shortest_path_length(T, s)[v] % 2) == labels[v] for v in T)
or all((nx.single_source_shortest_path_length(T, s)[v] % 2) != labels[v] for v in T)
for s in T
)
return dict(eA=GA.number_of_edges(), eB=GB.number_of_edges(), ecross=ecross,
betti=bA + bB, cA=cA, cB=cB, realiz=realiz)
def main(cap=12000, time_limit=6.0):
g6 = open(os.path.join(HERE, 'fig210_dual.g6')).read().strip()
T, _ = dual_triangulation(sage_to_nx(Graph(g6)))
n = T.number_of_nodes()
parts, _ = valid_parity_partitions_via_coloring(T)
code = EdgeCode(T.nodes())
code.state0 = code.state_of(T)
print('T: n=%d, e_cross should be 2n-4=%d; %d valid partitions'
% (n, 2 * n - 4, len(parts)), flush=True)
by_betti = defaultdict(lambda: [0, 0]) # betti -> [found, not_found]
ecross_vals = set()
t0 = time.time()
for k, labels in enumerate(parts):
st = parity_stats(T, labels)
ecross_vals.add(st['ecross'])
status, sz, depth = search_partition(code, labels, n, cap, time_limit)
slot = 0 if status == 'found' else 1
by_betti[st['betti']][slot] += 1
if status == 'found':
print(' found k=%d betti=%d depth=%s orbit=%d realiz=%s'
% (k, st['betti'], depth, sz, st['realiz']), flush=True)
if (k + 1) % 50 == 0:
print(' ...%d/%d (%.0fs)' % (k + 1, len(parts), time.time() - t0), flush=True)
print('\ne_cross values over all partitions: %s (constant = identity check)'
% sorted(ecross_vals), flush=True)
print('betti -> [bridge-derived, not-found-at-cap=%d]:' % cap, flush=True)
for b in sorted(by_betti):
print(' betti=%d : %s' % (b, by_betti[b]), flush=True)
print('(%.0fs)' % (time.time() - t0), flush=True)
if __name__ == '__main__':
main()