dual_decomposition: reduced-dual definition, verification, and step figures

Add Definition 2.1 (reduced dual) and a remark on cubicity/planarity, plus an
experiment verifying it on the icosahedron/dodecahedron and four figures, one
per construction step.

reduced_dual.py builds G' = dodecahedron (dual of the icosahedron), applies the
construction, and confirms the result is a cubic, planar, simple graph whose
dual is a simple triangulation. Finding: the construction is an n -> n-2
reduction (12 -> 10 here), not n-1, since the single apex v_n collapses one more
vertex than a standard pentagon re-triangulation; the result also re-introduces
degree-3 and degree-4 vertices (degree seq [7,5,5,5,5,5,5,4,4,3]).

draw_reduced_dual_steps.py renders fig_reduced_dual_step1..4.png, embedded as a
2x2 grid after the definition.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-22 18:50:38 -04:00
parent bd8526eb11
commit 1791b68f4a
12 changed files with 508 additions and 27 deletions
@@ -0,0 +1,174 @@
"""Draw the four steps of the reduced-dual construction (Definition 2.1).
Uses the dodecahedron G' = dual of the icosahedron, with F_v the inner pentagon,
as built in reduced_dual.py. Produces fig_reduced_dual_step{1..4}.png.
"""
import os
import math
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
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__)))
GRAY = '#9ca3af'
DARK = '#374151'
GHOST = '#fca5a5'
DEG2 = '#f59e0b'
APEX = '#16a34a'
CHORD = '#2563eb'
FACE = '#fef9c3'
def draw_edges(ax, G, pos, nodes=None, **kw):
for u, v in G.edges():
if nodes is not None and (u not in nodes or v not in nodes):
continue
(x0, y0), (x1, y1) = pos[u], pos[v]
ax.plot([x0, x1], [y0, y1], **kw)
def draw_nodes(ax, pos, nodes, **kw):
xs = [pos[v][0] for v in nodes]
ys = [pos[v][1] for v in nodes]
ax.scatter(xs, ys, **kw)
def face_F_polygon(pos):
"""The new central face F: decagon alternating b_i, c_i clockwise."""
order = []
for i in range(5):
order += [('b', i), ('c', i)]
return [pos[v] for v in order]
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 main():
Gp, pos, Fv = build_dual()
res = apply_reduction(Gp, pos, Fv, i=0)
Ghat, npos, A = res['Ghat'], res['pos'], res['A']
v_n, apex_nbrs, chord = res['v_n'], res['apex_nbrs'], res['chord']
survivors = [v for v in Gp if v not in Fv] # b, c, d families
surv_set = set(survivors)
deg2 = list(A) # the five b_i
# surviving edges (both endpoints survive) vs deleted edges (touch an a_i)
surv_edges = [(u, v) for u, v in Gp.edges()
if u in surv_set and v in surv_set]
del_edges = [(u, v) for u, v in Gp.edges()
if u not in surv_set or v not in surv_set]
def draw_surviving(ax):
ax.add_patch(Polygon(face_F_polygon(pos), closed=True,
facecolor=FACE, edgecolor='none', zorder=0))
for u, v in surv_edges:
(x0, y0), (x1, y1) = pos[u], pos[v]
ax.plot([x0, x1], [y0, y1], color=GRAY, lw=1.6, zorder=1)
others = [v for v in survivors if v not in deg2]
draw_nodes(ax, pos, others, s=120, color=DARK, zorder=3)
def draw_ghosts(ax):
for u, v in del_edges:
(x0, y0), (x1, y1) = pos[u], pos[v]
ax.plot([x0, x1], [y0, y1], color=GHOST, lw=1.2, ls='--', zorder=1)
draw_nodes(ax, pos, Fv, s=120, color='white', edgecolors=GHOST,
linewidths=1.5, zorder=2)
for v in Fv:
ax.plot(*pos[v], marker='x', color=GHOST, ms=8, zorder=3)
# ----- Step 1: delete F_v's boundary; five degree-2 vertices on face F -----
fig, ax = base_canvas(
"Step 1: delete the five dual vertices on $\\partial F_v$.\n"
"Their outer neighbours drop to degree 2 (orange) and lie on a new "
"face $F$ (shaded).")
draw_surviving(ax)
draw_ghosts(ax)
draw_nodes(ax, pos, deg2, s=260, color=DEG2, edgecolors='black',
linewidths=1.0, zorder=4)
cx = sum(pos[('a', i)][0] for i in range(5)) / 5
cy = sum(pos[('a', i)][1] for i in range(5)) / 5
ax.text(cx, cy, '$F$', fontsize=16, ha='center', va='center',
color='#a16207', zorder=5)
ax.legend(handles=[
Line2D([0], [0], marker='x', color=GHOST, lw=0, label='deleted (was $\\partial F_v$)'),
Line2D([0], [0], marker='o', color='w', markerfacecolor=DEG2,
markeredgecolor='black', label='degree-2 vertex'),
], loc='upper left', fontsize=10)
fig.savefig(os.path.join(OUT_DIR, 'fig_reduced_dual_step1.png'),
dpi=170, bbox_inches='tight'); plt.close(fig)
# ----- Step 2: order the five degree-2 vertices clockwise as A_0..A_4 -----
fig, ax = base_canvas(
"Step 2: list the degree-2 vertices clockwise around $F$ as "
"$A_0,\\dots,A_4$.")
draw_surviving(ax)
draw_nodes(ax, pos, deg2, s=300, color=DEG2, edgecolors='black',
linewidths=1.0, zorder=4)
for k, v in enumerate(A):
x, y = pos[v]
ax.annotate(f'$A_{k}$', (x, y), textcoords='offset points',
xytext=(0, 0), ha='center', va='center', fontsize=10,
fontweight='bold', color='black', zorder=5)
# outward label too
ax.annotate(f'$A_{k}$', (x * 1.18, y * 1.18), ha='center', va='center',
fontsize=12, color='#a16207', zorder=5)
fig.savefig(os.path.join(OUT_DIR, 'fig_reduced_dual_step2.png'),
dpi=170, bbox_inches='tight'); plt.close(fig)
# ----- Step 3: add v_n joined to A_i, A_{i+1}, A_{i+2} -----
fig, ax = base_canvas(
"Step 3: add a vertex $v_n$ joined to $A_i, A_{i+1}, A_{i+2}$ "
"(here $i=0$).")
draw_surviving(ax)
draw_nodes(ax, pos, deg2, s=300, color=DEG2, edgecolors='black',
linewidths=1.0, zorder=4)
for k, v in enumerate(A):
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 u in apex_nbrs:
(x0, y0), (x1, y1) = npos[v_n], pos[u]
ax.plot([x0, x1], [y0, y1], color=APEX, lw=2.4, zorder=5)
draw_nodes(ax, npos, [v_n], s=320, color=APEX, 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=APEX, zorder=7)
fig.savefig(os.path.join(OUT_DIR, 'fig_reduced_dual_step3.png'),
dpi=170, bbox_inches='tight'); plt.close(fig)
# ----- Step 4: add chord A_{i+3} A_{i+4}; the reduced dual -----
fig, ax = base_canvas(
"Step 4: add the edge $A_{i+3} A_{i+4}$. The result $\\widehat{G}'_{v,i}$ "
"is again cubic and planar.")
draw_surviving(ax)
draw_nodes(ax, pos, deg2, s=300, color=DEG2, edgecolors='black',
linewidths=1.0, zorder=4)
for k, v in enumerate(A):
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 u in apex_nbrs:
(x0, y0), (x1, y1) = npos[v_n], pos[u]
ax.plot([x0, x1], [y0, y1], color=APEX, lw=2.4, zorder=5)
draw_nodes(ax, npos, [v_n], s=320, color=APEX, 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=APEX, zorder=7)
(x0, y0), (x1, y1) = pos[chord[0]], pos[chord[1]]
ax.plot([x0, x1], [y0, y1], color=CHORD, lw=2.8, zorder=5)
fig.savefig(os.path.join(OUT_DIR, 'fig_reduced_dual_step4.png'),
dpi=170, bbox_inches='tight'); plt.close(fig)
print("wrote fig_reduced_dual_step1..4.png to", OUT_DIR)
if __name__ == '__main__':
main()
@@ -0,0 +1,184 @@
"""Reduced dual: construction and verification.
Test input is the icosahedron G (the unique 5-regular triangulation, n=12).
Its dual G' is the dodecahedron (a cubic plane graph, 20 vertices). We pick a
degree-5 vertex v of G -- equivalently a pentagonal face F_v of G' -- and apply
the reduced-dual construction of Definition 2.1:
1. delete the 5 dual vertices on the boundary of F_v (and incident edges),
leaving 5 degree-2 vertices on a new face F;
2. order those 5 vertices clockwise around F as A_0..A_4;
3. add a vertex v_n joined to A_i, A_{i+1}, A_{i+2};
4. add an edge A_{i+3} A_{i+4}.
We verify the result is again a cubic plane graph, and report the triangulation
it is the dual of (its face count = the primal vertex count), to see how the
vertex count changes relative to n.
The dodecahedron is built directly in its concentric "Schlegel" layout with
F_v the inner pentagon, so the figures (draw_reduced_dual_steps.py) are clean.
"""
import math
import networkx as nx
# ---------------------------------------------------------------------------
# Build G' = dodecahedron with concentric positions; F_v = inner pentagon.
# Vertex families a (inner pentagon), b, c, d (outer pentagon), 5 each.
# Angles increase *clockwise* (90 - 72*i deg) so index order is clockwise.
# ---------------------------------------------------------------------------
def build_dual():
pos = {}
R = {'a': 1.0, 'b': 2.2, 'c': 3.6, 'd': 4.8}
for i in range(5):
for fam in ('a', 'b'):
th = math.radians(90 - 72 * i)
pos[(fam, i)] = (R[fam] * math.cos(th), R[fam] * math.sin(th))
for fam in ('c', 'd'):
th = math.radians(90 - 72 * i - 36) # offset half a step
pos[(fam, i)] = (R[fam] * math.cos(th), R[fam] * math.sin(th))
Gp = nx.Graph()
Gp.add_nodes_from(pos)
for i in range(5):
Gp.add_edge(('a', i), ('a', (i + 1) % 5)) # inner pentagon
Gp.add_edge(('a', i), ('b', i)) # spokes a-b
Gp.add_edge(('b', i), ('c', i)) # b-c
Gp.add_edge(('b', i), ('c', (i - 1) % 5)) # b-c (other side)
Gp.add_edge(('c', i), ('d', i)) # spokes c-d
Gp.add_edge(('d', i), ('d', (i + 1) % 5)) # outer pentagon
Fv_boundary = [('a', i) for i in range(5)] # inner pentagon
return Gp, pos, Fv_boundary
# ---------------------------------------------------------------------------
# Face / dual helpers.
# ---------------------------------------------------------------------------
def faces_of(G):
"""Return the list of faces (each a list of vertices) of a plane graph."""
ok, emb = nx.check_planarity(G)
assert ok, "graph is not planar"
seen, faces = set(), []
for u in emb:
for v in emb[u]:
if (u, v) not in seen:
faces.append(emb.traverse_face(u, v, mark_half_edges=seen))
return faces
def dual_of(G):
"""Combinatorial dual (all faces, including outer) of a plane graph."""
faces = faces_of(G)
edge_faces = {}
for fi, face in enumerate(faces):
for j in range(len(face)):
e = frozenset((face[j], face[(j + 1) % len(face)]))
edge_faces.setdefault(e, []).append(fi)
D = nx.MultiGraph()
D.add_nodes_from(range(len(faces)))
for e, fs in edge_faces.items():
if len(fs) == 2:
D.add_edge(fs[0], fs[1])
elif len(fs) == 1: # shouldn't happen for 2-connected G
pass
return D, faces
# ---------------------------------------------------------------------------
# The reduced-dual construction.
# ---------------------------------------------------------------------------
def clockwise_order(verts, pos):
"""Order verts clockwise around their centroid, starting from the topmost."""
cx = sum(pos[v][0] for v in verts) / len(verts)
cy = sum(pos[v][1] for v in verts) / len(verts)
ang = {v: math.atan2(pos[v][1] - cy, pos[v][0] - cx) for v in verts}
ccw = sorted(verts, key=lambda v: ang[v]) # counterclockwise
cw = list(reversed(ccw)) # clockwise
start = max(range(len(cw)), key=lambda k: pos[cw[k]][1]) # topmost first
return cw[start:] + cw[:start]
def apply_reduction(Gp, pos, Fv_boundary, i=0):
"""Apply Definition 2.1 and return a dict capturing each stage."""
Ghat = Gp.copy()
npos = dict(pos)
# (1) delete the 5 boundary dual vertices of F_v
Ghat.remove_nodes_from(Fv_boundary)
deg2 = [v for v in Ghat if Ghat.degree(v) == 2]
assert len(deg2) == 5, f"expected 5 degree-2 vertices, got {len(deg2)}"
# (2) order them clockwise around the new face F
A = clockwise_order(deg2, pos)
# (3) new vertex v_n joined to A_i, A_{i+1}, A_{i+2}
apex_nbrs = [A[(i + k) % 5] for k in range(3)]
ax = sum(npos[v][0] for v in apex_nbrs) / 3
ay = sum(npos[v][1] for v in apex_nbrs) / 3
v_n = 'v_n'
npos[v_n] = (ax * 0.55, ay * 0.55) # pull toward the 3 nbrs
Ghat.add_node(v_n)
for u in apex_nbrs:
Ghat.add_edge(v_n, u)
# (4) chord between the remaining two
chord = (A[(i + 3) % 5], A[(i + 4) % 5])
Ghat.add_edge(*chord)
return {
'Ghat': Ghat, 'pos': npos, 'A': A, 'v_n': v_n,
'apex_nbrs': apex_nbrs, 'chord': chord,
'deleted': list(Fv_boundary),
}
def main():
Gp, pos, Fv = build_dual()
# --- verify G' is the dodecahedron = dual of the icosahedron ---
assert nx.check_planarity(Gp)[0]
assert all(d == 3 for _, d in Gp.degree()), "G' not cubic"
assert nx.is_isomorphic(Gp, nx.dodecahedral_graph()), "G' is not dodecahedron"
Dico, _ = dual_of(Gp)
Dico = nx.Graph(Dico)
print(f"G (icosahedron) : dual of G' has {Dico.number_of_nodes()} vertices, "
f"degrees {sorted({d for _, d in Dico.degree()})}")
print(f"G' (dodecahedron): {Gp.number_of_nodes()} vertices, "
f"{Gp.number_of_edges()} edges, "
f"{len(faces_of(Gp))} faces; cubic={all(d==3 for _,d in Gp.degree())}")
# --- apply the reduced-dual construction ---
res = apply_reduction(Gp, pos, Fv, i=0)
Ghat = res['Ghat']
cubic = all(d == 3 for _, d in Ghat.degree())
planar = nx.check_planarity(Ghat)[0]
ghat_simple = (nx.number_of_selfloops(Ghat) == 0) # Graph: no parallels
nfaces = len(faces_of(Ghat))
print()
print(f"reduced dual G^_v,i : {Ghat.number_of_nodes()} vertices, "
f"{Ghat.number_of_edges()} edges, {nfaces} faces")
print(f" cubic : {cubic}")
print(f" planar : {planar}")
print(f" simple : {ghat_simple}")
# --- the triangulation it is dual to ---
Dred_multi, _ = dual_of(Ghat)
Dred = nx.Graph(Dred_multi)
dred_simple = (Dred.number_of_edges() == Dred_multi.number_of_edges())
is_tri = all(len(f) == 3 for f in faces_of(Dred)) if planar else None
print()
print(f"dual of reduced dual : {Dred.number_of_nodes()} vertices "
f"(= faces of G^), degree seq "
f"{sorted((d for _, d in Dred.degree()), reverse=True)}")
print(f" is a triangulation : {is_tri}")
print(f" simple : {dred_simple}")
n = Dico.number_of_nodes()
print()
print(f"VERTEX COUNT: G has n = {n}; reduced triangulation has "
f"{Dred.number_of_nodes()} (change = "
f"{Dred.number_of_nodes() - n}).")
if __name__ == '__main__':
main()
Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

