kleine Änderungen

This commit is contained in:
dschlueter 2026-09-09 07:37:07 +02:00
commit dc088fa214
47 changed files with 183868 additions and 573 deletions

View file

@ -91,9 +91,43 @@ def loese() -> tuple[list[tuple[int, int, int, int]], int]:
return plan, loeser.Value(makespan)
def untere_schranke() -> int:
"""Wie in JobShop_Intervalle.py: laengster Auftrag bzw. hoechste Maschinenlast.
Kein Plan kann kuerzer sein als der laengste Auftrag (seine Schritte laufen
nacheinander) und auch nicht kuerzer als die am staerksten belegte Maschine
(ihre Schritte koennen sich nicht ueberlappen)."""
je_auftrag = max(sum(dauer for _, dauer in auftrag)
for auftrag in AUFTRAEGE)
last = [0] * len(MASCHINENNAMEN)
for auftrag in AUFTRAEGE:
for maschine, dauer in auftrag:
last[maschine] += dauer
return max(je_auftrag, max(last))
def stillstaende(plan):
"""Luecken ZWISCHEN zwei Arbeitsgaengen derselben Maschine.
Nur die inneren: Was eine Maschine vor ihrem ersten oder nach ihrem letzten
Arbeitsgang tut, ist keine Luecke im Plan, sondern sein Rand."""
luecken = []
for maschine in range(len(MASCHINENNAMEN)):
zeiten = sorted((beginn, beginn + dauer)
for _, m, beginn, dauer in plan if m == maschine)
for (_, ende), (naechster_beginn, _) in zip(zeiten, zeiten[1:]):
if naechster_beginn > ende:
luecken.append((maschine, ende, naechster_beginn))
return luecken
def zeichne_statisch(plan, makespan: int) -> None:
"""Matplotlib-Fassung fuer das PDF."""
figur, achse = plt.subplots(figsize=(9.0, 3.2))
figur, achse = plt.subplots(figsize=(9.0, 3.4))
for maschine, von, bis in stillstaende(plan):
achse.barh(y=maschine, width=bis - von, left=von, height=0.55,
facecolor="none", edgecolor="#be123c", linewidth=1.2,
hatch="///", zorder=2)
for auftrag, maschine, beginn, dauer in plan:
achse.barh(y=maschine, width=dauer, left=beginn, height=0.55,
color=FARBEN[auftrag % len(FARBEN)],
@ -108,7 +142,21 @@ def zeichne_statisch(plan, makespan: int) -> None:
achse.set_xlabel("Zeiteinheiten")
achse.set_xlim(0, makespan)
achse.set_xticks(range(makespan + 1))
achse.set_title(f"Job-Shop-Plan, Makespan = {makespan}", fontsize=11)
schranke = untere_schranke()
achse.axvline(schranke, color="#059669", linestyle="--", linewidth=1.5,
zorder=5)
# x in Datenkoordinaten, y als Anteil der Achsenhoehe: Die y-Achse ist
# umgekehrt, ein fester y-Wert laege sonst ausserhalb des Bildes.
unten = achse.get_xaxis_transform()
# Der Makespan steht schon im Titel - hier nur die Schranke, sonst
# stossen beide Beschriftungen aneinander.
achse.text(schranke - 0.12, 0.03, f"untere Schranke {schranke}",
transform=unten, fontsize=8.5, color="#059669", ha="right",
va="bottom", zorder=6)
achse.set_title(f"Job-Shop-Plan: Makespan {makespan}, untere Schranke "
f"{schranke} — schraffiert steht die Maschine still",
fontsize=11)
achse.grid(axis="x", linestyle=":", alpha=0.5)
for rand in ("top", "right", "left"):
achse.spines[rand].set_visible(False)
@ -170,6 +218,40 @@ def zeichne_interaktiv(plan, makespan: int) -> None:
if __name__ == "__main__":
plan, makespan = loese()
print(f"Makespan: {makespan}")
schranke = untere_schranke()
print(f"Makespan: {makespan}, untere Schranke: {schranke}")
for maschine, von, bis in stillstaende(plan):
print(f" Stillstand: {MASCHINENNAMEN[maschine]} von {von} bis {bis}")
# Gegenprobe zu den Zahlen, die das Kapitel abdruckt.
if schranke > makespan:
raise SystemExit(f"Gantt: Die untere Schranke {schranke} liegt ueber "
f"dem Makespan {makespan} - eine der beiden Zahlen "
f"ist falsch.")
if (schranke, makespan) != (10, 11):
raise SystemExit(f"Gantt: Schranke {schranke} / Makespan {makespan}; "
f"das Kapitel druckt 10 / 11 ab.")
if not any(m == 1 and von == 4 for m, von, _ in stillstaende(plan)):
raise SystemExit("Gantt: Die Luecke in der Dreherei bei Zeitpunkt 4 "
"fehlt - der Text daneben bespricht genau sie.")
# Der Text daneben rechnet vor: Die Engpassmaschine ist von 0 bis zum
# Makespan belegt, ihre Arbeit ist die Schranke, der Rest Stillstand.
last = [0] * len(MASCHINENNAMEN)
for auftrag in AUFTRAEGE:
for maschine, dauer in auftrag:
last[maschine] += dauer
engpass = last.index(max(last))
leerlauf = sum(bis - von for m, von, bis in stillstaende(plan)
if m == engpass)
if last[engpass] + leerlauf != makespan:
raise SystemExit(
f"Gantt: {MASCHINENNAMEN[engpass]} arbeitet {last[engpass]} und "
f"steht {leerlauf} still, zusammen "
f"{last[engpass] + leerlauf} statt {makespan}. Der Text daneben "
f"rechnet genau diese Summe vor.")
print(f" Engpass {MASCHINENNAMEN[engpass]}: {last[engpass]} Arbeit + "
f"{leerlauf} Stillstand = {makespan}")
zeichne_statisch(plan, makespan)
zeichne_interaktiv(plan, makespan)