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:
dschlueter 2026-09-08 13:18:05 +02:00
commit 35cc0da166
22 changed files with 232 additions and 29 deletions

View file

@ -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:

View file

@ -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.
---

View file

@ -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.
---

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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.**'"),
]