codexmobius-divisor-cancellation.py
mobius-divisor-cancellation.py
"""Draw the subset cube of divisors of 30; write a basename PNG to cwd.
Tested with Python 3.14.4 and Matplotlib 3.10.7.
Reproduce: make _media/mobius-divisor-cancellation.png
"""
from itertools import product
from math import prod
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
def main():
primes = (2, 3, 5)
vertices = list(product((0, 1), repeat=3))
divisors = {v: prod(p for p, bit in zip(primes, v) if bit)
for v in vertices}
weights = {v: (-1) ** sum(v) for v in vertices}
assert sorted(divisors.values()) == [1, 2, 3, 5, 6, 10, 15, 30]
assert sum(weights.values()) == 0
assert all(weights[v] == -weights[(1, v[1], v[2])]
for v in vertices if v[0] == 0)
ink, positive, negative = "#243746", "#176997", "#b45325"
positions = {v: (2.4 * v[0] + 0.95 * v[1],
0.9 * v[1] + 2.25 * v[2]) for v in vertices}
fig, (ax, key) = plt.subplots(
1, 2, figsize=(9.8, 5.4), dpi=110, facecolor="white",
gridspec_kw={"width_ratios": [1.6, 1]})
for v in vertices:
for i in range(3):
if v[i]:
continue
w = tuple(1 if j == i else bit for j, bit in enumerate(v))
x, y = positions[v]
end_x, end_y = positions[w]
ax.plot([x, end_x], [y, end_y],
color="#71899a" if i == 0 else "#c4ced5",
lw=2.2 if i == 0 else 1.5,
linestyle="--" if i == 1 else "-", zorder=1)
for v in vertices:
x, y = positions[v]
sign = "+1" if weights[v] == 1 else "−1"
ax.text(x, y, f"d = {divisors[v]}\nμ(d) = {sign}",
ha="center", va="center", fontsize=12, zorder=3,
color=positive if weights[v] == 1 else negative,
bbox={"boxstyle": "round,pad=0.48", "linewidth": 1.3,
"edgecolor": positive if weights[v] == 1 else negative,
"facecolor": "#edf5fa" if weights[v] == 1 else "#fff2e9"})
ax.text(1.2, -0.51, "insert 2 → sign flips", ha="center", color=ink,
fontsize=11)
ax.set(xlim=(-0.58, 3.93), ylim=(-0.78, 3.72))
ax.set_aspect("equal")
ax.axis("off")
ax.set_title("Each node selects a subset of {2, 3, 5}", fontsize=13,
color=ink, pad=12)
key.axis("off")
key.text(0.5, 0.95, "Pair by inserting 2", fontsize=14, weight="bold",
ha="center", color=ink)
for row, pair in enumerate(((1, 2), (3, 6), (5, 10), (15, 30))):
y = 0.79 - row * 0.145
key.text(0.5, y, f"μ({pair[0]}) + μ({pair[1]}) = 0", fontsize=13,
ha="center", color=ink)
key.text(0.5, 0.13, r"$1-3+3-1=0$", fontsize=18,
ha="center", color=ink)
key.text(0.5, 0.01, r"$(1-1)^3=0$", fontsize=18,
ha="center", color=ink)
fig.suptitle("Möbius weights cancel over the divisors of 30",
fontsize=17, color=ink, y=0.97)
fig.text(0.5, 0.035, "Every edge inserts one prime. Blue: +1; orange: −1.",
ha="center", fontsize=12, color=ink)
fig.subplots_adjust(left=0.03, right=0.985, bottom=0.14,
top=0.82, wspace=0.13)
fig.savefig(Path.cwd() / Path(__file__).with_suffix(".png").name,
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()