codexgreedy-coloring-order.py
greedy-coloring-order.py
"""Draw greedy-coloring-order.png in cwd; tested with Python 3.14.4.
Uses Matplotlib and verifies every vertex order of P4 with standard-library enumeration.
"""
from collections import Counter
from itertools import permutations, product
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
EDGES = ((1, 2), (2, 3), (3, 4))
PALETTE = {1: "#9ed8f0", 2: "#ffd38a", 3: "#cebbeb"}
ORDERS = ((1, 2, 3, 4), (1, 4, 2, 3))
def greedy(order):
colors = {}
for vertex in order:
neighbors = {v if u == vertex else u for u, v in EDGES if vertex in (u, v)}
forbidden = {colors[v] for v in neighbors if v in colors}
color = 1
while color in forbidden:
color += 1
colors[vertex] = color
return colors
def check_examples():
assert greedy(ORDERS[0]) == {1: 1, 2: 2, 3: 1, 4: 2}
assert greedy(ORDERS[1]) == {1: 1, 4: 1, 2: 2, 3: 3}
counts = Counter()
for order in permutations(range(1, 5)):
colors = greedy(order)
assert all(colors[u] != colors[v] for u, v in EDGES)
assert max(colors.values()) <= 3
counts[max(colors.values())] += 1
assert sum(counts.values()) == 24
degrees = [sum(v in edge for edge in EDGES) for v in range(1, 5)]
assert degrees == [1, 2, 2, 1]
colorings = [sum(all(colors[u - 1] != colors[v - 1] for u, v in EDGES)
for colors in product(range(k), repeat=4)) for k in (1, 2)]
assert colorings == [0, 2]
print(f"Verified both assignments and all 24 P4 orders: {dict(sorted(counts.items()))}.")
print("Verified P4 has chromatic number 2, maximum degree 2, and greedy bound 3.")
def main():
check_examples()
plt.rcParams.update({"font.size": 12, "font.family": "DejaVu Sans"})
fig, axes = plt.subplots(2, 1, figsize=(8.4, 5.0), facecolor="white")
fig.suptitle("Same path, different greedy orders", fontsize=19, y=0.97)
for ax, order in zip(axes, ORDERS):
colors = greedy(order)
steps = {v: i + 1 for i, v in enumerate(order)}
ax.plot([1, 4], [0, 0], color="#46515c", linewidth=3, zorder=1)
for vertex in range(1, 5):
ax.add_patch(Circle((vertex, 0), 0.17, facecolor=PALETTE[colors[vertex]],
edgecolor="#24313d", linewidth=1.5, zorder=2))
ax.text(vertex, 0, str(colors[vertex]), ha="center", va="center", fontsize=14)
ax.text(vertex, 0.33, f"vertex {vertex}", ha="center", va="center", fontsize=11)
ax.text(vertex, -0.34, f"step {steps[vertex]}", ha="center", va="center", fontsize=11)
ax.set_title("Order " + " → ".join(map(str, order))
+ f" | {max(colors.values())} colours", fontsize=14, pad=7)
ax.text(2.5, -0.72, "Assignments in processing order: "
+ ", ".join(f"c({v})={colors[v]}" for v in order),
ha="center", va="center", fontsize=11)
ax.set(xlim=(0.5, 4.5), ylim=(-0.9, 0.58), aspect="equal", facecolor="white")
ax.axis("off")
fig.text(0.5, 0.035, "Number inside each dot: assigned colour • Edges: 1–2, 2–3, 3–4",
ha="center", fontsize=11, color="#46515c")
fig.subplots_adjust(left=0.035, right=0.965, bottom=0.1, top=0.81, hspace=0.68)
fig.savefig(Path(__file__).with_suffix(".png").name, dpi=120, facecolor="white",
transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()