Prove outerplanarity and draft edge-flip resolution algorithm
- Promote Prop 3.1 (outerplanarity of level subgraphs) to Theorem 3.1 with a proof by contradiction via a BFS-path argument; drop the $n \leq 10$ caveat and the now-resolved open question. - Add Section 5 "An edge-flip resolution algorithm": apex classification of $L_k$-edges, bridge lemma, cross-level flip pass, definition of tricky-everywhere odd cycles and facial depth (seeded from inner faces with $\geq 2$ outer-face edges), and the depth-guided flip procedure. Observation 5.5 records empirical termination at $n = 9, 10, 11$; Question 5.6 asks if it holds in general. - Add experiments/depth_monovariant_check.py (sanity check over triangulation iso-classes, confirms the count-of-tricky-faces monovariant strictly decreases per flip on all 1400 tricky configs at $n \leq 11$), viz_cycling.py and debug_cycling.py, and cycling_visualization.png illustrating the depth-definition fix. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 303 KiB |
@@ -0,0 +1,88 @@
|
||||
"""Dump one cycling case to see what's going on."""
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
import networkx as nx
|
||||
from collections import defaultdict
|
||||
from triangulation_gen import enumerate_all_triangulations
|
||||
from level_cycles import compute_levels, level_sources
|
||||
from depth_monovariant_check import (
|
||||
faces_of_subgraph, canonical_face, edges_of_face,
|
||||
apex_levels_for_edge, identify_outer_face, face_depths,
|
||||
is_both_k_everywhere, tricky_odd_faces, lowest_depth_neighbor_flip,
|
||||
)
|
||||
|
||||
|
||||
def dump(G, emb, levels, nodes_k, k, source_label):
|
||||
print(f" source: {source_label}, levels:")
|
||||
by_level = defaultdict(list)
|
||||
for v, lv in levels.items():
|
||||
by_level[lv].append(v)
|
||||
for lv in sorted(by_level):
|
||||
print(f" L_{lv} = {sorted(by_level[lv])}")
|
||||
print(f" examining L_{k} = {sorted(nodes_k)}")
|
||||
L_k = G.subgraph(nodes_k)
|
||||
print(f" L_k edges: {sorted(L_k.edges())}")
|
||||
faces = faces_of_subgraph(G, emb, nodes_k)
|
||||
print(f" faces of L_k (inherited embedding):")
|
||||
for f in faces:
|
||||
print(f" {f} len={len(f)} canon={canonical_face(f)}")
|
||||
outer = identify_outer_face(faces, G, emb, levels, k)
|
||||
print(f" outer face: {outer}")
|
||||
depths = face_depths(faces, outer)
|
||||
print(f" depths: {depths}")
|
||||
print(f" edge-by-edge apex-level pairs:")
|
||||
for f in faces:
|
||||
cf = canonical_face(f)
|
||||
if cf == outer:
|
||||
continue
|
||||
if len(f) < 3:
|
||||
continue
|
||||
print(f" face {f} (depth={depths.get(cf)}, len={len(f)}):")
|
||||
for (u, v) in edges_of_face(f):
|
||||
result = apex_levels_for_edge(G, emb, u, v, levels)
|
||||
if result is None:
|
||||
print(f" ({u},{v}): no apex")
|
||||
continue
|
||||
(la, lb), (w, x) = result
|
||||
print(f" ({u},{v}): apexes ({w}@L{la}, {x}@L{lb})")
|
||||
tricky = tricky_odd_faces(faces, G, emb, levels, k, depths, outer)
|
||||
print(f" tricky odd faces: {[(f, d) for cf, f, d in tricky]}")
|
||||
if tricky:
|
||||
cf_t, face_t, d_t = max(tricky, key=lambda x: x[2])
|
||||
print(f" picking deepest tricky face: {face_t} at depth {d_t}")
|
||||
flip = lowest_depth_neighbor_flip(face_t, G, emb, levels, k,
|
||||
depths, faces, outer)
|
||||
print(f" flip choice: {flip}")
|
||||
|
||||
|
||||
# n=10, tri_idx=6, source face (0,4,2), k=1
|
||||
tris = enumerate_all_triangulations(10)
|
||||
G = tris[6]
|
||||
ip, emb = nx.check_planarity(G)
|
||||
print(f"G edges: {sorted(G.edges())}")
|
||||
source = {0, 4, 2}
|
||||
levels = compute_levels(G, source)
|
||||
by_level = defaultdict(list)
|
||||
for v, lv in levels.items():
|
||||
by_level[lv].append(v)
|
||||
nodes_k = by_level[1]
|
||||
dump(G, emb, levels, nodes_k, 1, ('face', (0, 4, 2)))
|
||||
|
||||
print("\n--- after one flip ---")
|
||||
flip_choice = None
|
||||
faces = faces_of_subgraph(G, emb, nodes_k)
|
||||
outer = identify_outer_face(faces, G, emb, levels, 1)
|
||||
depths = face_depths(faces, outer)
|
||||
tricky = tricky_odd_faces(faces, G, emb, levels, 1, depths, outer)
|
||||
if tricky:
|
||||
cf_t, face_t, d_t = max(tricky, key=lambda x: x[2])
|
||||
flip_choice = lowest_depth_neighbor_flip(face_t, G, emb, levels, 1,
|
||||
depths, faces, outer)
|
||||
if flip_choice:
|
||||
u, v, w, x, _ = flip_choice
|
||||
Gp = G.copy()
|
||||
Gp.remove_edge(u, v)
|
||||
Gp.add_edge(w, x)
|
||||
print(f"Flipped ({u},{v}) -> ({w},{x})")
|
||||
ip2, emb_p = nx.check_planarity(Gp)
|
||||
dump(Gp, emb_p, levels, nodes_k, 1, ('face', (0, 4, 2)))
|
||||
+369
@@ -0,0 +1,369 @@
|
||||
"""
|
||||
Sanity check for the facial-depth monovariant on tricky (k,k) configurations.
|
||||
|
||||
For each (G, S, k) where L_k has at least one "tricky-everywhere" odd face
|
||||
(every edge is a (k,k) apex pair):
|
||||
- Run the proposed algorithm: pick the deepest tricky-everywhere odd face,
|
||||
flip the edge whose other-side face has min facial depth.
|
||||
- Iterate until no tricky-everywhere odd face remains, or step budget hits.
|
||||
- Track multiple candidate monovariants per flip.
|
||||
|
||||
Reports counts of (a) terminations within budget, (b) cycle/failure cases,
|
||||
(c) which monovariant (if any) decreases on every flip.
|
||||
"""
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
import networkx as nx
|
||||
from collections import defaultdict, deque
|
||||
from triangulation_gen import enumerate_all_triangulations
|
||||
from level_cycles import (
|
||||
compute_levels, get_all_faces, inherited_embedding, level_sources
|
||||
)
|
||||
|
||||
|
||||
# -- helpers ------------------------------------------------------------
|
||||
|
||||
def faces_of_subgraph(G, emb_G, nodes_k):
|
||||
if len(nodes_k) < 3:
|
||||
return []
|
||||
L_k = G.subgraph(nodes_k)
|
||||
if L_k.number_of_edges() < 3:
|
||||
return []
|
||||
try:
|
||||
emb_L = inherited_embedding(emb_G, nodes_k)
|
||||
return get_all_faces(emb_L)
|
||||
except Exception:
|
||||
ip, emb_L = nx.check_planarity(L_k)
|
||||
if not ip:
|
||||
return []
|
||||
return get_all_faces(emb_L)
|
||||
|
||||
|
||||
def canonical_face(face):
|
||||
rots = [tuple(face[i:] + face[:i]) for i in range(len(face))] \
|
||||
+ [tuple(face[::-1][i:] + face[::-1][:i]) for i in range(len(face))]
|
||||
return min(rots)
|
||||
|
||||
|
||||
def edges_of_face(face):
|
||||
n = len(face)
|
||||
return [(face[i], face[(i+1) % n]) for i in range(n)]
|
||||
|
||||
|
||||
def apex_levels_for_edge(G, emb_G, u, v, levels):
|
||||
if not G.has_edge(u, v):
|
||||
return None
|
||||
f1 = emb_G.traverse_face(u, v)
|
||||
f2 = emb_G.traverse_face(v, u)
|
||||
if len(f1) != 3 or len(f2) != 3:
|
||||
return None
|
||||
w = next(x for x in f1 if x != u and x != v)
|
||||
x = next(y for y in f2 if y != u and y != v)
|
||||
return (levels.get(w), levels.get(x)), (w, x)
|
||||
|
||||
|
||||
def identify_outer_face(faces, G, emb_G, levels, k):
|
||||
"""Outer face = the face whose 'outside' connects to lower levels.
|
||||
Score each face by how many edges have at least one apex at level < k
|
||||
on the opposite side; pick highest score, longest boundary as tiebreak."""
|
||||
best = (-1, -1, None)
|
||||
for face in faces:
|
||||
score = 0
|
||||
for (u, v) in edges_of_face(face):
|
||||
if not G.has_edge(u, v):
|
||||
continue
|
||||
f1 = emb_G.traverse_face(u, v)
|
||||
f2 = emb_G.traverse_face(v, u)
|
||||
if len(f1) != 3 or len(f2) != 3:
|
||||
continue
|
||||
w = next(x for x in f1 if x != u and x != v)
|
||||
x = next(y for y in f2 if y != u and y != v)
|
||||
if (levels.get(w, k) < k) or (levels.get(x, k) < k):
|
||||
score += 1
|
||||
key = (score, len(face))
|
||||
if key > (best[0], best[1]):
|
||||
best = (score, len(face), face)
|
||||
return canonical_face(best[2]) if best[2] is not None else None
|
||||
|
||||
|
||||
def face_depths(faces, outer_canon):
|
||||
"""BFS depth in the dual graph from the seed set:
|
||||
inner faces with >= 2 edges incident to the outer face."""
|
||||
edge_to_faces = defaultdict(list)
|
||||
canon_set = set()
|
||||
for face in faces:
|
||||
cf = canonical_face(face)
|
||||
canon_set.add(cf)
|
||||
for (a, b) in edges_of_face(face):
|
||||
edge_to_faces[frozenset([a, b])].append(cf)
|
||||
# Outer-face edges = edges of the outer face.
|
||||
outer_face_edges = set()
|
||||
for face in faces:
|
||||
if canonical_face(face) == outer_canon:
|
||||
for (a, b) in edges_of_face(face):
|
||||
outer_face_edges.add(frozenset([a, b]))
|
||||
break
|
||||
# Seed set: inner faces with >= 2 outer-face edges.
|
||||
seeds = []
|
||||
for face in faces:
|
||||
cf = canonical_face(face)
|
||||
if cf == outer_canon:
|
||||
continue
|
||||
count = 0
|
||||
for (a, b) in edges_of_face(face):
|
||||
if frozenset([a, b]) in outer_face_edges:
|
||||
count += 1
|
||||
if count >= 2:
|
||||
seeds.append(cf)
|
||||
if not seeds:
|
||||
# Fall back: no seeds means no "easy" odd face nearby. Return empty.
|
||||
return {}
|
||||
D = nx.Graph()
|
||||
for cf in canon_set:
|
||||
if cf != outer_canon:
|
||||
D.add_node(cf)
|
||||
for e, fs in edge_to_faces.items():
|
||||
if len(fs) == 2:
|
||||
f1, f2 = fs
|
||||
if f1 != outer_canon and f2 != outer_canon:
|
||||
D.add_edge(f1, f2)
|
||||
# Multi-source BFS.
|
||||
depths = {}
|
||||
queue = deque()
|
||||
for s in seeds:
|
||||
if s in D:
|
||||
depths[s] = 0
|
||||
queue.append(s)
|
||||
while queue:
|
||||
u = queue.popleft()
|
||||
for v in D.neighbors(u):
|
||||
if v not in depths:
|
||||
depths[v] = depths[u] + 1
|
||||
queue.append(v)
|
||||
return depths
|
||||
|
||||
|
||||
def is_both_k_everywhere(face, G, emb_G, levels, k):
|
||||
for (u, v) in edges_of_face(face):
|
||||
result = apex_levels_for_edge(G, emb_G, u, v, levels)
|
||||
if result is None:
|
||||
return False
|
||||
(la, lb), _ = result
|
||||
if (la, lb) != (k, k):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def tricky_odd_faces(faces, G, emb_G, levels, k, depths, outer_canon):
|
||||
"""Return list of (canon, face, depth) for odd faces that are tricky-
|
||||
everywhere AND have at least one (k,k) edge whose other-side face is
|
||||
not the outer face (i.e., we can flip toward an inner neighbor)."""
|
||||
out = []
|
||||
for face in faces:
|
||||
cf = canonical_face(face)
|
||||
if cf == outer_canon:
|
||||
continue
|
||||
if len(face) % 2 != 1:
|
||||
continue
|
||||
if not is_both_k_everywhere(face, G, emb_G, levels, k):
|
||||
continue
|
||||
d = depths.get(cf)
|
||||
if d is None:
|
||||
continue
|
||||
out.append((cf, face, d))
|
||||
return out
|
||||
|
||||
|
||||
def odd_faces_all(faces, depths, outer_canon):
|
||||
out = []
|
||||
for face in faces:
|
||||
cf = canonical_face(face)
|
||||
if cf == outer_canon:
|
||||
continue
|
||||
if len(face) % 2 != 1:
|
||||
continue
|
||||
d = depths.get(cf)
|
||||
if d is None:
|
||||
continue
|
||||
out.append((cf, face, d))
|
||||
return out
|
||||
|
||||
|
||||
def lowest_depth_neighbor_flip(face, G, emb_G, levels, k, depths, faces,
|
||||
outer_canon):
|
||||
"""Among (k,k) edges of `face`, return the flip toward the lowest-depth
|
||||
non-outer neighbor face. Returns (u, v, w, x, neighbor_depth) or None."""
|
||||
edge_to_other = {}
|
||||
face_canon = canonical_face(face)
|
||||
for f in faces:
|
||||
cf = canonical_face(f)
|
||||
if cf == face_canon:
|
||||
continue
|
||||
for (a, b) in edges_of_face(f):
|
||||
e = frozenset([a, b])
|
||||
edge_to_other.setdefault(e, cf)
|
||||
best = None
|
||||
for (u, v) in edges_of_face(face):
|
||||
result = apex_levels_for_edge(G, emb_G, u, v, levels)
|
||||
if result is None:
|
||||
continue
|
||||
(la, lb), (w, x) = result
|
||||
if (la, lb) != (k, k):
|
||||
continue
|
||||
if G.has_edge(w, x):
|
||||
continue
|
||||
e = frozenset([u, v])
|
||||
other_canon = edge_to_other.get(e)
|
||||
if other_canon is None or other_canon == outer_canon:
|
||||
continue
|
||||
other_depth = depths.get(other_canon)
|
||||
if other_depth is None:
|
||||
continue
|
||||
if best is None or other_depth < best[4]:
|
||||
best = (u, v, w, x, other_depth)
|
||||
return best
|
||||
|
||||
|
||||
# -- main routine -------------------------------------------------------
|
||||
|
||||
def analyze_config(G, emb, levels, nodes_k, k, max_steps=20):
|
||||
"""Run the user's algorithm iteratively. Returns:
|
||||
{'terminated': bool, 'steps': n, 'trace': list of monovariant tuples}
|
||||
A trace entry per step is (max_tricky_depth, num_tricky, max_odd_depth).
|
||||
"""
|
||||
Gc = G.copy()
|
||||
emb_c = emb
|
||||
trace = []
|
||||
for step in range(max_steps):
|
||||
faces = faces_of_subgraph(Gc, emb_c, nodes_k)
|
||||
if len(faces) < 2:
|
||||
return {'terminated': True, 'steps': step, 'trace': trace,
|
||||
'reason': 'no_faces'}
|
||||
outer = identify_outer_face(faces, Gc, emb_c, levels, k)
|
||||
depths = face_depths(faces, outer)
|
||||
if depths is None:
|
||||
return {'terminated': True, 'steps': step, 'trace': trace,
|
||||
'reason': 'no_depths'}
|
||||
odd_all = odd_faces_all(faces, depths, outer)
|
||||
tricky = tricky_odd_faces(faces, Gc, emb_c, levels, k, depths, outer)
|
||||
max_tricky = max((d for _, _, d in tricky), default=-1)
|
||||
max_odd = max((d for _, _, d in odd_all), default=-1)
|
||||
trace.append((max_tricky, len(tricky), max_odd))
|
||||
if not tricky:
|
||||
return {'terminated': True, 'steps': step, 'trace': trace,
|
||||
'reason': 'no_tricky'}
|
||||
# Pick deepest tricky face; flip toward lowest-depth neighbor.
|
||||
cf_t, face_t, d_t = max(tricky, key=lambda x: x[2])
|
||||
flip = lowest_depth_neighbor_flip(face_t, Gc, emb_c, levels, k,
|
||||
depths, faces, outer)
|
||||
if flip is None:
|
||||
return {'terminated': False, 'steps': step, 'trace': trace,
|
||||
'reason': 'no_flip'}
|
||||
u, v, w, x, _ = flip
|
||||
Gc.remove_edge(u, v)
|
||||
Gc.add_edge(w, x)
|
||||
ip, emb_c = nx.check_planarity(Gc)
|
||||
if not ip:
|
||||
return {'terminated': False, 'steps': step, 'trace': trace,
|
||||
'reason': 'nonplanar'}
|
||||
return {'terminated': False, 'steps': max_steps, 'trace': trace,
|
||||
'reason': 'budget'}
|
||||
|
||||
|
||||
def monovariant_decreases(trace, key):
|
||||
"""Does `trace[i][key]` strictly decrease at each step (except when
|
||||
the algorithm has already terminated)?"""
|
||||
vals = [t[key] for t in trace]
|
||||
for i in range(1, len(vals)):
|
||||
if vals[i] >= vals[i - 1]:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def run_check(n_values, max_steps=20):
|
||||
total_configs = 0
|
||||
terminated = 0
|
||||
nonterm = 0
|
||||
mono_max_tricky = 0
|
||||
mono_count_tricky = 0
|
||||
mono_max_odd = 0
|
||||
nonterm_examples = []
|
||||
|
||||
for n in n_values:
|
||||
print(f"\n=== n = {n} ===")
|
||||
tris = enumerate_all_triangulations(n)
|
||||
print(f" {len(tris)} iso-classes")
|
||||
for tri_idx, G in enumerate(tris):
|
||||
ip, emb = nx.check_planarity(G)
|
||||
if not ip:
|
||||
continue
|
||||
for kind, label, source_set in level_sources(G, emb):
|
||||
levels = compute_levels(G, source_set)
|
||||
by_level = defaultdict(list)
|
||||
for v, lv in levels.items():
|
||||
by_level[lv].append(v)
|
||||
for k, nodes_k in by_level.items():
|
||||
if k == 0:
|
||||
continue
|
||||
faces = faces_of_subgraph(G, emb, nodes_k)
|
||||
if len(faces) < 2:
|
||||
continue
|
||||
outer = identify_outer_face(faces, G, emb, levels, k)
|
||||
if outer is None:
|
||||
continue
|
||||
depths = face_depths(faces, outer)
|
||||
if depths is None:
|
||||
continue
|
||||
tricky = tricky_odd_faces(faces, G, emb, levels, k,
|
||||
depths, outer)
|
||||
if not tricky:
|
||||
continue
|
||||
total_configs += 1
|
||||
result = analyze_config(G, emb, levels, nodes_k, k,
|
||||
max_steps)
|
||||
if result['terminated']:
|
||||
terminated += 1
|
||||
else:
|
||||
nonterm += 1
|
||||
if len(nonterm_examples) < 5:
|
||||
nonterm_examples.append({
|
||||
'n': n, 'tri_idx': tri_idx,
|
||||
'source': (kind, label),
|
||||
'k': k,
|
||||
'reason': result['reason'],
|
||||
'trace': result['trace'],
|
||||
'steps': result['steps'],
|
||||
})
|
||||
# Monovariant check (only meaningful if trace has >= 2)
|
||||
tr = result['trace']
|
||||
if len(tr) >= 2:
|
||||
if monovariant_decreases(tr, 0):
|
||||
mono_max_tricky += 1
|
||||
if monovariant_decreases(tr, 1):
|
||||
mono_count_tricky += 1
|
||||
if monovariant_decreases(tr, 2):
|
||||
mono_max_odd += 1
|
||||
|
||||
print(f"\n=== summary ===")
|
||||
print(f"tricky configs encountered: {total_configs}")
|
||||
print(f" terminated within {max_steps} steps: {terminated}")
|
||||
print(f" non-terminating / failed: {nonterm}")
|
||||
print(f" candidate monovariants (strict decrease per step):")
|
||||
print(f" max depth of tricky faces: {mono_max_tricky}")
|
||||
print(f" count of tricky faces: {mono_count_tricky}")
|
||||
print(f" max depth of all odd faces: {mono_max_odd}")
|
||||
if nonterm_examples:
|
||||
print(f"\nnon-terminating examples (first {len(nonterm_examples)}):")
|
||||
for ex in nonterm_examples:
|
||||
print(f" n={ex['n']} tri={ex['tri_idx']} src={ex['source']} "
|
||||
f"k={ex['k']} reason={ex['reason']} steps={ex['steps']}")
|
||||
print(f" trace (max_tricky, n_tricky, max_odd): {ex['trace']}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
ns = [int(x) for x in sys.argv[1:]]
|
||||
else:
|
||||
ns = [9, 10]
|
||||
run_check(ns)
|
||||
@@ -0,0 +1,197 @@
|
||||
"""Visualize the cycling case for the (k,k) tricky-everywhere algorithm.
|
||||
|
||||
Shows L_1 of triangulation index 6 at n=10, with source face (0,4,2).
|
||||
Renders 4 steps of the algorithm side by side.
|
||||
"""
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
import networkx as nx
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.patches as mpatches
|
||||
from collections import defaultdict
|
||||
from triangulation_gen import enumerate_all_triangulations
|
||||
from level_cycles import compute_levels
|
||||
from depth_monovariant_check import (
|
||||
faces_of_subgraph, canonical_face, edges_of_face, apex_levels_for_edge,
|
||||
identify_outer_face, face_depths, is_both_k_everywhere,
|
||||
tricky_odd_faces, lowest_depth_neighbor_flip,
|
||||
)
|
||||
|
||||
|
||||
def layout_outerplanar(nodes_k, outer_face, G_full):
|
||||
"""Place outer-face vertices on a circle in the cyclic order they appear,
|
||||
and interior vertices via a weighted average of their neighbors on the
|
||||
circle."""
|
||||
outer_list = list(outer_face)
|
||||
n = len(outer_list)
|
||||
pos = {}
|
||||
for i, v in enumerate(outer_list):
|
||||
angle = np.pi / 2 - 2 * np.pi * i / n
|
||||
pos[v] = np.array([np.cos(angle), np.sin(angle)])
|
||||
interior = [v for v in nodes_k if v not in pos]
|
||||
if interior:
|
||||
Lk = G_full.subgraph(nodes_k)
|
||||
for v in interior:
|
||||
nbrs = [u for u in Lk.neighbors(v) if u in pos]
|
||||
if nbrs:
|
||||
pos[v] = np.mean([pos[u] for u in nbrs], axis=0)
|
||||
else:
|
||||
pos[v] = np.array([0.0, 0.0])
|
||||
return pos
|
||||
|
||||
|
||||
def draw_panel(ax, G_full, emb, levels, nodes_k, k, title,
|
||||
highlight_edge=None, new_edge=None):
|
||||
"""Draw L_k with faces shaded by depth and tricky odd face highlighted."""
|
||||
faces = faces_of_subgraph(G_full, emb, nodes_k)
|
||||
outer = identify_outer_face(faces, G_full, emb, levels, k)
|
||||
depths = face_depths(faces, outer)
|
||||
tricky = tricky_odd_faces(faces, G_full, emb, levels, k, depths, outer)
|
||||
tricky_canons = {cf for cf, _, _ in tricky}
|
||||
|
||||
# Find the outer face actual tuple (for layout)
|
||||
outer_face = None
|
||||
for f in faces:
|
||||
if canonical_face(f) == outer:
|
||||
outer_face = f
|
||||
break
|
||||
pos = layout_outerplanar(nodes_k, outer_face, G_full)
|
||||
|
||||
# Shade faces by depth (skip outer face)
|
||||
max_depth = max(d for d in depths.values()) if depths else 1
|
||||
for f in faces:
|
||||
cf = canonical_face(f)
|
||||
if cf == outer:
|
||||
continue
|
||||
d = depths.get(cf, 0)
|
||||
if cf in tricky_canons:
|
||||
color = '#ff5555' # red for tricky
|
||||
alpha = 0.7
|
||||
else:
|
||||
# Gradient from light yellow (depth 1) to orange (deep)
|
||||
shade = 0.3 + 0.4 * (d / max(max_depth, 1))
|
||||
color = (1.0, 1.0 - shade * 0.3, 0.7 - shade * 0.4)
|
||||
alpha = 0.5
|
||||
poly = plt.Polygon([pos[v] for v in f], color=color, alpha=alpha,
|
||||
zorder=1)
|
||||
ax.add_patch(poly)
|
||||
# Label face center with depth
|
||||
cx, cy = np.mean([pos[v] for v in f], axis=0)
|
||||
face_len = len(f)
|
||||
parity_mark = ' (odd)' if face_len % 2 == 1 else ''
|
||||
tricky_mark = ' TRICKY' if cf in tricky_canons else ''
|
||||
ax.text(cx, cy, f"d={d}\nlen={face_len}{parity_mark}{tricky_mark}",
|
||||
fontsize=9, ha='center', va='center', zorder=3,
|
||||
fontweight='bold' if cf in tricky_canons else 'normal')
|
||||
|
||||
# Draw edges of L_k
|
||||
Lk = G_full.subgraph(nodes_k)
|
||||
hl_set = frozenset(highlight_edge) if highlight_edge else None
|
||||
new_set = frozenset(new_edge) if new_edge else None
|
||||
for u, v in Lk.edges():
|
||||
eset = frozenset([u, v])
|
||||
if hl_set and eset == hl_set:
|
||||
ax.plot([pos[u][0], pos[v][0]], [pos[u][1], pos[v][1]],
|
||||
color='red', linewidth=4.0, zorder=2.5,
|
||||
linestyle='--')
|
||||
else:
|
||||
ax.plot([pos[u][0], pos[v][0]], [pos[u][1], pos[v][1]],
|
||||
color='black', linewidth=1.6, zorder=2)
|
||||
# Sketch where the new edge will land (dotted green)
|
||||
if new_set:
|
||||
nu, nv = new_edge
|
||||
if nu in pos and nv in pos:
|
||||
ax.plot([pos[nu][0], pos[nv][0]], [pos[nu][1], pos[nv][1]],
|
||||
color='green', linewidth=2.5, zorder=2.5,
|
||||
linestyle=':')
|
||||
|
||||
# Draw vertices
|
||||
for v in nodes_k:
|
||||
ax.plot(pos[v][0], pos[v][1], 'o', color='black', markersize=12,
|
||||
zorder=4)
|
||||
ax.text(pos[v][0] * 1.13, pos[v][1] * 1.13, str(v), fontsize=14,
|
||||
ha='center', va='center', color='blue', zorder=5,
|
||||
fontweight='bold')
|
||||
|
||||
ax.set_title(title, fontsize=12)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
ax.set_xlim(-1.3, 1.3)
|
||||
ax.set_ylim(-1.3, 1.3)
|
||||
return tricky
|
||||
|
||||
|
||||
def main():
|
||||
tris = enumerate_all_triangulations(10)
|
||||
G = tris[6]
|
||||
ip, emb = nx.check_planarity(G)
|
||||
source = {0, 4, 2}
|
||||
levels = compute_levels(G, source)
|
||||
by_level = defaultdict(list)
|
||||
for v, lv in levels.items():
|
||||
by_level[lv].append(v)
|
||||
nodes_k = by_level[1]
|
||||
k = 1
|
||||
|
||||
fig, axes_grid = plt.subplots(2, 2, figsize=(14, 14))
|
||||
axes = axes_grid.flatten()
|
||||
fig.suptitle(
|
||||
f"Cycling case: n=10, tri[6], source face (0,4,2), $L_{k}$\n"
|
||||
f"Red = tricky-everywhere odd face (depth 2). Yellow = depth-1 odd "
|
||||
f"faces (have free edges). Algorithm flips a (k,k) edge of the red "
|
||||
f"face toward its lowest-depth neighbor each step.",
|
||||
fontsize=13
|
||||
)
|
||||
|
||||
Gc = G.copy()
|
||||
emb_c = emb
|
||||
for step in range(4):
|
||||
ax = axes[step]
|
||||
# Compute flip choice first so we can render highlight before draw
|
||||
faces = faces_of_subgraph(Gc, emb_c, nodes_k)
|
||||
outer = identify_outer_face(faces, Gc, emb_c, levels, k)
|
||||
depths = face_depths(faces, outer)
|
||||
tricky_pre = tricky_odd_faces(faces, Gc, emb_c, levels, k, depths,
|
||||
outer)
|
||||
flip = None
|
||||
if tricky_pre:
|
||||
cf_t, face_t, d_t = max(tricky_pre, key=lambda x: x[2])
|
||||
flip = lowest_depth_neighbor_flip(face_t, Gc, emb_c, levels, k,
|
||||
depths, faces, outer)
|
||||
hl = None
|
||||
new_e = None
|
||||
if flip is not None:
|
||||
u, v, w, x, _ = flip
|
||||
hl = (u, v)
|
||||
new_e = (w, x)
|
||||
tricky = draw_panel(ax, Gc, emb_c, levels, nodes_k, k,
|
||||
f"Step {step}",
|
||||
highlight_edge=hl, new_edge=new_e)
|
||||
if not tricky:
|
||||
ax.set_title(f"Step {step}: no tricky face — done",
|
||||
fontsize=12)
|
||||
continue
|
||||
if flip is None:
|
||||
ax.set_title(f"Step {step}: no flip available", fontsize=12)
|
||||
continue
|
||||
u, v, w, x, _ = flip
|
||||
ax.set_title(
|
||||
f"Step {step}: tricky face {face_t}\n"
|
||||
f"red-dashed: edge ({u},{v}) being flipped → "
|
||||
f"green-dotted: new edge ({w},{x})",
|
||||
fontsize=11)
|
||||
# Apply flip
|
||||
Gc.remove_edge(u, v)
|
||||
Gc.add_edge(w, x)
|
||||
ip2, emb_c = nx.check_planarity(Gc)
|
||||
|
||||
plt.tight_layout(rect=[0, 0, 1, 0.93])
|
||||
out = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
'..', 'cycling_visualization.png')
|
||||
plt.savefig(out, dpi=130, bbox_inches='tight')
|
||||
print(f"saved: {out}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -19,26 +19,39 @@
|
||||
\citation{appelhaken}
|
||||
\citation{rsst}
|
||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{1}{Introduction}}{1}{section.1}\protected@file@percent }
|
||||
\citation{chartrand}
|
||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{2}{Definitions}}{2}{section.2}\protected@file@percent }
|
||||
\newlabel{def:resolution}{{2.4}{2}{Level resolution}{theorem.2.4}{}}
|
||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{3}{Structural foundation: outerplanarity of level subgraphs}}{2}{section.3}\protected@file@percent }
|
||||
\newlabel{sec:outerplanar}{{3}{2}{Structural foundation: outerplanarity of level subgraphs}{section.3}{}}
|
||||
\newlabel{prop:outerplanar}{{3.1}{2}{}{theorem.3.1}{}}
|
||||
\newlabel{prop:bipartite-suffices}{{3.2}{2}{}{theorem.3.2}{}}
|
||||
\newlabel{thm:outerplanar}{{3.1}{2}{}{theorem.3.1}{}}
|
||||
\citation{chartrand}
|
||||
\newlabel{prop:bipartite-suffices}{{3.2}{3}{}{theorem.3.2}{}}
|
||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{4}{The four-color conjecture via level resolutions}}{3}{section.4}\protected@file@percent }
|
||||
\newlabel{conj:preimage}{{4.1}{3}{Resolution preimage}{theorem.4.1}{}}
|
||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{5}{Computational evidence}}{3}{section.5}\protected@file@percent }
|
||||
\@writefile{toc}{\contentsline {subsection}{\tocsubsection {}{5.1}{Coverage at $n = 6, \ldots , 11$}}{3}{subsection.5.1}\protected@file@percent }
|
||||
\@writefile{lot}{\contentsline {table}{\numberline {1}{\ignorespaces Iso-class coverage under the level-resolution definition.}}{3}{table.1}\protected@file@percent }
|
||||
\newlabel{tab:coverage}{{1}{3}{Iso-class coverage under the level-resolution definition}{table.1}{}}
|
||||
\newlabel{obs:preimage}{{5.1}{3}{}{theorem.5.1}{}}
|
||||
\@writefile{toc}{\contentsline {paragraph}{\tocparagraph {}{}{Equivalence to 4-colorability.}}{3}{section*.1}\protected@file@percent }
|
||||
\@writefile{lot}{\contentsline {table}{\numberline {1}{\ignorespaces Iso-class coverage under the level-resolution definition.}}{4}{table.1}\protected@file@percent }
|
||||
\newlabel{tab:coverage}{{1}{4}{Iso-class coverage under the level-resolution definition}{table.1}{}}
|
||||
\@writefile{toc}{\contentsline {paragraph}{\tocparagraph {}{}{Equivalence to 4-colorability.}}{4}{section*.1}\protected@file@percent }
|
||||
\@writefile{toc}{\contentsline {subsection}{\tocsubsection {}{5.2}{Surjectivity at $n = 12$: the icosahedron}}{4}{subsection.5.2}\protected@file@percent }
|
||||
\newlabel{obs:icosa}{{5.2}{4}{}{theorem.5.2}{}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\tocsubsection {}{5.3}{Restatement of the resolution-preimage conjecture}}{4}{subsection.5.3}\protected@file@percent }
|
||||
\newlabel{conj:md4}{{5.3}{4}{$\mathrm {md}_4$ surjectivity}{theorem.5.3}{}}
|
||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{6}{Discussion and open questions}}{4}{section.6}\protected@file@percent }
|
||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{6}{An edge-flip resolution algorithm}}{5}{section.6}\protected@file@percent }
|
||||
\newlabel{sec:flip-algorithm}{{6}{5}{An edge-flip resolution algorithm}{section.6}{}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\tocsubsection {}{6.1}{Apex classification of $L_k$-edges}}{5}{subsection.6.1}\protected@file@percent }
|
||||
\newlabel{lem:bridge-apex}{{6.1}{5}{}{theorem.6.1}{}}
|
||||
\newlabel{prop:flip-target}{{6.2}{5}{}{theorem.6.2}{}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\tocsubsection {}{6.2}{Cross-level flip pass}}{5}{subsection.6.2}\protected@file@percent }
|
||||
\@writefile{toc}{\contentsline {subsection}{\tocsubsection {}{6.3}{Tricky-everywhere cycles}}{5}{subsection.6.3}\protected@file@percent }
|
||||
\newlabel{def:facial-depth}{{6.3}{5}{Facial depth}{theorem.6.3}{}}
|
||||
\@writefile{toc}{\contentsline {subsection}{\tocsubsection {}{6.4}{The algorithm}}{6}{subsection.6.4}\protected@file@percent }
|
||||
\newlabel{obs:terminate}{{6.4}{6}{}{theorem.6.4}{}}
|
||||
\newlabel{q:terminate-all-n}{{6.5}{6}{}{theorem.6.5}{}}
|
||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{7}{Discussion and open questions}}{6}{section.7}\protected@file@percent }
|
||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{8}{Implementation}}{6}{section.8}\protected@file@percent }
|
||||
\newlabel{sec:impl}{{8}{6}{Implementation}{section.8}{}}
|
||||
\bibcite{appelhaken}{1}
|
||||
\bibcite{rsst}{2}
|
||||
\bibcite{tutte}{3}
|
||||
@@ -48,7 +61,5 @@
|
||||
\newlabel{tocindent1}{17.77782pt}
|
||||
\newlabel{tocindent2}{29.38873pt}
|
||||
\newlabel{tocindent3}{0pt}
|
||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{7}{Implementation}}{5}{section.7}\protected@file@percent }
|
||||
\newlabel{sec:impl}{{7}{5}{Implementation}{section.7}{}}
|
||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{}{References}}{5}{section*.2}\protected@file@percent }
|
||||
\gdef \@abspage@last{5}
|
||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{}{References}}{7}{section*.2}\protected@file@percent }
|
||||
\gdef \@abspage@last{7}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 19 MAY 2026 23:33
|
||||
This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 20 MAY 2026 01:17
|
||||
entering extended mode
|
||||
restricted \write18 enabled.
|
||||
file:line:error style messages enabled.
|
||||
%&-line parsing enabled.
|
||||
**/Users/didericis/Code/math-research/papers/level_resolutions_of_maximal_planar_graphs/paper.tex
|
||||
(/Users/didericis/Code/math-research/papers/level_resolutions_of_maximal_planar_graphs/paper.tex
|
||||
**paper.tex
|
||||
(./paper.tex
|
||||
LaTeX2e <2021-11-15> patch level 1
|
||||
L3 programming layer <2022-02-24> (/usr/local/texlive/2022/texmf-dist/tex/latex/amscls/amsart.cls
|
||||
L3 programming layer <2022-02-24>
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/amscls/amsart.cls
|
||||
Document Class: amsart 2020/05/29 v2.20.6
|
||||
\linespacing=\dimen138
|
||||
\normalparindent=\dimen139
|
||||
@@ -18,14 +18,17 @@ Package: amsmath 2021/10/15 v2.17l AMS math features
|
||||
For additional information on amsmath, use the `?' option.
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amstext.sty
|
||||
Package: amstext 2021/08/26 v2.01 AMS text
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsgen.sty
|
||||
File: amsgen.sty 1999/11/30 v2.0 generic functions
|
||||
\@emptytoks=\toks16
|
||||
\ex@=\dimen140
|
||||
)) (/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsbsy.sty
|
||||
))
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsbsy.sty
|
||||
Package: amsbsy 1999/11/29 v1.2d Bold Symbols
|
||||
\pmbraise@=\dimen141
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsopn.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsopn.sty
|
||||
Package: amsopn 2021/08/26 v2.02 operator names
|
||||
)
|
||||
\inf@bad=\count185
|
||||
@@ -66,10 +69,13 @@ LaTeX Font Info: Redeclaring font encoding OMS on input line 744.
|
||||
LaTeX Info: Redefining \[ on input line 2938.
|
||||
LaTeX Info: Redefining \] on input line 2939.
|
||||
)
|
||||
LaTeX Font Info: Trying to load font information for U+msa on input line 397.
|
||||
LaTeX Font Info: Trying to load font information for U+msa on input line 397
|
||||
.
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/umsa.fd
|
||||
File: umsa.fd 2013/01/14 v3.01 AMS symbols A
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/amsfonts.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/amsfonts.sty
|
||||
Package: amsfonts 2013/01/14 v3.01 Basic AMSFonts support
|
||||
\symAMSa=\mathgroup4
|
||||
\symAMSb=\mathgroup5
|
||||
@@ -100,51 +106,69 @@ LaTeX Font Info: Overwriting math alphabet `\mathfrak' in version `bold'
|
||||
\thm@postskip=\skip55
|
||||
\thm@headsep=\skip56
|
||||
\dth@everypar=\toks26
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/latex/hyperref/hyperref.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/hyperref/hyperref.sty
|
||||
Package: hyperref 2022-02-21 v7.00n Hypertext links for LaTeX
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/generic/ltxcmds/ltxcmds.sty
|
||||
Package: ltxcmds 2020-05-10 v1.25 LaTeX kernel commands for general use (HO)
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/generic/iftex/iftex.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/generic/iftex/iftex.sty
|
||||
Package: iftex 2022/02/03 v1.0f TeX engine tests
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/generic/pdftexcmds/pdftexcmds.sty
|
||||
Package: pdftexcmds 2020-06-27 v0.33 Utility functions of pdfTeX for LuaTeX (HO)
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/generic/pdftexcmds/pdftexcmds.sty
|
||||
Package: pdftexcmds 2020-06-27 v0.33 Utility functions of pdfTeX for LuaTeX (HO
|
||||
)
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/generic/infwarerr/infwarerr.sty
|
||||
Package: infwarerr 2019/12/03 v1.5 Providing info/warning/error messages (HO)
|
||||
)
|
||||
Package pdftexcmds Info: \pdf@primitive is available.
|
||||
Package pdftexcmds Info: \pdf@ifprimitive is available.
|
||||
Package pdftexcmds Info: \pdfdraftmode found.
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/latex/graphics/keyval.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/graphics/keyval.sty
|
||||
Package: keyval 2014/10/28 v1.15 key=value parser (DPC)
|
||||
\KV@toks@=\toks27
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/generic/kvsetkeys/kvsetkeys.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/generic/kvsetkeys/kvsetkeys.sty
|
||||
Package: kvsetkeys 2019/12/15 v1.18 Key value parser (HO)
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/generic/kvdefinekeys/kvdefinekeys.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/generic/kvdefinekeys/kvdefinekeys.sty
|
||||
Package: kvdefinekeys 2019-12-19 v1.6 Define keys (HO)
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/generic/pdfescape/pdfescape.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/generic/pdfescape/pdfescape.sty
|
||||
Package: pdfescape 2019/12/09 v1.15 Implements pdfTeX's escape features (HO)
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/latex/hycolor/hycolor.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/hycolor/hycolor.sty
|
||||
Package: hycolor 2020-01-27 v1.10 Color options for hyperref/bookmark (HO)
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/latex/letltxmacro/letltxmacro.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/letltxmacro/letltxmacro.sty
|
||||
Package: letltxmacro 2019/12/03 v1.6 Let assignment for LaTeX macros (HO)
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/latex/auxhook/auxhook.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/auxhook/auxhook.sty
|
||||
Package: auxhook 2019-12-17 v1.6 Hooks for auxiliary files (HO)
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/latex/kvoptions/kvoptions.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/kvoptions/kvoptions.sty
|
||||
Package: kvoptions 2020-10-07 v3.14 Key value format for package options (HO)
|
||||
)
|
||||
\@linkdim=\dimen150
|
||||
\Hy@linkcounter=\count272
|
||||
\Hy@pagecounter=\count273
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/hyperref/pd1enc.def
|
||||
File: pd1enc.def 2022-02-21 v7.00n Hyperref: PDFDocEncoding definition (HO)
|
||||
Now handling font encoding PD1 ...
|
||||
... no UTF-8 mapping file for font encoding PD1
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/generic/intcalc/intcalc.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/generic/intcalc/intcalc.sty
|
||||
Package: intcalc 2019/12/15 v1.3 Expandable calculations with integers (HO)
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/generic/etexcmds/etexcmds.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/generic/etexcmds/etexcmds.sty
|
||||
Package: etexcmds 2019/12/15 v1.7 Avoid name clashes with e-TeX commands (HO)
|
||||
)
|
||||
\Hy@SavedSpaceFactor=\count274
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/hyperref/puenc.def
|
||||
File: puenc.def 2022-02-21 v7.00n Hyperref: PDF Unicode definition (HO)
|
||||
Now handling font encoding PU ...
|
||||
@@ -158,16 +182,20 @@ Package hyperref Info: Backreferencing OFF on input line 4157.
|
||||
Package hyperref Info: Implicit mode ON; LaTeX internals redefined.
|
||||
Package hyperref Info: Bookmarks ON on input line 4390.
|
||||
\c@Hy@tempcnt=\count275
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/url/url.sty
|
||||
\Urlmuskip=\muskip17
|
||||
Package: url 2013/09/16 ver 3.4 Verb mode for urls, etc.
|
||||
)
|
||||
LaTeX Info: Redefining \url on input line 4749.
|
||||
\XeTeXLinkMargin=\dimen151
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/generic/bitset/bitset.sty
|
||||
Package: bitset 2019/12/09 v1.3 Handle bit-vector datatype (HO)
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/generic/bigintcalc/bigintcalc.sty
|
||||
Package: bigintcalc 2019/12/15 v1.5 Expandable calculations on big integers (HO)
|
||||
Package: bigintcalc 2019/12/15 v1.5 Expandable calculations on big integers (HO
|
||||
)
|
||||
))
|
||||
\Fld@menulength=\count276
|
||||
\Field@Width=\dimen152
|
||||
@@ -181,6 +209,7 @@ Package hyperref Info: Link coloring with OCG OFF on input line 6052.
|
||||
Package hyperref Info: PDF/A mode OFF on input line 6057.
|
||||
LaTeX Info: Redefining \ref on input line 6097.
|
||||
LaTeX Info: Redefining \pageref on input line 6101.
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/base/atbegshi-ltx.sty
|
||||
Package: atbegshi-ltx 2021/01/10 v1.0c Emulation of the original atbegshi
|
||||
package with kernel methods
|
||||
@@ -190,20 +219,26 @@ package with kernel methods
|
||||
\c@Hfootnote=\count279
|
||||
)
|
||||
Package hyperref Info: Driver (autodetected): hpdftex.
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/hyperref/hpdftex.def
|
||||
File: hpdftex.def 2022-02-21 v7.00n Hyperref driver for pdfTeX
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/base/atveryend-ltx.sty
|
||||
Package: atveryend-ltx 2020/08/19 v1.0a Emulation of the original atveryend package
|
||||
Package: atveryend-ltx 2020/08/19 v1.0a Emulation of the original atveryend pac
|
||||
kage
|
||||
with kernel methods
|
||||
)
|
||||
\Fld@listcount=\count280
|
||||
\c@bookmark@seq@number=\count281
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/rerunfilecheck/rerunfilecheck.sty
|
||||
Package: rerunfilecheck 2019/12/05 v1.9 Rerun checks for auxiliary files (HO)
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/generic/uniquecounter/uniquecounter.sty
|
||||
Package: uniquecounter 2019/12/15 v1.4 Provide unlimited unique counter (HO)
|
||||
)
|
||||
Package uniquecounter Info: New unique counter `rerunfilecheck' on input line 286.
|
||||
Package uniquecounter Info: New unique counter `rerunfilecheck' on input line 2
|
||||
86.
|
||||
)
|
||||
\Hy@SectionHShift=\skip57
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/latex/enumitem/enumitem.sty
|
||||
@@ -216,11 +251,13 @@ Package: enumitem 2019/06/20 v3.9 Customized lists
|
||||
\enitdp@description=\count283
|
||||
)
|
||||
\c@theorem=\count284
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def
|
||||
File: l3backend-pdftex.def 2022-02-07 L3 backend support: PDF output (pdfTeX)
|
||||
\l__color_backend_stack_int=\count285
|
||||
\l__pdf_internal_box=\box54
|
||||
) (./paper.aux)
|
||||
)
|
||||
(./paper.aux)
|
||||
\openout1 = `paper.aux'.
|
||||
|
||||
LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 59.
|
||||
@@ -242,19 +279,26 @@ LaTeX Font Info: ... okay on input line 59.
|
||||
LaTeX Font Info: Checking defaults for PU/pdf/m/n on input line 59.
|
||||
LaTeX Font Info: ... okay on input line 59.
|
||||
LaTeX Font Info: Trying to load font information for U+msa on input line 59.
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/umsa.fd
|
||||
File: umsa.fd 2013/01/14 v3.01 AMS symbols A
|
||||
)
|
||||
LaTeX Font Info: Trying to load font information for U+msb on input line 59.
|
||||
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/umsb.fd
|
||||
File: umsb.fd 2013/01/14 v3.01 AMS symbols B
|
||||
)
|
||||
Package hyperref Info: Link coloring OFF on input line 59.
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/hyperref/nameref.sty
|
||||
Package: nameref 2021-04-02 v2.47 Cross-referencing by name of section
|
||||
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/latex/refcount/refcount.sty
|
||||
Package: refcount 2019/12/15 v3.6 Data extraction from label references (HO)
|
||||
) (/usr/local/texlive/2022/texmf-dist/tex/generic/gettitlestring/gettitlestring.sty
|
||||
)
|
||||
(/usr/local/texlive/2022/texmf-dist/tex/generic/gettitlestring/gettitlestring.s
|
||||
ty
|
||||
Package: gettitlestring 2019/12/15 v1.6 Cleanup title references (HO)
|
||||
)
|
||||
\c@section@level=\count286
|
||||
@@ -267,55 +311,92 @@ LaTeX Info: Redefining \nameref on input line 59.
|
||||
\openout3 = `paper.out'.
|
||||
|
||||
|
||||
Overfull \hbox (1.57487pt too wide) in paragraph at lines 104--110
|
||||
\OT1/cmr/m/n/10 Equiv-a-lently, ev-ery max-i-mal pla-nar graph (tri-an-gu-la-tion) is 4-colorable. The Appel--
|
||||
Overfull \hbox (1.57487pt too wide) in paragraph at lines 103--109
|
||||
\OT1/cmr/m/n/10 Equiv-a-lently, ev-ery max-i-mal pla-nar graph (tri-an-gu-la-ti
|
||||
on) is 4-colorable. The Appel--
|
||||
[]
|
||||
|
||||
|
||||
Overfull \hbox (3.88962pt too wide) in paragraph at lines 104--110
|
||||
\OT1/cmr/m/n/10 Haken proof [[]] and sub-se-quent Robertson--Sanders--Seymour--Thomas re-fine-ment [[]]
|
||||
Overfull \hbox (3.88962pt too wide) in paragraph at lines 103--109
|
||||
\OT1/cmr/m/n/10 Haken proof [[]] and sub-se-quent Robertson--Sanders--Seymour--
|
||||
Thomas re-fine-ment [[]]
|
||||
[]
|
||||
|
||||
|
||||
Overfull \hbox (12.21368pt too wide) in paragraph at lines 104--110
|
||||
\OT1/cmr/m/n/10 rely on dis-charg-ing ar-gu-ments and computer-verified re-ducible con-fig-u-ra-tions. Human-
|
||||
Overfull \hbox (12.21368pt too wide) in paragraph at lines 103--109
|
||||
\OT1/cmr/m/n/10 rely on dis-charg-ing ar-gu-ments and computer-verified re-duci
|
||||
ble con-fig-u-ra-tions. Human-
|
||||
[]
|
||||
|
||||
[1{/usr/local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] [2]
|
||||
[1{/usr/local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map}]
|
||||
[2]
|
||||
|
||||
Package hyperref Warning: Token not allowed in a PDF string (Unicode):
|
||||
(hyperref) removing `math shift' on input line 250.
|
||||
(hyperref) removing `math shift' on input line 278.
|
||||
|
||||
|
||||
Package hyperref Warning: Token not allowed in a PDF string (Unicode):
|
||||
(hyperref) removing `math shift' on input line 250.
|
||||
(hyperref) removing `math shift' on input line 278.
|
||||
|
||||
|
||||
LaTeX Warning: `h' float specifier changed to `ht'.
|
||||
|
||||
[3]
|
||||
|
||||
Package hyperref Warning: Token not allowed in a PDF string (Unicode):
|
||||
(hyperref) removing `math shift' on input line 296.
|
||||
(hyperref) removing `math shift' on input line 324.
|
||||
|
||||
|
||||
Package hyperref Warning: Token not allowed in a PDF string (Unicode):
|
||||
(hyperref) removing `math shift' on input line 296.
|
||||
(hyperref) removing `math shift' on input line 324.
|
||||
|
||||
[4] [5] (./paper.aux)
|
||||
[4]
|
||||
|
||||
Package hyperref Warning: Token not allowed in a PDF string (Unicode):
|
||||
(hyperref) removing `math shift' on input line 370.
|
||||
|
||||
|
||||
Package hyperref Warning: Token not allowed in a PDF string (Unicode):
|
||||
(hyperref) removing `subscript' on input line 370.
|
||||
|
||||
|
||||
Package hyperref Warning: Token not allowed in a PDF string (Unicode):
|
||||
(hyperref) removing `math shift' on input line 370.
|
||||
|
||||
[5] [6] [7] (./paper.aux)
|
||||
Package rerunfilecheck Info: File `paper.out' has not changed.
|
||||
(rerunfilecheck) Checksum: EEEB5CE29153D98296A2AD7EF6DBBA0A;2386.
|
||||
(rerunfilecheck) Checksum: C4EC0643C07D7F8B157295F889BACC80;3432.
|
||||
)
|
||||
Here is how much of TeX's memory you used:
|
||||
8910 strings out of 478268
|
||||
137894 string characters out of 5846347
|
||||
439445 words of memory out of 5000000
|
||||
26840 multiletter control sequences out of 15000+600000
|
||||
8935 strings out of 478268
|
||||
137960 string characters out of 5846347
|
||||
440651 words of memory out of 5000000
|
||||
26851 multiletter control sequences out of 15000+600000
|
||||
475834 words of font info for 54 fonts, out of 8000000 for 9000
|
||||
1302 hyphenation exceptions out of 8191
|
||||
69i,9n,76p,482b,426s stack positions out of 10000i,1000n,20000p,200000b,200000s
|
||||
</usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmcsc10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi6.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy6.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmti10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmti8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmtt10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/symbols/msam10.pfb>
|
||||
Output written on paper.pdf (5 pages, 235833 bytes).
|
||||
69i,9n,76p,396b,463s stack positions out of 10000i,1000n,20000p,200000b,200000s
|
||||
</usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb
|
||||
></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmcsc10.pfb
|
||||
></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb>
|
||||
</usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi6.pfb></
|
||||
usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb></us
|
||||
r/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi8.pfb></usr/
|
||||
local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb></usr/lo
|
||||
cal/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb></usr/local
|
||||
/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr8.pfb></usr/local/te
|
||||
xlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy10.pfb></usr/local/tex
|
||||
live/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy5.pfb></usr/local/texli
|
||||
ve/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy6.pfb></usr/local/texlive
|
||||
/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy7.pfb></usr/local/texlive/2
|
||||
022/texmf-dist/fonts/type1/public/amsfonts/cm/cmti10.pfb></usr/local/texlive/20
|
||||
22/texmf-dist/fonts/type1/public/amsfonts/cm/cmti8.pfb></usr/local/texlive/2022
|
||||
/texmf-dist/fonts/type1/public/amsfonts/cm/cmtt10.pfb></usr/local/texlive/2022/
|
||||
texmf-dist/fonts/type1/public/amsfonts/symbols/msam10.pfb></usr/local/texlive/2
|
||||
022/texmf-dist/fonts/type1/public/amsfonts/symbols/msbm10.pfb>
|
||||
Output written on paper.pdf (7 pages, 254719 bytes).
|
||||
PDF statistics:
|
||||
212 PDF objects out of 1000 (max. 8388607)
|
||||
169 compressed objects within 2 object streams
|
||||
40 named destinations out of 1000 (max. 500000)
|
||||
89 words of extra memory for PDF output out of 10000 (max. 10000000)
|
||||
264 PDF objects out of 1000 (max. 8388607)
|
||||
216 compressed objects within 3 object streams
|
||||
55 named destinations out of 1000 (max. 500000)
|
||||
129 words of extra memory for PDF output out of 10000 (max. 10000000)
|
||||
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
\BOOKMARK [2][-]{subsection.5.1}{\376\377\0005\000.\0001\000.\000\040\000C\000o\000v\000e\000r\000a\000g\000e\000\040\000a\000t\000\040\000n\000\040\000=\000\040\0006\000,\000\040\040\046\000,\000\040\0001\0001}{section.5}% 6
|
||||
\BOOKMARK [2][-]{subsection.5.2}{\376\377\0005\000.\0002\000.\000\040\000S\000u\000r\000j\000e\000c\000t\000i\000v\000i\000t\000y\000\040\000a\000t\000\040\000n\000\040\000=\000\040\0001\0002\000:\000\040\000t\000h\000e\000\040\000i\000c\000o\000s\000a\000h\000e\000d\000r\000o\000n}{section.5}% 7
|
||||
\BOOKMARK [2][-]{subsection.5.3}{\376\377\0005\000.\0003\000.\000\040\000R\000e\000s\000t\000a\000t\000e\000m\000e\000n\000t\000\040\000o\000f\000\040\000t\000h\000e\000\040\000r\000e\000s\000o\000l\000u\000t\000i\000o\000n\000-\000p\000r\000e\000i\000m\000a\000g\000e\000\040\000c\000o\000n\000j\000e\000c\000t\000u\000r\000e}{section.5}% 8
|
||||
\BOOKMARK [1][-]{section.6}{\376\377\0006\000.\000\040\000D\000i\000s\000c\000u\000s\000s\000i\000o\000n\000\040\000a\000n\000d\000\040\000o\000p\000e\000n\000\040\000q\000u\000e\000s\000t\000i\000o\000n\000s}{}% 9
|
||||
\BOOKMARK [1][-]{section.7}{\376\377\0007\000.\000\040\000I\000m\000p\000l\000e\000m\000e\000n\000t\000a\000t\000i\000o\000n}{}% 10
|
||||
\BOOKMARK [1][-]{section*.2}{\376\377\000R\000e\000f\000e\000r\000e\000n\000c\000e\000s}{}% 11
|
||||
\BOOKMARK [1][-]{section.6}{\376\377\0006\000.\000\040\000A\000n\000\040\000e\000d\000g\000e\000-\000f\000l\000i\000p\000\040\000r\000e\000s\000o\000l\000u\000t\000i\000o\000n\000\040\000a\000l\000g\000o\000r\000i\000t\000h\000m}{}% 9
|
||||
\BOOKMARK [2][-]{subsection.6.1}{\376\377\0006\000.\0001\000.\000\040\000A\000p\000e\000x\000\040\000c\000l\000a\000s\000s\000i\000f\000i\000c\000a\000t\000i\000o\000n\000\040\000o\000f\000\040\000L\000k\000-\000e\000d\000g\000e\000s}{section.6}% 10
|
||||
\BOOKMARK [2][-]{subsection.6.2}{\376\377\0006\000.\0002\000.\000\040\000C\000r\000o\000s\000s\000-\000l\000e\000v\000e\000l\000\040\000f\000l\000i\000p\000\040\000p\000a\000s\000s}{section.6}% 11
|
||||
\BOOKMARK [2][-]{subsection.6.3}{\376\377\0006\000.\0003\000.\000\040\000T\000r\000i\000c\000k\000y\000-\000e\000v\000e\000r\000y\000w\000h\000e\000r\000e\000\040\000c\000y\000c\000l\000e\000s}{section.6}% 12
|
||||
\BOOKMARK [2][-]{subsection.6.4}{\376\377\0006\000.\0004\000.\000\040\000T\000h\000e\000\040\000a\000l\000g\000o\000r\000i\000t\000h\000m}{section.6}% 13
|
||||
\BOOKMARK [1][-]{section.7}{\376\377\0007\000.\000\040\000D\000i\000s\000c\000u\000s\000s\000i\000o\000n\000\040\000a\000n\000d\000\040\000o\000p\000e\000n\000\040\000q\000u\000e\000s\000t\000i\000o\000n\000s}{}% 14
|
||||
\BOOKMARK [1][-]{section.8}{\376\377\0008\000.\000\040\000I\000m\000p\000l\000e\000m\000e\000n\000t\000a\000t\000i\000o\000n}{}% 15
|
||||
\BOOKMARK [1][-]{section*.2}{\376\377\000R\000e\000f\000e\000r\000e\000n\000c\000e\000s}{}% 16
|
||||
|
||||
Binary file not shown.
@@ -88,8 +88,7 @@ source if the subgraphs of $G'$ induced by even- and odd-level vertices are
|
||||
both bipartite. By construction, any level resolution admits an explicit
|
||||
4-coloring obtained by 2-coloring each parity subgraph independently. The
|
||||
structural foundation of this approach is that each level subgraph $L_k$
|
||||
of $G$ is outerplanar (verified for all triangulations and sources at
|
||||
$n \leq 10$), and outerplanar graphs are 3-chromatic; the level-resolution
|
||||
of $G$ is outerplanar, and outerplanar graphs are 3-chromatic; the level-resolution
|
||||
problem is precisely to flip edges of $G$ to reduce each $L_k$ from
|
||||
chromatic number $3$ to $2$. We present computational results characterizing
|
||||
which isomorphism classes of maximal planar graphs on $n = 6, \ldots, 11$
|
||||
@@ -179,20 +178,49 @@ disjoint color sets and so are properly colored.
|
||||
For each integer $k \geq 0$ and each $(G, S)$, write $L_k$ for the subgraph
|
||||
of $G$ induced by the level-$k$ vertices.
|
||||
|
||||
\begin{proposition}
|
||||
\label{prop:outerplanar}
|
||||
\begin{theorem}
|
||||
\label{thm:outerplanar}
|
||||
For every plane triangulation $G$ and every level source $S$ of $G$, each
|
||||
level subgraph $L_k$ is outerplanar.
|
||||
\end{proposition}
|
||||
\end{theorem}
|
||||
|
||||
A planar embedding witnessing outerplanarity is inherited from $G$: in the
|
||||
planar embedding $\Pi_G$, the vertices at distance $\leq k - 1$ from the
|
||||
source lie strictly on one side of the boundary of $L_k$, so all $L_k$
|
||||
vertices can be placed on a common face of $L_k$. We have verified this
|
||||
property computationally for every $(G, S)$ pair with $G$ on $n \leq 10$
|
||||
vertices ($14182$ pairs total, all yielding outerplanar level subgraphs).
|
||||
\begin{proof}
|
||||
For $k = 0$, $L_0$ is either a single vertex (when $S$ is a degree-3
|
||||
vertex) or the triangle bounding the source face (when $S$ is a face),
|
||||
both outerplanar. Fix $k \geq 1$ and suppose, for contradiction, that
|
||||
$L_k$ is not outerplanar.
|
||||
|
||||
The combinatorial significance of Proposition~\ref{prop:outerplanar} is
|
||||
Let $D_k$ denote the planar drawing of $L_k$ inherited from $\Pi_G$:
|
||||
that is, the set of points and curves in the plane representing the
|
||||
vertices and edges of $L_k$ exactly as they appear in the embedding
|
||||
$\Pi_G$. Since $L_k$ is not outerplanar, no face of $D_k$ has every
|
||||
vertex of $L_k$ on its boundary.
|
||||
|
||||
Let $F^\ast$ be the face of $D_k$ containing the source: when
|
||||
$S = \{v\}$, the face containing the point $v$; when $S$ is a face $F$
|
||||
of $G$, the face containing the open region of $F$ together with its
|
||||
three bounding vertices. The latter is well defined because each
|
||||
vertex of $F$ lies at level $0$ (hence is not a vertex of $L_k$) and
|
||||
each edge of $F$ joins two level-$0$ vertices (hence is not an edge of
|
||||
$L_k$), so $F$ and its boundary lie in a single component of
|
||||
$\mathbb{R}^2 \setminus D_k$. By assumption there exists $u \in L_k$
|
||||
with $u \notin \partial F^\ast$.
|
||||
|
||||
Choose a BFS path $P : v_0, v_1, \ldots, v_k = u$ with $v_0 \in S$ and
|
||||
$v_i \in L_i$. For $0 \leq i \leq k - 1$, $v_i$ lies in $L_i$ and so is
|
||||
not a vertex of $L_k$; for $1 \leq i \leq k$, the edge $v_{i-1} v_i$
|
||||
joins $L_{i-1}$ to $L_i$ and so is not an edge of $L_k$. Hence, viewed
|
||||
as a curve in the plane, $P$ meets the drawing $D_k$ only at its
|
||||
endpoint $u$.
|
||||
|
||||
The complement $\mathbb{R}^2 \setminus D_k$ is open, and $P \setminus
|
||||
\{u\}$ is its continuous image of a connected set, hence lies in a
|
||||
single face of $D_k$. Since $v_0 \in F^\ast$, in fact
|
||||
$P \setminus \{u\} \subseteq F^\ast$, so $u \in \overline{F^\ast}$ and
|
||||
therefore $u \in \partial F^\ast$, contradicting the choice of $u$.
|
||||
\end{proof}
|
||||
|
||||
The combinatorial significance of Theorem~\ref{thm:outerplanar} is
|
||||
that outerplanar graphs are $3$-chromatic~\cite{chartrand}: their chromatic
|
||||
number is at most $3$. Hence each $L_k$ admits an independent 3-coloring,
|
||||
giving an immediate (but suboptimal) coloring of $G$ using at most
|
||||
@@ -328,7 +356,116 @@ BFS-level parity cardinality on the same vertex set. Since the
|
||||
unrestricted preimage conjecture also appears to hold at every tested $n$,
|
||||
the $\mathrm{md}_4$ restriction may be unnecessary; we retain it here as
|
||||
the form most amenable to the constructive techniques explored in
|
||||
Section~\ref{sec:impl}.
|
||||
Section~\ref{sec:flip-algorithm}.
|
||||
|
||||
\section{An edge-flip resolution algorithm}
|
||||
\label{sec:flip-algorithm}
|
||||
|
||||
We describe an iterative edge-flip procedure aimed at producing, for a given
|
||||
$(G, S)$, a triangulation $G'$ on the same vertex set whose simple level
|
||||
cycles (with respect to the $G$-levels from $S$) are all even.
|
||||
|
||||
\subsection{Apex classification of $L_k$-edges}
|
||||
|
||||
Let $k \geq 1$. For each $uv \in E(L_k)$, the two triangles of $G$ bounding
|
||||
$uv$ have third vertices $w, x$, called the \emph{apexes} of $uv$, with
|
||||
$\ell_G(w), \ell_G(x) \in \{k-1, k, k+1\}$ by BFS. We call $uv$
|
||||
\emph{intra-level} when $\ell_G(w) = \ell_G(x) = k$, and \emph{cross-level}
|
||||
otherwise.
|
||||
|
||||
\begin{lemma}
|
||||
\label{lem:bridge-apex}
|
||||
If both apexes of $uv \in E(L_k)$ are at level $k - 1$, then $uv$ is a
|
||||
bridge of $L_k$.
|
||||
\end{lemma}
|
||||
|
||||
\begin{proof}[Proof sketch]
|
||||
In a plane triangulation, the neighbors of $u$ in $G$ at level $\leq k - 1$
|
||||
form a contiguous arc in the cyclic order around $u$. If both apexes $w, x$
|
||||
of $uv$ lie at level $k - 1$ on opposite sides of $uv$, then $v$ lies in the
|
||||
complementary cyclic arc, which contains no other level-$k$ neighbor of $u$.
|
||||
The symmetric statement around $v$ gives that $u$ is $v$'s only level-$k$
|
||||
neighbor in the corresponding arc, so $uv$ is a bridge of $L_k$.
|
||||
\end{proof}
|
||||
|
||||
In particular every edge on a cycle of $L_k$ has at least one apex at level
|
||||
$k$ or $k+1$.
|
||||
|
||||
\begin{proposition}
|
||||
\label{prop:flip-target}
|
||||
Flipping $uv \in E(L_k)$ with apexes $w, x$ replaces $uv$ with $wx$ in $G$.
|
||||
The new edge $wx$ belongs to $L_k$ iff $\ell_G(w) = \ell_G(x) = k$, and to
|
||||
$L_{k+1}$ iff $\ell_G(w) = \ell_G(x) = k + 1$; otherwise $wx$ is cross-parity
|
||||
and lies in no level subgraph. In all cases $uv$ is removed from $L_k$.
|
||||
\end{proposition}
|
||||
|
||||
\subsection{Cross-level flip pass}
|
||||
|
||||
For each odd simple cycle $C$ of each $L_k$ containing a cross-level edge,
|
||||
flip one such edge. By Proposition~\ref{prop:flip-target} the new edge
|
||||
either enters $L_{k+1}$ (in the apex case $(k+1, k+1)$) or is cross-parity
|
||||
(otherwise). Choosing apex pairs distinctly across cycles makes the set of
|
||||
new edges entering any single level $L_j$ a matching, hence a forest, and
|
||||
similarly for new same-parity-distance-$2$ edges entering the relevant
|
||||
parity subgraph; these therefore introduce no odd cycle.
|
||||
|
||||
\subsection{Tricky-everywhere cycles}
|
||||
|
||||
After the cross-level pass, the only odd simple cycles remaining in any
|
||||
$L_k$ are those whose every edge is intra-level; we call such a cycle
|
||||
\emph{tricky-everywhere}. By Proposition~\ref{prop:flip-target}, flipping
|
||||
any edge of a tricky-everywhere cycle replaces it with another edge of $L_k$,
|
||||
so the local triangle pair $(uvw, uvx)$ becomes $(uwx, vwx)$: still a pair
|
||||
of odd triangles inside $L_k$. To make global progress on these cycles we
|
||||
use a facial-depth potential to choose the flip.
|
||||
|
||||
\begin{definition}[Facial depth]
|
||||
\label{def:facial-depth}
|
||||
Let $L_k$ be drawn with the outerplanar embedding inherited from $\Pi_G$,
|
||||
let $D$ be the dual graph of this drawing with the outer face removed, and
|
||||
let $\mathcal{B}$ be the set of inner faces incident to at least two edges
|
||||
of the outer face of $L_k$. The \emph{facial depth} of an inner face $F$ of
|
||||
$L_k$ is
|
||||
\[
|
||||
\mathrm{depth}(F) \;=\; \min_{F' \in \mathcal{B}} \mathrm{dist}_D(F, F'),
|
||||
\]
|
||||
with the convention $\mathrm{depth}(F) = \infty$ if no such $F'$ exists.
|
||||
\end{definition}
|
||||
|
||||
\subsection{The algorithm}
|
||||
|
||||
\begin{enumerate}
|
||||
\item \emph{Cross-level flip pass.} For each $L_k$ and each odd simple cycle
|
||||
$C \subseteq L_k$ containing a cross-level edge, flip one such edge,
|
||||
selecting apex pairs to keep the newly added edges a matching in each
|
||||
target level subgraph and in the relevant parity subgraph.
|
||||
\item \emph{Intra-level flip loop.} While some $L_k$ contains a
|
||||
tricky-everywhere odd simple cycle:
|
||||
\begin{enumerate}
|
||||
\item compute facial depths for all simple level cycles of $L_k$;
|
||||
\item among tricky-everywhere odd simple cycles of maximum facial depth,
|
||||
pick any $C$;
|
||||
\item among the edges of $C$, pick one whose other incident inner face has
|
||||
minimum facial depth, and flip it.
|
||||
\end{enumerate}
|
||||
\end{enumerate}
|
||||
|
||||
\begin{observation}
|
||||
\label{obs:terminate}
|
||||
For every plane triangulation $G$ on $n \in \{9, 10, 11\}$ vertices, every
|
||||
level source $S$, and every $k$ such that $L_k$ contains a tricky-everywhere
|
||||
odd simple cycle, Step~2 terminates with no tricky-everywhere odd simple
|
||||
cycle remaining in any $L_k$. Moreover, the total number of
|
||||
tricky-everywhere odd simple cycles strictly decreases on every flip chosen
|
||||
by Step~2(c).
|
||||
\end{observation}
|
||||
|
||||
\begin{question}
|
||||
\label{q:terminate-all-n}
|
||||
Does Observation~\ref{obs:terminate} hold for all $n$? Equivalently, does
|
||||
the count of tricky-everywhere odd simple cycles strictly decrease on every
|
||||
Step~2(c) flip, in every plane triangulation?
|
||||
\end{question}
|
||||
|
||||
\section{Discussion and open questions}
|
||||
|
||||
@@ -340,7 +477,7 @@ The computational results suggest the following:
|
||||
arise as level resolutions, and the icosahedron does at $n = 12$
|
||||
(Observations~\ref{obs:preimage} and~\ref{obs:icosa}).
|
||||
\item Each level subgraph $L_k$ of $G$ is outerplanar
|
||||
(Proposition~\ref{prop:outerplanar}), so each $L_k$ is 3-chromatic
|
||||
(Theorem~\ref{thm:outerplanar}), so each $L_k$ is 3-chromatic
|
||||
classically and independently of 4CT. The level-resolution problem
|
||||
reduces to flipping edges of $G$ so that each $L_k$'s chromatic
|
||||
number drops from $3$ to $2$, while avoiding creation of $G$-level-2
|
||||
@@ -355,20 +492,12 @@ The computational results suggest the following:
|
||||
that does not invoke 4CT.
|
||||
\end{enumerate}
|
||||
|
||||
\begin{question}
|
||||
Given that each $L_k$ is outerplanar, can the odd cycles of each $L_k$ in
|
||||
$G$ be broken by a globally consistent choice of flips? Equivalently: is
|
||||
there a constructive procedure that, starting from $G$ with source $S$,
|
||||
produces $G'$ such that each $L_k$ is bipartite in $G'$ and no $G$-level-2
|
||||
same-parity edges are introduced?
|
||||
\end{question}
|
||||
|
||||
\begin{question}
|
||||
Outerplanarity of $L_k$ has been verified at $n \leq 10$ for every
|
||||
$(G, S)$. Does it hold for all $n$? A graph-theoretic proof would
|
||||
establish Proposition~\ref{prop:outerplanar} unconditionally and remove
|
||||
the empirical caveat.
|
||||
\end{question}
|
||||
The algorithm of Section~\ref{sec:flip-algorithm} is the candidate
|
||||
constructive answer: cross-level flips dispose of every odd cycle of $L_k$
|
||||
that admits one, and the facial-depth-guided intra-level flip loop attacks
|
||||
the residual tricky-everywhere cycles. Observation~\ref{obs:terminate}
|
||||
records that the loop terminates on all tested $(G, S, k)$ at $n \leq 11$;
|
||||
Question~\ref{q:terminate-all-n} asks whether termination holds for all $n$.
|
||||
|
||||
\section{Implementation}
|
||||
\label{sec:impl}
|
||||
|
||||
Reference in New Issue
Block a user