@@ -8,4 +8,8 @@
\newlabel{tocindent1}{17.77782pt} \newlabel{tocindent1}{17.77782pt}
\newlabel{tocindent2}{0pt} \newlabel{tocindent2}{0pt}
\newlabel{tocindent3}{0pt} \newlabel{tocindent3}{0pt}
\gdef \@abspage@last{2} \@writefile{toc}{\contentsline {section}{\tocsection {}{2}{The reduced dual}}{2}{}\protected@file@percent }
\newlabel{def:reduced-dual}{{2.1}{2}}
\@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}}
\gdef \@abspage@last{3}
@@ -1,5 +1,5 @@
# Fdb version 3 # Fdb version 3
["pdflatex"] 1779488879 "paper.tex" "paper.pdf" "paper" 1779488879 ["pdflatex"] 1779490218 "paper.tex" "paper.pdf" "paper" 1779490219
"/usr/local/texlive/2022/texmf-dist/fonts/map/fontname/texfonts.map" 1577235249 3524 cb3e574dea2d1052e39280babc910dc8 "" "/usr/local/texlive/2022/texmf-dist/fonts/map/fontname/texfonts.map" 1577235249 3524 cb3e574dea2d1052e39280babc910dc8 ""
"/usr/local/texlive/2022/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex7.tfm" 1246382020 1004 54797486969f23fa377b128694d548df "" "/usr/local/texlive/2022/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex7.tfm" 1246382020 1004 54797486969f23fa377b128694d548df ""
"/usr/local/texlive/2022/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex8.tfm" 1246382020 988 bdf658c3bfc2d96d3c8b02cfc1c94c20 "" "/usr/local/texlive/2022/texmf-dist/fonts/tfm/public/amsfonts/cmextra/cmex8.tfm" 1246382020 988 bdf658c3bfc2d96d3c8b02cfc1c94c20 ""
@@ -21,7 +21,9 @@
"/usr/local/texlive/2022/texmf-dist/fonts/tfm/public/cm/cmti8.tfm" 1136768653 1504 1747189e0441d1c18f3ea56fafc1c480 "" "/usr/local/texlive/2022/texmf-dist/fonts/tfm/public/cm/cmti8.tfm" 1136768653 1504 1747189e0441d1c18f3ea56fafc1c480 ""
"/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb" 1248133631 34811 78b52f49e893bcba91bd7581cdc144c0 "" "/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb" 1248133631 34811 78b52f49e893bcba91bd7581cdc144c0 ""
"/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmcsc10.pfb" 1248133631 32001 6aeea3afe875097b1eb0da29acd61e28 "" "/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmcsc10.pfb" 1248133631 32001 6aeea3afe875097b1eb0da29acd61e28 ""
"/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmex10.pfb" 1248133631 30251 6afa5cb1d0204815a708a080681d4674 ""
"/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb" 1248133631 36299 5f9df58c2139e7edcf37c8fca4bd384d "" "/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb" 1248133631 36299 5f9df58c2139e7edcf37c8fca4bd384d ""
"/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb" 1248133631 36281 c355509802a035cadc5f15869451dcee ""
"/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb" 1248133631 35752 024fb6c41858982481f6968b5fc26508 "" "/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb" 1248133631 35752 024fb6c41858982481f6968b5fc26508 ""
"/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb" 1248133631 32762 224316ccc9ad3ca0423a14971cfa7fc1 "" "/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb" 1248133631 32762 224316ccc9ad3ca0423a14971cfa7fc1 ""
"/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr8.pfb" 1248133631 32726 0a1aea6fcd6468ee2cf64d891f5c43c8 "" "/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr8.pfb" 1248133631 32726 0a1aea6fcd6468ee2cf64d891f5c43c8 ""
@@ -54,8 +56,12 @@
"/usr/local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map" 1647878959 4410336 7d30a02e9fa9a16d7d1f8d037ba69641 "" "/usr/local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map" 1647878959 4410336 7d30a02e9fa9a16d7d1f8d037ba69641 ""
"/usr/local/texlive/2022/texmf-var/web2c/pdftex/pdflatex.fmt" 1665017617 2826443 7e98410c533054b636c6470db83a27bc "" "/usr/local/texlive/2022/texmf-var/web2c/pdftex/pdflatex.fmt" 1665017617 2826443 7e98410c533054b636c6470db83a27bc ""
"/usr/local/texlive/2022/texmf.cnf" 1647878952 577 209b46be99c9075fd74d4c0369380e8c "" "/usr/local/texlive/2022/texmf.cnf" 1647878952 577 209b46be99c9075fd74d4c0369380e8c ""
"paper.aux" 1779488879 395 3d9d6ecb308d4771fc574ef59dbc631f "pdflatex" "fig_reduced_dual_step1.png" 1779490218 117795 4da7754ac28df9e809cfa1069e081c53 ""
"paper.tex" 1779488875 3976 7b376fa4f80996836d72b6d62b391567 "" "fig_reduced_dual_step2.png" 1779490218 96839 4f94c996220a2758dd0ff21ebdb9b2be ""
"fig_reduced_dual_step3.png" 1779490218 102877 d2a5db5532697441e3150e2ad26b9173 ""
"fig_reduced_dual_step4.png" 1779490218 107439 b30c7a68e32660f9bd3a8070bdb96944 ""
"paper.aux" 1779490219 1214 93cc6b97abaa1c8b9c54e346f15b0d5f "pdflatex"
"paper.tex" 1779490059 7089 91fabcb0498579524cd3a441fd2aa0f4 ""
(generated) (generated)
"paper.aux" "paper.aux"
"paper.log" "paper.log"
@@ -227,10 +227,32 @@ INPUT /usr/local/texlive/2022/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm1
INPUT /usr/local/texlive/2022/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm7.tfm INPUT /usr/local/texlive/2022/texmf-dist/fonts/tfm/public/amsfonts/symbols/msbm7.tfm
OUTPUT paper.pdf OUTPUT paper.pdf
INPUT /usr/local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map INPUT /usr/local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map
INPUT ./fig_reduced_dual_step1.png
INPUT ./fig_reduced_dual_step1.png
INPUT fig_reduced_dual_step1.png
INPUT ./fig_reduced_dual_step1.png
INPUT ./fig_reduced_dual_step1.png
INPUT ./fig_reduced_dual_step2.png
INPUT ./fig_reduced_dual_step2.png
INPUT fig_reduced_dual_step2.png
INPUT ./fig_reduced_dual_step2.png
INPUT ./fig_reduced_dual_step2.png
INPUT ./fig_reduced_dual_step3.png
INPUT ./fig_reduced_dual_step3.png
INPUT fig_reduced_dual_step3.png
INPUT ./fig_reduced_dual_step3.png
INPUT ./fig_reduced_dual_step3.png
INPUT ./fig_reduced_dual_step4.png
INPUT ./fig_reduced_dual_step4.png
INPUT fig_reduced_dual_step4.png
INPUT ./fig_reduced_dual_step4.png
INPUT ./fig_reduced_dual_step4.png
INPUT paper.aux INPUT paper.aux
INPUT /usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb INPUT /usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb
INPUT /usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmcsc10.pfb INPUT /usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmcsc10.pfb
INPUT /usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmex10.pfb
INPUT /usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb INPUT /usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb
INPUT /usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb
INPUT /usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb INPUT /usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb
INPUT /usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb INPUT /usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb
INPUT /usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr8.pfb INPUT /usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr8.pfb
@@ -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 18:27 This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 22 MAY 2026 18:50
entering extended mode entering extended mode
restricted \write18 enabled. restricted \write18 enabled.
%&-line parsing enabled. %&-line parsing enabled.
@@ -192,31 +192,63 @@ File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv
e e
)) ))
[1{/usr/local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] [1{/usr/local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map}]
[2] (./paper.aux) ) Overfull \hbox (41.917pt too wide) in paragraph at lines 143--145
[]\OT1/cmr/m/n/10 List the five degree-$2$ ver-tices in clock-wise or-der aroun
d $\OML/cmm/m/it/10 F$ \OT1/cmr/m/n/10 as $\OML/cmm/m/it/10 A \OT1/cmr/m/n/10 =
(\OML/cmm/m/it/10 A[]; A[]; A[]; A[]; A[]\OT1/cmr/m/n/10 )$.
[]
<fig_reduced_dual_step1.png, id=17, 517.79329pt x 499.08812pt>
File: fig_reduced_dual_step1.png Graphic file (type png)
<use fig_reduced_dual_step1.png>
Package pdftex.def Info: fig_reduced_dual_step1.png used on input line 163.
(pdftex.def) Requested size: 172.79846pt x 166.55775pt.
<fig_reduced_dual_step2.png, id=19, 490.16064pt x 483.35876pt>
File: fig_reduced_dual_step2.png Graphic file (type png)
<use fig_reduced_dual_step2.png>
Package pdftex.def Info: fig_reduced_dual_step2.png used on input line 164.
(pdftex.def) Requested size: 172.79846pt x 170.39505pt.
<fig_reduced_dual_step3.png, id=20, 490.16064pt x 483.35876pt>
File: fig_reduced_dual_step3.png Graphic file (type png)
<use fig_reduced_dual_step3.png>
Package pdftex.def Info: fig_reduced_dual_step3.png used on input line 165.
(pdftex.def) Requested size: 172.79846pt x 170.39505pt.
<fig_reduced_dual_step4.png, id=21, 490.16064pt x 486.3346pt>
File: fig_reduced_dual_step4.png Graphic file (type png)
<use fig_reduced_dual_step4.png>
Package pdftex.def Info: fig_reduced_dual_step4.png used on input line 166.
(pdftex.def) Requested size: 172.79846pt x 171.44409pt.
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>] (./paper.aux) )
Here is how much of TeX's memory you used: Here is how much of TeX's memory you used:
2983 strings out of 478268 3014 strings out of 478268
41531 string characters out of 5846347 42429 string characters out of 5846347
338080 words of memory out of 5000000 340098 words of memory out of 5000000
21033 multiletter control sequences out of 15000+600000 21059 multiletter control sequences out of 15000+600000
475666 words of font info for 53 fonts, out of 8000000 for 9000 475666 words of font info for 53 fonts, out of 8000000 for 9000
1302 hyphenation exceptions out of 8191 1302 hyphenation exceptions out of 8191
69i,8n,76p,242b,225s stack positions out of 10000i,1000n,20000p,200000b,200000s 69i,8n,76p,664b,225s stack positions out of 10000i,1000n,20000p,200000b,200000s
</usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfo </usr/local
nts/cm/cmbx10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfon /texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb></usr/local/
ts/cm/cmcsc10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfon texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmcsc10.pfb></usr/local/
ts/cm/cmmi10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfont texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmex10.pfb></usr/local/t
s/cm/cmr10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/ exlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb></usr/local/te
cm/cmr7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/ xlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb></usr/local/texl
cmr8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cms ive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb></usr/local/texliv
y10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy e/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb></usr/local/texlive/2
7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmti10 022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr8.pfb></usr/local/texlive/2022
.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmti8.p /texmf-dist/fonts/type1/public/amsfonts/cm/cmsy10.pfb></usr/local/texlive/2022/
fb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/symbols/msam texmf-dist/fonts/type1/public/amsfonts/cm/cmsy7.pfb></usr/local/texlive/2022/te
10.pfb> xmf-dist/fonts/type1/public/amsfonts/cm/cmti10.pfb></usr/local/texlive/2022/tex
Output written on paper.pdf (2 pages, 142068 bytes). mf-dist/fonts/type1/public/amsfonts/cm/cmti8.pfb></usr/local/texlive/2022/texmf
-dist/fonts/type1/public/amsfonts/symbols/msam10.pfb>
Output written on paper.pdf (3 pages, 490295 bytes).
PDF statistics: PDF statistics:
66 PDF objects out of 1000 (max. 8388607) 88 PDF objects out of 1000 (max. 8388607)
39 compressed objects within 1 object stream 48 compressed objects within 1 object stream
0 named destinations out of 1000 (max. 500000) 0 named destinations out of 1000 (max. 500000)
1 words of extra memory for PDF output out of 10000 (max. 10000000) 21 words of extra memory for PDF output out of 10000 (max. 10000000)
@@ -115,4 +115,63 @@ $G$, a contradiction.
Hence $\delta(G) \ge 5$. Hence $\delta(G) \ge 5$.
\end{proof} \end{proof}
\section{The reduced dual}
Write $G'$ for the dual of $G$: since $G$ is a triangulation, $G'$ is a cubic
plane graph in which each vertex of $G$ corresponds to a face of $G'$, each face
of $G$ to a vertex of $G'$, and each edge to a dual edge. A vertex of $G$ of
degree $k$ corresponds to a $k$-gonal face of $G'$.
By Lemma~\ref{lem:mindeg}, $\delta(G) \ge 5$, and Euler's formula gives
$\sum_{u \in V(G)}(6 - \deg u) = 12$, so $G$ has a vertex of degree exactly $5$
(indeed at least twelve). Fix such a vertex $v$. Its dual face $F_v$ is a
pentagon, bounded by the five dual vertices corresponding to the five faces of
$G$ incident to $v$.
\begin{definition}[Reduced dual]
\label{def:reduced-dual}
Let $v$ be a degree-$5$ vertex of $G$ with pentagonal dual face $F_v$, and fix an
index $i \in \{0,1,2,3,4\}$. The \emph{reduced dual} $\widehat{G}'_{v,i}$ is the
plane graph obtained from $G'$ as follows.
\begin{enumerate}
\item Delete the five dual vertices on the boundary of $F_v$, together with all
edges incident to them. Each deleted vertex is cubic, with two edges on
$\partial F_v$ and one edge leaving $F_v$; deleting the five boundary
vertices therefore removes the five external edges as well, dropping their
five outer endpoints from degree $3$ to degree $2$. These five degree-$2$
vertices lie on the boundary of a single face $F$ of the resulting graph.
\item List the five degree-$2$ vertices in clockwise order around $F$ as
$A = (A_0, A_1, A_2, A_3, A_4)$.
\item Add a new vertex $v_n$ and join it to $A_i$, $A_{i+1}$, and $A_{i+2}$
(indices mod $5$) by three new edges.
\item Add a new edge between $A_{i+3}$ and $A_{i+4}$ (indices mod $5$).
\end{enumerate}
\end{definition}
\begin{remark}
Steps (3) and (4) restore cubicity: $A_i, A_{i+1}, A_{i+2}$ each gain one edge to
$v_n$ and $A_{i+3}, A_{i+4}$ each gain the new edge, so all five return to degree
$3$, and $v_n$ has degree $3$. Since $A_i,\dots,A_{i+2}$ and $A_{i+3}, A_{i+4}$
are each consecutive along $\partial F$, the new vertex and edge can be drawn
inside $F$ without crossings, so $\widehat{G}'_{v,i}$ is again a cubic plane
graph. The construction depends on the choice of $i$ up to the rotational
symmetry of $A$.
\end{remark}
\begin{figure}[h]
\centering
\includegraphics[width=0.48\textwidth]{fig_reduced_dual_step1.png}\hfill
\includegraphics[width=0.48\textwidth]{fig_reduced_dual_step2.png}\\[0.5em]
\includegraphics[width=0.48\textwidth]{fig_reduced_dual_step3.png}\hfill
\includegraphics[width=0.48\textwidth]{fig_reduced_dual_step4.png}
\caption{The four steps of Definition~\ref{def:reduced-dual}, 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
$\widehat{G}'_{v,0}$.}
\label{fig:reduced-dual-steps}
\end{figure}
\end{document} \end{document}