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:
@@ -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()
|
||||
Reference in New Issue
Block a user