codexchinese-remainder-residue-grids.py
chinese-remainder-residue-grids.py
"""Draw coprime and noncoprime residue-pair grids into the current directory."""
from math import gcd, lcm
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
def residue_grid(ax, m, n, highlight, title):
period = lcm(m, n)
pairs = {(x % m, x % n): x for x in range(period)}
assert len(pairs) == period
assert all((r - s) % gcd(m, n) == 0 for r, s in pairs)
assert (highlight % m, highlight % n) in pairs
for r in range(m):
for s in range(n):
attainable = (r, s) in pairs
selected = attainable and pairs[(r, s)] == highlight
color = "#18844f" if selected else "#e0edf6" if attainable else "#ededed"
ax.add_patch(Rectangle((r - 0.5, s - 0.5), 1, 1, facecolor=color,
edgecolor="white", linewidth=2))
if attainable:
ax.text(r, s, str(pairs[(r, s)]), ha="center", va="center",
color="white" if selected else "#194665",
fontsize=13 if m == 3 else 11, fontweight="bold" if selected else "normal")
else:
ax.text(r, s, "×", ha="center", va="center", color="#969696", fontsize=14)
ax.set_xticks(range(m))
ax.set_yticks(range(n))
ax.set_xlabel(f"Remainder modulo {m}")
ax.set_ylabel(f"Remainder modulo {n}")
ax.set_xlim(-0.5, m - 0.5)
ax.set_ylim(-0.5, n - 0.5)
ax.set_aspect("equal")
ax.set_title(title, fontsize=14, pad=13)
ax.tick_params(length=0)
for spine in ax.spines.values():
spine.set_visible(False)
return pairs
def main():
plt.rcParams.update({"font.size": 12})
fig, axes = plt.subplots(1, 2, figsize=(10, 5.3), dpi=120)
fig.patch.set_facecolor("white")
pairs = residue_grid(axes[0], 3, 5, 8, "3 and 5: all 15 pairs occur")
assert pairs[(2, 3)] == 8
pairs = residue_grid(axes[1], 6, 8, 19, "6 and 8: only 24 compatible pairs")
assert pairs[(1, 3)] == 19
assert (1, 2) not in pairs
fig.text(0.28, 0.075, "Numbers in cells are representatives modulo 15", ha="center", fontsize=10)
fig.text(0.75, 0.075, "Representatives modulo 24; × means impossible", ha="center", fontsize=10)
fig.subplots_adjust(left=0.07, right=0.96, top=0.90, bottom=0.19, wspace=0.26)
output = Path.cwd() / Path(__file__).with_suffix(".png").name
fig.savefig(output, facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()