dual_decomposition: chord-apex proof + diagrams

- Replace the chord-apex TODO with a full proof by contradiction: assume
  merged != spike, define X, Y, Z, W, lift to G' so that the externals
  inherit \psi(f) = (X, Y, Z, W, W), and split on W in {X, Z}. Either case
  meets the hypothesis of lem:pentagonal-externals, which extends \psi to a
  proper 3-edge-colouring of G' --- contradicting non-3-edge-colourability
  via Tait.
- Add fig:chord-apex-proof: the assumed reduced-dual colouring on top, and
  the two lifted-G' cases (W=Z, W=X) below, rendered on the dodecahedron.
- Add experiments/draw_chord_apex_proof.py.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-23 02:31:54 -04:00
parent 0303225f39
commit 409dea565a
8 changed files with 293 additions and 39 deletions
@@ -0,0 +1,180 @@
r"""Draw diagrams illustrating the proof of Lemma 2.6 (chord-apex).
Three figures rendered on the dodecahedral G':
step1: the assumed proper 3-edge-colouring of \widehat{G}'_{v,0}, with the
v_n-edges receiving distinct colours X (red), Y (green, spike),
Z (blue), and the chord coloured W with W != Y, forcing W in {X, Z}.
step2: lift to G' in the case W = Z. The externals inherit
psi(f) = (X, Y, Z, Z, Z) and Lemma 2.4 completes partial F_v.
step3: lift to G' in the case W = X with psi(f) = (X, Y, Z, X, X).
"""
import os
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from reduced_dual import build_dual, apply_reduction
OUT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
C1 = '#dc2626' # red -> X
C2 = '#16a34a' # green -> Y (spike)
C3 = '#2563eb' # blue -> Z
DARK = '#374151'
DEG2 = '#f59e0b'
GRAY = '#9ca3af'
LIGHT = '#e5e7eb'
APEX_FILL = '#fef3c7'
def base_canvas(title):
fig, ax = plt.subplots(figsize=(8.5, 8.5))
ax.set_aspect('equal')
ax.axis('off')
ax.set_title(title, fontsize=12)
return fig, ax
def draw_lift(ax, Gp, pos, A, B, other_surv, f_cols, e_cols, f_labels):
"""G' with f_k and partial F_v boundary edges coloured; rest in light gray."""
pentagon_edges = set()
for k in range(5):
pentagon_edges.add(frozenset((A[k], B[k]))) # f_k
pentagon_edges.add(frozenset((B[k], B[(k + 1) % 5]))) # boundary
for u, v in Gp.edges():
if frozenset((u, v)) in pentagon_edges:
continue
(x0, y0), (x1, y1) = pos[u], pos[v]
ax.plot([x0, x1], [y0, y1], color=LIGHT, lw=1.2, zorder=1)
other = [v for v in other_surv if v not in A and v not in B]
xs = [pos[v][0] for v in other]
ys = [pos[v][1] for v in other]
ax.scatter(xs, ys, s=50, color=LIGHT, zorder=2)
for k, v in enumerate(A):
ax.scatter(*pos[v], s=240, color=DEG2, edgecolors='black',
linewidths=0.8, zorder=4)
ax.annotate(f'$A_{k}$', (pos[v][0] * 1.18, pos[v][1] * 1.18),
ha='center', va='center', fontsize=12, color='#a16207',
zorder=5)
for k, v in enumerate(B):
ax.scatter(*pos[v], s=160, color='white', edgecolors=DARK,
linewidths=1.2, zorder=4)
ax.annotate(f'$B_{k}$', (pos[v][0] * 0.62, pos[v][1] * 0.62),
ha='center', va='center', fontsize=11, color=DARK,
zorder=5)
for k in range(5):
(x0, y0), (x1, y1) = pos[B[k]], pos[A[k]]
ax.plot([x0, x1], [y0, y1], color=f_cols[k], lw=3.2, zorder=3)
mx, my = 0.55 * x0 + 0.45 * x1, 0.55 * y0 + 0.45 * y1
ax.annotate(f_labels[k], (mx, my), fontsize=10, color=f_cols[k],
fontweight='bold', ha='center', va='center', zorder=7,
bbox=dict(boxstyle='round,pad=0.15', fc='white',
ec=f_cols[k], lw=0.5))
for k in range(5):
(x0, y0), (x1, y1) = pos[B[k]], pos[B[(k + 1) % 5]]
ax.plot([x0, x1], [y0, y1], color=e_cols[k], lw=3.2, zorder=3)
def main():
Gp, pos, Fv = build_dual()
res = apply_reduction(Gp, pos, Fv, i=0)
npos, A = res['pos'], res['A']
v_n, apex_nbrs, chord = res['v_n'], res['apex_nbrs'], res['chord']
a_pair = {}
for u in A:
for nbr in Gp.neighbors(u):
if nbr in Fv:
a_pair[u] = nbr
break
B = [a_pair[A[k]] for k in range(5)]
survivors = [v for v in Gp if v not in Fv]
surv_set = set(survivors)
surv_edges = [(u, v) for u, v in Gp.edges()
if u in surv_set and v in surv_set]
other_surv = [v for v in survivors if v not in A]
# ----- Step 1: assumed colouring of the reduced dual -----
fig, ax = base_canvas(
"Step 1: $\\varphi$ on $\\widehat{G}'_{v,0}$ assigns distinct colours "
"$X, Y, Z$ to the $v_n$-edges (propriety at $v_n$);\n"
"by hypothesis $W \\neq Y$, forcing $W \\in \\{X, Z\\}$.")
for u, v in surv_edges:
(x0, y0), (x1, y1) = pos[u], pos[v]
ax.plot([x0, x1], [y0, y1], color=GRAY, lw=1.4, zorder=1)
xs = [pos[v][0] for v in other_surv]
ys = [pos[v][1] for v in other_surv]
ax.scatter(xs, ys, s=80, color=DARK, zorder=3)
for k, v in enumerate(A):
ax.scatter(*pos[v], s=240, color=DEG2, edgecolors='black',
linewidths=0.8, zorder=4)
ax.annotate(f'$A_{k}$', (pos[v][0] * 1.18, pos[v][1] * 1.18),
ha='center', va='center', fontsize=12, color='#a16207',
zorder=5)
for k, (color, lbl) in enumerate([(C1, '$X$'), (C2, '$Y$'), (C3, '$Z$')]):
u = A[k]
(x0, y0), (x1, y1) = npos[v_n], pos[u]
ax.plot([x0, x1], [y0, y1], color=color, lw=3.4, zorder=5)
mx, my = 0.5 * x1 + 0.5 * x0, 0.5 * y1 + 0.5 * y0
ax.annotate(lbl, (mx, my), fontsize=12, color=color, fontweight='bold',
ha='center', va='center', zorder=7,
bbox=dict(boxstyle='round,pad=0.18', fc='white', ec=color,
lw=0.6))
ax.scatter(*npos[v_n], s=300, color=APEX_FILL, marker='s',
edgecolors='black', linewidths=1.0, zorder=6)
ax.annotate('$v_n$', npos[v_n], textcoords='offset points', xytext=(0, 14),
ha='center', fontsize=12, fontweight='bold', color=DARK,
zorder=7)
(x0, y0), (x1, y1) = pos[chord[0]], pos[chord[1]]
ax.plot([x0, x1], [y0, y1], color=DARK, lw=2.4, ls='--', zorder=5)
mx, my = (x0 + x1) / 2, (y0 + y1) / 2
ax.annotate('$W$', (mx, my), fontsize=12, color=DARK, fontweight='bold',
ha='center', va='center', zorder=7,
bbox=dict(boxstyle='round,pad=0.18', fc='white', ec=DARK,
lw=0.6))
ax.legend(handles=[
Line2D([0], [0], color=C1, lw=3, label='$X$ (side)'),
Line2D([0], [0], color=C2, lw=3, label='$Y$ (spike)'),
Line2D([0], [0], color=C3, lw=3, label='$Z$ (side)'),
Line2D([0], [0], color=DARK, lw=2, ls='--',
label='$W$ (merged), $W \\neq Y$'),
], loc='upper left', fontsize=10)
fig.savefig(os.path.join(OUT_DIR, 'fig_chord_apex_step1.png'),
dpi=170, bbox_inches='tight')
plt.close(fig)
cases = [
dict(
title=("Step 2: lift to $G'$ when $W = Z$. The externals inherit "
"$\\psi(f) = (X, Y, Z, Z, Z)$;\n"
"Lemma 2.4 colours the five edges of $\\partial F_v$."),
f_cols=[C1, C2, C3, C3, C3],
e_cols=[C3, C1, C2, C1, C2],
f_labels=['$X$', '$Y$', '$Z$', '$Z$', '$Z$'],
out='fig_chord_apex_step2.png',
),
dict(
title=("Step 3: lift to $G'$ when $W = X$. The externals inherit "
"$\\psi(f) = (X, Y, Z, X, X)$;\n"
"Lemma 2.4 colours the five edges of $\\partial F_v$."),
f_cols=[C1, C2, C3, C1, C1],
e_cols=[C3, C1, C2, C3, C2],
f_labels=['$X$', '$Y$', '$Z$', '$X$', '$X$'],
out='fig_chord_apex_step3.png',
),
]
for case in cases:
fig, ax = base_canvas(case['title'])
draw_lift(ax, Gp, pos, A, B, other_surv,
case['f_cols'], case['e_cols'], case['f_labels'])
fig.savefig(os.path.join(OUT_DIR, case['out']),
dpi=170, bbox_inches='tight')
plt.close(fig)
print(f"wrote fig_chord_apex_step{{1,2,3}}.png to {OUT_DIR}")
if __name__ == '__main__':
main()
Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

