codexline-breaking-global-choice.py
line-breaking-global-choice.py
"""Compare greedy and optimal breaks in an original fixed-width toy model."""
from pathlib import Path
import math
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
WIDTHS = (3, 2, 2, 5)
LIMIT = 7
COLORS = ("#347ea8", "#329185", "#cb8742", "#8866a7")
def length(group):
return sum(WIDTHS[i] for i in group) + len(group) - 1
def greedy():
lines, current = [], []
for i in range(len(WIDTHS)):
if current and length(current + [i]) > LIMIT:
lines.append(current)
current = []
current.append(i)
return lines + [current]
def optimum():
n = len(WIDTHS)
costs, previous = [0] + [math.inf] * n, [None] * (n + 1)
for end in range(1, n + 1):
for start in range(end):
extent = length(range(start, end))
if extent <= LIMIT:
candidate = costs[start] + (0 if end == n else (LIMIT - extent) ** 2)
if candidate < costs[end]:
costs[end], previous[end] = candidate, start
groups, end = [], n
while end:
start = previous[end]
groups.append(list(range(start, end)))
end = start
return list(reversed(groups))
def main():
fig, axes = plt.subplots(1, 2, figsize=(9, 4.6), dpi=100, facecolor="white")
fig.subplots_adjust(left=0.045, right=0.98, bottom=0.2, top=0.76, wspace=0.25)
fig.suptitle("Choosing breaks for the whole paragraph", y=0.97,
fontsize=16, weight="bold", color="#172330")
fig.text(0.5, 0.885, "Word widths: (3, 2, 2, 5); spaces: 1; maximum line width: 7",
ha="center", fontsize=11, color="#45535d")
for ax, groups, name in zip(axes, [greedy(), optimum()],
["Greedy choice", "Global optimum"]):
total = sum((LIMIT - length(g)) ** 2 for g in groups[:-1])
ax.set_title(f"{name}: total cost {total}", fontsize=12, pad=17)
for row, group in enumerate(groups):
y = 3 - row
ax.add_patch(Rectangle((0, y - 0.27), LIMIT, 0.54,
facecolor="#f2f4f6", edgecolor="#9aabb5",
linewidth=1, linestyle="--"))
x = 0
for index in group:
width = WIDTHS[index]
ax.add_patch(Rectangle((x, y - 0.27), width, 0.54,
facecolor=COLORS[index], edgecolor="white"))
ax.text(x + width / 2, y, f"word {index + 1}",
ha="center", va="center", color="white", fontsize=10)
x += width + 1
cost = (LIMIT - length(group)) ** 2
label = f"cost {cost}" if row < len(groups) - 1 else "free"
ax.text(7.16, y, label, va="center", fontsize=10, color="#45535d")
ax.set_xlim(-0.1, 8.5)
ax.set_ylim(0.4, 3.65)
ax.set_xticks(range(8))
ax.set_yticks([])
ax.tick_params(axis="x", labelsize=9)
for side in ["left", "right", "top"]:
ax.spines[side].set_visible(False)
ax.spines["bottom"].set_color("#9aabb5")
fig.text(0.5, 0.115, "Cost = squared unused width; the final line is unpenalized.",
ha="center", fontsize=11, color="#172330")
fig.text(0.5, 0.045, "Original schematic with hypothetical widths and a simplified cost function.",
ha="center", fontsize=10, color="#45535d")
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), dpi=100,
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()