Achter Fund (Uebung-Verweise) und Phase 8.3: Dockerfile
Zwei Dinge in einem Commit, weil beide den Plan abschliessen.
ACHTER FUND: sieben Saetze der Bauart "Uebung 8.5 laesst Sie diese Balance
untersuchen" - und sechs davon standen in alter Zaehlung. "8" war in Version
03 das QP/NLP-Kapitel, heute ist es Kapitel 11. Dieselbe Familie wie die
Denkfehler-Verweise aus 6.1a, nur mit einem Wort, das keine der bestehenden
Pruefungen kannte.
Aufgaben haben kein eigenes Label, ein {ref:} auf eine einzelne Aufgabe ist
also nicht moeglich. Verwiesen wird stattdessen auf Abschnitt plus
Aufgabentitel - und der ist stabil. Jedes Ziel wurde einzeln ueber die alte
Zaehlung bestimmt und am Zusammenhang geprueft.
Ein Fall war knifflig: "Uebung 6.7 (Wochendienstplan)" meinte die siebte
CP-SAT-Aufgabe der alten Zaehlung, also "Eigener Dienstplan" - die heute an
achter Stelle steht, weil in Phase 6.3 eine Aufgabe davor eingefuegt wurde.
Wer nur die Kapitelnummer angepasst haette, waere bei der falschen Aufgabe
gelandet.
--check kennt jetzt auch "Uebung"/"Übung". Gegengetestet.
PHASE 8.3: Dockerfile, zweistufig. Die erste Stufe uebersetzt die
Abhaengigkeiten in eine virtuelle Umgebung und braucht dafuer einen
Compiler, die zweite kopiert nur /opt/venv. Installiert werden die Gruppen
finance, large-scale, api und dev aus pyproject.toml; figures fehlt bewusst,
weil es zusaetzlich Graphviz verlangt.
Es wurde nicht behauptet, sondern gebaut. Ergebnis: 1,31 GB, und darin der
Installationstest mit allen drei Solver-Funktionstests bestanden, die 33
pytest-Tests bestanden und alle 69 netzfreien Programme fehlerfrei -
einschliesslich der drei aus 8.2, deren spawn-Isolation im Container ebenso
traegt wie ausserhalb.
Zwei Dinge, die der Bau gelehrt hat: libgomp1 fehlt im python:3.12-slim-Image
und wird von OR-Tools und HiGHS zur Laufzeit gebraucht (sonst
"libgomp.so.1: cannot open shared object file"). Und ein eigener Fehler:
USER kurs stand vor dem mkdir /buch/output, /buch gehoert root, der Bau
brach in der letzten Zeile ab. Beides steht jetzt als Kommentar im
Dockerfile.
Das Image fuehrt die Programme aus und baut das Buch nicht. Ein
.dockerignore haelt Website, PDF und Notebooks aus dem Build-Kontext. Und es
enthaelt ortools UND highspy, obwohl sie sich nicht gemeinsam importieren
lassen - der Konflikt wird zur Laufzeit durch getrennte Prozesse geloest,
nicht durch Weglassen.
Damit ist Phase 8 abgeschlossen und der Plan abgearbeitet.
Stand: 825 Querverweise, 76 Programme, 33 pytest-Tests, PDF 760 Seiten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
862e92bc7b
commit
35cc0da166
22 changed files with 232 additions and 29 deletions
28
.dockerignore
Normal file
28
.dockerignore
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# Was NICHT in den Build-Kontext gehoert. Ohne diese Datei schickt Docker das
|
||||
# ganze Verzeichnis an den Daemon - mitsamt Website (rund 50 MB), PDF und
|
||||
# Notebooks, die im Image nichts zu suchen haben.
|
||||
|
||||
# Erzeugte Ausgaben
|
||||
OR_HTML_04/
|
||||
Notebooks_04/
|
||||
*.pdf
|
||||
Operations_Research_mit_Python_Version_04.md
|
||||
|
||||
# Quellen des Buchsatzes - das Image fuehrt die Programme aus, es baut das
|
||||
# Buch nicht. Wer das PDF bauen will, braucht pandoc, xelatex und inkscape
|
||||
# und ist mit einer lokalen Installation besser bedient.
|
||||
bilder_04/
|
||||
pandoc/
|
||||
pandoc-defaults-*.yaml
|
||||
Kritik_und_Verbesserungsvorschlaege/
|
||||
PLAN.md
|
||||
PROGRESS.md
|
||||
CLAUDE.md
|
||||
|
||||
# Von Laeufen erzeugte Dateien
|
||||
**/__pycache__/
|
||||
**/output/
|
||||
*.xlsx
|
||||
.git/
|
||||
.venv/
|
||||
venv/
|
||||
|
|
@ -33,6 +33,7 @@ Notebooks_04/ generiert: ein .ipynb je Kapitel
|
|||
Kritik_und_Verbesserungsvorschlaege/ Quelle: Rezension, Verbesserungsvorschläge,
|
||||
NEUER_TITEL.md (Vorlage des Titelblatts)
|
||||
pyproject.toml Quelle: Abhängigkeiten in Gruppen
|
||||
Dockerfile, .dockerignore Quelle: Kurs-Image (nur Programme)
|
||||
pandoc-defaults-basis.yaml, pandoc/, pandoc-defaults-buch.yaml PDF-Konfiguration
|
||||
```
|
||||
|
||||
|
|
|
|||
79
Dockerfile
Normal file
79
Dockerfile
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# Kurs-Image zu "Optimierte Entscheidungsfindung mit Python".
|
||||
#
|
||||
# Was es ist: eine reproduzierbare Umgebung, in der alle Beispielprogramme
|
||||
# laufen - ohne dass jemand Solver, BLAS-Bibliotheken und Python-Versionen von
|
||||
# Hand zusammensuchen muss.
|
||||
#
|
||||
# Was es NICHT ist: eine Bauumgebung fuer das Buch. Das PDF braucht pandoc,
|
||||
# xelatex und inkscape, zusammen ueber ein Gigabyte. Wer das Buch selbst baut,
|
||||
# ist mit einer lokalen Installation besser bedient (siehe README.md).
|
||||
#
|
||||
# docker build -t or-mit-python .
|
||||
# docker run --rm or-mit-python Installationstest.py
|
||||
# docker run --rm -it or-mit-python # Python-Eingabe
|
||||
# docker run --rm -v "$PWD/ausgabe:/buch/output" or-mit-python Excel_Bruecke.py
|
||||
#
|
||||
# Zwei Stufen: Die erste baut die Abhaengigkeiten in eine virtuelle Umgebung
|
||||
# (und braucht dafuer Compiler), die zweite kopiert nur das Ergebnis. Das
|
||||
# spart im fertigen Image die gesamte Bauumgebung.
|
||||
|
||||
# --- Stufe 1: Abhaengigkeiten uebersetzen und einsammeln ---------------------
|
||||
FROM python:3.12-slim AS bau
|
||||
|
||||
# build-essential wird von Paketen gebraucht, die kein passendes Wheel
|
||||
# mitbringen. Bleibt in dieser Stufe und landet nie im fertigen Image.
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
build-essential \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV PIP_NO_CACHE_DIR=1 \
|
||||
PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||
RUN python -m venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
# Nur die Abhaengigkeitsbeschreibung kopieren, nicht den Quelltext: So bleibt
|
||||
# diese Schicht im Cache, solange sich die Abhaengigkeiten nicht aendern.
|
||||
WORKDIR /buch
|
||||
COPY pyproject.toml README.md ./
|
||||
|
||||
# Die Gruppen aus pyproject.toml. 'figures' fehlt bewusst - es dient dem
|
||||
# Neuerzeugen der Diagramme, wofuer zusaetzlich Graphviz noetig waere.
|
||||
#
|
||||
# ACHTUNG, gewollt: Das Image enthaelt ortools UND highspy, obwohl beide eine
|
||||
# eigene HiGHS-Kopie mitbringen und sich nicht gemeinsam importieren lassen.
|
||||
# Der Konflikt wird nicht durch Weglassen geloest, sondern zur Laufzeit durch
|
||||
# getrennte Prozesse (Kapitel Oekosystem). Ein Image, das nur eines von beiden
|
||||
# enthaelt, koennte die Haelfte der Beispiele nicht ausfuehren.
|
||||
RUN pip install ".[finance,large-scale,api,dev]"
|
||||
|
||||
# --- Stufe 2: das eigentliche Image -----------------------------------------
|
||||
FROM python:3.12-slim AS laufzeit
|
||||
|
||||
# libgomp1 wird von OR-Tools und HiGHS zur Laufzeit gebraucht (OpenMP) und ist
|
||||
# im slim-Image nicht enthalten. Ohne es scheitert der erste Solveraufruf mit
|
||||
# einem 'libgomp.so.1: cannot open shared object file'.
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
libgomp1 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=bau /opt/venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH" \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
MPLBACKEND=Agg
|
||||
|
||||
# Kein root. Die Programme brauchen keine Rechte, und ein Kurs-Image, das als
|
||||
# root laeuft, ist eine schlechte Angewohnheit, die man weitergibt.
|
||||
RUN useradd --create-home --uid 1000 kurs
|
||||
WORKDIR /buch
|
||||
COPY --chown=kurs:kurs Operations_Research_mit_Python_Version_04_Programme/ ./
|
||||
|
||||
# Verzeichnis fuer erzeugte Dateien - als Volume einhaengbar, damit
|
||||
# Excel-Ausgaben und Diagramme den Container ueberleben. Angelegt wird es
|
||||
# VOR dem Benutzerwechsel, denn /buch gehoert root.
|
||||
RUN mkdir -p /buch/output && chown kurs:kurs /buch/output
|
||||
USER kurs
|
||||
|
||||
# Ohne Argument eine Python-Eingabeaufforderung, mit Argument das genannte
|
||||
# Programm: 'docker run --rm or-mit-python Rucksack.py'
|
||||
ENTRYPOINT ["python"]
|
||||
CMD []
|
||||
Binary file not shown.
|
|
@ -718,7 +718,7 @@ g_i(\mathbf{x}) \le b_i \qquad \text{bzw.} \qquad h_j(\mathbf{x}) = 0
|
|||
<li><strong>Harte Bedingungen:</strong> <span class="math inline">0{,}5x_1 + 0{,}6x_2 \le 90</span> (Mehl); <span class="math inline">4x_1 + 3x_2 \le 600</span> (Ofen); <span class="math inline">x_1 \ge 40</span> (Vertrag).</li>
|
||||
<li><strong>Weiche Bedingungen:</strong> keine.</li>
|
||||
</ul>
|
||||
<p>Dieses Problem lösen Sie in Übung 1.5 selbst.</p>
|
||||
<p>Dieses Problem lösen Sie in der Aufgabe <em>Die Bäckerei programmieren</em> (<a href="#sec:einfuehrung-uebungsaufgaben">Abschnitt 1.9</a>) selbst.</p>
|
||||
</blockquote>
|
||||
<p>Die Vorlage lässt sich fast wörtlich in Code übersetzen — wer die fünf Zeilen ausgefüllt hat, hat den größten Teil der Modellierungsarbeit schon erledigt:</p>
|
||||
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||||
|
|
|
|||
|
|
@ -541,7 +541,7 @@ Bestmoegliche Volatilitaet bei perfektem Wissen: 11.84 % p.a.
|
|||
</table>
|
||||
<p><strong>Wichtig ist, Text und Code konsistent auf dieselbe Variante zu beziehen</strong> — zum Beispiel <code>sklearn.covariance.LedoitWolf</code>, das die skalierte Einheitsmatrix verwendet, versus eine manuelle Implementierung des Konstant-Korrelations-Ziels. Dieses Buch nennt beide und macht transparent, welches wo zum Einsatz kommt.</p>
|
||||
<blockquote>
|
||||
<p><strong>💡 Welches Ziel ist besser?</strong> Es kommt darauf an. Die <strong>Einheitsmatrix</strong> unterstellt, dass alle Titel gleich riskant und unkorreliert sind — eine starke, aber sehr stabile Annahme. Das <strong>Konstant-Korrelations-Ziel</strong> behält die geschätzten Einzelvarianzen und glättet nur die Korrelationen; das ist bei Aktien meist realistischer, weil Titel tatsächlich sehr unterschiedliche Volatilitäten haben. In Übung 11.5 implementieren Sie es selbst und vergleichen.</p>
|
||||
<p><strong>💡 Welches Ziel ist besser?</strong> Es kommt darauf an. Die <strong>Einheitsmatrix</strong> unterstellt, dass alle Titel gleich riskant und unkorreliert sind — eine starke, aber sehr stabile Annahme. Das <strong>Konstant-Korrelations-Ziel</strong> behält die geschätzten Einzelvarianzen und glättet nur die Korrelationen; das ist bei Aktien meist realistischer, weil Titel tatsächlich sehr unterschiedliche Volatilitäten haben. In der Aufgabe <em>Beide Shrinkage-Ziele vergleichen</em> (<a href="#sec:finanzdaten-uebungsaufgaben">Abschnitt 18.7</a>) implementieren Sie es selbst und vergleichen.</p>
|
||||
</blockquote>
|
||||
<p>Das Ergebnis ist in jedem Fall garantiert <strong>positiv definit</strong>, wohlkonditioniert und stabil invertierbar.</p>
|
||||
<hr />
|
||||
|
|
|
|||
|
|
@ -3713,7 +3713,7 @@ g_i(\mathbf{x}) \le b_i \qquad \text{bzw.} \qquad h_j(\mathbf{x}) = 0
|
|||
<li><strong>Harte Bedingungen:</strong> <span class="math inline">0{,}5x_1 + 0{,}6x_2 \le 90</span> (Mehl); <span class="math inline">4x_1 + 3x_2 \le 600</span> (Ofen); <span class="math inline">x_1 \ge 40</span> (Vertrag).</li>
|
||||
<li><strong>Weiche Bedingungen:</strong> keine.</li>
|
||||
</ul>
|
||||
<p>Dieses Problem lösen Sie in Übung 1.5 selbst.</p>
|
||||
<p>Dieses Problem lösen Sie in der Aufgabe <em>Die Bäckerei programmieren</em> (<a href="#sec:einfuehrung-uebungsaufgaben">Abschnitt 1.9</a>) selbst.</p>
|
||||
</blockquote>
|
||||
<p>Die Vorlage lässt sich fast wörtlich in Code übersetzen — wer die fünf Zeilen ausgefüllt hat, hat den größten Teil der Modellierungsarbeit schon erledigt:</p>
|
||||
<div class="sourceCode" id="cb9"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||||
|
|
@ -8876,7 +8876,7 @@ Pruefung: komplementaerer Schlupf fuer alle Ressourcen erfuellt.
|
|||
</blockquote>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Grenzen der Schattenpreis-Aussage</strong></p>
|
||||
<p>Der Schattenpreis gilt nur <strong>lokal</strong>, in einem begrenzten Intervall um die aktuelle Kapazität. Kauft man 200 Prüfstunden zu, wird irgendwann eine andere Ressource zum Engpass, und der Schattenpreis springt auf einen neuen Wert (oder auf null). Wer große Kapazitätsänderungen bewerten will, muss das Modell <strong>neu rechnen</strong> — nicht linear hochrechnen. Übung 4.6 macht diesen Effekt sichtbar.</p>
|
||||
<p>Der Schattenpreis gilt nur <strong>lokal</strong>, in einem begrenzten Intervall um die aktuelle Kapazität. Kauft man 200 Prüfstunden zu, wird irgendwann eine andere Ressource zum Engpass, und der Schattenpreis springt auf einen neuen Wert (oder auf null). Wer große Kapazitätsänderungen bewerten will, muss das Modell <strong>neu rechnen</strong> — nicht linear hochrechnen. Die Aufgabe <em>Gültigkeitsbereich des Schattenpreises</em> (<a href="#sec:lp-uebungsaufgaben">Abschnitt 5.10</a>) macht diesen Effekt sichtbar.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:lp-entartung">5.9 Wann Schattenpreise lügen: Entartung und Toleranzen</h2>
|
||||
|
|
@ -16742,7 +16742,7 @@ US-Treasuries 3.0 % 7.0 % 0.45 %
|
|||
<li><strong>Multistart.</strong> Zehn Startpunkte, und die Spannweite der Ergebnisse wird gemessen. Sind alle gleich, ist das ein starkes Indiz für Konvexität. Weichen sie ab, wissen Sie sofort, dass Sie einem lokalen Optimum aufsitzen. Diese fünf Zeilen sollten in jedem SLSQP-Projekt stehen.</li>
|
||||
<li><strong>Analytischer Gradient.</strong> <code>jac=gradient</code> spart nicht nur Zeit — die numerische Approximation von Ableitungen ist bei Termen wie <span class="math inline">\ln w</span> nahe null numerisch heikel.</li>
|
||||
</ol>
|
||||
<p><strong>Zur Skalierung:</strong> Mit <span class="math inline">\alpha = 1</span> ist der Ertragsterm (<span class="math inline">\approx 0{,}1</span>) zehnmal größer als der Varianzterm (<span class="math inline">\approx 0{,}01</span>). Das Modell ist also stark renditegetrieben. Übung 8.5 lässt Sie diese Balance untersuchen — sie ist eine fachliche Entscheidung, keine technische.</p>
|
||||
<p><strong>Zur Skalierung:</strong> Mit <span class="math inline">\alpha = 1</span> ist der Ertragsterm (<span class="math inline">\approx 0{,}1</span>) zehnmal größer als der Varianzterm (<span class="math inline">\approx 0{,}01</span>). Das Modell ist also stark renditegetrieben. Die Aufgabe <em>Effekt der Gewichtung untersuchen</em> (<a href="#sec:qp-nlp-uebungsaufgaben">Abschnitt 11.7</a>) lässt Sie diese Balance untersuchen — sie ist eine fachliche Entscheidung, keine technische.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:qp-nlp-nichtkonvex">11.6 Jenseits der Konvexität: lokale Optima, Multistart und MINLP</h2>
|
||||
|
|
@ -17683,7 +17683,7 @@ Feinsuche (Raster 100..500): Optimum bei Kapazitaet 180, Kosten 12,810 EUR
|
|||
<p><strong>🎯 Eine wichtige Einschränkung — und was man daraus lernt</strong></p>
|
||||
<p>Hier kostet die naive Mittelwertplanung nur <strong>1 %</strong>. In der Handrechnung zum Fluch des Durchschnitts waren es 2,7 %, in Lehrbüchern liest man von 20 % und mehr. <strong>Wie groß der Effekt ist, hängt von der Verteilung ab</strong> — und das ist selbst die Lektion.</p>
|
||||
<p>Bei dieser Mischverteilung liegt zwischen dem Normalbetrieb (um 150) und den Lastspitzen (um 450) ein Bereich, in dem kaum Wahrscheinlichkeitsmasse liegt. Zusätzliche Kapazität zwischen 200 und 400 nützt daher wenig: Sie ist im Normalfall Leerlauf und reicht im Krisenfall trotzdem nicht. Deshalb ist die Kostenkurve dort flach, und die Wahl zwischen 180 und 196 macht kaum einen Unterschied.</p>
|
||||
<p><strong>Was Sie mitnehmen sollten:</strong> Die Frage „Wie teuer ist Mittelwertplanung?“ hat keine allgemeine Antwort — <strong>rechnen Sie es aus.</strong> Genau dafür ist Monte-Carlo da. Und beachten Sie die Spalte „Unterdeckung“: Bei Kapazität 200 wird in <strong>24 % der Fälle</strong> nachgekauft. Ob das akzeptabel ist, entscheidet kein Optimierer, sondern ein Servicelevel-Ziel (Übung 9.5).</p>
|
||||
<p><strong>Was Sie mitnehmen sollten:</strong> Die Frage „Wie teuer ist Mittelwertplanung?“ hat keine allgemeine Antwort — <strong>rechnen Sie es aus.</strong> Genau dafür ist Monte-Carlo da. Und beachten Sie die Spalte „Unterdeckung“: Bei Kapazität 200 wird in <strong>24 % der Fälle</strong> nachgekauft. Ob das akzeptabel ist, entscheidet kein Optimierer, sondern ein Servicelevel-Ziel (Aufgabe <em>Monte-Carlo erweitern</em>, <a href="#sec:unsicherheit-uebungsaufgaben">Abschnitt 12.8</a>).</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p><strong>💡 Wann Monte-Carlo das richtige Werkzeug ist</strong> Immer dann, wenn Sie <strong>eine Kennzahl brauchen, die keine Formel hat</strong>: die Wahrscheinlichkeit, ein Servicelevel zu verfehlen; der erwartete Verlust in den schlechtesten 5 % der Fälle; die Verteilung der Projektdauer. Der Preis ist, dass Monte-Carlo nur <strong>bewertet</strong> — die Optimierung müssen Sie durch Rastersuche oder ein eigenes Modell ergänzen.</p>
|
||||
|
|
@ -17862,7 +17862,7 @@ den Mittelwert (225), weil Unterdeckung (120 EUR)
|
|||
deutlich teurer ist als Leerlauf (5 EUR).
|
||||
==================================================================================</code></pre>
|
||||
<p><strong>Lesen Sie die Vergleichstabelle von unten nach oben.</strong> Die beiden extremen Haltungen sind die teuersten: Wer den Worst Case abdeckt (500 Einheiten), zahlt 5 000 € zu viel für Kapazität, die in 80 % der Fälle brachliegt. Wer optimistisch plant (100), zahlt 2 625 € Strafe für ständige Notzukäufe. Die naive Mittelwertplanung liegt dazwischen — aber eben auch nicht optimal.</p>
|
||||
<p>Der <strong>EVPI von 7 375 €</strong> ist bemerkenswert hoch: 45 % der Gesamtkosten entstehen allein daraus, dass man die Zukunft nicht kennt. In so einem Fall lohnt sich Investition in bessere Prognosen tatsächlich — anders als in dem Beispiel aus Übung 9.4.</p>
|
||||
<p>Der <strong>EVPI von 7 375 €</strong> ist bemerkenswert hoch: 45 % der Gesamtkosten entstehen allein daraus, dass man die Zukunft nicht kennt. In so einem Fall lohnt sich Investition in bessere Prognosen tatsächlich — anders als in dem Beispiel aus der Aufgabe <em>EVPI interpretieren</em> (<a href="#sec:unsicherheit-uebungsaufgaben">Abschnitt 12.8</a>).</p>
|
||||
<blockquote>
|
||||
<p><strong>💡 Was ist der EVPI?</strong> Der <strong>Expected Value of Perfect Information</strong> beziffert, wie viel eine perfekte Prognose wert wäre: die Differenz zwischen den Kosten unter Unsicherheit und den Kosten bei vollständigem Wissen. Er ist eine <strong>Obergrenze für jedes Prognoseprojekt</strong>. Wenn der EVPI bei 12 000 € pro Jahr liegt, lohnt sich keine Prognosesoftware für 50 000 € — selbst wenn sie perfekt wäre. Diese Zahl bewahrt Projekte vor teuren Fehlinvestitionen.</p>
|
||||
</blockquote>
|
||||
|
|
@ -22599,7 +22599,7 @@ Bestmoegliche Volatilitaet bei perfektem Wissen: 11.84 % p.a.
|
|||
</table>
|
||||
<p><strong>Wichtig ist, Text und Code konsistent auf dieselbe Variante zu beziehen</strong> — zum Beispiel <code>sklearn.covariance.LedoitWolf</code>, das die skalierte Einheitsmatrix verwendet, versus eine manuelle Implementierung des Konstant-Korrelations-Ziels. Dieses Buch nennt beide und macht transparent, welches wo zum Einsatz kommt.</p>
|
||||
<blockquote>
|
||||
<p><strong>💡 Welches Ziel ist besser?</strong> Es kommt darauf an. Die <strong>Einheitsmatrix</strong> unterstellt, dass alle Titel gleich riskant und unkorreliert sind — eine starke, aber sehr stabile Annahme. Das <strong>Konstant-Korrelations-Ziel</strong> behält die geschätzten Einzelvarianzen und glättet nur die Korrelationen; das ist bei Aktien meist realistischer, weil Titel tatsächlich sehr unterschiedliche Volatilitäten haben. In Übung 11.5 implementieren Sie es selbst und vergleichen.</p>
|
||||
<p><strong>💡 Welches Ziel ist besser?</strong> Es kommt darauf an. Die <strong>Einheitsmatrix</strong> unterstellt, dass alle Titel gleich riskant und unkorreliert sind — eine starke, aber sehr stabile Annahme. Das <strong>Konstant-Korrelations-Ziel</strong> behält die geschätzten Einzelvarianzen und glättet nur die Korrelationen; das ist bei Aktien meist realistischer, weil Titel tatsächlich sehr unterschiedliche Volatilitäten haben. In der Aufgabe <em>Beide Shrinkage-Ziele vergleichen</em> (<a href="#sec:finanzdaten-uebungsaufgaben">Abschnitt 18.7</a>) implementieren Sie es selbst und vergleichen.</p>
|
||||
</blockquote>
|
||||
<p>Das Ergebnis ist in jedem Fall garantiert <strong>positiv definit</strong>, wohlkonditioniert und stabil invertierbar.</p>
|
||||
<hr />
|
||||
|
|
@ -27801,7 +27801,7 @@ ein unzuverlaessiger Test (siehe JobShop_Intervalle.py).
|
|||
</blockquote>
|
||||
<p><strong>Aufgabe 22.1 ⭐ — Hart oder weich, revisited.</strong> Nennen Sie für ein Vertretungsplanungssystem je zwei Bedingungen, die (a) zwingend hart bleiben müssen, (b) unbedingt weich sein sollten, (c) diskutabel sind. Begründen Sie.</p>
|
||||
<p><strong>Aufgabe 22.2 ⭐ — Zeitlimit wählen.</strong> Für welche Szenarien setzen Sie welches Zeitlimit und welchen Gap? (a) Taxi-Disposition in Echtzeit, (b) Wochendienstplan, freitags erstellt, (c) Jahresproduktionsplanung, (d) Portfolio-Rebalancing monatlich.</p>
|
||||
<p><strong>Aufgabe 22.3 ⭐⭐ — Relaxation einbauen.</strong> Nehmen Sie Ihr Modell aus Übung 6.7 (Wochendienstplan) und machen Sie es <code>INFEASIBLE</code>-sicher: Schlupfvariablen für unbesetzte Schichten, gestaffelte Strafen. Testen Sie mit einem bewusst überlasteten Szenario.</p>
|
||||
<p><strong>Aufgabe 22.3 ⭐⭐ — Relaxation einbauen.</strong> Nehmen Sie Ihr Modell aus der Aufgabe <em>Eigener Dienstplan</em> (<a href="#sec:cpsat-uebungsaufgaben">Abschnitt 7.9</a>) und machen Sie es <code>INFEASIBLE</code>-sicher: Schlupfvariablen für unbesetzte Schichten, gestaffelte Strafen. Testen Sie mit einem bewusst überlasteten Szenario.</p>
|
||||
<p><strong>Aufgabe 22.4 ⭐⭐ — Erklärbarkeit implementieren.</strong> Erweitern Sie ein beliebiges Modell aus dem Kurs um einen <code>erklaere(loesung)</code>-Report, der die drei Fragen aus <a href="#sec:praxisfallen-die-fuenf-typischen-praxisfallen">Abschnitt 22.3</a> beantwortet.</p>
|
||||
<p><strong>Aufgabe 22.5 ⭐⭐ — Den Bericht in die Irre führen.</strong> <code>Constraint_Attribution.py</code> erzeugt seinen Bericht aus gerechneten Zahlen — richtig ist er deshalb noch nicht. (a) Setzen Sie den Deckungsbeitrag von <em>Deckel</em> von 9 € auf 20 €. Wie ändern sich Plan, Rangliste und Bericht? Welche Sätze bleiben wörtlich stehen, obwohl sie jetzt etwas anderes bedeuten? (b) Der Bericht nennt „Liefervertrag Träger” als teuerste Bindung. Formulieren Sie den Satz so um, dass ein Leser erkennt, <strong>worauf</strong> die Aussage beruht. (c) Welche Angabe müsste das Programm zusätzlich ausgeben, damit ein Empfänger die Belastbarkeit selbst einschätzen kann?</p>
|
||||
<p><strong>Aufgabe 22.6 ⭐⭐⭐ — Gap gegen Laufzeit.</strong> Nehmen Sie das MILP-Portfolio aus <a href="#kap-milp">Kapitel 6</a> und vergrößern Sie es auf 50 Anlagen. Messen Sie Laufzeit und Zielwert bei Gap-Vorgaben von 10 %, 5 %, 2 %, 1 %, 0,1 % und 0 %. Stellen Sie den Zusammenhang grafisch dar und leiten Sie eine Empfehlung ab.</p>
|
||||
|
|
|
|||
|
|
@ -1121,7 +1121,7 @@ Pruefung: komplementaerer Schlupf fuer alle Ressourcen erfuellt.
|
|||
</blockquote>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Grenzen der Schattenpreis-Aussage</strong></p>
|
||||
<p>Der Schattenpreis gilt nur <strong>lokal</strong>, in einem begrenzten Intervall um die aktuelle Kapazität. Kauft man 200 Prüfstunden zu, wird irgendwann eine andere Ressource zum Engpass, und der Schattenpreis springt auf einen neuen Wert (oder auf null). Wer große Kapazitätsänderungen bewerten will, muss das Modell <strong>neu rechnen</strong> — nicht linear hochrechnen. Übung 4.6 macht diesen Effekt sichtbar.</p>
|
||||
<p>Der Schattenpreis gilt nur <strong>lokal</strong>, in einem begrenzten Intervall um die aktuelle Kapazität. Kauft man 200 Prüfstunden zu, wird irgendwann eine andere Ressource zum Engpass, und der Schattenpreis springt auf einen neuen Wert (oder auf null). Wer große Kapazitätsänderungen bewerten will, muss das Modell <strong>neu rechnen</strong> — nicht linear hochrechnen. Die Aufgabe <em>Gültigkeitsbereich des Schattenpreises</em> (<a href="#sec:lp-uebungsaufgaben">Abschnitt 5.10</a>) macht diesen Effekt sichtbar.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:lp-entartung">5.9 Wann Schattenpreise lügen: Entartung und Toleranzen</h2>
|
||||
|
|
|
|||
|
|
@ -2197,7 +2197,7 @@ ein unzuverlaessiger Test (siehe JobShop_Intervalle.py).
|
|||
</blockquote>
|
||||
<p><strong>Aufgabe 22.1 ⭐ — Hart oder weich, revisited.</strong> Nennen Sie für ein Vertretungsplanungssystem je zwei Bedingungen, die (a) zwingend hart bleiben müssen, (b) unbedingt weich sein sollten, (c) diskutabel sind. Begründen Sie.</p>
|
||||
<p><strong>Aufgabe 22.2 ⭐ — Zeitlimit wählen.</strong> Für welche Szenarien setzen Sie welches Zeitlimit und welchen Gap? (a) Taxi-Disposition in Echtzeit, (b) Wochendienstplan, freitags erstellt, (c) Jahresproduktionsplanung, (d) Portfolio-Rebalancing monatlich.</p>
|
||||
<p><strong>Aufgabe 22.3 ⭐⭐ — Relaxation einbauen.</strong> Nehmen Sie Ihr Modell aus Übung 6.7 (Wochendienstplan) und machen Sie es <code>INFEASIBLE</code>-sicher: Schlupfvariablen für unbesetzte Schichten, gestaffelte Strafen. Testen Sie mit einem bewusst überlasteten Szenario.</p>
|
||||
<p><strong>Aufgabe 22.3 ⭐⭐ — Relaxation einbauen.</strong> Nehmen Sie Ihr Modell aus der Aufgabe <em>Eigener Dienstplan</em> (<a href="cpsat.html#sec:cpsat-uebungsaufgaben">Abschnitt 7.9</a>) und machen Sie es <code>INFEASIBLE</code>-sicher: Schlupfvariablen für unbesetzte Schichten, gestaffelte Strafen. Testen Sie mit einem bewusst überlasteten Szenario.</p>
|
||||
<p><strong>Aufgabe 22.4 ⭐⭐ — Erklärbarkeit implementieren.</strong> Erweitern Sie ein beliebiges Modell aus dem Kurs um einen <code>erklaere(loesung)</code>-Report, der die drei Fragen aus <a href="#sec:praxisfallen-die-fuenf-typischen-praxisfallen">Abschnitt 22.3</a> beantwortet.</p>
|
||||
<p><strong>Aufgabe 22.5 ⭐⭐ — Den Bericht in die Irre führen.</strong> <code>Constraint_Attribution.py</code> erzeugt seinen Bericht aus gerechneten Zahlen — richtig ist er deshalb noch nicht. (a) Setzen Sie den Deckungsbeitrag von <em>Deckel</em> von 9 € auf 20 €. Wie ändern sich Plan, Rangliste und Bericht? Welche Sätze bleiben wörtlich stehen, obwohl sie jetzt etwas anderes bedeuten? (b) Der Bericht nennt „Liefervertrag Träger” als teuerste Bindung. Formulieren Sie den Satz so um, dass ein Leser erkennt, <strong>worauf</strong> die Aussage beruht. (c) Welche Angabe müsste das Programm zusätzlich ausgeben, damit ein Empfänger die Belastbarkeit selbst einschätzen kann?</p>
|
||||
<p><strong>Aufgabe 22.6 ⭐⭐⭐ — Gap gegen Laufzeit.</strong> Nehmen Sie das MILP-Portfolio aus <a href="milp.html#kap-milp">Kapitel 6</a> und vergrößern Sie es auf 50 Anlagen. Messen Sie Laufzeit und Zielwert bei Gap-Vorgaben von 10 %, 5 %, 2 %, 1 %, 0,1 % und 0 %. Stellen Sie den Zusammenhang grafisch dar und leiten Sie eine Empfehlung ab.</p>
|
||||
|
|
|
|||
|
|
@ -784,7 +784,7 @@ US-Treasuries 3.0 % 7.0 % 0.45 %
|
|||
<li><strong>Multistart.</strong> Zehn Startpunkte, und die Spannweite der Ergebnisse wird gemessen. Sind alle gleich, ist das ein starkes Indiz für Konvexität. Weichen sie ab, wissen Sie sofort, dass Sie einem lokalen Optimum aufsitzen. Diese fünf Zeilen sollten in jedem SLSQP-Projekt stehen.</li>
|
||||
<li><strong>Analytischer Gradient.</strong> <code>jac=gradient</code> spart nicht nur Zeit — die numerische Approximation von Ableitungen ist bei Termen wie <span class="math inline">\ln w</span> nahe null numerisch heikel.</li>
|
||||
</ol>
|
||||
<p><strong>Zur Skalierung:</strong> Mit <span class="math inline">\alpha = 1</span> ist der Ertragsterm (<span class="math inline">\approx 0{,}1</span>) zehnmal größer als der Varianzterm (<span class="math inline">\approx 0{,}01</span>). Das Modell ist also stark renditegetrieben. Übung 8.5 lässt Sie diese Balance untersuchen — sie ist eine fachliche Entscheidung, keine technische.</p>
|
||||
<p><strong>Zur Skalierung:</strong> Mit <span class="math inline">\alpha = 1</span> ist der Ertragsterm (<span class="math inline">\approx 0{,}1</span>) zehnmal größer als der Varianzterm (<span class="math inline">\approx 0{,}01</span>). Das Modell ist also stark renditegetrieben. Die Aufgabe <em>Effekt der Gewichtung untersuchen</em> (<a href="#sec:qp-nlp-uebungsaufgaben">Abschnitt 11.7</a>) lässt Sie diese Balance untersuchen — sie ist eine fachliche Entscheidung, keine technische.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:qp-nlp-nichtkonvex">11.6 Jenseits der Konvexität: lokale Optima, Multistart und MINLP</h2>
|
||||
|
|
|
|||
|
|
@ -536,7 +536,7 @@ Feinsuche (Raster 100..500): Optimum bei Kapazitaet 180, Kosten 12,810 EUR
|
|||
<p><strong>🎯 Eine wichtige Einschränkung — und was man daraus lernt</strong></p>
|
||||
<p>Hier kostet die naive Mittelwertplanung nur <strong>1 %</strong>. In der Handrechnung zum Fluch des Durchschnitts waren es 2,7 %, in Lehrbüchern liest man von 20 % und mehr. <strong>Wie groß der Effekt ist, hängt von der Verteilung ab</strong> — und das ist selbst die Lektion.</p>
|
||||
<p>Bei dieser Mischverteilung liegt zwischen dem Normalbetrieb (um 150) und den Lastspitzen (um 450) ein Bereich, in dem kaum Wahrscheinlichkeitsmasse liegt. Zusätzliche Kapazität zwischen 200 und 400 nützt daher wenig: Sie ist im Normalfall Leerlauf und reicht im Krisenfall trotzdem nicht. Deshalb ist die Kostenkurve dort flach, und die Wahl zwischen 180 und 196 macht kaum einen Unterschied.</p>
|
||||
<p><strong>Was Sie mitnehmen sollten:</strong> Die Frage „Wie teuer ist Mittelwertplanung?“ hat keine allgemeine Antwort — <strong>rechnen Sie es aus.</strong> Genau dafür ist Monte-Carlo da. Und beachten Sie die Spalte „Unterdeckung“: Bei Kapazität 200 wird in <strong>24 % der Fälle</strong> nachgekauft. Ob das akzeptabel ist, entscheidet kein Optimierer, sondern ein Servicelevel-Ziel (Übung 9.5).</p>
|
||||
<p><strong>Was Sie mitnehmen sollten:</strong> Die Frage „Wie teuer ist Mittelwertplanung?“ hat keine allgemeine Antwort — <strong>rechnen Sie es aus.</strong> Genau dafür ist Monte-Carlo da. Und beachten Sie die Spalte „Unterdeckung“: Bei Kapazität 200 wird in <strong>24 % der Fälle</strong> nachgekauft. Ob das akzeptabel ist, entscheidet kein Optimierer, sondern ein Servicelevel-Ziel (Aufgabe <em>Monte-Carlo erweitern</em>, <a href="#sec:unsicherheit-uebungsaufgaben">Abschnitt 12.8</a>).</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p><strong>💡 Wann Monte-Carlo das richtige Werkzeug ist</strong> Immer dann, wenn Sie <strong>eine Kennzahl brauchen, die keine Formel hat</strong>: die Wahrscheinlichkeit, ein Servicelevel zu verfehlen; der erwartete Verlust in den schlechtesten 5 % der Fälle; die Verteilung der Projektdauer. Der Preis ist, dass Monte-Carlo nur <strong>bewertet</strong> — die Optimierung müssen Sie durch Rastersuche oder ein eigenes Modell ergänzen.</p>
|
||||
|
|
@ -715,7 +715,7 @@ den Mittelwert (225), weil Unterdeckung (120 EUR)
|
|||
deutlich teurer ist als Leerlauf (5 EUR).
|
||||
==================================================================================</code></pre>
|
||||
<p><strong>Lesen Sie die Vergleichstabelle von unten nach oben.</strong> Die beiden extremen Haltungen sind die teuersten: Wer den Worst Case abdeckt (500 Einheiten), zahlt 5 000 € zu viel für Kapazität, die in 80 % der Fälle brachliegt. Wer optimistisch plant (100), zahlt 2 625 € Strafe für ständige Notzukäufe. Die naive Mittelwertplanung liegt dazwischen — aber eben auch nicht optimal.</p>
|
||||
<p>Der <strong>EVPI von 7 375 €</strong> ist bemerkenswert hoch: 45 % der Gesamtkosten entstehen allein daraus, dass man die Zukunft nicht kennt. In so einem Fall lohnt sich Investition in bessere Prognosen tatsächlich — anders als in dem Beispiel aus Übung 9.4.</p>
|
||||
<p>Der <strong>EVPI von 7 375 €</strong> ist bemerkenswert hoch: 45 % der Gesamtkosten entstehen allein daraus, dass man die Zukunft nicht kennt. In so einem Fall lohnt sich Investition in bessere Prognosen tatsächlich — anders als in dem Beispiel aus der Aufgabe <em>EVPI interpretieren</em> (<a href="#sec:unsicherheit-uebungsaufgaben">Abschnitt 12.8</a>).</p>
|
||||
<blockquote>
|
||||
<p><strong>💡 Was ist der EVPI?</strong> Der <strong>Expected Value of Perfect Information</strong> beziffert, wie viel eine perfekte Prognose wert wäre: die Differenz zwischen den Kosten unter Unsicherheit und den Kosten bei vollständigem Wissen. Er ist eine <strong>Obergrenze für jedes Prognoseprojekt</strong>. Wenn der EVPI bei 12 000 € pro Jahr liegt, lohnt sich keine Prognosesoftware für 50 000 € — selbst wenn sie perfekt wäre. Diese Zahl bewahrt Projekte vor teuren Fehlinvestitionen.</p>
|
||||
</blockquote>
|
||||
|
|
|
|||
|
|
@ -1146,7 +1146,7 @@ Damit die Zerlegung zur Gewohnheit wird, hier eine Vorlage, die Sie bei jedem ne
|
|||
> * **Harte Bedingungen:** $0{,}5x_1 + 0{,}6x_2 \le 90$ (Mehl); $4x_1 + 3x_2 \le 600$ (Ofen); $x_1 \ge 40$ (Vertrag).
|
||||
> * **Weiche Bedingungen:** keine.
|
||||
>
|
||||
> Dieses Problem lösen Sie in Übung 1.5 selbst.
|
||||
> Dieses Problem lösen Sie in der Aufgabe *Die Bäckerei programmieren* ([Abschnitt 1.9](#sec:einfuehrung-uebungsaufgaben)) selbst.
|
||||
|
||||
Die Vorlage lässt sich fast wörtlich in Code übersetzen — wer die fünf Zeilen ausgefüllt hat, hat den größten Teil der Modellierungsarbeit schon erledigt:
|
||||
|
||||
|
|
@ -5531,7 +5531,7 @@ Der Zukauf für 18 €/h ist hochprofitabel: Jede zusätzliche Prüfstunde bring
|
|||
|
||||
> **⚠️ Grenzen der Schattenpreis-Aussage**
|
||||
>
|
||||
> Der Schattenpreis gilt nur **lokal**, in einem begrenzten Intervall um die aktuelle Kapazität. Kauft man 200 Prüfstunden zu, wird irgendwann eine andere Ressource zum Engpass, und der Schattenpreis springt auf einen neuen Wert (oder auf null). Wer große Kapazitätsänderungen bewerten will, muss das Modell **neu rechnen** — nicht linear hochrechnen. Übung 4.6 macht diesen Effekt sichtbar.
|
||||
> Der Schattenpreis gilt nur **lokal**, in einem begrenzten Intervall um die aktuelle Kapazität. Kauft man 200 Prüfstunden zu, wird irgendwann eine andere Ressource zum Engpass, und der Schattenpreis springt auf einen neuen Wert (oder auf null). Wer große Kapazitätsänderungen bewerten will, muss das Modell **neu rechnen** — nicht linear hochrechnen. Die Aufgabe *Gültigkeitsbereich des Schattenpreises* ([Abschnitt 5.10](#sec:lp-uebungsaufgaben)) macht diesen Effekt sichtbar.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -12845,7 +12845,7 @@ Interessant ist auch die Wirkung des Entropieterms: Er verschiebt nur rund 7 Pro
|
|||
> 2. **Multistart.** Zehn Startpunkte, und die Spannweite der Ergebnisse wird gemessen. Sind alle gleich, ist das ein starkes Indiz für Konvexität. Weichen sie ab, wissen Sie sofort, dass Sie einem lokalen Optimum aufsitzen. Diese fünf Zeilen sollten in jedem SLSQP-Projekt stehen.
|
||||
> 3. **Analytischer Gradient.** `jac=gradient` spart nicht nur Zeit — die numerische Approximation von Ableitungen ist bei Termen wie $\ln w$ nahe null numerisch heikel.
|
||||
>
|
||||
> **Zur Skalierung:** Mit $\alpha = 1$ ist der Ertragsterm ($\approx 0{,}1$) zehnmal größer als der Varianzterm ($\approx 0{,}01$). Das Modell ist also stark renditegetrieben. Übung 8.5 lässt Sie diese Balance untersuchen — sie ist eine fachliche Entscheidung, keine technische.
|
||||
> **Zur Skalierung:** Mit $\alpha = 1$ ist der Ertragsterm ($\approx 0{,}1$) zehnmal größer als der Varianzterm ($\approx 0{,}01$). Das Modell ist also stark renditegetrieben. Die Aufgabe *Effekt der Gewichtung untersuchen* ([Abschnitt 11.7](#sec:qp-nlp-uebungsaufgaben)) lässt Sie diese Balance untersuchen — sie ist eine fachliche Entscheidung, keine technische.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -13690,7 +13690,7 @@ Feinsuche (Raster 100..500): Optimum bei Kapazitaet 180, Kosten 12,810 EUR
|
|||
>
|
||||
> Bei dieser Mischverteilung liegt zwischen dem Normalbetrieb (um 150) und den Lastspitzen (um 450) ein Bereich, in dem kaum Wahrscheinlichkeitsmasse liegt. Zusätzliche Kapazität zwischen 200 und 400 nützt daher wenig: Sie ist im Normalfall Leerlauf und reicht im Krisenfall trotzdem nicht. Deshalb ist die Kostenkurve dort flach, und die Wahl zwischen 180 und 196 macht kaum einen Unterschied.
|
||||
>
|
||||
> **Was Sie mitnehmen sollten:** Die Frage „Wie teuer ist Mittelwertplanung?“ hat keine allgemeine Antwort — **rechnen Sie es aus.** Genau dafür ist Monte-Carlo da. Und beachten Sie die Spalte „Unterdeckung“: Bei Kapazität 200 wird in **24 % der Fälle** nachgekauft. Ob das akzeptabel ist, entscheidet kein Optimierer, sondern ein Servicelevel-Ziel (Übung 9.5).
|
||||
> **Was Sie mitnehmen sollten:** Die Frage „Wie teuer ist Mittelwertplanung?“ hat keine allgemeine Antwort — **rechnen Sie es aus.** Genau dafür ist Monte-Carlo da. Und beachten Sie die Spalte „Unterdeckung“: Bei Kapazität 200 wird in **24 % der Fälle** nachgekauft. Ob das akzeptabel ist, entscheidet kein Optimierer, sondern ein Servicelevel-Ziel (Aufgabe *Monte-Carlo erweitern*, [Abschnitt 12.8](#sec:unsicherheit-uebungsaufgaben)).
|
||||
|
||||
> **💡 Wann Monte-Carlo das richtige Werkzeug ist** Immer dann, wenn Sie **eine Kennzahl brauchen, die keine Formel hat**: die Wahrscheinlichkeit, ein Servicelevel zu verfehlen; der erwartete Verlust in den schlechtesten 5 % der Fälle; die Verteilung der Projektdauer. Der Preis ist, dass Monte-Carlo nur **bewertet** — die Optimierung müssen Sie durch Rastersuche oder ein eigenes Modell ergänzen.
|
||||
|
||||
|
|
@ -13885,7 +13885,7 @@ deutlich teurer ist als Leerlauf (5 EUR).
|
|||
|
||||
**Lesen Sie die Vergleichstabelle von unten nach oben.** Die beiden extremen Haltungen sind die teuersten: Wer den Worst Case abdeckt (500 Einheiten), zahlt 5 000 € zu viel für Kapazität, die in 80 % der Fälle brachliegt. Wer optimistisch plant (100), zahlt 2 625 € Strafe für ständige Notzukäufe. Die naive Mittelwertplanung liegt dazwischen — aber eben auch nicht optimal.
|
||||
|
||||
Der **EVPI von 7 375 €** ist bemerkenswert hoch: 45 % der Gesamtkosten entstehen allein daraus, dass man die Zukunft nicht kennt. In so einem Fall lohnt sich Investition in bessere Prognosen tatsächlich — anders als in dem Beispiel aus Übung 9.4.
|
||||
Der **EVPI von 7 375 €** ist bemerkenswert hoch: 45 % der Gesamtkosten entstehen allein daraus, dass man die Zukunft nicht kennt. In so einem Fall lohnt sich Investition in bessere Prognosen tatsächlich — anders als in dem Beispiel aus der Aufgabe *EVPI interpretieren* ([Abschnitt 12.8](#sec:unsicherheit-uebungsaufgaben)).
|
||||
|
||||
> **💡 Was ist der EVPI?** Der **Expected Value of Perfect Information**`\index{EVPI}`{=latex} beziffert, wie viel eine perfekte Prognose wert wäre: die Differenz zwischen den Kosten unter Unsicherheit und den Kosten bei vollständigem Wissen. Er ist eine **Obergrenze für jedes Prognoseprojekt**. Wenn der EVPI bei 12 000 € pro Jahr liegt, lohnt sich keine Prognosesoftware für 50 000 € — selbst wenn sie perfekt wäre. Diese Zahl bewahrt Projekte vor teuren Fehlinvestitionen.
|
||||
|
||||
|
|
@ -18236,7 +18236,7 @@ Ein häufiges Missverständnis: Es gibt nämlich **mehrere** Ledoit-Wolf-Variant
|
|||
|
||||
**Wichtig ist, Text und Code konsistent auf dieselbe Variante zu beziehen** — zum Beispiel `sklearn.covariance.LedoitWolf`, das die skalierte Einheitsmatrix verwendet, versus eine manuelle Implementierung des Konstant-Korrelations-Ziels. Dieses Buch nennt beide und macht transparent, welches wo zum Einsatz kommt.
|
||||
|
||||
> **💡 Welches Ziel ist besser?** Es kommt darauf an. Die **Einheitsmatrix** unterstellt, dass alle Titel gleich riskant und unkorreliert sind — eine starke, aber sehr stabile Annahme. Das **Konstant-Korrelations-Ziel** behält die geschätzten Einzelvarianzen und glättet nur die Korrelationen; das ist bei Aktien meist realistischer, weil Titel tatsächlich sehr unterschiedliche Volatilitäten haben. In Übung 11.5 implementieren Sie es selbst und vergleichen.
|
||||
> **💡 Welches Ziel ist besser?** Es kommt darauf an. Die **Einheitsmatrix** unterstellt, dass alle Titel gleich riskant und unkorreliert sind — eine starke, aber sehr stabile Annahme. Das **Konstant-Korrelations-Ziel** behält die geschätzten Einzelvarianzen und glättet nur die Korrelationen; das ist bei Aktien meist realistischer, weil Titel tatsächlich sehr unterschiedliche Volatilitäten haben. In der Aufgabe *Beide Shrinkage-Ziele vergleichen* ([Abschnitt 18.7](#sec:finanzdaten-uebungsaufgaben)) implementieren Sie es selbst und vergleichen.
|
||||
|
||||
Das Ergebnis ist in jedem Fall garantiert **positiv definit**, wohlkonditioniert und stabil invertierbar.
|
||||
|
||||
|
|
@ -23124,7 +23124,7 @@ Wenn Sie doch tiefer in die Methodik wollen, sind das die lohnendsten Richtungen
|
|||
|
||||
**Aufgabe 22.2 ⭐ — Zeitlimit wählen.** Für welche Szenarien setzen Sie welches Zeitlimit und welchen Gap? (a) Taxi-Disposition in Echtzeit, (b) Wochendienstplan, freitags erstellt, (c) Jahresproduktionsplanung, (d) Portfolio-Rebalancing monatlich.
|
||||
|
||||
**Aufgabe 22.3 ⭐⭐ — Relaxation einbauen.** Nehmen Sie Ihr Modell aus Übung 6.7 (Wochendienstplan) und machen Sie es `INFEASIBLE`-sicher: Schlupfvariablen für unbesetzte Schichten, gestaffelte Strafen. Testen Sie mit einem bewusst überlasteten Szenario.
|
||||
**Aufgabe 22.3 ⭐⭐ — Relaxation einbauen.** Nehmen Sie Ihr Modell aus der Aufgabe *Eigener Dienstplan* ([Abschnitt 7.9](#sec:cpsat-uebungsaufgaben)) und machen Sie es `INFEASIBLE`-sicher: Schlupfvariablen für unbesetzte Schichten, gestaffelte Strafen. Testen Sie mit einem bewusst überlasteten Szenario.
|
||||
|
||||
**Aufgabe 22.4 ⭐⭐ — Erklärbarkeit implementieren.** Erweitern Sie ein beliebiges Modell aus dem Kurs um einen `erklaere(loesung)`-Report, der die drei Fragen aus [Abschnitt 22.3](#sec:praxisfallen-die-fuenf-typischen-praxisfallen) beantwortet.
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -528,7 +528,8 @@ ausfüllen können — vor der ersten Codezeile.
|
|||
> $4x_1 + 3x_2 \le 600$ (Ofen); $x_1 \ge 40$ (Vertrag).
|
||||
> * **Weiche Bedingungen:** keine.
|
||||
>
|
||||
> Dieses Problem lösen Sie in Übung 1.5 selbst.
|
||||
> Dieses Problem lösen Sie in der Aufgabe *Die Bäckerei programmieren*
|
||||
> ({ref:sec:einfuehrung-uebungsaufgaben}) selbst.
|
||||
|
||||
Die Vorlage lässt sich fast wörtlich in Code übersetzen — wer die fünf Zeilen ausgefüllt
|
||||
hat, hat den größten Teil der Modellierungsarbeit schon erledigt:
|
||||
|
|
|
|||
|
|
@ -933,7 +933,8 @@ Deckungsbeitrag, also 15,33 € Reingewinn.
|
|||
> Kapazität. Kauft man 200 Prüfstunden zu, wird irgendwann eine andere Ressource zum
|
||||
> Engpass, und der Schattenpreis springt auf einen neuen Wert (oder auf null). Wer große
|
||||
> Kapazitätsänderungen bewerten will, muss das Modell **neu rechnen** — nicht linear
|
||||
> hochrechnen. Übung 4.6 macht diesen Effekt sichtbar.
|
||||
> hochrechnen. Die Aufgabe *Gültigkeitsbereich des Schattenpreises*
|
||||
> ({ref:sec:lp-uebungsaufgaben}) macht diesen Effekt sichtbar.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -783,7 +783,8 @@ unverändert gelassen. **Der weiche Term verteilt, die harte Schranke kappt.**
|
|||
>
|
||||
> **Zur Skalierung:** Mit $\alpha = 1$ ist der Ertragsterm ($\approx 0{,}1$) zehnmal größer
|
||||
> als der Varianzterm ($\approx 0{,}01$). Das Modell ist also stark renditegetrieben.
|
||||
> Übung 8.5 lässt Sie diese Balance untersuchen — sie ist eine fachliche Entscheidung, keine
|
||||
> Die Aufgabe *Effekt der Gewichtung untersuchen* ({ref:sec:qp-nlp-uebungsaufgaben}) lässt
|
||||
> Sie diese Balance untersuchen — sie ist eine fachliche Entscheidung, keine
|
||||
> technische.
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -428,7 +428,7 @@ Feinsuche (Raster 100..500): Optimum bei Kapazitaet 180, Kosten 12,810 EUR
|
|||
> allgemeine Antwort — **rechnen Sie es aus.** Genau dafür ist Monte-Carlo da. Und beachten
|
||||
> Sie die Spalte „Unterdeckung“: Bei Kapazität 200 wird in **24 % der Fälle** nachgekauft.
|
||||
> Ob das akzeptabel ist, entscheidet kein Optimierer, sondern ein Servicelevel-Ziel
|
||||
> (Übung 9.5).
|
||||
> (Aufgabe *Monte-Carlo erweitern*, {ref:sec:unsicherheit-uebungsaufgaben}).
|
||||
|
||||
> **💡 Wann Monte-Carlo das richtige Werkzeug ist**
|
||||
> Immer dann, wenn Sie **eine Kennzahl brauchen, die keine Formel hat**: die
|
||||
|
|
@ -642,7 +642,8 @@ auch nicht optimal.
|
|||
|
||||
Der **EVPI von 7 375 €** ist bemerkenswert hoch: 45 % der Gesamtkosten entstehen allein
|
||||
daraus, dass man die Zukunft nicht kennt. In so einem Fall lohnt sich Investition in bessere
|
||||
Prognosen tatsächlich — anders als in dem Beispiel aus Übung 9.4.
|
||||
Prognosen tatsächlich — anders als in dem Beispiel aus der Aufgabe *EVPI interpretieren*
|
||||
({ref:sec:unsicherheit-uebungsaufgaben}).
|
||||
|
||||
> **💡 Was ist der EVPI?**
|
||||
> Der **Expected Value of Perfect Information**{idx:EVPI} beziffert, wie viel eine perfekte Prognose
|
||||
|
|
|
|||
|
|
@ -448,7 +448,8 @@ beide und macht transparent, welches wo zum Einsatz kommt.
|
|||
> unkorreliert sind — eine starke, aber sehr stabile Annahme. Das
|
||||
> **Konstant-Korrelations-Ziel** behält die geschätzten Einzelvarianzen und glättet nur die
|
||||
> Korrelationen; das ist bei Aktien meist realistischer, weil Titel tatsächlich sehr
|
||||
> unterschiedliche Volatilitäten haben. In Übung 11.5 implementieren Sie es selbst und
|
||||
> unterschiedliche Volatilitäten haben. In der Aufgabe *Beide Shrinkage-Ziele vergleichen*
|
||||
> ({ref:sec:finanzdaten-uebungsaufgaben}) implementieren Sie es selbst und
|
||||
> vergleichen.
|
||||
|
||||
Das Ergebnis ist in jedem Fall garantiert **positiv definit**, wohlkonditioniert und stabil
|
||||
|
|
|
|||
|
|
@ -2112,7 +2112,8 @@ Echtzeit, (b) Wochendienstplan, freitags erstellt, (c) Jahresproduktionsplanung,
|
|||
(d) Portfolio-Rebalancing monatlich.
|
||||
|
||||
**Aufgabe ⭐⭐ — Relaxation einbauen.**
|
||||
Nehmen Sie Ihr Modell aus Übung 6.7 (Wochendienstplan) und machen Sie es
|
||||
Nehmen Sie Ihr Modell aus der Aufgabe *Eigener Dienstplan*
|
||||
({ref:sec:cpsat-uebungsaufgaben}) und machen Sie es
|
||||
`INFEASIBLE`-sicher: Schlupfvariablen für unbesetzte Schichten, gestaffelte Strafen. Testen
|
||||
Sie mit einem bewusst überlasteten Szenario.
|
||||
|
||||
|
|
|
|||
|
|
@ -268,6 +268,13 @@ def pruefe_dateien() -> list[str]:
|
|||
"auf den Denkfehler-Abschnitt verweist {ref:sec:<kapitel>-denkfehler}"),
|
||||
(re.compile(r"Micro-Quiz\s+\d+"),
|
||||
"die Nummer vergibt nummeriere_marken()"),
|
||||
# 'Uebung 8.5' meinte in Version 03 das QP/NLP-Kapitel; heute ist das
|
||||
# Kapitel 11, und die Nummer zeigt woandershin. Sechs von sieben solcher
|
||||
# Verweise standen noch in alter Zaehlung. Aufgaben haben kein eigenes
|
||||
# Label - verwiesen wird deshalb auf den Abschnitt plus den TITEL der
|
||||
# Aufgabe, und der ist stabil.
|
||||
(re.compile(r"(?:Übung|Uebung)\s+\d+\.\d+"),
|
||||
"gemeint ist 'die Aufgabe *Titel* ({ref:sec:<kapitel>-uebungsaufgaben})'"),
|
||||
(re.compile(r"^\*\*\d{1,2}\.\d{1,2} — ", re.M),
|
||||
"im Quelltext steht dort '**{loesung} — Titel.**'"),
|
||||
]
|
||||
|
|
|
|||
55
PROGRESS.md
55
PROGRESS.md
|
|
@ -81,7 +81,7 @@ sie unerwartet ab, ist etwas kaputtgegangen.
|
|||
| Größe des Gesamtdokuments | 606 KB | **1 622 KB** |
|
||||
| Hauptüberschriften | 131 | **302** |
|
||||
| registrierte Abschnitte | 122 | **296** |
|
||||
| aufgelöste Querverweise | 314 | **818** (0 unaufgelöst) |
|
||||
| aufgelöste Querverweise | 314 | **825** (0 unaufgelöst) |
|
||||
| Indexmarken | 295 | **328** |
|
||||
| Beispielprogramme | 41 | **76** (alle lauffähig) |
|
||||
| PDF-Seiten | — | **760** |
|
||||
|
|
@ -1822,6 +1822,59 @@ entfernt, und `--check` meldet diesen Fall jetzt. Gegengetestet.
|
|||
|
||||
Stand danach: 818 Querverweise, PDF **760** Seiten, 69 netzfreie Programme fehlerfrei.
|
||||
|
||||
### ✅ Achter Fund: die „Übung N.N"-Verweise
|
||||
|
||||
Sieben Sätze der Bauart „Übung 8.5 lässt Sie diese Balance untersuchen" — und **sechs davon
|
||||
standen in alter Zählung**. „8" war in Version 03 das QP/NLP-Kapitel, heute ist es
|
||||
Kapitel 11. Dieselbe Familie wie die Denkfehler-Verweise aus 6.1a, nur mit einem Wort, das
|
||||
keine der bestehenden Prüfungen kannte.
|
||||
|
||||
Aufgaben haben kein eigenes Label, ein `{ref:}` auf eine einzelne Aufgabe ist also nicht
|
||||
möglich. Verwiesen wird stattdessen auf **Abschnitt plus Aufgabentitel** — und der ist
|
||||
stabil: „die Aufgabe *Gültigkeitsbereich des Schattenpreises*
|
||||
({ref:sec:lp-uebungsaufgaben})". Jedes Ziel wurde einzeln über die alte Zählung bestimmt
|
||||
und am Zusammenhang geprüft.
|
||||
|
||||
**Ein Fall war knifflig:** „Übung 6.7 (Wochendienstplan)" meinte die siebte CP-SAT-Aufgabe
|
||||
der alten Zählung, also *Eigener Dienstplan* — die heute an achter Stelle steht, weil ich in
|
||||
Phase 6.3 selbst eine Aufgabe davor eingefügt habe. Wer nur die Kapitelnummer angepasst
|
||||
hätte, wäre bei der falschen Aufgabe gelandet.
|
||||
|
||||
`--check` kennt jetzt auch „Übung"/„Uebung". Gegengetestet. Querverweise 818 → 825.
|
||||
|
||||
### ✅ 8.3 Dockerfile — gebaut und durchgemessen
|
||||
|
||||
Setzt den letzten Teil von Paket 1 aus `Verbesserungen_02.md` um. Zweistufig: Die erste
|
||||
Stufe übersetzt die Abhängigkeiten in eine virtuelle Umgebung und braucht dafür einen
|
||||
Compiler, die zweite kopiert nur `/opt/venv` — die Bauumgebung landet nicht im Image.
|
||||
Installiert werden die Gruppen `finance`, `large-scale`, `api` und `dev` aus
|
||||
`pyproject.toml`; `figures` fehlt bewusst, weil es zusätzlich Graphviz verlangt.
|
||||
|
||||
**Es wurde nicht behauptet, sondern gebaut.** Ergebnis: **1,31 GB**, und darin
|
||||
|
||||
* der `Installationstest.py` mit allen drei Solver-Funktionstests bestanden,
|
||||
* die 33 pytest-Tests bestanden,
|
||||
* **alle 69 netzfreien Programme fehlerfrei** — einschließlich der drei aus 8.2, deren
|
||||
`spawn`-Isolation im Container ebenso trägt wie außerhalb.
|
||||
|
||||
**Zwei Dinge, die der Bau gelehrt hat.** Erstens: `libgomp1` fehlt im
|
||||
`python:3.12-slim`-Image und wird von OR-Tools und HiGHS zur Laufzeit gebraucht — ohne es
|
||||
scheitert der erste Solveraufruf mit `libgomp.so.1: cannot open shared object file`.
|
||||
Zweitens, ein eigener Fehler: Ich hatte `USER kurs` **vor** das `mkdir /buch/output` gesetzt;
|
||||
`/buch` gehört root, und der Bau brach in der letzten Zeile ab. Beides steht jetzt als
|
||||
Kommentar im Dockerfile.
|
||||
|
||||
Das Image führt die Programme aus und **baut das Buch nicht** — pandoc, xelatex und inkscape
|
||||
wären zusammen über ein Gigabyte ohne Nutzen für jemanden, der die Beispiele durchrechnen
|
||||
will. Ein `.dockerignore` hält Website, PDF und Notebooks aus dem Build-Kontext.
|
||||
|
||||
Und der Punkt, der erklärungsbedürftig ist: Das Image enthält `ortools` **und** `highspy`,
|
||||
obwohl sie sich nicht gemeinsam importieren lassen. Der Konflikt wird nicht durch Weglassen
|
||||
gelöst, sondern zur Laufzeit durch getrennte Prozesse — ein Image mit nur einem von beiden
|
||||
könnte die Hälfte der Beispiele nicht ausführen.
|
||||
|
||||
**Damit ist Phase 8 abgeschlossen und der Plan abgearbeitet.**
|
||||
|
||||
---
|
||||
|
||||
## 8. Commit-Historie des V04-Strangs
|
||||
|
|
|
|||
29
README.md
29
README.md
|
|
@ -23,6 +23,7 @@ daraus ab, und alle Befehle unten werden **hier** ausgeführt.
|
|||
| `Notebooks_04/` | generiert: ein Jupyter-Notebook je Kapitel |
|
||||
| `PLAN.md` / `PROGRESS.md` | das Ziel des Umbaus und der erreichte Stand |
|
||||
| `pyproject.toml` | Abhängigkeiten in Gruppen (`finance`, `large-scale`, `api`, …) |
|
||||
| `Dockerfile`, `.dockerignore` | zweistufiges Kurs-Image (führt die Programme aus, baut nicht das Buch) |
|
||||
| `pandoc-defaults-*.yaml`, `pandoc/` | Konfiguration des PDF-Baus |
|
||||
|
||||
**Nur die als *Quelle* markierten Verzeichnisse werden von Hand bearbeitet.** Alles andere
|
||||
|
|
@ -84,6 +85,34 @@ mitgebracht hat.
|
|||
`bilder_04/erzeuge_architektur_diagramme.py` gebraucht, nicht von den Beispielprogrammen,
|
||||
und steht darum nur in `[figures]`.
|
||||
|
||||
### Oder im Container
|
||||
|
||||
Wer nichts installieren will, baut das Kurs-Image:
|
||||
|
||||
```bash
|
||||
docker build -t or-mit-python .
|
||||
docker run --rm or-mit-python Installationstest.py
|
||||
docker run --rm or-mit-python Rucksack.py
|
||||
docker run --rm -it or-mit-python # Python-Eingabe
|
||||
docker run --rm -v "$PWD/ausgabe:/buch/output" or-mit-python Excel_Bruecke.py
|
||||
```
|
||||
|
||||
Zweistufiger Bau: Die erste Stufe übersetzt die Abhängigkeiten in eine virtuelle Umgebung
|
||||
und braucht dafür einen Compiler, die zweite kopiert nur das Ergebnis — die Bauumgebung
|
||||
landet nicht im Image. Enthalten sind die Gruppen `finance`, `large-scale`, `api` und `dev`;
|
||||
`figures` fehlt bewusst, weil es zusätzlich Graphviz verlangt und nur dem Neuerzeugen der
|
||||
Diagramme dient.
|
||||
|
||||
**Das Image führt die Programme aus, es baut das Buch nicht.** Für PDF und Website braucht
|
||||
es pandoc, xelatex und inkscape — zusammen über ein Gigabyte, ohne Nutzen für jemanden, der
|
||||
die Beispiele durchrechnen will.
|
||||
|
||||
Zwei Punkte, die nicht offensichtlich sind: Das Image enthält `ortools` **und** `highspy`,
|
||||
obwohl sie sich nicht gemeinsam importieren lassen — der Konflikt wird zur Laufzeit durch
|
||||
getrennte Prozesse gelöst, nicht durch Weglassen. Und `libgomp1` muss im schlanken
|
||||
Basis-Image nachinstalliert werden, sonst scheitert der erste Solveraufruf mit
|
||||
`libgomp.so.1: cannot open shared object file`.
|
||||
|
||||
**Externe Werkzeuge**, je nachdem, was gebaut werden soll:
|
||||
|
||||
| Werkzeug | wofür | ohne es |
|
||||
|
|
|
|||
Loading…
Reference in a new issue