Kapitel 4: Vom Management-Wunsch zum Modell
📌 Kapitel auf einen Blick
Worum geht es? Um den Schritt, der vor jedem Solver kommt und über den kaum ein Lehrbuch spricht: aus einem Satz in einer Besprechung ein Modell zu machen. Genau hier scheitern Projekte — nicht an der Mathematik.
Voraussetzungen: Kapitel 1 (die vier Bausteine eines Modells). Kein Solverwissen nötig; das ganze Kapitel kommt mit einer einzigen
linprog-Zeile aus.Danach können Sie: eine Anforderung daraufhin abklopfen, was sie nicht sagt; die Zielgröße so wählen, dass sie keinen Fehlanreiz setzt; harte von weichen Regeln unterscheiden — und begründen, warum diese Unterscheidung ein Jahr später über die Betriebsfähigkeit entscheidet.
Zeitbedarf: ca. 3 Stunden.
Programme:
Vom_Wunsch_zum_Modell.pyNotebook: modellierung.ipynb — herunterladen und in Jupyter öffnen, in Colab hochladen oder mit dem Kurs-Image starten
4.1 In 5 Minuten gelöst
🚀 In 5 Minuten gelöst: „Maximieren Sie den Umsatz”
Eine Lohnfertigung hat fünf Anfragen und 60 freie Maschinenstunden. Die Anfragen verlangen zusammen 160 Stunden — es muss ausgewählt werden.
Auftrag Stunden Umsatz Material Deckungsbeitrag A 60 60 000 € 55 000 € 5 000 € B 30 22 000 € 12 000 € 10 000 € C 30 20 000 € 11 000 € 9 000 € D 25 18 000 € 9 000 € 9 000 € E 15 12 000 € 7 000 € 5 000 € import numpy as np from scipy.optimize import [linprog](anhang-glossar.md#gloss:linprog){.glossar-link} # Auftrag: A B C D E stunden = np.array([ 60, 30, 30, 25, 15], dtype=float) umsatz = np.array([ 60_000, 22_000, 20_000, 18_000, 12_000], dtype=float) material = np.array([ 55_000, 12_000, 11_000, 9_000, 7_000], dtype=float) KAPAZITAET = 60 # Maschinenstunden; die Anfragen verlangen 160 waehle = lambda ziel: np.round(linprog( -ziel, A_ub=[stunden], b_ub=[KAPAZITAET], bounds=(0, 1), integrality=1, method="highs").x).astype(int) for wunsch, ziel in [("Umsatz maximieren", umsatz), ("Deckungsbeitrag maximieren", umsatz - material)]: plan = waehle(ziel) print(f"{wunsch:<27} -> {''.join(b for b, ja in zip('ABCDE', plan) if ja):<5}" f" Umsatz {umsatz @ plan:>7,.0f} DB {(umsatz - material) @ plan:>6,.0f}")Ausgabe:
Umsatz maximieren -> A Umsatz 60,000 DB 5,000 Deckungsbeitrag maximieren -> BD Umsatz 40,000 DB 19,000
Und jetzt der Punkt. Beide Modelle sind korrekt. Beide Pläne sind zulässig. Beide sind optimal — nur für verschiedene Fragen.
Wer „Umsatz maximieren” sagt, bekommt Auftrag A: 60 000 € Umsatz und 5 000 € Deckungsbeitrag. Wer „Deckungsbeitrag maximieren” sagt, bekommt B und D: 20 000 € weniger Umsatz und 14 000 € mehr Ergebnis. Der Umsatzplan verkauft die gesamte Kapazität für eine Marge von 8 %.
Niemand in der Besprechung hätte behauptet, Umsatz sei wichtiger als Ertrag. Der Satz „maximieren Sie den Umsatz” ist trotzdem gefallen, weil Umsatz die Zahl ist, die im Monatsbericht steht.
🎯 Merksatz Ein Modell rechnet nicht aus, was man will, sondern was man aufgeschrieben hat. Die Differenz zwischen beidem ist die eigentliche Arbeit dieses Kapitels.
Warum funktioniert das? Weil eine Zielfunktion eine vollständige Aussage darüber ist, was zählt. Alles, was nicht darin steht, ist dem Modell gleichgültig — nicht „weniger wichtig”, sondern wertlos. Der Umsatzplan opfert den Deckungsbeitrag nicht aus Bosheit; er sieht ihn schlicht nicht.
4.2 Lernziele
Nach diesem Kapitel können Sie …
- … erklären, warum die Zielgröße die folgenreichste Entscheidung eines OR-Projekts ist — folgenreicher als die Wahl des Solvers.
- … die vier Fragen stellen, die aus einer Anforderung ein Modell machen.
- … erkennen, dass ein Satz wie „Stammkunden dürfen wir nicht verlieren” mehrere Lesarten hat, und den Unterschied in Euro beziffern.
- … begründen, wann eine Regel hart und wann sie weich sein muss — und was eine harte Regel im Betrieb anrichtet, wenn sie einmal nicht erfüllbar ist.
- … einen Kennzahlen-Fehlanreiz benennen, bevor er in die Zielfunktion gerät.
- … einen Satz aus einer Besprechung in den passenden Modellierungsbaustein übersetzen — und die fünf Wendungen erkennen, bei denen genau das nicht geht, ohne vorher nachzufragen.
4.3 Ein Satz ist noch kein Modell
Was aus einer Besprechung mitkommt, klingt meist so:
„Wir müssen die Maschinen besser auslasten. Und die Stammkunden dürfen wir nicht verlieren.”
Zwei Sätze, aus denen ein Modell werden soll. Sie enthalten: keine Entscheidungsvariable, keine messbare Zielgröße, keine Nebenbedingung. Sie enthalten nicht einmal genug, um zu erkennen, was entschieden werden soll.
Der Weg dorthin führt über vier Fragen. Sie sind unspektakulär, und genau deshalb werden sie übersprungen.
| # | Frage | Was ohne sie passiert |
|---|---|---|
| 1 | Worüber wird entschieden? Welche Größen kann der Betrieb tatsächlich festlegen? | Man modelliert Dinge, die gar nicht zur Disposition stehen — oder übersieht die eine Stellschraube, um die es geht. |
| 2 | Woran wird der Erfolg gemessen? Welche Zahl steht am Jahresende im Bericht? | Man optimiert eine Kennzahl, die niemanden interessiert — oder eine, deren Maximierung schadet. |
| 3 | Was ist unverhandelbar, was nur unerwünscht? | Jede unnötig harte Regel ist eine Zeitbombe: Irgendwann ist sie nicht erfüllbar, und das System antwortet gar nicht mehr. |
| 4 | Was passiert, wenn es nicht geht? | Der Nachtlauf bricht ab, und niemand weiß, welche Regel schuld war. |
📖 Zur zweiten Frage
Sie ist absichtlich anders gestellt als „Was ist Ihnen wichtig?“. Auf diese Frage antwortet jeder Betrieb mit einer Liste, in der alles wichtig ist. Die brauchbare Frage lautet: Welche Zahl steht am Jahresende im Bericht, und wer wird danach beurteilt?
Die Antwort ist unbequem und aufschlussreich — und sie erklärt, warum in der Besprechung „Umsatz” gesagt wird, obwohl „Deckungsbeitrag” gemeint ist.
4.4 Derselbe Datensatz, fünf Modelle
Das Programm dieses Kapitels arbeitet die vier Fragen an einer Auftragsannahme ab: 14 Anfragen verlangen 800 Maschinenstunden, verfügbar sind 300.
Es ist bewusst das einfachste Modell des ganzen Buchs — eine Binärvariable je Auftrag, eine Nebenbedingung. Alles, was sich zwischen den fünf Varianten ändert, ist die Frage.
#!/usr/bin/env python3
# Vom_Wunsch_zum_Modell.py
"""
Kapitel Modellierung: Derselbe Datensatz, fuenf zulaessige Modelle, fuenf andere Plaene.
Eine Lohnfertigung kann nicht alle Anfragen annehmen: 14 Auftraege verlangen
zusammen 800 Maschinenstunden, verfuegbar sind 300. Es muss also ausgewaehlt
werden. Die Daten stehen fest - was FEHLT, ist die Frage.
Das Programm zeigt in vier Teilen, was daran haengt:
1. Drei naheliegende Ziele aus dem Managementgespraech ("Umsatz", "Auslastung",
"Deckungsbeitrag") - und wie weit die Plaene auseinanderlaufen.
2. Der Satz "Stammkunden duerfen wir nicht verlieren" in drei Lesarten. Alle
drei sind vertretbar, alle drei kosten unterschiedlich viel.
3. Was ein Strafgewicht daraus macht - und ab wann es dasselbe tut wie eine
harte Regel.
4. Was die harte Lesart ein Quartal spaeter anrichtet.
Der Punkt des Kapitels: Nicht die Daten bestimmen das Modell, sondern die
Frage. Und die steht selten in der Anforderung.
Benoetigt: numpy, scipy
"""
from __future__ import annotations
import numpy as np
from scipy.optimize import linprog
# (Nummer, Kunde, Stammkunde?, Maschinenstunden, Umsatz, Materialkosten)
AUFTRAEGE = [
("A-101", "Weber GmbH", True, 40, 28_000, 19_000),
("A-102", "Weber GmbH", True, 25, 15_000, 9_500),
("A-103", "Kranz AG", True, 60, 33_000, 24_000),
("A-104", "Kranz AG", True, 35, 19_000, 13_500),
("A-105", "Obermeier KG", True, 20, 12_000, 7_000),
("A-106", "Siedler & Co", False, 120, 84_000, 71_000),
("A-107", "Siedler & Co", False, 110, 74_000, 63_000),
("A-108", "Novatek", False, 95, 61_000, 52_000),
("A-109", "Novatek", False, 30, 31_000, 17_000),
("A-110", "Hellwig", False, 15, 17_000, 8_000),
("A-111", "Hellwig", False, 55, 41_000, 30_000),
("A-112", "Pfeiffer Werke", False, 80, 46_000, 39_000),
("A-113", "Obermeier KG", True, 45, 26_000, 17_000),
("A-114", "Pfeiffer Werke", False, 70, 52_000, 36_000),
]
KAPAZITAET = 300 # Maschinenstunden im Planungszeitraum
STUNDEN = np.array([a[3] for a in AUFTRAEGE], dtype=float)
UMSATZ = np.array([a[4] for a in AUFTRAEGE], dtype=float)
DECKUNGSBEITRAG = np.array([a[4] - a[5] for a in AUFTRAEGE], dtype=float)
IST_STAMM = np.array([a[2] for a in AUFTRAEGE])
STAMMKUNDEN = sorted({a[1] for a in AUFTRAEGE if a[2]})
def waehle_aus(ziel: np.ndarray, zusatz_ub=None, zusatz_b_ub=None,
zusatz_eq=None, zusatz_b_eq=None, auftraege=AUFTRAEGE,
stunden=STUNDEN, kapazitaet=KAPAZITAET):
"""Ein Auftrag wird angenommen oder nicht - mehr Modell ist das nicht.
Der ganze Unterschied zwischen den fuenf Varianten unten steckt in 'ziel'
und in den Zusatzbedingungen. Das Modell selbst bleibt dasselbe.
"""
ergebnis = linprog(
-ziel,
A_ub=[stunden] + (zusatz_ub or []),
b_ub=[kapazitaet] + (zusatz_b_ub or []),
A_eq=zusatz_eq, b_eq=zusatz_b_eq,
bounds=(0, 1), integrality=1, method="highs")
if not ergebnis.success:
return None
return np.round(ergebnis.x).astype(int)
def kennzahlen(plan, auftraege=AUFTRAEGE, stunden=STUNDEN, umsatz=UMSATZ,
db=DECKUNGSBEITRAG, ist_stamm=IST_STAMM, kapazitaet=KAPAZITAET):
"""Immer dieselben fuenf Zahlen - nur so sind die Varianten vergleichbar."""
abgelehnte_stammauftraege = int(((1 - plan) & ist_stamm.astype(int)).sum())
leer_ausgegangen = sum(
1 for kunde in sorted({a[1] for a in auftraege if a[2]})
if not any(plan[i] for i, a in enumerate(auftraege) if a[1] == kunde))
return {"umsatz": float(umsatz @ plan), "db": float(db @ plan),
"auslastung": float(stunden @ plan) / kapazitaet * 100,
"stamm_abgelehnt": abgelehnte_stammauftraege,
"kunden_leer": leer_ausgegangen, "angenommen": int(plan.sum())}
def zeile(name: str, plan) -> None:
if plan is None:
print(f" {name:<34} {'UNZULAESSIG - kein Plan moeglich':>44}")
return
k = kennzahlen(plan)
print(f" {name:<34} {k['umsatz']:>10,.0f} {k['db']:>9,.0f} "
f"{k['auslastung']:>6.0f}% {k['stamm_abgelehnt']:>7} "
f"{k['kunden_leer']:>6} {k['angenommen']:>7}")
def kopfzeile() -> None:
print(f" {'':<34} {'Umsatz':>10} {'DB':>9} {'Aus-':>7} {'Stamm-':>7} "
f"{'Kunden':>6} {'ange-':>7}")
print(f" {'':<34} {'':>10} {'':>9} {'lastung':>7} {'auftr.':>7} "
f"{'ohne':>6} {'nommen':>7}")
print(" " + "-" * 78)
if __name__ == "__main__":
print("=" * 84)
print(" VOM MANAGEMENT-WUNSCH ZUM MODELL")
print("=" * 84)
print(f"{len(AUFTRAEGE)} Anfragen verlangen {STUNDEN.sum():.0f} Maschinenstunden, "
f"verfuegbar sind {KAPAZITAET}.")
print(f"Es muss also ausgewaehlt werden. {len(STAMMKUNDEN)} der Kunden sind "
f"Stammkunden:")
print(f" {', '.join(STAMMKUNDEN)}\n")
# --- 1. Drei Saetze aus dem Gespraech, drei Ziele ---------------------
print("-" * 84)
print("1. Was im Gespraech gesagt wurde - drei naheliegende Ziele\n")
kopfzeile()
plaene = {}
for name, ziel in [("\"Umsatz maximieren\"", UMSATZ),
("\"Maschinen besser auslasten\"", STUNDEN),
("\"Deckungsbeitrag maximieren\"", DECKUNGSBEITRAG)]:
plaene[name] = waehle_aus(ziel)
zeile(name, plaene[name])
umsatzplan = kennzahlen(plaene["\"Umsatz maximieren\""])
auslastungsplan = kennzahlen(plaene["\"Maschinen besser auslasten\""])
dbplan = kennzahlen(plaene["\"Deckungsbeitrag maximieren\""])
mehr_umsatz = umsatzplan["umsatz"] - dbplan["umsatz"]
weniger_db = dbplan["db"] - umsatzplan["db"]
print(f"\n Der Umsatzplan bringt {mehr_umsatz:,.0f} EUR mehr Umsatz und "
f"{weniger_db:,.0f} EUR WENIGER")
print(f" Deckungsbeitrag. Fuer {mehr_umsatz:,.0f} EUR Umsatz werden also "
f"{weniger_db:,.0f} EUR Ergebnis")
print(f" aufgegeben - und {umsatzplan['stamm_abgelehnt']} von "
f"{int(IST_STAMM.sum())} Stammkundenauftraegen dazu.")
print()
print(" \"Auslastung\" ist der haeufigste Wunsch und der schaedlichste. Der")
print(f" darauf optimierte Plan bringt {dbplan['db'] - auslastungsplan['db']:,.0f} EUR weniger "
f"Deckungsbeitrag und")
print(f" {dbplan['umsatz'] - auslastungsplan['umsatz']:,.0f} EUR weniger Umsatz als der "
f"DB-Plan - und erreicht dabei")
print(f" nicht einmal mehr Auslastung: alle drei liegen bei "
f"{dbplan['auslastung']:.0f} %.")
print(" Eine volle Maschine ist eben kein Ziel, sondern ein Nebenprodukt.")
# --- 2. Ein Satz, drei Lesarten --------------------------------------
print("\n" + "-" * 84)
print("2. \"Stammkunden duerfen wir nicht verlieren\" - aber was heisst das?\n")
kopfzeile()
zeile("ohne die Regel (DB maximieren)", waehle_aus(DECKUNGSBEITRAG))
# Lesart A: jeder Stammkundenauftrag wird angenommen
alle_stamm = [[1.0 if IST_STAMM[i] else 0.0 for i in range(len(AUFTRAEGE))]]
lesart_a = waehle_aus(DECKUNGSBEITRAG, zusatz_eq=alle_stamm,
zusatz_b_eq=[float(IST_STAMM.sum())])
zeile("A: jeden Stammauftrag annehmen", lesart_a)
# Lesart B: kein Stammkunde geht leer aus (mindestens ein Auftrag je Kunde)
je_kunde_ub, je_kunde_b = [], []
for kunde in STAMMKUNDEN:
je_kunde_ub.append([-1.0 if a[1] == kunde else 0.0 for a in AUFTRAEGE])
je_kunde_b.append(-1.0)
lesart_b = waehle_aus(DECKUNGSBEITRAG, zusatz_ub=je_kunde_ub,
zusatz_b_ub=je_kunde_b)
zeile("B: kein Stammkunde geht leer aus", lesart_b)
a, b = kennzahlen(lesart_a), kennzahlen(lesart_b)
ohne = kennzahlen(waehle_aus(DECKUNGSBEITRAG))
print("\n Beide Lesarten erreichen dasselbe: kein Stammkunde geht leer aus.")
print(f" Lesart A kostet dafuer {ohne['db'] - a['db']:,.0f} EUR Deckungsbeitrag, "
f"Lesart B nur {ohne['db'] - b['db']:,.0f} EUR -")
print(f" ein Unterschied von {b['db'] - a['db']:,.0f} EUR fuer denselben Satz aus derselben")
print(" Besprechung. Wer nicht nachfragt, entscheidet das selbst, ohne es")
print(" zu merken.")
# --- 3. Die weiche Variante ------------------------------------------
print("\n" + "-" * 84)
print("3. Dieselbe Regel als Strafkosten je abgelehntem Stammauftrag\n")
kopfzeile()
for strafe in (3_000, 6_000, 10_000):
ziel = DECKUNGSBEITRAG + np.where(IST_STAMM, float(strafe), 0.0)
zeile(f"C: Strafe {strafe:>6,} EUR je Auftrag", waehle_aus(ziel))
print("\n Bei 3.000 EUR aendert sich nichts: Die Strafe liegt unter dem, was")
print(" die Auftraege an Deckungsbeitrag verdraengen wuerden. Bei 10.000 EUR")
print(" kommt genau Lesart A heraus. Eine harte Regel ist also nichts")
print(" anderes als eine weiche mit hinreichend grosser Strafe - was ein")
print(" Strafgewicht sonst noch bedeutet, steht im Kapitel CP-SAT.")
# --- 4. Was die harte Lesart ein Quartal spaeter anrichtet -----------
print("\n" + "-" * 84)
print("4. Ein Quartal spaeter: Weber fragt einen Grossauftrag an\n")
erweitert = AUFTRAEGE + [("A-115", "Weber GmbH", True, 320, 210_000, 150_000)]
stunden_neu = np.array([a[3] for a in erweitert], dtype=float)
db_neu = np.array([a[4] - a[5] for a in erweitert], dtype=float)
stamm_neu = np.array([a[2] for a in erweitert])
print(f" A-115: Weber GmbH, {erweitert[-1][3]} Maschinenstunden - allein mehr,")
print(f" als der ganze Zeitraum hergibt ({KAPAZITAET} h).\n")
alle_stamm_neu = [[1.0 if stamm_neu[i] else 0.0 for i in range(len(erweitert))]]
hart = waehle_aus(db_neu, zusatz_eq=alle_stamm_neu,
zusatz_b_eq=[float(stamm_neu.sum())],
auftraege=erweitert, stunden=stunden_neu)
weich = waehle_aus(db_neu + np.where(stamm_neu, 10_000.0, 0.0),
auftraege=erweitert, stunden=stunden_neu)
print(f" Lesart A (hart): "
f"{'UNZULAESSIG - der Nachtlauf bricht ab' if hart is None else 'loesbar'}")
if weich is not None:
k = kennzahlen(weich, erweitert, stunden_neu,
np.array([a[4] for a in erweitert], dtype=float),
db_neu, stamm_neu)
print(f" Lesart C (weich): loesbar - {k['db']:,.0f} EUR Deckungsbeitrag, "
f"{k['stamm_abgelehnt']} Stammauftrag abgelehnt")
print("\n" + "=" * 84)
print(" WORAUF ES ANKOMMT")
print("=" * 84)
print("Die Daten waren in allen vier Teilen dieselben. Was sich geaendert hat,")
print("war nur die Frage - und mit ihr der Plan, der Deckungsbeitrag und die")
print("Kundenbeziehung.")
print()
print("Drei Dinge, die deshalb vor dem ersten Modell geklaert gehoeren:")
print()
print(" 1. WORAN wird der Erfolg gemessen? Nicht 'was ist Ihnen wichtig',")
print(" sondern: Welche Zahl steht am Jahresende im Bericht? Umsatz,")
print(" Auslastung und Deckungsbeitrag fuehren hier zu drei")
print(" verschiedenen Plaenen.")
print(" 2. WAS GENAU heisst der Satz? 'Stammkunden nicht verlieren' hat")
print(f" mindestens drei Lesarten mit {b['db'] - a['db']:,.0f} EUR Unterschied. Die Frage")
print(" 'meinen Sie jeden Auftrag oder jeden Kunden?' dauert zehn")
print(" Sekunden.")
print(" 3. WAS PASSIERT, WENN ES NICHT GEHT? Eine harte Regel, die niemand")
print(" hinterfragt hat, macht das System eines Tages unloesbar - und")
print(" zwar genau dann, wenn ein besonders grosser Auftrag hereinkommt.")
print(" Weiche Regeln antworten auch dann noch.")
print("=" * 84)Erwartete Ausgabe:
====================================================================================
VOM MANAGEMENT-WUNSCH ZUM MODELL
====================================================================================
14 Anfragen verlangen 800 Maschinenstunden, verfuegbar sind 300.
Es muss also ausgewaehlt werden. 3 der Kunden sind Stammkunden:
Kranz AG, Obermeier KG, Weber GmbH
------------------------------------------------------------------------------------
1. Was im Gespraech gesagt wurde - drei naheliegende Ziele
Umsatz DB Aus- Stamm- Kunden ange-
lastung auftr. ohne nommen
------------------------------------------------------------------------------
"Umsatz maximieren" 227,000 66,000 100% 5 2 6
"Maschinen besser auslasten" 205,000 54,000 100% 4 1 5
"Deckungsbeitrag maximieren" 222,000 78,500 100% 2 1 8
Der Umsatzplan bringt 5,000 EUR mehr Umsatz und 12,500 EUR WENIGER
Deckungsbeitrag. Fuer 5,000 EUR Umsatz werden also 12,500 EUR Ergebnis
aufgegeben - und 5 von 6 Stammkundenauftraegen dazu.
"Auslastung" ist der haeufigste Wunsch und der schaedlichste. Der
darauf optimierte Plan bringt 24,500 EUR weniger Deckungsbeitrag und
17,000 EUR weniger Umsatz als der DB-Plan - und erreicht dabei
nicht einmal mehr Auslastung: alle drei liegen bei 100 %.
Eine volle Maschine ist eben kein Ziel, sondern ein Nebenprodukt.
------------------------------------------------------------------------------------
2. "Stammkunden duerfen wir nicht verlieren" - aber was heisst das?
Umsatz DB Aus- Stamm- Kunden ange-
lastung auftr. ohne nommen
------------------------------------------------------------------------------
ohne die Regel (DB maximieren) 222,000 78,500 100% 2 1 8
A: jeden Stammauftrag annehmen 181,000 66,000 90% 0 0 8
B: kein Stammkunde geht leer aus 213,000 75,000 98% 2 0 8
Beide Lesarten erreichen dasselbe: kein Stammkunde geht leer aus.
Lesart A kostet dafuer 12,500 EUR Deckungsbeitrag, Lesart B nur 3,500 EUR -
ein Unterschied von 9,000 EUR fuer denselben Satz aus derselben
Besprechung. Wer nicht nachfragt, entscheidet das selbst, ohne es
zu merken.
------------------------------------------------------------------------------------
3. Dieselbe Regel als Strafkosten je abgelehntem Stammauftrag
Umsatz DB Aus- Stamm- Kunden ange-
lastung auftr. ohne nommen
------------------------------------------------------------------------------
C: Strafe 3,000 EUR je Auftrag 222,000 78,500 100% 2 1 8
C: Strafe 6,000 EUR je Auftrag 205,000 73,000 100% 1 0 8
C: Strafe 10,000 EUR je Auftrag 181,000 66,000 90% 0 0 8
Bei 3.000 EUR aendert sich nichts: Die Strafe liegt unter dem, was
die Auftraege an Deckungsbeitrag verdraengen wuerden. Bei 10.000 EUR
kommt genau Lesart A heraus. Eine harte Regel ist also nichts
anderes als eine weiche mit hinreichend grosser Strafe - was ein
Strafgewicht sonst noch bedeutet, steht im Kapitel CP-SAT.
------------------------------------------------------------------------------------
4. Ein Quartal spaeter: Weber fragt einen Grossauftrag an
A-115: Weber GmbH, 320 Maschinenstunden - allein mehr,
als der ganze Zeitraum hergibt (300 h).
Lesart A (hart): UNZULAESSIG - der Nachtlauf bricht ab
Lesart C (weich): loesbar - 66,000 EUR Deckungsbeitrag, 1 Stammauftrag abgelehnt
====================================================================================
WORAUF ES ANKOMMT
====================================================================================
Die Daten waren in allen vier Teilen dieselben. Was sich geaendert hat,
war nur die Frage - und mit ihr der Plan, der Deckungsbeitrag und die
Kundenbeziehung.
Drei Dinge, die deshalb vor dem ersten Modell geklaert gehoeren:
1. WORAN wird der Erfolg gemessen? Nicht 'was ist Ihnen wichtig',
sondern: Welche Zahl steht am Jahresende im Bericht? Umsatz,
Auslastung und Deckungsbeitrag fuehren hier zu drei
verschiedenen Plaenen.
2. WAS GENAU heisst der Satz? 'Stammkunden nicht verlieren' hat
mindestens drei Lesarten mit 9,000 EUR Unterschied. Die Frage
'meinen Sie jeden Auftrag oder jeden Kunden?' dauert zehn
Sekunden.
3. WAS PASSIERT, WENN ES NICHT GEHT? Eine harte Regel, die niemand
hinterfragt hat, macht das System eines Tages unloesbar - und
zwar genau dann, wenn ein besonders grosser Auftrag hereinkommt.
Weiche Regeln antworten auch dann noch.
====================================================================================
Was Sie in der Abbildung sehen. Jeder Plan gewinnt auf seiner eigenen Achse — das ist keine Überraschung, sondern die Definition. Interessant ist, was daneben passiert: Der Auslastungsplan liegt bei der Auslastung gleichauf mit den anderen und verliert beim Deckungsbeitrag ein knappes Drittel. ### Teil 1: Drei Ziele, drei Pläne
| Zielgröße | Umsatz | Deckungsbeitrag | Auslastung | abgelehnte Stammaufträge |
|---|---|---|---|---|
| „Umsatz maximieren” | 227 000 € | 66 000 € | 100 % | 5 von 6 |
| „Maschinen besser auslasten” | 205 000 € | 54 000 € | 100 % | 4 von 6 |
| „Deckungsbeitrag maximieren” | 222 000 € | 78 500 € | 100 % | 2 von 6 |
Zwei Beobachtungen, die im Gespräch niemand vorhergesagt hätte:
Der Umsatzplan kostet 12 500 € Ergebnis, um 5 000 € Umsatz zu gewinnen — und nimmt dabei fünf von sechs Stammkundenaufträgen aus dem Plan. Das Wechselkursverhältnis ist 1 : 2,5 gegen den Betrieb.
Der Auslastungsplan ist in jeder Hinsicht der schlechteste — auch bei der Auslastung. Alle drei Pläne belegen die Maschinen zu 100 %; der eigens darauf optimierte Plan erreicht nur nicht mehr, sondern verliert dabei 24 500 € Deckungsbeitrag. Der Grund ist einfach: Bei knapper Kapazität ist eine volle Maschine keine Leistung, sondern die Voreinstellung. Zu optimieren gibt es nur, womit sie voll wird.
⚠️ Auslastung ist ein Ergebnis, kein Ziel
„Wir müssen die Maschinen besser auslasten” ist der häufigste Satz in Produktionsbesprechungen und fast immer die falsche Zielgröße. Auslastung misst, wie viel Zeit vergeht — nicht, was dabei herauskommt. Wer sie maximiert, belohnt lange, schlecht bezahlte Aufträge.
Die Ausnahme, die die Regel erklärt: Wenn Maschinen tatsächlich leer stehen, weil zu wenig hereinkommt, ist Auslastung ein sinnvolles Symptom — aber dann liegt das Problem im Vertrieb und nicht in der Planung.
Teil 2: Ein Satz, drei Lesarten
„Stammkunden dürfen wir nicht verlieren.” Jeder im Raum nickt. Niemand merkt, dass drei verschiedene Modelle gemeint sein können:
| Lesart | Deckungsbeitrag | kostet gegenüber „ohne Regel” |
|---|---|---|
| ohne die Regel | 78 500 € | — |
| A: jeden Stammkundenauftrag annehmen | 66 000 € | 12 500 € |
| B: kein Stammkunde geht leer aus | 75 000 € | 3 500 € |
Beide Lesarten erreichen dasselbe Ziel — kein Stammkunde geht leer aus. Lesart A kostet dafür das Dreieinhalbfache. Der Unterschied von 9 000 € entsteht durch eine Frage, die zehn Sekunden dauert:
„Meinen Sie jeden Auftrag oder jeden Kunden?“
Wer sie nicht stellt, entscheidet sie trotzdem — nur unbewusst, beim Tippen.
Teil 3: Hart oder weich
Dieselbe Regel als Strafkosten je abgelehntem Stammkundenauftrag:
| Strafe je Auftrag | Deckungsbeitrag | abgelehnte Stammaufträge |
|---|---|---|
| 3 000 € | 78 500 € | 2 |
| 6 000 € | 73 000 € | 1 |
| 10 000 € | 66 000 € | 0 |
Bei 3 000 € ändert sich nichts: Die Strafe liegt unter dem Deckungsbeitrag, den die Stammkundenaufträge verdrängen würden. Bei 10 000 € kommt genau Lesart A heraus.
Daraus folgt eine Einsicht, die das Modellieren erleichtert: Eine harte Regel ist eine weiche mit hinreichend großer Strafe. Man kann also immer weich anfangen und die Strafe hochdrehen, bis die Regel greift — und sieht dabei, was sie kostet. Was ein Strafgewicht darüber hinaus bedeutet und warum zwei Gewichte einen Wechselkurs festlegen und keine Wichtigkeiten, steht in Abschnitt 7.10.
Teil 4: Ein Quartal später
Die harte Lesart A wurde eingebaut, alles lief drei Monate lang. Dann fragt Weber einen Auftrag über 320 Maschinenstunden an — mehr, als der ganze Zeitraum hergibt.
Lesart A (hart): UNZULAESSIG - der Nachtlauf bricht ab
Lesart C (weich): loesbar - 66,000 EUR Deckungsbeitrag, 1 Stammauftrag abgelehnt
Das ist kein konstruierter Sonderfall, sondern der Normalfall: Harte Regeln scheitern nicht bei ihrer Einführung, sondern Monate später — und zwar bevorzugt dann, wenn etwas Ungewöhnliches passiert, also genau dann, wenn man die Planung am dringendsten braucht.
Die weiche Variante antwortet auch dann noch. Sie lehnt den Großauftrag ab, weist das im Bericht aus, und ein Mensch entscheidet. Das ist der ganze Unterschied — und er wird beim Schreiben der Anforderung festgelegt, nicht beim Programmieren.
🎯 Merksatz Hart ist nur, was rechtlich oder physikalisch unmöglich ist. Alles andere wird weich mit hoher Strafe. Dann liefert der Solver den am wenigsten schlechten Plan statt einer Fehlermeldung — und die Fehlermeldung ist das, was niemand gebrauchen kann.
4.5 Der Gesprächsleitfaden
Was aus den vier Teilen als Handwerkszeug bleibt — Fragen, die man in der ersten Besprechung stellt, bevor eine Zeile Code entsteht:
📎 Zwölf Fragen für das erste Gespräch
Zur Entscheidung 1. Was genau wird entschieden — und von wem heute? 2. Was steht dabei nicht zur Disposition? 3. Wie oft wird entschieden, und wie viel Zeit ist dafür?
Zum Ziel 4. Welche Zahl steht am Jahresende im Bericht? 5. Wenn genau diese Zahl maximiert würde — welcher Plan käme heraus, und wäre er akzeptabel? 6. Gibt es eine zweite Zahl, die auch stimmen muss? Was ist Ihnen ein Prozent der ersten wert, um ein Prozent der zweiten zu gewinnen?
Zu den Regeln 7. Welche dieser Regeln ist gesetzlich oder physikalisch zwingend? 8. Welche würden Sie in einer Ausnahmesituation brechen — und was wäre eine Ausnahmesituation? 9. Bei „darf nicht”: Betrifft das jeden einzelnen Fall oder das Gesamtbild?
Zum Betrieb 10. Was soll passieren, wenn es keine zulässige Lösung gibt? 11. Wer sieht das Ergebnis, und was muss er daran erkennen können? 12. Woran würden Sie in einem halben Jahr merken, dass das System nicht mehr das Richtige tut?
Frage 5 ist die wichtigste. Sie verwandelt eine abstrakte Zielangabe in einen konkreten Plan, den man ablehnen kann — und Ablehnung ist die einzige Form von Anforderungsklärung, die zuverlässig funktioniert.
4.6 Deutsch — OR: ein Übersetzungslexikon
Die zwölf Fragen liefern Sätze. Sätze sind noch kein Modell — aber die meisten von ihnen haben eine Standardübersetzung, und wer sie kennt, spart sich das Nachdenken für die Fälle, in denen es keine gibt.
Die Tabelle liest sich von links nach rechts: Was in der Besprechung gesagt wird, was es bedeutet, und welcher Baustein daraus wird. Die B-Nummern verweisen auf Anhang B, wo jedes Muster mit Formulierung und Code steht.
| Was gesagt wird | Was gemeint ist | Baustein |
|---|---|---|
| „Wir haben nur 400 Stunden.” | eine Obergrenze, die nicht überschritten werden darf | harte Kapazitätsgrenze \le b (Kapitel 5) |
| „Mehr als zwei Millionen gibt es nicht.” | dasselbe, auf Geld | Budgetlimit (B27) |
| „Möglichst nicht über 40 Stunden.” | eine Grenze, die im Notfall gebrochen werden darf | weiche Grenze mit Strafkosten (B8) |
| „Wir können nur ganze Kisten liefern.” | die Menge ist nicht teilbar | Ganzzahligkeitsbedingung (Kapitel 6) |
| „Wenn wir die Anlage nutzen, fallen Fixkosten an.” | Kosten, die erst ab der ersten Einheit anfallen | Aktivierungsschalter (B1) |
| „Entweder gar nicht oder mindestens 50.” | kein Betrieb im Kleinen | semikontinuierliche Variable (B2) |
| „Wenn wir A bauen, brauchen wir auch B.” | eine Folgeverpflichtung | Implikation (B3) |
| „Höchstens drei Positionen im Depot.” | eine Obergrenze auf die Anzahl, nicht die Menge | Kardinalität (B6) |
| „Der Anteil muss mindestens 30 % betragen.” | eine Bedingung auf ein Verhältnis | Verhältnis-Bedingung (B12) |
| „Jeder Auftrag genau einem Mitarbeiter.” | eine vollständige, eindeutige Zuordnung | Zuordnung 1:1 (B23) |
| „Eine Maschine kann nur eines gleichzeitig.” | zeitliche Ausschließlichkeit | Nichtüberlappung (B14) |
| „B kann erst nach A.” | eine Reihenfolge | Vorrangbeziehung (B13) |
| „Höchstens fünf Tage am Stück.” | eine Bedingung über ein gleitendes Fenster | gleitendes Fenster (B16) |
| „Umstellen kostet uns eine halbe Stunde.” | reihenfolgeabhängige Kosten | Umrüstkosten (B17), Rüstzeit als Kapazität (B26) |
| „Was reinkommt, muss auch wieder raus.” | Erhaltung an jedem Knoten | Flusserhaltung (B22) |
| „Notfalls brechen wir die Regel.” | die Bedingung ist weich, aber teuer | Schlupfvariablen (B18) |
| „Erst Termintreue, dann Kosten.” | eine Rangfolge zwischen Zielen | hierarchische Ziele (B19) |
| „Es soll gerecht zugehen.” | den Schlechtestgestellten verbessern | Min/Max in der Zielfunktion (B11) |
| „Was brächte uns eine zusätzliche Stunde?” | die Frage nach dem Grenzwert einer Ressource | Schattenpreis (Kapitel 5, Abschnitt 22.4) |
| „Mit 95 % Sicherheit muss es halten.” | eine Zusage auf eine Quote, nicht auf einen Mittelwert | Chance Constraint (Abschnitt 12.7) |
| „Wir sichern uns gegen Schätzfehler ab.” | gegen die ungünstigste Parameterlage planen | Worst-Case-Abzug (B21) |
Fünf Wendungen, bei denen die Übersetzung eine Entscheidung erzwingt
Die Tabelle oben tut so, als sei die Zuordnung eindeutig. Bei den folgenden fünf ist sie es nicht — und das Nachfragen ist die eigentliche Modellierungsarbeit:
| Wendung | Die Frage, die dahinter steckt |
|---|---|
| „möglichst” | Hart oder weich? Und wenn weich: Was darf ein Verstoß kosten? Ohne Zahl ist „möglichst” keine Bedingung, sondern eine Stimmung. |
| „nicht mehr als drei pro Woche” | Je Person oder über alle zusammen? Kalenderwoche oder gleitende sieben Tage? Beide Lesarten sind vertretbar und ergeben verschiedene Modelle. |
| „im Durchschnitt” | Fast immer eine Falle. Der Durchschnittskunde kauft nie — siehe Abschnitt 12.3. Gemeint ist meist ein Quantil („in 9 von 10 Fällen”). |
| „so schnell wie möglich” | Welche Zahl? Ende des letzten Auftrags, Summe aller Fertigstellungszeiten oder größte Verspätung? Drei Zielfunktionen, drei verschiedene Pläne. |
| „fair” | Den Schlechtesten verbessern, die Spannweite verkleinern oder gleiche Anteile erzwingen? Erst die Wahl macht daraus ein Modell — und sie gehört dem Betrieb, nicht dem Modellierer. |
🎯 Der Nutzen dieser Liste Sie ersetzt kein Nachdenken. Sie sorgt dafür, dass das Nachdenken an den richtigen vier oder fünf Stellen stattfindet, statt an allen zwanzig gleichzeitig.
Und die Gegenrichtung: OR — Deutsch
Dieselbe Barriere gibt es rückwärts. Diese Sätze haben sich bewährt, wenn ein Ergebnis jemandem erklärt werden muss, der das Modell nicht kennt:
| Fachbegriff | Was Sie in der Besprechung sagen |
|---|---|
| Schattenpreis / Dualwert | „Die nächste Stunde auf dieser Maschine wäre uns 9 € wert.” |
| bindende Bedingung mit Dualwert 0 | „Die Regel berührt den Plan, kostet uns aber nichts — dort zu verhandeln bringt nichts.” |
INFEASIBLE |
„Ihre Regeln widersprechen sich.” Nicht: „Der Computer schafft es nicht.” |
| Optimalitätslücke von 2 % | „Besser als das hier geht es höchstens um 2 % — und die liegen unter unserer Datenungenauigkeit.” |
| CVaR | „Wenn es schiefgeht, verlieren wir im Mittel so viel.” (Der VaR sagt nur, ob es schiefgeht.) |
| EVPI | „Selbst eine perfekte Prognose wäre uns höchstens so viel wert.” |
| Relaxation | „Wir haben die Regel probeweise gelockert, um zu sehen, was sie kostet.” |
| Chance Constraint | „Der Plan hält in 95 von 100 Fällen — und der nächste Prozentpunkt kostet …” |
4.7 Übungsaufgaben
Lösungen: Abschnitt A.4.
Aufgabe 4.1 ⭐ — Die fehlende Lesart. Der Text nennt zwei Lesarten von „Stammkunden dürfen wir nicht verlieren”. Formulieren Sie eine dritte, die weder A noch B ist, und sagen Sie, welchen Betrieb sie beschreiben würde.
Aufgabe 4.2 ⭐ — Frage 5 anwenden. Ein Krankenhaus möchte „die Wartezeiten in der Notaufnahme senken”. Wenden Sie Frage 5 an: Welcher Plan käme heraus, wenn genau die durchschnittliche Wartezeit minimiert würde — und was wäre daran nicht akzeptabel?
Aufgabe 4.3 ⭐⭐ — Der Kompromiss dazwischen. Zwischen Lesart A (12 500 €) und Lesart B (3 500 €) liegt Spielraum. Bauen Sie eine Variante, in der jeder Stammkunde mindestens die Hälfte seiner Auftragsstunden zugeteilt bekommt. Was kostet sie?
Aufgabe 4.4 ⭐⭐ — Zwei Ziele gleichzeitig. Maximieren Sie \text{DB} + \lambda \cdot \text{Umsatz} für \lambda \in \{0; 0{,}1; 0{,}3; 1\} und tragen Sie die Ergebnisse als Tabelle auf. Ab welchem \lambda kippt der Plan von der DB- in die Umsatzlösung? Was sagt dieser Wert dem Betrieb?
Aufgabe 4.5 ⭐⭐ — Übersetzen, wo es nicht eindeutig ist. Übersetzen Sie mit Abschnitt 4.6: (a) „Die Monteure sollen möglichst gleichmäßig ausgelastet sein.” Nennen Sie drei Zielfunktionen, die alle „gleichmäßig” bedeuten können, und je einen Fall, in dem die Wahl den Plan sichtbar ändert. (b) „Kein Kunde darf länger als drei Tage warten.” Formulieren Sie die Bedingung einmal hart und einmal weich. Welche Frage müssen Sie dem Betrieb stellen, um zu entscheiden? (c) Suchen Sie in einer echten Anforderung aus Ihrem Umfeld einen Satz, der nach der Tabelle eindeutig aussieht, es aber nicht ist.
Aufgabe 4.6 ⭐⭐⭐ — Die Anforderung schreiben. Formulieren Sie für den Fall dieses Kapitels eine vollständige, prüfbare Anforderung: Ziel, harte Regeln, weiche Regeln mit Strafgewichten, Verhalten bei Unlösbarkeit, auszuweisende Kennzahlen. Zwei Seiten genügen — sie sind mehr wert als zwei Wochen Programmierung.
4.8 Finde den Denkfehler
🐛 „Die Engpassmaschine soll zu mindestens 92 % ausgelastet sein”
Der Werkleiter formuliert eine klare, messbare, prüfbare Anforderung:
„Die Engpassmaschine soll in jedem Planungszeitraum zu mindestens 92 % ausgelastet sein. > Das ist unsere teuerste Anlage, Leerlauf können wir uns nicht leisten.”
Der Entwickler baut sie als harte Nebenbedingung ein — sie ist ja klar formuliert. Die Abnahme läuft mit den Daten des letzten Quartals: Der Plan hält die Vorgabe ein, der Deckungsbeitrag stimmt, alle Tests grün. Das System geht in Betrieb.
Diese Anforderung enthält zwei verschiedene Fehler. Welche?
Ein Hinweis für den zweiten: Sehen Sie sich an, was das Modell im Abnahmetest tatsächlich geprüft hat — und rechnen Sie einen Monat durch, in dem weniger Anfragen hereinkommen.
4.9 Micro-Quiz
❓ Drei Fragen
1. Warum liefert „Umsatz maximieren” hier einen schlechteren Plan als „Deckungsbeitrag maximieren”, obwohl beide Modelle korrekt sind? a) Weil der Solver bei Umsatzzielen ungenauer rechnet. b) Weil alles, was nicht in der Zielfunktion steht, für das Modell wertlos ist — nicht weniger wichtig. c) Weil Umsatzdaten in der Praxis unzuverlässiger sind als Kostendaten.
2. Eine Regel als harte Nebenbedingung statt als Strafkosten zu formulieren, ist vor allem deshalb riskant, weil … a) … harte Nebenbedingungen den Solver verlangsamen. b) … das Modell unlösbar wird, sobald die Regel einmal nicht erfüllbar ist — und dann gar keine Antwort mehr liefert. c) … sich harte Regeln nachträglich nicht mehr ändern lassen.
3. Alle drei Zielgrößen erreichen 100 % Auslastung. Was folgt daraus? a) Die Auslastung war schon vorher optimal, das Projekt ist überflüssig. b) Bei knapper Kapazität ist volle Auslastung die Voreinstellung; zu entscheiden ist nur, womit die Maschine voll wird. c) Die Kapazitätsdaten sind vermutlich falsch erfasst.
4.10 Selbsttest
- Warum ist „Was ist Ihnen wichtig?” eine schlechte Frage und „Welche Zahl steht im Jahresbericht?” eine gute?
- Nennen Sie zwei Kennzahlen aus Ihrem eigenen Arbeitsumfeld, deren Maximierung schaden würde.
- Erklären Sie in einem Satz, warum eine harte Regel eine weiche mit großer Strafe ist — und wann der Unterschied trotzdem zählt.
- Ein Kunde sagt: „Kein Mitarbeiter soll mehr als zwei Wochenenden im Monat arbeiten.” Nennen Sie zwei Lesarten und je eine Situation, in der sie auseinanderfallen.
- Was antworten Sie auf die Frage „Was soll passieren, wenn es keine zulässige Lösung gibt?” — und warum ist „das kommt nicht vor” keine Antwort?
4.11 Zusammenfassung
- Ein Modell rechnet aus, was aufgeschrieben wurde, nicht was gemeint war. Die Zielfunktion ist eine vollständige Aussage: Was nicht darin steht, ist wertlos.
- Die Zielgröße ist die folgenreichste Entscheidung eines OR-Projekts. Umsatz, Auslastung und Deckungsbeitrag führten hier auf demselben Datensatz zu drei verschiedenen Plänen mit 24 500 € Unterschied.
- Auslastung ist ein Ergebnis, kein Ziel. Bei knapper Kapazität ist die Maschine ohnehin voll; entscheidend ist, womit.
- Ein Satz aus einer Besprechung hat meist mehrere Lesarten. „Stammkunden nicht verlieren” kostete je nach Lesart 3 500 € oder 12 500 € — bei identischem Ergebnis für die Kunden.
- Hart ist nur, was rechtlich oder physikalisch unmöglich ist. Eine harte Regel ist eine weiche mit hinreichend großer Strafe; der Unterschied zeigt sich erst, wenn sie einmal nicht erfüllbar ist — dann liefert die harte Variante gar nichts mehr.
- Die meisten Sätze haben eine Standardübersetzung — das Lexikon in Abschnitt 4.6 nennt sie. Sein Wert liegt aber in den fünf Wendungen, bei denen es keine gibt: „möglichst”, „nicht mehr als”, „im Durchschnitt”, „so schnell wie möglich”, „fair”. Dort ist Nachfragen die Modellierungsarbeit.
- Die vier Fragen — worüber wird entschieden, woran gemessen, was ist unverhandelbar, was bei Unlösbarkeit — gehören in die erste Besprechung. Der Leitfaden in Abschnitt 4.5 macht zwölf daraus.