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:
2026-05-20 01:20:27 -04:00
parent bd9c46d3e4
commit db245eecea
9 changed files with 992 additions and 112 deletions
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)))
@@ -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
@@ -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}