@@ -9,10 +9,12 @@
\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces The four steps of Definition\nonbreakingspace 2.1\hbox {}, illustrated on $G' = $ the dodecahedron (dual of the icosahedron) with $F_v$ the inner pentagon and $i = 0$. Top left: delete the five boundary vertices of $F_v$, leaving five degree-$2$ vertices on a new face $F$. Top right: order them clockwise as $A_0,\dots ,A_4$. Bottom left: add $v_n$ joined to $A_0, A_1, A_2$. Bottom right: add the chord $A_3 A_4$, giving the cubic plane graph $\setbox \z@ \hbox {\mathsurround \z@ $\textstyle G$}\mathaccent "0362{G}'_{v,0}$.}}{3}{}\protected@file@percent }
\newlabel{fig:reduced-dual-steps}{{1}{3}}
\newlabel{lem:pentagonal-externals}{{2.4}{3}}
\newlabel{lem:chord-apex}{{2.6}{4}}
\@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces The proof of Lemma\nonbreakingspace 2.6\hbox {}, illustrated for $i = 0$ on $G' = $ the dodecahedron. Top: under the assumption $W \neq Y$, propriety at $v_n$ forces $W \in \{X, Z\}$. Bottom: in either case the lift to $G'$ has externals satisfying the hypothesis of Lemma\nonbreakingspace 2.4\hbox {}, which colours $\partial F_v$ to extend $\psi $ to a proper $3$-edge-colouring of $G'$.}}{5}{}\protected@file@percent }
\newlabel{fig:chord-apex-proof}{{2}{5}}
\newlabel{tocindent-1}{0pt}
\newlabel{tocindent0}{0pt}
\newlabel{tocindent1}{17.77782pt}
\newlabel{tocindent2}{0pt}
\newlabel{tocindent3}{0pt}
\newlabel{lem:chord-apex}{{2.6}{4}}
\gdef \@abspage@last{4}
\gdef \@abspage@last{6}
@@ -1,4 +1,4 @@
This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 22 MAY 2026 20:19
This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 22 MAY 2026 20:45
entering extended mode
restricted \write18 enabled.
%&-line parsing enabled.
@@ -222,33 +222,54 @@ Package pdftex.def Info: fig_reduced_dual_step4.png used on input line 166.
LaTeX Warning: `h' float specifier changed to `ht'.
[2] [3 <./fig_reduced_dual_step1.png> <./fig_reduced_dual_step2.png> <./fig_red
uced_dual_step3.png> <./fig_reduced_dual_step4.png>] [4] (./paper.aux) )
uced_dual_step3.png> <./fig_reduced_dual_step4.png>]
<fig_chord_apex_step1.png, id=34, 505.03976pt x 502.06393pt>
File: fig_chord_apex_step1.png Graphic file (type png)
<use fig_chord_apex_step1.png>
Package pdftex.def Info: fig_chord_apex_step1.png used on input line 286.
(pdftex.def) Requested size: 251.9989pt x 250.5104pt.
<fig_chord_apex_step2.png, id=35, 490.16064pt x 499.51323pt>
File: fig_chord_apex_step2.png Graphic file (type png)
<use fig_chord_apex_step2.png>
Package pdftex.def Info: fig_chord_apex_step2.png used on input line 287.
(pdftex.def) Requested size: 172.79846pt x 176.08986pt.
<fig_chord_apex_step3.png, id=36, 490.16064pt x 499.51323pt>
File: fig_chord_apex_step3.png Graphic file (type png)
<use fig_chord_apex_step3.png>
Package pdftex.def Info: fig_chord_apex_step3.png used on input line 288.
(pdftex.def) Requested size: 172.79846pt x 176.08986pt.
LaTeX Warning: `h' float specifier changed to `ht'.
[4] [5 <./fig_chord_apex_step1.png> <./fig_chord_apex_step2.png> <./fig_chord_a
pex_step3.png>] [6] (./paper.aux) )
Here is how much of TeX's memory you used:
3020 strings out of 478268
42520 string characters out of 5846347
343128 words of memory out of 5000000
21064 multiletter control sequences out of 15000+600000
3042 strings out of 478268
43139 string characters out of 5846347
343136 words of memory out of 5000000
21083 multiletter control sequences out of 15000+600000
476364 words of font info for 55 fonts, out of 8000000 for 9000
1302 hyphenation exceptions out of 8191
69i,8n,76p,664b,298s stack positions out of 10000i,1000n,20000p,200000b,200000s
</usr/l
ocal/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb></usr/lo
cal/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmcsc10.pfb></usr/lo
cal/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmex10.pfb></usr/loc
al/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb></usr/loca
l/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb></usr/local/
texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb></usr/local/te
xlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb></usr/local/texli
ve/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/2
022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy7.pfb></usr/local/texlive/202
2/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/t
exmf-dist/fonts/type1/public/amsfonts/symbols/msam10.pfb>
Output written on paper.pdf (4 pages, 501796 bytes).
</usr/local/texlive/2022/texmf-dist/fonts/ty
pe1/public/amsfonts/cm/cmbx10.pfb></usr/local/texlive/2022/texmf-dist/fonts/typ
e1/public/amsfonts/cm/cmcsc10.pfb></usr/local/texlive/2022/texmf-dist/fonts/typ
e1/public/amsfonts/cm/cmex10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type
1/public/amsfonts/cm/cmmi10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1
/public/amsfonts/cm/cmmi7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/p
ublic/amsfonts/cm/cmr10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/pub
lic/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/am
sfonts/cm/cmsy10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/ams
fonts/cm/cmsy7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfo
nts/cm/cmti10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfon
ts/cm/cmti8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts
/symbols/msam10.pfb>
Output written on paper.pdf (6 pages, 750077 bytes).
PDF statistics:
91 PDF objects out of 1000 (max. 8388607)
50 compressed objects within 1 object stream
103 PDF objects out of 1000 (max. 8388607)
54 compressed objects within 1 object stream
0 named destinations out of 1000 (max. 500000)
21 words of extra memory for PDF output out of 10000 (max. 10000000)
36 words of extra memory for PDF output out of 10000 (max. 10000000)
@@ -281,20 +281,71 @@ $\widehat{G}'_{v,i}$, the merged edge and the spike edge receive the same
colour.
\end{lemma}
\begin{figure}[h]
\centering
\includegraphics[width=0.7\textwidth]{fig_chord_apex_step1.png}\\[0.4em]
\includegraphics[width=0.48\textwidth]{fig_chord_apex_step2.png}\hfill
\includegraphics[width=0.48\textwidth]{fig_chord_apex_step3.png}
\caption{The proof of Lemma~\ref{lem:chord-apex}, illustrated for $i = 0$ on
$G' = $ the dodecahedron. Top: under the assumption $W \neq Y$, propriety at
$v_n$ forces $W \in \{X, Z\}$. Bottom: in either case the lift to $G'$ has
externals satisfying the hypothesis of
Lemma~\ref{lem:pentagonal-externals}, which colours $\partial F_v$ to extend
$\psi$ to a proper $3$-edge-colouring of $G'$.}
\label{fig:chord-apex-proof}
\end{figure}
\begin{proof}
% TODO. Intended argument: given a proper 3-edge-colouring of
% \widehat{G}'_{v,i}, the colour at each A_k of the new edge there (one of the
% three v_n-edges for k in {i, i+1, i+2}, or the chord for k in {i+3, i+4})
% determines the colour of f_k in any lift to G' --- it is the unique colour
% not used by the two original edges at A_k. Because the chord has a single
% colour, f_{i+3} and f_{i+4} agree. If the merged edge and the spike edge
% receive distinct colours, the three v_n-edges contribute three distinct
% colours to f_i, f_{i+1}, f_{i+2}, and the resulting f-vector has shape
% (X, Y, Z, W, W) with X, Y, Z distinct and W \neq Y. By
% Lemma~\ref{lem:pentagonal-externals} applied to G' at the face F_v, this
% extends to a proper 3-edge-colouring of G' --- contradicting that G' (the
% dual of the minimal counterexample G) is not 3-edge-colourable. Hence the
% merged edge and the spike edge must share a colour.
After cyclically relabelling, assume $i = 0$. Suppose for contradiction that
$\varphi$ is a proper $3$-edge-colouring of $\widehat{G}'_{v,0}$ in which the
merged edge $\{A_3, A_4\}$ and the spike edge $\{A_1, v_n\}$ receive different
colours (Figure~\ref{fig:chord-apex-proof}, top), and write
\[
X = \varphi(\{A_0, v_n\}), \quad
Y = \varphi(\{A_1, v_n\}), \quad
Z = \varphi(\{A_2, v_n\}), \quad
W = \varphi(\{A_3, A_4\}).
\]
Propriety of $\varphi$ at $v_n$ forces $\{X, Y, Z\} = \{1, 2, 3\}$, and the
assumption $W \neq Y$ leaves $W \in \{X, Z\}$.
We lift $\varphi$ to a colouring $\psi$ of $E(G')$ as follows. Let
$B_0, \dots, B_4$ be the boundary vertices of $\partial F_v$ in $G'$, indexed
so that $f_k = B_k A_k$. On every edge of $G'$ that survived the reduction,
set $\psi = \varphi$. At each $A_k$ the two surviving edges retain their
$\varphi$-colours, so the remaining edge at $A_k$ --- in $G'$ this is the
external $f_k$; in $\widehat{G}'_{v,0}$ this is a $v_n$-edge ($k \in
\{0, 1, 2\}$) or the chord ($k \in \{3, 4\}$) --- is forced to take the third
colour at $A_k$. Since the two-surviving-edge colours at $A_k$ agree in $G'$
and $\widehat{G}'_{v,0}$, the third colour does too, giving
\[
\psi(f_0) = X, \quad \psi(f_1) = Y, \quad \psi(f_2) = Z, \quad
\psi(f_3) = \psi(f_4) = W
\]
(the last two equalities holding because the chord is a single edge contributing
its colour at each of $A_3$ and $A_4$).
It remains to assign colours to the five boundary edges $B_k B_{k+1}$ of
$\partial F_v$. Apply Lemma~\ref{lem:pentagonal-externals} to $G'$ at the face
$F_v$ with the $B_k$'s as its boundary vertices and the same indexing. The
external vector $(\psi(f_0), \dots, \psi(f_4)) = (X, Y, Z, W, W)$ falls into
one of two cases (Figure~\ref{fig:chord-apex-proof}, bottom):
\begin{itemize}
\item if $W = Z$, it is $(X, Y, Z, Z, Z)$: three consecutive $Z$'s at
positions $2, 3, 4$, with $\{X, Y\} = \{1, 2, 3\} \setminus \{Z\}$;
\item if $W = X$, it is $(X, Y, Z, X, X)$: three consecutive $X$'s at
positions $3, 4, 0$, with $\{Y, Z\} = \{1, 2, 3\} \setminus \{X\}$.
\end{itemize}
Each case satisfies the hypothesis of Lemma~\ref{lem:pentagonal-externals};
its $(\Leftarrow)$ direction therefore assigns colours to the boundary edges
$B_k B_{k+1}$ that make $\psi$ proper at every $B_k$.
The resulting $\psi$ is a proper $3$-edge-colouring of $G'$: proper at every
$B_k$ by the lemma, at every $A_k$ by the construction, and at every other
vertex because such a vertex has the same neighbourhood in $G'$ as in
$\widehat{G}'_{v,0}$ with the same incident-edge colours. By Tait's theorem,
$G'$ is $3$-edge-colourable iff $G$ is $4$-vertex-colourable, contradicting
that $G$ is a counterexample. The assumption $W \neq Y$ is therefore false.
\end{proof}
\end{document}