operations_research/OR_HTML_04/projektwerkstatt.html

351 lines
40 KiB
HTML
Raw Normal View History

Version 04 als eigenes Repository Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python" (Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch Version_03 (eingefroren) verwaltet und Version_04/ ignoriert. Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist. Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise, 325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren, 25 Notebooks, PDF mit 715 Seiten. Zusaetzlich in diesem Commit: * pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api, figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt unveraendert daneben bestehen. ortools steht in der Grundausstattung, highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der schlanken Installation gar nicht erst auftreten. * Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo steht in requirements.txt, wird aber von keinem Programm importiert, sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in [empfehlungen]). * NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen. * PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den tatsaechlichen aus erzeuge_titelseite.py korrigiert. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Projektwerkstatt · Optimierte Entscheidungsfindung mit Python</title>
<script>
(function () {
try {
var t = localStorage.getItem("or-theme");
if (t) document.documentElement.setAttribute("data-theme", t);
} catch (e) {}
})();
</script>
<link rel="stylesheet" href="assets/highlight.css" />
<link rel="stylesheet" href="katex/katex.min.css" />
<script defer="" src="katex/katex.min.js"></script>
<script>document.addEventListener("DOMContentLoaded", function () {
var mathElements = document.getElementsByClassName("math");
var macros = [];
for (var i = 0; i < mathElements.length; i++) {
var texText = mathElements[i].firstChild;
if (mathElements[i].tagName == "SPAN") {
katex.render(texText.data, mathElements[i], {
displayMode: mathElements[i].classList.contains('display'),
throwOnError: false,
macros: macros,
fleqn: false
});
}}
// Der Browser springt zu einem #anker in der URL schon beim ersten Rendern
// an, BEVOR die KaTeX-Formeln oben im Text ihre finale Hoehe bekommen -
// durch den Reflow landet der Anker danach zu weit unten. Nach dem
// Formel-Rendering hier erneut zum Anker springen, das behebt es.
if (location.hash) {
var ziel = document.getElementById(decodeURIComponent(location.hash.slice(1)));
if (ziel) ziel.scrollIntoView({behavior: "instant", block: "start"});
}
});
</script>
<link rel="stylesheet" href="assets/site.css" />
</head>
<body>
<svg style="display:none" aria-hidden="true"><symbol id="icon-menu" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/>
</symbol>
<symbol id="icon-search" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.2" y2="16.2"/>
</symbol>
<symbol id="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
<circle cx="12" cy="12" r="4.5"/>
<line x1="12" y1="1.5" x2="12" y2="4"/><line x1="12" y1="20" x2="12" y2="22.5"/>
<line x1="1.5" y1="12" x2="4" y2="12"/><line x1="20" y1="12" x2="22.5" y2="12"/>
<line x1="4.5" y1="4.5" x2="6.2" y2="6.2"/><line x1="17.8" y1="17.8" x2="19.5" y2="19.5"/>
<line x1="19.5" y1="4.5" x2="17.8" y2="6.2"/><line x1="6.2" y1="17.8" x2="4.5" y2="19.5"/>
</symbol>
<symbol id="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 14.5A8.5 8.5 0 1 1 9.5 4a6.8 6.8 0 0 0 10.5 10.5z"/>
</symbol>
<symbol id="icon-chevron-left" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="15 4 7 12 15 20"/>
</symbol>
<symbol id="icon-chevron-right" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="9 4 17 12 9 20"/>
</symbol>
<symbol id="icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="4 13 9.5 18.5 20 6"/>
</symbol>
<symbol id="icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 13.5V19a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 19V7A1.5 1.5 0 0 1 5 5.5h5.5"/>
<polyline points="14.5 3.5 20.5 3.5 20.5 9.5"/><line x1="11" y1="13" x2="20" y2="4"/>
</symbol>
<symbol id="icon-book" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 5.5A2 2 0 0 1 6 4h6v16H6a2 2 0 0 0-2 1.5z"/>
<path d="M20 5.5A2 2 0 0 0 18 4h-6v16h6a2 2 0 0 1 2 1.5z"/>
</symbol>
<symbol id="icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
</symbol>
<symbol id="icon-download" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 3v12"/><polyline points="7 10 12 15 17 10"/><path d="M4 19.5h16"/>
</symbol></svg>
<header class="site-header">
<button type="button" class="icon-btn" id="sidebar-toggle" aria-label="Menü öffnen"><svg class="icon" aria-hidden="true"><use href="#icon-menu"></use></svg></button>
<a class="brand" href="index.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> <span>Optimierte Entscheidungsfindung mit Python</span></a>
<div class="site-search">
<input id="suche-eingabe" type="search" placeholder="Suchen …" aria-label="Suche" autocomplete="off" />
<svg class="icon such-icon" aria-hidden="true"><use href="#icon-search"></use></svg>
<div id="suche-ergebnisse" class="suche-ergebnisse" hidden></div>
</div>
<button type="button" class="icon-btn" id="theme-toggle" aria-label="Darstellung umschalten">
<svg class="icon icon-sun" aria-hidden="true"><use href="#icon-sun"></use></svg><svg class="icon icon-moon" aria-hidden="true"><use href="#icon-moon"></use></svg>
</button>
</header>
<div class="site-body">
<div class="sidebar-overlay" id="sidebar-overlay" hidden></div>
<nav class="sidebar" id="sidebar" aria-label="Kapitelnavigation"><div class="sidebar-inhalt"><details class="sidebar-gruppe"><summary>Einstieg</summary><ul><li data-kapitel="vorwort.html"><a href="vorwort.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Vorwort & Lesehilfe</span></a></li><li data-kapitel="notation.html"><a href="notation.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Notation & Abkürzungen</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil I: Grundlagen des Operations Research</summary><ul><li data-kapitel="einfuehrung.html"><a href="einfuehrung.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 1: Einführung in Operations Research — Vom Ursprung zur mathematischen Entscheidungsfindung</span></a></li><li data-kapitel="fundament.html"><a href="fundament.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 2: Das mathematische Fundament — Vektoren, Matrizen, Konvexität</span></a></li><li data-kapitel="oekosystem.html"><a href="oekosystem.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 3: Das Python-Ökosystem für OR — Solver, Bindings und Modellierungsschichten</span></a></li><li data-kapitel="modellierung.html"><a href="modellierung.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 4: Vom Management-Wunsch zum Modell</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil II: Die Kernverfahren der deterministischen Optimierung</summary><ul><li data-kapitel="lp.html"><a href="lp.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 5: Lineare Programmierung — Simplex, Dualität und Schattenpreise</span></a></li><li data-kapitel="milp.html"><a href="milp.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 6: Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound</span></a></li><li data-kapitel="cpsat.html"><a href="cpsat.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 7: Constraint Programming mit CP-SAT — Logik, Scheduling und Zuweisung</span></a></li><li data-kapitel="graphen.html"><a href="graphen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 8: Graphen, Flüsse und Touren — Min-Cost-Flow, Matching und VRP</span></a></li><li data-kapitel="metaheuristiken.html"><a href="metaheuristiken.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 9: Metaheuristiken — wenn der exakte Solver aussteigt</span></a></li><li data-kapitel="dekomposition.html"><a href="dekomposition.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 10: Spaltengenerierung — das Modell umbauen statt die Lösung raten</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil III: Nichtlinearität, Unsicherheit und mehrperiodige Dynamik</summary><ul><li data-kapitel="qp-nlp.html"><a href="qp-nlp.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 11: Quadratische und nichtlineare Optimierung — KKT, Lagrange, Konvexität</span></a></li><li data-kapitel="unsicherheit.html"><a href="unsicherheit.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></
<main class="content">
<nav class="breadcrumb" aria-label="Breadcrumb"><a href="index.html">Start</a> <span>Teil V</span> <span>Projektwerkstatt</span></nav>
<nav class="prev-next"><a class="prev-next-knopf prev-next-prev" href="testing.html"><svg class="icon" aria-hidden="true"><use href="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 23: Testen, Messen, Ausliefern</span></a><a class="prev-next-knopf prev-next-next" href="anhang-loesungen.html"><span><small>Weiter</small>Anhang A: Lösungen zu allen Übungsaufgaben</span><svg class="icon" aria-hidden="true"><use href="#icon-chevron-right"></use></svg></a></nav>
<article>
<h1 id="projektwerkstatt-elf-eigene-anwendungen">Projektwerkstatt — elf eigene Anwendungen</h1>
<div class="card card-blick">
<blockquote>
<p><strong>📌 Auf einen Blick</strong></p>
<p><strong>Worum geht es?</strong> Um den Schritt, auf den der ganze Kurs zuläuft: <strong>eine eigene Anwendung bauen.</strong> Elf vollständig ausgearbeitete Projektaufträge, jeder mit Datenquellen, Modellskizze, Abnahmekriterien und Stolperfallen. P1P8 bauen je ein Modell; <strong>P9P11 setzen dort an, wo eines schon steht</strong> — wenn es zu langsam wird, wenn zwei Ziele gegeneinanderstehen, wenn es jemand anderes benutzen soll.</p>
<p><strong>Voraussetzungen:</strong> je Projekt angegeben.</p>
<p><strong>Zeitbedarf:</strong> 1025 Stunden je Projekt.</p>
</blockquote>
</div>
<hr />
<h2 id="wie-sie-ein-projekt-bearbeiten">Wie Sie ein Projekt bearbeiten</h2>
<p>Halten Sie sich an diese Reihenfolge — sie ist aus vielen gescheiterten und einigen gelungenen Projekten destilliert:</p>
<table>
<colgroup>
<col style="width: 25%" />
<col style="width: 25%" />
<col style="width: 25%" />
<col style="width: 25%" />
</colgroup>
<thead>
<tr class="header">
<th>Phase</th>
<th>Dauer</th>
<th>Ergebnis</th>
<th>Häufigster Fehler</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>1. Zerlegen</strong></td>
<td>10 %</td>
<td>Ausgefüllte Bausteine-Vorlage (<a href="einfuehrung.html#sec:einfuehrung-die-vier-universellen-bausteine-jedes-or">Abschnitt 1.6</a>) auf <strong>Papier</strong></td>
<td>Sofort programmieren</td>
</tr>
<tr class="even">
<td><strong>2. Kleinstinstanz</strong></td>
<td>15 %</td>
<td>Modell mit 35 Elementen, Lösung <strong>von Hand</strong> geprüft</td>
<td>Gleich mit echten Daten anfangen</td>
</tr>
<tr class="odd">
<td><strong>3. Daten</strong></td>
<td>20 %</td>
<td>Echte Daten geladen, validiert, dokumentiert</td>
<td>Datenqualität unterschätzen</td>
</tr>
<tr class="even">
<td><strong>4. Skalieren</strong></td>
<td>20 %</td>
<td>Volles Modell läuft im Zeitlimit</td>
<td>Zu viele harte Bedingungen</td>
</tr>
<tr class="odd">
<td><strong>5. Erklärbar machen</strong></td>
<td>20 %</td>
<td>Report, den ein Fachanwender versteht</td>
<td>Ganz weglassen</td>
</tr>
<tr class="even">
<td><strong>6. Abnahme</strong></td>
<td>15 %</td>
<td>Kriterien geprüft, Grenzen dokumentiert</td>
<td>„Läuft ja“ als Abnahme</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>🎯 Die wichtigste Regel</strong> <strong>Phase 2 ist nicht optional.</strong> Ein Modell, das Sie an drei Mitarbeitenden und vier Schichten nicht von Hand nachrechnen können, werden Sie an 200 Mitarbeitenden nie debuggen. Jede Stunde in Phase 2 spart drei in Phase 4.</p>
</blockquote>
<hr />
<h2 id="p1-vertretungsplaner-für-eine-schule">P1 — Vertretungsplaner für eine Schule</h2>
<blockquote>
<p><strong>Schwierigkeit:</strong> ⭐⭐ · <strong>Kapitel:</strong> <a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a>, <a href="milp.html#kap-milp">Kapitel 6</a>, <a href="cpsat.html#kap-cpsat">Kapitel 7</a>, <a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a> · <strong>Zeit:</strong> ca. 15 Stunden</p>
</blockquote>
<p><strong>Ausgangslage.</strong> Morgens um 7:15 Uhr meldet sich die dritte Lehrkraft krank. Die stellvertretende Schulleitung hat 20 Minuten, um einen Vertretungsplan zu erstellen, der Qualifikationen, Arbeitszeiten, bereits geleistete Vertretungen und persönliche Wünsche berücksichtigt.</p>
<p><strong>Daten.</strong> Stundenplan (CSV: Klasse, Tag, Stunde, Fach, Lehrkraft, Raum) — in diesem Projektordner erzeugen die Skripte <code>stundenplan*.py</code> genau solche Dateien und eignen sich als Datenquelle. Zusätzlich: Qualifikationsmatrix, Deputate, Abwesenheitsmeldungen.</p>
<p><strong>Modellskizze.</strong> * Variablen: <span class="math inline">x_{p,s} \in \{0,1\}</span> — Person <span class="math inline">p</span> übernimmt Slot <span class="math inline">s</span>. * Hart: genau eine Person je Slot; Qualifikation; keine Doppelbelegung; Höchstzahl Vertretungsstunden; Ruhezeiten. * Weich: Vorbelastung, Freistundenlöcher, Fachnähe, Wünsche, Fairness über die Woche. * Solver: CP-SAT.</p>
<p><strong>Abnahmekriterien.</strong> - [ ] Läuft in unter 10 Sekunden für eine ganze Schule (60 Lehrkräfte, 30 Slots). - [ ] Liefert <strong>immer</strong> einen Plan — auch wenn nicht alle Slots besetzbar sind (Relaxation). - [ ] Weist je Zuweisung eine Begründung aus. - [ ] Ausgabe als CSV <strong>und</strong> als lesbare Tagestabelle. - [ ] Vergleich gegen die manuelle Lösung: Wie viele Wünsche werden erfüllt?</p>
<p><strong>Stolperfallen.</strong> * Zu viele harte Regeln → <code>INFEASIBLE</code> an genau dem Tag, an dem man das System braucht. * Fairness nur über einen Tag statt über die Woche → dieselbe Person trifft es ständig. * Akzeptanz: Ohne Begründungsanzeige wird der Plan überschrieben.</p>
<p><strong>Erweiterungen.</strong> Mehrtagesplanung; Raumkonflikte; Springerstunden; Schnittstelle zum Schulverwaltungsprogramm.</p>
<hr />
<h2 id="p2-schichtplanung-für-ein-pflegeteam">P2 — Schichtplanung für ein Pflegeteam</h2>
<blockquote>
<p><strong>Schwierigkeit:</strong> ⭐⭐⭐ · <strong>Kapitel:</strong> <a href="milp.html#kap-milp">Kapitel 6</a>, <a href="cpsat.html#kap-cpsat">Kapitel 7</a>, <a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a> · <strong>Zeit:</strong> ca. 20 Stunden</p>
</blockquote>
<p><strong>Ausgangslage.</strong> 25 Pflegekräfte, drei Schichten täglich, 28-Tage-Zyklus. Es gelten Arbeitszeitgesetz, Tarifvertrag, Qualifikationsmix und individuelle Wünsche.</p>
<p><strong>Modellskizze.</strong> * Variablen: <span class="math inline">x_{p,t,s} \in \{0,1\}</span> — Person, Tag, Schicht. * Hart: Mindestbesetzung je Schicht <strong>und</strong> Qualifikationsmix (mindestens eine examinierte Kraft); nach Nachtschicht ≥ 2 freie Tage; höchstens 6 Arbeitstage in Folge; monatliche Sollstunden ± 10 %. * Weich: Wunschfrei, gleichmäßige Wochenendverteilung, ungeteilte Dienste, stabile Schichtfolgen (nicht FrühNachtFrüh). * Solver: CP-SAT mit Intervall- und Cumulative-Constraints.</p>
<p><strong>Abnahmekriterien.</strong> - [ ] Alle gesetzlichen Regeln nachweislich eingehalten (per <code>assert</code> geprüft). - [ ] Wunscherfüllungsquote wird ausgewiesen und ist fair verteilt (Gini-Koeffizient). - [ ] Läuft in unter 60 Sekunden. - [ ] Bei Unlösbarkeit: Notfallplan plus benannte Ursache.</p>
<p><strong>Stolperfallen.</strong> Der 28-Tage-Zyklus erzeugt viele Variablen (25 × 28 × 3 = 2100) — Symmetriebrechung und gute Suchheuristiken werden wichtig. Fairness über einen Monat ist etwas anderes als Fairness über eine Woche.</p>
<hr />
<h2 id="p3-tourenplanung-für-einen-lieferdienst">P3 — Tourenplanung für einen Lieferdienst</h2>
<blockquote>
<p><strong>Schwierigkeit:</strong> ⭐⭐ · <strong>Kapitel:</strong> <a href="graphen.html#kap-graphen">Kapitel 8</a> · <strong>Zeit:</strong> ca. 12 Stunden</p>
</blockquote>
<p><strong>Ausgangslage.</strong> Ein regionaler Lieferdienst fährt täglich 4080 Adressen mit 4 Fahrzeugen an. Kunden haben Zeitfenster, Fahrzeuge Kapazitäten, Fahrer Arbeitszeiten.</p>
<p><strong>Daten.</strong> Adressen aus einer CSV; Entfernungen über OpenStreetMap (<code>osmnx</code>, <code>openrouteservice</code>) oder als Luftlinie mit Umwegfaktor 1,3 als Näherung.</p>
<p><strong>Modellskizze.</strong> OR-Tools Routing-Bibliothek mit Kapazitäts- und Zeitdimension; Metaheuristik <code>GUIDED_LOCAL_SEARCH</code>, Zeitlimit 30 Sekunden.</p>
<p><strong>Abnahmekriterien.</strong> - [ ] Alle Kunden werden innerhalb ihrer Zeitfenster beliefert. - [ ] Vergleich gegen die bisherige manuelle Tourenplanung: Ersparnis in km und Minuten. - [ ] Kartendarstellung der Touren (<code>folium</code>). - [ ] Robust gegen Ausfall eines Fahrzeugs (Neuplanung in unter 30 s).</p>
<p><strong>Stolperfallen.</strong> Luftlinie unterschätzt Fahrzeiten systematisch — mit realistischem Umwegfaktor arbeiten oder echte Routing-Distanzen holen. Zeitfenster, die physisch nicht erreichbar sind, führen zu „keine Lösung“ ohne Erklärung: Vorabprüfung einbauen (siehe <a href="graphen.html#kap-graphen">Kapitel 8</a>).</p>
<hr />
<h2 id="p4-standort--und-lagernetzplanung">P4 — Standort- und Lagernetzplanung</h2>
<blockquote>
<p><strong>Schwierigkeit:</strong> ⭐⭐⭐ · <strong>Kapitel:</strong> <a href="milp.html#kap-milp">Kapitel 6</a>, <a href="graphen.html#kap-graphen">Kapitel 8</a> · <strong>Zeit:</strong> ca. 15 Stunden</p>
</blockquote>
<p><strong>Ausgangslage.</strong> Ein Handelsunternehmen prüft, welche von 12 möglichen Lagerstandorten eröffnet werden sollen, um 60 Filialen zu versorgen.</p>
<p><strong>Modellskizze.</strong> Kombiniertes Standort- und Transportproblem: * <span class="math inline">y_j \in \{0,1\}</span> — Lager <span class="math inline">j</span> eröffnen (Fixkosten). * <span class="math inline">x_{ij} \ge 0</span> — Menge von Lager <span class="math inline">j</span> zu Filiale <span class="math inline">i</span>. * Kopplung: <span class="math inline">x_{ij} \le M\,y_j</span>; Kapazität je Lager; Bedarfsdeckung je Filiale. * Ziel: Fixkosten + Transportkosten minimieren.</p>
<p><strong>Abnahmekriterien.</strong> - [ ] Sensitivitätsanalyse: Wie verändert sich die Lösung bei ±20 % Transportkosten? - [ ] Was-wäre-wenn: Standort X wird politisch vorgegeben — was kostet das? - [ ] Kartendarstellung mit Zuordnungslinien. - [ ] Amortisationsrechnung über 10 Jahre.</p>
<p><strong>Stolperfallen.</strong> Big-M zu groß wählen (<a href="milp.html#kap-milp">Kapitel 6</a>) — hier ist die Lagerkapazität die natürliche Wahl. Fixkosten sind einmalig, Transportkosten laufend: <strong>Barwerte rechnen</strong>, nicht einfach addieren.</p>
<hr />
<h2 id="p5-produktionsplanung-mit-rüstkosten">P5 — Produktionsplanung mit Rüstkosten</h2>
<blockquote>
<p><strong>Schwierigkeit:</strong> ⭐⭐⭐ · <strong>Kapitel:</strong> <a href="lp.html#kap-lp">Kapitel 5</a>, <a href="milp.html#kap-milp">Kapitel 6</a>, <a href="cpsat.html#kap-cpsat">Kapitel 7</a> · <strong>Zeit:</strong> ca. 18 Stunden</p>
</blockquote>
<p><strong>Ausgangslage.</strong> Eine Fertigung produziert 15 Varianten auf 4 Maschinen. Jeder Produktwechsel kostet Rüstzeit; die Rüstzeit hängt von der Reihenfolge ab.</p>
<p><strong>Modellskizze.</strong> Los- und Reihenfolgeplanung: * Variablen: Produktionsmengen, Rüstentscheidungen, Reihenfolge (Intervallvariablen). * Hart: Bedarfsdeckung je Periode, Maschinenkapazität, Mindestlosgrößen. * Ziel: Rüst- + Lager- + Fehlmengenkosten minimieren. * Solver: CP-SAT mit <code>AddNoOverlap</code> und reihenfolgeabhängigen Übergangszeiten.</p>
<p><strong>Abnahmekriterien.</strong> - [ ] Gantt-Diagramm der Maschinenbelegung. - [ ] Vergleich gegen die aktuelle Praxis (Ersparnis in Rüststunden). - [ ] Schattenpreise: Welche Maschine ist der Engpass, was wäre eine zusätzliche Schicht wert?</p>
<hr />
<h2 id="p6-portfolio-rebalancer-für-ein-privatdepot">P6 — Portfolio-Rebalancer für ein Privatdepot</h2>
<blockquote>
<p><strong>Schwierigkeit:</strong> ⭐⭐⭐ · <strong>Kapitel:</strong> <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> bis <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a> · <strong>Zeit:</strong> ca. 20 Stunden</p>
<p>⚠️ <strong>Keine Anlageberatung.</strong> Dieses Projekt dient dem Methodenverständnis. Setzen Sie kein echtes Geld auf ein selbstgebautes Modell, dessen Grenzen Sie nicht vollständig verstehen.</p>
</blockquote>
<p><strong>Ausgangslage.</strong> Ein Privatdepot aus 1015 ETFs und Einzeltiteln soll quartalsweise zurückgeführt werden — unter Berücksichtigung von Ordergebühren, Mindestordergrößen und der Steuerfreibetragsnutzung.</p>
<p><strong>Modellskizze.</strong> * Variablen: Zielgewichte <span class="math inline">w_i</span>; Binärvariablen für „Position wird gehandelt“. * Hart: Vollinvestition, keine Leerverkäufe, Positionsobergrenzen, Mindestordergröße (semikontinuierlich, <a href="milp.html#kap-milp">Kapitel 6</a>), höchstens <span class="math inline">K</span> Transaktionen je Rebalancing. * Ziel: erwartete Rendite Risikoterm Transaktionskosten Steuerwirkung. * Solver: CVXPY (konvexer Teil) oder MIQP für die Kardinalität.</p>
<p><strong>Abnahmekriterien.</strong> - [ ] Toleranzband: Es wird nur gehandelt, wenn die Abweichung &gt; 5 Prozentpunkte beträgt. - [ ] Alle Kosten (Ordergebühr, Spread, Steuer) sind explizit ausgewiesen. - [ ] Backtest über 5 Jahre mit Lookahead-Selbsttest. - [ ] Vergleich gegen: nie rebalancen, jährlich rebalancen, Gleichgewichtung. - [ ] Bericht, den ein Nicht-Fachmann versteht.</p>
<p><strong>Stolperfallen.</strong> Steuern sind pfadabhängig (FIFO, Freibetrag) und passen nicht sauber in ein einperiodiges Modell — Näherung wählen und die Näherung <strong>dokumentieren</strong>. Und: Wenn Ihre Strategie die Gleichgewichtung nicht schlägt, ist das ein Ergebnis, kein Misserfolg.</p>
<hr />
<h2 id="p7-risikoreport-mit-cvar-und-stresstests">P7 — Risikoreport mit CVaR und Stresstests</h2>
<blockquote>
<p><strong>Schwierigkeit:</strong> ⭐⭐ · <strong>Kapitel:</strong> <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a>, <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a>, <a href="cvar.html#kap-cvar">Kapitel 20</a> · <strong>Zeit:</strong> ca. 12 Stunden</p>
</blockquote>
<p><strong>Ausgangslage.</strong> Für ein bestehendes Portfolio soll ein monatlicher Risikobericht entstehen.</p>
<p><strong>Inhalte des Berichts.</strong> * VaR und CVaR auf 95 % und 99 %, historisch <strong>und</strong> Monte-Carlo-simuliert. * Risikobeiträge je Position (<em>marginal CVaR</em>): Wer treibt das Risiko? * Stresstests: Was passiert bei 20 % Aktienmarkt, +200 Basispunkten Zins, Korrelationsanstieg auf 0,9? * Historische Szenarien nachspielen (2008, März 2020). * Konzentrationskennzahlen (Herfindahl-Index, effektive Titelzahl).</p>
<p><strong>Abnahmekriterien.</strong> - [ ] Bericht als PDF, automatisch erzeugt. - [ ] Alle Kennzahlen mit zwei unabhängigen Methoden berechnet und verglichen. - [ ] Klartext-Zusammenfassung: „Im schlechtesten Prozent der Monate verlieren Sie typischerweise X €.“</p>
<p><strong>Stolperfallen.</strong> Die Wurzel-Zeit-Regel bei CVaR (<a href="cvar.html#kap-cvar">Kapitel 20</a>) — nicht blind anwenden. Korrelationen sind in Krisen andere als im Mittel: Stresstest mit erhöhten Korrelationen rechnen.</p>
<hr />
<h2 id="p9-wenn-der-solver-aussteigt-tourenplanung-in-echtgröße">P9 — Wenn der Solver aussteigt: Tourenplanung in Echtgröße</h2>
<blockquote>
<p><strong>Schwierigkeit:</strong> ⭐⭐⭐ · <strong>Kapitel:</strong> <a href="graphen.html#kap-graphen">Kapitel 8</a>, <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a> · <strong>Zeit:</strong> ca. 18 Stunden</p>
</blockquote>
<p><strong>Ausgangslage.</strong> P3 hat funktioniert — mit 30 Kunden. Der Auftraggeber kommt mit 400 zurück, und derselbe Code liefert nach zwanzig Minuten noch keine Lösung. Das ist keine Panne, sondern der erwartbare Umschlagpunkt.</p>
<p><strong>Modellskizze.</strong> Zwei Verfahren am <strong>selben</strong> Problem, verglichen unter <strong>gleichem Zeitbudget</strong>: * Exakt: MILP oder CP-SAT wie in P3, mit Zeitlimit und protokolliertem Gap. * Heuristisch: Startlösung mit einer Faustregel, dann Verbesserung durch Simulated Annealing oder Large Neighborhood Search (<a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a>). * Messgröße ist nicht „wer gewinnt”, sondern <strong>ab welcher Instanzgröße</strong> sich das Blatt wendet.</p>
<p><strong>Abnahmekriterien.</strong> - [ ] Eine Tabelle über mindestens vier Instanzgrößen: exakt gegen heuristisch, jeweils Zielwert und Laufzeit. - [ ] Der Umschlagpunkt ist auf ±50 Kunden eingegrenzt und <strong>benannt</strong>. - [ ] Bei kleinen Instanzen wird gegen die bewiesen optimale Lösung geprüft — sonst weiß niemand, wie gut die Heuristik wirklich ist. - [ ] Fester Seed, reproduzierbarer Lauf; das Zugbudget ist fix, nicht die Uhrzeit.</p>
<blockquote>
<p>⚠️ <strong>Die Falle, in die hier fast jeder tappt:</strong> die Heuristik nur auf großen Instanzen zu testen, wo man das Optimum nicht kennt. Dann sieht jede Lösung gut aus.</p>
</blockquote>
<hr />
<h2 id="p10-zwei-ziele-eine-entscheidung-kosten-gegen-co₂">P10 — Zwei Ziele, eine Entscheidung: Kosten gegen CO₂</h2>
<blockquote>
<p><strong>Schwierigkeit:</strong> ⭐⭐ · <strong>Kapitel:</strong> <a href="milp.html#kap-milp">Kapitel 6</a>, <a href="mehrziel.html#kap-mehrziel">Kapitel 14</a> · <strong>Zeit:</strong> ca. 14 Stunden</p>
</blockquote>
<p><strong>Ausgangslage.</strong> Die Geschäftsführung will „günstiger <strong>und</strong> grüner”. Beides zugleich gibt es nicht — und die übliche Antwort, beide Ziele mit Gewichten zu verrechnen, verdeckt genau die Frage, um die es geht.</p>
<p><strong>Modellskizze.</strong> Ein Transport-, Beschaffungs- oder Produktionsmodell mit zwei Zielen: * Erst beide Ziele <strong>einzeln</strong> optimieren — das gibt die Eckpunkte und damit den Rahmen. * Dann die Front über das <span class="math inline">\varepsilon</span>-Constraint-Verfahren abfahren (<a href="mehrziel.html#kap-mehrziel">Kapitel 14</a>): ein Ziel minimieren, das andere als Nebenbedingung schrittweise verschärfen. * Ergebnis ist <strong>keine Lösung, sondern eine Kurve</strong> — plus die Angabe, was jeder eingesparte Kilogramm CO₂ an Mehrkosten bedeutet.</p>
<p><strong>Abnahmekriterien.</strong> - [ ] Die Pareto-Front ist berechnet und gezeichnet, nicht nur beschrieben. - [ ] Für mindestens zwei Punkte ist der Aufpreis je eingesparter Einheit ausgerechnet. - [ ] Es ist geprüft und dokumentiert, welche Punkte der Front eine <strong>gewichtete Summe niemals</strong> finden würde — und warum. - [ ] Die Entscheidungsvorlage nennt drei Punkte zur Auswahl, nicht dreißig.</p>
<hr />
<h2 id="p11-vom-skript-zum-dienst-das-modell-übergeben">P11 — Vom Skript zum Dienst: das Modell übergeben</h2>
<blockquote>
<p><strong>Schwierigkeit:</strong> ⭐⭐⭐ · <strong>Kapitel:</strong> <a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a>, <a href="testing.html#kap-testing">Kapitel 23</a> · <strong>Zeit:</strong> ca. 16 Stunden</p>
</blockquote>
<p><strong>Ausgangslage.</strong> Ihr Modell rechnet. Jetzt soll es jemand anderes benutzen — jemand, der weder Python noch Ihr Notebook kennt, und der es auch dann noch braucht, wenn Sie im Urlaub sind. Nehmen Sie <strong>eines Ihrer eigenen</strong> Projekte P1P10 als Grundlage; dies ist kein neues Modell, sondern der Schritt danach.</p>
<p><strong>Modellskizze.</strong> Vier Schichten, jede einzeln abnehmbar: * <strong>Domäne:</strong> Eingabedaten als validierte Objekte (Pydantic), nicht als lose Dictionaries — ein falscher Wert soll beim Einlesen auffallen, nicht im Solver (<a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a>). * <strong>Kern:</strong> Modellaufbau und Lösung hinter einer Funktion, die ein <code>Loesung</code>-Objekt zurückgibt und <strong>alle</strong> Statusfälle behandelt. * <strong>Tests:</strong> eine Suite, die auch die Fälle abdeckt, in denen es <em>keine</em> Lösung gibt (<a href="testing.html#kap-testing">Kapitel 23</a>). * <strong>Schnittstelle:</strong> ein HTTP-Dienst, der ein JSON entgegennimmt und eines zurückgibt.</p>
<p><strong>Abnahmekriterien.</strong> - [ ] Eine ungültige Eingabe wird <strong>vor</strong> dem Solver abgewiesen, mit einer Meldung, die den Fehler benennt. - [ ] Die Testsuite läuft grün und enthält mindestens einen INFEASIBLE-Fall. - [ ] Ein Mutationstest zeigt, dass die Tests eine absichtlich eingebaute Modelländerung auch wirklich bemerken. - [ ] Der Dienst antwortet auf eine Beispielanfrage per <code>curl</code> — dokumentiert samt Aufruf. - [ ] Es gibt eine Betriebsseite: Was tun, wenn der Solver <code>INFEASIBLE</code> meldet? Der Notfallplan gehört dazu, nicht die Fehlermeldung (<a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a>).</p>
<blockquote>
<p><strong>🎯 Der Prüfstein</strong> Geben Sie das Projekt einer Person, die nicht dabei war, zusammen mit dem README — und sagen Sie nichts. Was sie nicht allein zum Laufen bringt, ist nicht fertig.</p>
</blockquote>
<hr />
<h2 id="p8-freies-projekt-aus-ihrem-eigenen-umfeld">P8 — Freies Projekt aus Ihrem eigenen Umfeld</h2>
<blockquote>
<p><strong>Schwierigkeit:</strong> offen · <strong>Zeit:</strong> 1025 Stunden</p>
</blockquote>
<p><strong>Der Auftrag.</strong> Nehmen Sie die Notiz aus der Aufgabe <em>Eigenes Problem zerlegen</em> (<a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a>) hervor — das Problem aus Ihrem eigenen Alltag oder Beruf. Bauen Sie es.</p>
<p><strong>Bewährte Kandidaten aus früheren Kursen:</strong></p>
<table>
<colgroup>
<col style="width: 33%" />
<col style="width: 33%" />
<col style="width: 33%" />
</colgroup>
<thead>
<tr class="header">
<th>Problem</th>
<th>Verfahren</th>
<th>Kapitel</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Sitzordnung für eine Hochzeit (Sympathien/Antipathien)</td>
<td>CP-SAT</td>
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
</tr>
<tr class="even">
<td>Trainingsplan eines Sportvereins (Hallen, Trainer, Altersgruppen)</td>
<td>CP-SAT</td>
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
</tr>
<tr class="odd">
<td>Budgetaufteilung auf Projekte mit Abhängigkeiten</td>
<td>MILP</td>
<td><a href="milp.html#kap-milp">Kapitel 6</a></td>
</tr>
<tr class="even">
<td>Schnittoptimierung für Zuschnitt (Holz, Blech, Stoff)</td>
<td>MILP / Spaltengenerierung</td>
<td><a href="dekomposition.html#kap-dekomposition">Kapitel 10</a></td>
</tr>
<tr class="odd">
<td>Speiseplan unter Nährwert- und Budgetgrenzen</td>
<td>LP</td>
<td><a href="lp.html#kap-lp">Kapitel 5</a></td>
</tr>
<tr class="even">
<td>Prüfungsplanung (keine Kollisionen, Erholungspausen)</td>
<td>CP-SAT</td>
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
</tr>
<tr class="odd">
<td>Ladeplanung für E-Fahrzeugflotte (Lastspitzen vermeiden)</td>
<td>MILP + Cumulative</td>
<td><a href="milp.html#kap-milp">Kapitel 6</a>, <a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
</tr>
<tr class="even">
<td>Bewässerungsplan im Kleingarten (Wasser, Wetterprognose)</td>
<td>Stochastisch</td>
<td><a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a></td>
</tr>
</tbody>
</table>
<p><strong>Abnahmekriterien (für jedes freie Projekt).</strong> - [ ] Die Bausteine-Vorlage ist ausgefüllt und liegt dem Projekt bei. - [ ] Eine Kleinstinstanz ist von Hand nachgerechnet und stimmt mit dem Solver überein. - [ ] Alle Nebenbedingungen werden nach dem Lösen per <code>assert</code> geprüft. - [ ] Es gibt einen Vergleich gegen die bisherige (manuelle) Lösung — mit Zahlen. - [ ] Das Ergebnis ist erklärbar: Warum diese Lösung, warum nicht die naheliegende Alternative, was würde sie verbessern? - [ ] Die Grenzen des Modells sind dokumentiert: Was bildet es <strong>nicht</strong> ab?</p>
<hr />
<h2 id="eine-bitte-zum-schluss">Eine Bitte zum Schluss</h2>
<p>Wenn Sie ein Projekt fertig haben, machen Sie zwei Dinge:</p>
<p><strong>Erstens: Zeigen Sie es jemandem, der nichts von Optimierung versteht.</strong> Wenn diese Person nach fünf Minuten sagen kann, was das Programm tut und warum sie dem Ergebnis trauen sollte, haben Sie es richtig gemacht. Wenn nicht, fehlt die Erklärbarkeit — nicht das Verständnis Ihres Gegenübers.</p>
<p><strong>Zweitens: Schreiben Sie auf, was schiefgegangen ist.</strong> Jeder, der optimiert, produziert Fehler wie die in diesem Buch besprochenen (siehe z. B. <a href="lp.html#sec:lp-die-vorzeichenfalle-bei-schattenpreisen">Abschnitt 5.7</a> oder <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a>). Wer sie dokumentiert, macht sie kein zweites Mal — und hilft dem Nächsten.</p>
<p>Viel Erfolg.</p>
</article>
<nav class="prev-next"><a class="prev-next-knopf prev-next-prev" href="testing.html"><svg class="icon" aria-hidden="true"><use href="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 23: Testen, Messen, Ausliefern</span></a><a class="prev-next-knopf prev-next-next" href="anhang-loesungen.html"><span><small>Weiter</small>Anhang A: Lösungen zu allen Übungsaufgaben</span><svg class="icon" aria-hidden="true"><use href="#icon-chevron-right"></use></svg></a></nav>
</main>
</div>
<footer class="site-footer">
<p>© Dieter Schlüter · <a href="gesamtdokument.html">Gesamtdokument</a> ·
<a href="programme.html">Beispielprogramme</a></p>
</footer>
<script defer src="assets/search-index.js"></script>
<script defer src="assets/programme.js"></script>
<script defer src="assets/site.js"></script>
</body>
</html>