Stichwortregister: automatische Markierung aller Glossarbegriffe (988 statt 456 Marker)
Neues Skript erzeuge_stichwortregister_04.py:
- Sucht alle Glossarbegriffe (Anzeigename) in den Kapiteldateien
und markiert die erste Fundstelle je Datei mit {idx:Indexmarke}
- Termliste aus glossar_eintraege_04.py + vorhandenen {idx:...}-Markern
- Idempotent: erkennt vorhandene Marker und überspringt sie
- Überspringt Codeblöcke, Inline-Code und Math
- --check und --bericht Modi
- 605 Marker eingefügt (2 Durchläufe: 597 + 8)
Zusätzlich:
- titeltexte_04.py _saeubern(): entfernt {idx:...}-Marker vor
Titeltext-Vergleich (pruefe_titeltexte schlug sonst fehl)
This commit is contained in:
parent
488c3d4368
commit
99cb85907c
107 changed files with 1529 additions and 1214 deletions
2
Notebooks_04/cpsat.ipynb
generated
2
Notebooks_04/cpsat.ipynb
generated
|
|
@ -4,7 +4,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Kapitel 7: Constraint Programming mit CP-SAT — Logik, Scheduling und Zuweisung\n",
|
||||
"# Kapitel 7: Constraint Programming mit CP-SAT{idx:CP-SAT} — Logik, Scheduling und Zuweisung\n",
|
||||
"\n",
|
||||
"Begleitnotebook zu *Optimierte Entscheidungsfindung mit Python*. Die Codezellen sind identisch mit den im Buch abgedruckten Programmen.\n"
|
||||
]
|
||||
|
|
|
|||
2
Notebooks_04/cvar.ipynb
generated
2
Notebooks_04/cvar.ipynb
generated
|
|
@ -4,7 +4,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Kapitel 20: Tail-Risiko, CVaR und Transaktionskosten\n",
|
||||
"# Kapitel 20: Tail-Risiko, CVaR und Transaktionskosten{idx:Transaktionskosten}\n",
|
||||
"\n",
|
||||
"Begleitnotebook zu *Optimierte Entscheidungsfindung mit Python*. Die Codezellen sind identisch mit den im Buch abgedruckten Programmen.\n"
|
||||
]
|
||||
|
|
|
|||
2
Notebooks_04/dynamische-programmierung.ipynb
generated
2
Notebooks_04/dynamische-programmierung.ipynb
generated
|
|
@ -4,7 +4,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Kapitel 13: Dynamische Programmierung — Die Bellman-Gleichung und Order-Execution\n",
|
||||
"# Kapitel 13: Dynamische Programmierung — Die Bellman-Gleichung{idx:Bellman-Gleichung} und Order-Execution\n",
|
||||
"\n",
|
||||
"Begleitnotebook zu *Optimierte Entscheidungsfindung mit Python*. Die Codezellen sind identisch mit den im Buch abgedruckten Programmen.\n"
|
||||
]
|
||||
|
|
|
|||
4
Notebooks_04/finanzdaten.ipynb
generated
4
Notebooks_04/finanzdaten.ipynb
generated
|
|
@ -25,7 +25,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Logarithmische Rendite\n",
|
||||
"## Logarithmische Rendite{idx:Logarithmische Rendite}\n",
|
||||
"\n",
|
||||
"`Renditen_Vergleich.py`\n"
|
||||
]
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Das Schätzfehler-Problem\n",
|
||||
"## Das Schätzfehler{idx:Schätzfehler}-Problem\n",
|
||||
"\n",
|
||||
"`Schaetzrauschen_Demo.py`\n"
|
||||
]
|
||||
|
|
|
|||
2
Notebooks_04/fundament.ipynb
generated
2
Notebooks_04/fundament.ipynb
generated
|
|
@ -4,7 +4,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Kapitel 2: Das mathematische Fundament — Vektoren, Matrizen, Konvexität\n",
|
||||
"# Kapitel 2: Das mathematische Fundament — Vektoren, Matrizen, Konvexität{idx:Konvexität}\n",
|
||||
"\n",
|
||||
"Begleitnotebook zu *Optimierte Entscheidungsfindung mit Python*. Die Codezellen sind identisch mit den im Buch abgedruckten Programmen.\n"
|
||||
]
|
||||
|
|
|
|||
2
Notebooks_04/graphen.ipynb
generated
2
Notebooks_04/graphen.ipynb
generated
|
|
@ -139,7 +139,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Der Satz von Birkhoff und von Neumann\n",
|
||||
"## Der Satz von Birkhoff und von Neumann{idx:Satz von Birkhoff und von Neumann}\n",
|
||||
"\n",
|
||||
"`Zuordnung_Ungarisch.py`\n"
|
||||
]
|
||||
|
|
|
|||
4
Notebooks_04/milp.ipynb
generated
4
Notebooks_04/milp.ipynb
generated
|
|
@ -4,7 +4,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Kapitel 6: Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound\n",
|
||||
"# Kapitel 6: Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound{idx:Branch-and-Bound}\n",
|
||||
"\n",
|
||||
"Begleitnotebook zu *Optimierte Entscheidungsfindung mit Python*. Die Codezellen sind identisch mit den im Buch abgedruckten Programmen.\n"
|
||||
]
|
||||
|
|
@ -133,7 +133,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Beispiel: Das Rucksackproblem\n",
|
||||
"## Beispiel: Das Rucksackproblem{idx:Rucksackproblem}\n",
|
||||
"\n",
|
||||
"`Rucksack.py`\n"
|
||||
]
|
||||
|
|
|
|||
4
Notebooks_04/praxisfallen.ipynb
generated
4
Notebooks_04/praxisfallen.ipynb
generated
|
|
@ -25,7 +25,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Falle 1 — Infeasibility\n",
|
||||
"## Falle 1 — Infeasibility{idx:Infeasibility}\n",
|
||||
"\n",
|
||||
"`Infeasibility_Diagnose.py`\n"
|
||||
]
|
||||
|
|
@ -256,7 +256,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraint Attribution: welche Bedingung kostet wie viel?\n",
|
||||
"## Constraint Attribution{idx:Constraint Attribution}: welche Bedingung kostet wie viel?\n",
|
||||
"\n",
|
||||
"`Constraint_Attribution.py`\n"
|
||||
]
|
||||
|
|
|
|||
2
Notebooks_04/prognose.ipynb
generated
2
Notebooks_04/prognose.ipynb
generated
|
|
@ -4,7 +4,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Kapitel 15: Predict-then-Optimize — die bessere Prognose, die schlechtere Entscheidung\n",
|
||||
"# Kapitel 15: Predict-then-Optimize{idx:Predict-then-Optimize} — die bessere Prognose, die schlechtere Entscheidung\n",
|
||||
"\n",
|
||||
"Begleitnotebook zu *Optimierte Entscheidungsfindung mit Python*. Die Codezellen sind identisch mit den im Buch abgedruckten Programmen.\n"
|
||||
]
|
||||
|
|
|
|||
4
Notebooks_04/unsicherheit.ipynb
generated
4
Notebooks_04/unsicherheit.ipynb
generated
|
|
@ -95,7 +95,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Monte-Carlo-Simulation\n",
|
||||
"## Monte-Carlo-Simulation{idx:Monte-Carlo-Simulation}\n",
|
||||
"\n",
|
||||
"`Monte_Carlo.py`\n"
|
||||
]
|
||||
|
|
@ -340,7 +340,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Robuste Optimierung: gegen den Worst Case absichern\n",
|
||||
"## Robuste Optimierung{idx:Robuste Optimierung}: gegen den Worst Case absichern\n",
|
||||
"\n",
|
||||
"`Robuste_Optimierung.py`\n"
|
||||
]
|
||||
|
|
|
|||
BIN
OR_HTML_04/Notebooks_04.zip
generated
BIN
OR_HTML_04/Notebooks_04.zip
generated
Binary file not shown.
2
OR_HTML_04/Notebooks_04/cpsat.ipynb
generated
2
OR_HTML_04/Notebooks_04/cpsat.ipynb
generated
|
|
@ -4,7 +4,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Kapitel 7: Constraint Programming mit CP-SAT — Logik, Scheduling und Zuweisung\n",
|
||||
"# Kapitel 7: Constraint Programming mit CP-SAT{idx:CP-SAT} — Logik, Scheduling und Zuweisung\n",
|
||||
"\n",
|
||||
"Begleitnotebook zu *Optimierte Entscheidungsfindung mit Python*. Die Codezellen sind identisch mit den im Buch abgedruckten Programmen.\n"
|
||||
]
|
||||
|
|
|
|||
2
OR_HTML_04/Notebooks_04/cvar.ipynb
generated
2
OR_HTML_04/Notebooks_04/cvar.ipynb
generated
|
|
@ -4,7 +4,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Kapitel 20: Tail-Risiko, CVaR und Transaktionskosten\n",
|
||||
"# Kapitel 20: Tail-Risiko, CVaR und Transaktionskosten{idx:Transaktionskosten}\n",
|
||||
"\n",
|
||||
"Begleitnotebook zu *Optimierte Entscheidungsfindung mit Python*. Die Codezellen sind identisch mit den im Buch abgedruckten Programmen.\n"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Kapitel 13: Dynamische Programmierung — Die Bellman-Gleichung und Order-Execution\n",
|
||||
"# Kapitel 13: Dynamische Programmierung — Die Bellman-Gleichung{idx:Bellman-Gleichung} und Order-Execution\n",
|
||||
"\n",
|
||||
"Begleitnotebook zu *Optimierte Entscheidungsfindung mit Python*. Die Codezellen sind identisch mit den im Buch abgedruckten Programmen.\n"
|
||||
]
|
||||
|
|
|
|||
4
OR_HTML_04/Notebooks_04/finanzdaten.ipynb
generated
4
OR_HTML_04/Notebooks_04/finanzdaten.ipynb
generated
|
|
@ -25,7 +25,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Logarithmische Rendite\n",
|
||||
"## Logarithmische Rendite{idx:Logarithmische Rendite}\n",
|
||||
"\n",
|
||||
"`Renditen_Vergleich.py`\n"
|
||||
]
|
||||
|
|
@ -110,7 +110,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Das Schätzfehler-Problem\n",
|
||||
"## Das Schätzfehler{idx:Schätzfehler}-Problem\n",
|
||||
"\n",
|
||||
"`Schaetzrauschen_Demo.py`\n"
|
||||
]
|
||||
|
|
|
|||
2
OR_HTML_04/Notebooks_04/fundament.ipynb
generated
2
OR_HTML_04/Notebooks_04/fundament.ipynb
generated
|
|
@ -4,7 +4,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Kapitel 2: Das mathematische Fundament — Vektoren, Matrizen, Konvexität\n",
|
||||
"# Kapitel 2: Das mathematische Fundament — Vektoren, Matrizen, Konvexität{idx:Konvexität}\n",
|
||||
"\n",
|
||||
"Begleitnotebook zu *Optimierte Entscheidungsfindung mit Python*. Die Codezellen sind identisch mit den im Buch abgedruckten Programmen.\n"
|
||||
]
|
||||
|
|
|
|||
2
OR_HTML_04/Notebooks_04/graphen.ipynb
generated
2
OR_HTML_04/Notebooks_04/graphen.ipynb
generated
|
|
@ -139,7 +139,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Der Satz von Birkhoff und von Neumann\n",
|
||||
"## Der Satz von Birkhoff und von Neumann{idx:Satz von Birkhoff und von Neumann}\n",
|
||||
"\n",
|
||||
"`Zuordnung_Ungarisch.py`\n"
|
||||
]
|
||||
|
|
|
|||
4
OR_HTML_04/Notebooks_04/milp.ipynb
generated
4
OR_HTML_04/Notebooks_04/milp.ipynb
generated
|
|
@ -4,7 +4,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Kapitel 6: Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound\n",
|
||||
"# Kapitel 6: Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound{idx:Branch-and-Bound}\n",
|
||||
"\n",
|
||||
"Begleitnotebook zu *Optimierte Entscheidungsfindung mit Python*. Die Codezellen sind identisch mit den im Buch abgedruckten Programmen.\n"
|
||||
]
|
||||
|
|
@ -133,7 +133,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Beispiel: Das Rucksackproblem\n",
|
||||
"## Beispiel: Das Rucksackproblem{idx:Rucksackproblem}\n",
|
||||
"\n",
|
||||
"`Rucksack.py`\n"
|
||||
]
|
||||
|
|
|
|||
4
OR_HTML_04/Notebooks_04/praxisfallen.ipynb
generated
4
OR_HTML_04/Notebooks_04/praxisfallen.ipynb
generated
|
|
@ -25,7 +25,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Falle 1 — Infeasibility\n",
|
||||
"## Falle 1 — Infeasibility{idx:Infeasibility}\n",
|
||||
"\n",
|
||||
"`Infeasibility_Diagnose.py`\n"
|
||||
]
|
||||
|
|
@ -256,7 +256,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Constraint Attribution: welche Bedingung kostet wie viel?\n",
|
||||
"## Constraint Attribution{idx:Constraint Attribution}: welche Bedingung kostet wie viel?\n",
|
||||
"\n",
|
||||
"`Constraint_Attribution.py`\n"
|
||||
]
|
||||
|
|
|
|||
2
OR_HTML_04/Notebooks_04/prognose.ipynb
generated
2
OR_HTML_04/Notebooks_04/prognose.ipynb
generated
|
|
@ -4,7 +4,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Kapitel 15: Predict-then-Optimize — die bessere Prognose, die schlechtere Entscheidung\n",
|
||||
"# Kapitel 15: Predict-then-Optimize{idx:Predict-then-Optimize} — die bessere Prognose, die schlechtere Entscheidung\n",
|
||||
"\n",
|
||||
"Begleitnotebook zu *Optimierte Entscheidungsfindung mit Python*. Die Codezellen sind identisch mit den im Buch abgedruckten Programmen.\n"
|
||||
]
|
||||
|
|
|
|||
4
OR_HTML_04/Notebooks_04/unsicherheit.ipynb
generated
4
OR_HTML_04/Notebooks_04/unsicherheit.ipynb
generated
|
|
@ -95,7 +95,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Monte-Carlo-Simulation\n",
|
||||
"## Monte-Carlo-Simulation{idx:Monte-Carlo-Simulation}\n",
|
||||
"\n",
|
||||
"`Monte_Carlo.py`\n"
|
||||
]
|
||||
|
|
@ -340,7 +340,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Robuste Optimierung: gegen den Worst Case absichern\n",
|
||||
"## Robuste Optimierung{idx:Robuste Optimierung}: gegen den Worst Case absichern\n",
|
||||
"\n",
|
||||
"`Robuste_Optimierung.py`\n"
|
||||
]
|
||||
|
|
|
|||
BIN
OR_HTML_04/Operations_Research_mit_Python_Version_04.pdf
generated
BIN
OR_HTML_04/Operations_Research_mit_Python_Version_04.pdf
generated
Binary file not shown.
2
OR_HTML_04/anhang-fehlerdiagnose.html
generated
2
OR_HTML_04/anhang-fehlerdiagnose.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/anhang-glossar.html
generated
2
OR_HTML_04/anhang-glossar.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/anhang-literatur.html
generated
2
OR_HTML_04/anhang-literatur.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/anhang-loesungen.html
generated
2
OR_HTML_04/anhang-loesungen.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/anhang-modellierungsmuster.html
generated
2
OR_HTML_04/anhang-modellierungsmuster.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/anhang-spickzettel.html
generated
2
OR_HTML_04/anhang-spickzettel.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/assets/search-index.js
generated
2
OR_HTML_04/assets/search-index.js
generated
File diff suppressed because one or more lines are too long
117
OR_HTML_04/bilder_04/titelseite.svg
generated
117
OR_HTML_04/bilder_04/titelseite.svg
generated
|
|
@ -2444,37 +2444,42 @@ z
|
|||
</g>
|
||||
</g>
|
||||
<g id="text_14">
|
||||
<!-- Stand: 9. September 2026 -->
|
||||
<!-- Stand: 10. September 2026 -->
|
||||
<g style="fill: #c7d2fe" transform="translate(71.4528 818.05749) scale(0.12 -0.12)">
|
||||
<defs>
|
||||
<path id="DejaVuSans-39" d="M 703 97
|
||||
L 703 672
|
||||
Q 941 559 1184 500
|
||||
Q 1428 441 1663 441
|
||||
Q 2288 441 2617 861
|
||||
Q 2947 1281 2994 2138
|
||||
Q 2813 1869 2534 1725
|
||||
Q 2256 1581 1919 1581
|
||||
Q 1219 1581 811 2004
|
||||
Q 403 2428 403 3163
|
||||
Q 403 3881 828 4315
|
||||
Q 1253 4750 1959 4750
|
||||
Q 2769 4750 3195 4129
|
||||
Q 3622 3509 3622 2328
|
||||
Q 3622 1225 3098 567
|
||||
Q 2575 -91 1691 -91
|
||||
Q 1453 -91 1209 -44
|
||||
Q 966 3 703 97
|
||||
<path id="DejaVuSans-31" d="M 794 531
|
||||
L 1825 531
|
||||
L 1825 4091
|
||||
L 703 3866
|
||||
L 703 4441
|
||||
L 1819 4666
|
||||
L 2450 4666
|
||||
L 2450 531
|
||||
L 3481 531
|
||||
L 3481 0
|
||||
L 794 0
|
||||
L 794 531
|
||||
z
|
||||
M 1959 2075
|
||||
Q 2384 2075 2632 2365
|
||||
Q 2881 2656 2881 3163
|
||||
Q 2881 3666 2632 3958
|
||||
Q 2384 4250 1959 4250
|
||||
Q 1534 4250 1286 3958
|
||||
Q 1038 3666 1038 3163
|
||||
Q 1038 2656 1286 2365
|
||||
Q 1534 2075 1959 2075
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-30" d="M 2034 4250
|
||||
Q 1547 4250 1301 3770
|
||||
Q 1056 3291 1056 2328
|
||||
Q 1056 1369 1301 889
|
||||
Q 1547 409 2034 409
|
||||
Q 2525 409 2770 889
|
||||
Q 3016 1369 3016 2328
|
||||
Q 3016 3291 2770 3770
|
||||
Q 2525 4250 2034 4250
|
||||
z
|
||||
M 2034 4750
|
||||
Q 2819 4750 3233 4129
|
||||
Q 3647 3509 3647 2328
|
||||
Q 3647 1150 3233 529
|
||||
Q 2819 -91 2034 -91
|
||||
Q 1250 -91 836 529
|
||||
Q 422 1150 422 2328
|
||||
Q 422 3509 836 4129
|
||||
Q 1250 4750 2034 4750
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-32" d="M 1228 531
|
||||
|
|
@ -2500,27 +2505,6 @@ Q 3191 2616 2906 2266
|
|||
Q 2828 2175 2409 1742
|
||||
Q 1991 1309 1228 531
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-30" d="M 2034 4250
|
||||
Q 1547 4250 1301 3770
|
||||
Q 1056 3291 1056 2328
|
||||
Q 1056 1369 1301 889
|
||||
Q 1547 409 2034 409
|
||||
Q 2525 409 2770 889
|
||||
Q 3016 1369 3016 2328
|
||||
Q 3016 3291 2770 3770
|
||||
Q 2525 4250 2034 4250
|
||||
z
|
||||
M 2034 4750
|
||||
Q 2819 4750 3233 4129
|
||||
Q 3647 3509 3647 2328
|
||||
Q 3647 1150 3233 529
|
||||
Q 2819 -91 2034 -91
|
||||
Q 1250 -91 836 529
|
||||
Q 422 1150 422 2328
|
||||
Q 422 3509 836 4129
|
||||
Q 1250 4750 2034 4750
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-36" d="M 2113 2584
|
||||
Q 1688 2584 1439 2293
|
||||
|
|
@ -2560,23 +2544,24 @@ z
|
|||
<use xlink:href="#DejaVuSans-64" transform="translate(227.34375 0)"/>
|
||||
<use xlink:href="#DejaVuSans-3a" transform="translate(290.820312 0)"/>
|
||||
<use xlink:href="#DejaVuSans-20" transform="translate(324.511719 0)"/>
|
||||
<use xlink:href="#DejaVuSans-39" transform="translate(356.298828 0)"/>
|
||||
<use xlink:href="#DejaVuSans-2e" transform="translate(419.921875 0)"/>
|
||||
<use xlink:href="#DejaVuSans-20" transform="translate(451.708984 0)"/>
|
||||
<use xlink:href="#DejaVuSans-53" transform="translate(483.496094 0)"/>
|
||||
<use xlink:href="#DejaVuSans-65" transform="translate(546.972656 0)"/>
|
||||
<use xlink:href="#DejaVuSans-70" transform="translate(608.496094 0)"/>
|
||||
<use xlink:href="#DejaVuSans-74" transform="translate(671.972656 0)"/>
|
||||
<use xlink:href="#DejaVuSans-65" transform="translate(711.181641 0)"/>
|
||||
<use xlink:href="#DejaVuSans-6d" transform="translate(772.705078 0)"/>
|
||||
<use xlink:href="#DejaVuSans-62" transform="translate(870.117188 0)"/>
|
||||
<use xlink:href="#DejaVuSans-65" transform="translate(933.59375 0)"/>
|
||||
<use xlink:href="#DejaVuSans-72" transform="translate(995.117188 0)"/>
|
||||
<use xlink:href="#DejaVuSans-20" transform="translate(1036.230469 0)"/>
|
||||
<use xlink:href="#DejaVuSans-32" transform="translate(1068.017578 0)"/>
|
||||
<use xlink:href="#DejaVuSans-30" transform="translate(1131.640625 0)"/>
|
||||
<use xlink:href="#DejaVuSans-32" transform="translate(1195.263672 0)"/>
|
||||
<use xlink:href="#DejaVuSans-36" transform="translate(1258.886719 0)"/>
|
||||
<use xlink:href="#DejaVuSans-31" transform="translate(356.298828 0)"/>
|
||||
<use xlink:href="#DejaVuSans-30" transform="translate(419.921875 0)"/>
|
||||
<use xlink:href="#DejaVuSans-2e" transform="translate(483.544922 0)"/>
|
||||
<use xlink:href="#DejaVuSans-20" transform="translate(515.332031 0)"/>
|
||||
<use xlink:href="#DejaVuSans-53" transform="translate(547.119141 0)"/>
|
||||
<use xlink:href="#DejaVuSans-65" transform="translate(610.595703 0)"/>
|
||||
<use xlink:href="#DejaVuSans-70" transform="translate(672.119141 0)"/>
|
||||
<use xlink:href="#DejaVuSans-74" transform="translate(735.595703 0)"/>
|
||||
<use xlink:href="#DejaVuSans-65" transform="translate(774.804688 0)"/>
|
||||
<use xlink:href="#DejaVuSans-6d" transform="translate(836.328125 0)"/>
|
||||
<use xlink:href="#DejaVuSans-62" transform="translate(933.740234 0)"/>
|
||||
<use xlink:href="#DejaVuSans-65" transform="translate(997.216797 0)"/>
|
||||
<use xlink:href="#DejaVuSans-72" transform="translate(1058.740234 0)"/>
|
||||
<use xlink:href="#DejaVuSans-20" transform="translate(1099.853516 0)"/>
|
||||
<use xlink:href="#DejaVuSans-32" transform="translate(1131.640625 0)"/>
|
||||
<use xlink:href="#DejaVuSans-30" transform="translate(1195.263672 0)"/>
|
||||
<use xlink:href="#DejaVuSans-32" transform="translate(1258.886719 0)"/>
|
||||
<use xlink:href="#DejaVuSans-36" transform="translate(1322.509766 0)"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="text_15">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 86 KiB |
2
OR_HTML_04/bruecke.html
generated
2
OR_HTML_04/bruecke.html
generated
File diff suppressed because one or more lines are too long
10
OR_HTML_04/cpsat.html
generated
10
OR_HTML_04/cpsat.html
generated
File diff suppressed because one or more lines are too long
6
OR_HTML_04/cvar.html
generated
6
OR_HTML_04/cvar.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/dekomposition.html
generated
2
OR_HTML_04/dekomposition.html
generated
File diff suppressed because one or more lines are too long
6
OR_HTML_04/dynamische-programmierung.html
generated
6
OR_HTML_04/dynamische-programmierung.html
generated
File diff suppressed because one or more lines are too long
6
OR_HTML_04/einfuehrung.html
generated
6
OR_HTML_04/einfuehrung.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/finanzdaten.html
generated
2
OR_HTML_04/finanzdaten.html
generated
File diff suppressed because one or more lines are too long
6
OR_HTML_04/fundament.html
generated
6
OR_HTML_04/fundament.html
generated
File diff suppressed because one or more lines are too long
11
OR_HTML_04/gesamtdokument.html
generated
11
OR_HTML_04/gesamtdokument.html
generated
|
|
@ -381,7 +381,7 @@
|
|||
<p>Mit Python planen, optimieren und entscheiden: von <strong>Personal, Schichten und Logistik</strong> über <strong>Energie, Ressourcen und Netzwerke</strong> bis zur <strong>Portfoliooptimierung an den Finanzmärkten</strong>.</p>
|
||||
<p>Autor / Herausgeber: Dieter Schlüter</p>
|
||||
<p><dieter(dot)schlueter(atsign)linix(dot)de></p>
|
||||
<p>Stand: 9. September 2026</p>
|
||||
<p>Stand: 10. September 2026</p>
|
||||
<hr />
|
||||
<nav id="TOC" role="doc-toc">
|
||||
<ul>
|
||||
|
|
@ -16655,7 +16655,7 @@ DCP-konvex (CVXPY-Pruefung)? False
|
|||
<p><span class="math display">
|
||||
\min_{\mathbf{w}}\quad \underbrace{\tfrac12\mathbf{w}^\top\boldsymbol{\Sigma}\mathbf{w}}_{\text{Risiko}}
|
||||
\;-\;\underbrace{\alpha\,\boldsymbol{\mu}^\top\mathbf{w}}_{\text{Ertrag}}
|
||||
\;-\;\underbrace{\beta\Big(-\textstyle\sum_i w_i\ln w_i\Big)}_{\text{Diversifikation}}
|
||||
\;-\;\underbrace{\beta\Big(-\textstyle\sum_i w_i\ln w_i\Big)}_{\text{Diversifikation`\index{Diversifikation}`{=latex}}}
|
||||
</span></p>
|
||||
<blockquote>
|
||||
<p><strong>📐 Formel-Lesehilfe zur Entropie</strong> <span class="math inline">H(\mathbf{w}) = -\sum_i w_i \ln w_i</span> ist ein Streuungsmaß: * Alles in einem Titel (<span class="math inline">w = (1,0,0,0)</span>): <span class="math inline">H = 0</span> — minimale Streuung. * Gleichverteilt (<span class="math inline">w_i = 1/4</span>): <span class="math inline">H = \ln 4 \approx 1{,}386</span> — maximale Streuung.</p>
|
||||
|
|
@ -19985,7 +19985,7 @@ e(x) \le \varepsilon
|
|||
<h2 id="sec:mehrziel-vorlegen">14.8 Wie man die Front vorlegt</h2>
|
||||
<p>Eine Front mit zehn Punkten ist kein Ergebnis, sondern eine Speisekarte. Damit sie entscheidbar wird, gehört eine Spalte dazu, die im Programm <code>EUR je kg</code> heißt:</p>
|
||||
<p><span class="math display">
|
||||
\text{Schattenpreis} = \frac{\text{Aufpreis gegenüber dem Kostenminimum}}
|
||||
\text{Schattenpreis`\index{Schattenpreis}`{=latex}} = \frac{\text{Aufpreis gegenüber dem Kostenminimum}}
|
||||
{\text{eingesparte Kilogramm}}
|
||||
</span></p>
|
||||
<p>Diese Zahl ist mit etwas vergleichbar, das das Unternehmen ohnehin kennt: dem internen CO₂-Preis oder dem Zertifikatspreis. Liegt der Schattenpreis darunter, ist die Entscheidung kaufmännisch schon getroffen.</p>
|
||||
|
|
@ -26173,6 +26173,11 @@ von allen Fehlversuchen genau einen: den erfolgreichsten.
|
|||
<h3 id="falle-5-laufzeitexplosion">Falle 5 — Laufzeitexplosion</h3>
|
||||
<p>Exakte Optimalität kann bei MILP oder CP-SAT Minuten bis Stunden dauern — und die Laufzeit wächst nicht linear mit der Problemgröße.</p>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 33%" />
|
||||
<col style="width: 33%" />
|
||||
<col style="width: 33%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
<th>Einsatzszenario</th>
|
||||
|
|
|
|||
6
OR_HTML_04/graphen.html
generated
6
OR_HTML_04/graphen.html
generated
File diff suppressed because one or more lines are too long
6
OR_HTML_04/handelsmaschine.html
generated
6
OR_HTML_04/handelsmaschine.html
generated
File diff suppressed because one or more lines are too long
6
OR_HTML_04/index.html
generated
6
OR_HTML_04/index.html
generated
File diff suppressed because one or more lines are too long
6
OR_HTML_04/lp.html
generated
6
OR_HTML_04/lp.html
generated
File diff suppressed because one or more lines are too long
6
OR_HTML_04/markowitz.html
generated
6
OR_HTML_04/markowitz.html
generated
File diff suppressed because one or more lines are too long
8
OR_HTML_04/mehrziel.html
generated
8
OR_HTML_04/mehrziel.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/metaheuristiken.html
generated
2
OR_HTML_04/metaheuristiken.html
generated
File diff suppressed because one or more lines are too long
10
OR_HTML_04/milp.html
generated
10
OR_HTML_04/milp.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/modellierung.html
generated
2
OR_HTML_04/modellierung.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/notation.html
generated
2
OR_HTML_04/notation.html
generated
File diff suppressed because one or more lines are too long
4
OR_HTML_04/notebooks.html
generated
4
OR_HTML_04/notebooks.html
generated
File diff suppressed because one or more lines are too long
6
OR_HTML_04/oekosystem.html
generated
6
OR_HTML_04/oekosystem.html
generated
File diff suppressed because one or more lines are too long
7
OR_HTML_04/praxisfallen.html
generated
7
OR_HTML_04/praxisfallen.html
generated
File diff suppressed because one or more lines are too long
6
OR_HTML_04/prognose.html
generated
6
OR_HTML_04/prognose.html
generated
File diff suppressed because one or more lines are too long
4
OR_HTML_04/programme.html
generated
4
OR_HTML_04/programme.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/projektwerkstatt.html
generated
2
OR_HTML_04/projektwerkstatt.html
generated
File diff suppressed because one or more lines are too long
4
OR_HTML_04/qp-nlp.html
generated
4
OR_HTML_04/qp-nlp.html
generated
File diff suppressed because one or more lines are too long
4
OR_HTML_04/stichwortverzeichnis.html
generated
4
OR_HTML_04/stichwortverzeichnis.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/supplychain.html
generated
2
OR_HTML_04/supplychain.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/synthese-anwendungen.html
generated
2
OR_HTML_04/synthese-anwendungen.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/synthese-grundlagen.html
generated
2
OR_HTML_04/synthese-grundlagen.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/synthese-kernverfahren.html
generated
2
OR_HTML_04/synthese-kernverfahren.html
generated
File diff suppressed because one or more lines are too long
6
OR_HTML_04/synthese-nichtlinear.html
generated
6
OR_HTML_04/synthese-nichtlinear.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/synthese-praxis.html
generated
2
OR_HTML_04/synthese-praxis.html
generated
File diff suppressed because one or more lines are too long
2
OR_HTML_04/testing.html
generated
2
OR_HTML_04/testing.html
generated
File diff suppressed because one or more lines are too long
6
OR_HTML_04/unsicherheit.html
generated
6
OR_HTML_04/unsicherheit.html
generated
File diff suppressed because one or more lines are too long
4
OR_HTML_04/vorwort.html
generated
4
OR_HTML_04/vorwort.html
generated
File diff suppressed because one or more lines are too long
920
Operations_Research_mit_Python_Version_04.md
generated
920
Operations_Research_mit_Python_Version_04.md
generated
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
|
@ -19,7 +19,7 @@
|
|||
## Von der mathematischen Modellierung zu praktischen intelligenten Lösungen für Betrieb, Technik und Finanzmärkte {.unlisted .unnumbered}
|
||||
|
||||
**Ein praxisorientiertes Kompendium für Entscheider** mit Constraint Programming, Vektor-
|
||||
und Matrixmethoden sowie HiGHS, SciPy, Google OR-Tools und CVXPY.
|
||||
und Matrixmethoden sowie HiGHS{idx:HiGHS}, SciPy, Google OR-Tools{idx:OR-Tools} und CVXPY.
|
||||
|
||||
Mit Python planen, optimieren und entscheiden: von **Personal, Schichten und Logistik** über **Energie, Ressourcen und Netzwerke** bis zur **Portfoliooptimierung an den Finanzmärkten**.
|
||||
|
||||
|
|
@ -83,8 +83,8 @@ sowie Mathematik auf Grundstudiumsniveau:
|
|||
|
||||
| Gebiet | Was Sie können sollten | Wo im Buch gebraucht |
|
||||
| --- | --- | --- |
|
||||
| **Lineare Algebra** | Vektoren, Matrizen, Matrix-Vektor-Produkt, Eigenwerte | ab {ref:kap:fundament}, zentral in {ref:kap:qp-nlp}, {ref:kap:finanzdaten}, {ref:kap:markowitz} |
|
||||
| **Analysis** | Ableitung, Gradient, notwendige Bedingung erster Ordnung | {ref:kap:qp-nlp} |
|
||||
| **Lineare Algebra** | Vektoren, Matrizen, Matrix-Vektor-Produkt{idx:Matrix-Vektor-Produkt}, Eigenwerte | ab {ref:kap:fundament}, zentral in {ref:kap:qp-nlp}, {ref:kap:finanzdaten}, {ref:kap:markowitz} |
|
||||
| **Analysis** | Ableitung, Gradient{idx:Gradient}, notwendige Bedingung erster Ordnung | {ref:kap:qp-nlp} |
|
||||
| **Statistik** | Erwartungswert, Varianz, Standardabweichung, Quantil | {ref:kap:unsicherheit}, 11–14 |
|
||||
| **Python** | Listen, Dictionaries, Schleifen, Funktionen, Klassen, NumPy-Arrays | durchgängig |
|
||||
|
||||
|
|
@ -132,8 +132,8 @@ Eine Besonderheit dabei — die Import-Reihenfolge ist bewusst gewählt: `highsp
|
|||
native Bibliothek zuerst. Der Grund: `ortools` und `highspy` bringen jeweils eine eigene
|
||||
HiGHS-Kopie mit, die sich nicht im selben Python-Prozess verträgt — und `cvxpy` importiert
|
||||
ein installiertes `highspy` bei der Solver-Erkennung selbst mit. Lädt deren HiGHS-Kopie
|
||||
zuerst, bricht der Test beim CP-SAT-Funktionstest mit einem kryptischen
|
||||
`ImportError: undefined symbol` ab; so gewinnt die Kopie von `ortools`, und CVXPY verzichtet
|
||||
zuerst, bricht der Test beim CP-SAT{idx:CP-SAT}-Funktionstest mit einem kryptischen
|
||||
`ImportError: undefined symbol` ab; so gewinnt die Kopie von `ortools`, und CVXPY{idx:CVXPY} verzichtet
|
||||
lediglich auf sein HIGHS-Interface (für alle Buchprogramme folgenlos). Details und
|
||||
Abhilfen: {ref:sec:oekosystem-ein-system-vier-programmieransaetze} und
|
||||
{ref:anhang:fehlerdiagnose}.
|
||||
|
|
@ -367,7 +367,7 @@ Suchen Sie sich einen aus. Sie können auch alle vier überspringen; nötig sind
|
|||
* **Für die Sitzung gibt es einen Bericht, keine Tabelle.**
|
||||
{ref:sec:praxisfallen-attribution} beziffert je Nebenbedingung, was sie den Plan kostet,
|
||||
und formuliert daraus Sätze in Alltagssprache. Für die Frage des Betriebsrats — *„warum
|
||||
ausgerechnet ich?“* — liefert {ref:kap:praxisfallen} den Constraint-Trace, der die
|
||||
ausgerechnet ich?“* — liefert {ref:kap:praxisfallen} den Constraint-Trace{idx:Constraint-Trace}, der die
|
||||
einzelne Zuweisung begründet.
|
||||
|
||||
**Ihr Weg.** Zuerst Pfad E (2–4 Stunden): {ref:sec:einfuehrung-historischer-kontext-und-evolution}
|
||||
|
|
@ -394,14 +394,14 @@ deshalb jedes Mal, worauf eine Zahl beruht.
|
|||
|
||||
* **Der Engpass lässt sich benennen und bepreisen.**
|
||||
{ref:sec:praxisfallen-attribution} rechnet für jede Kapazität aus, was die nächste Stunde
|
||||
wert ist — und wie weit dieser Wert trägt. Im Beispiel gilt der Schattenpreis der
|
||||
wert ist — und wie weit dieser Wert trägt. Im Beispiel gilt der Schattenpreis{idx:Schattenpreis} der
|
||||
Lackiererei exakt bis **+15 Stunden**; eine ganze Sonderschicht von 30 Stunden bringt
|
||||
deshalb 60 € statt der rechnerischen 120 €. **Die zweite Hälfte wäre bezahlt und
|
||||
wirkungslos.**
|
||||
* **Rüstzeiten, Reihenfolgen, Taktzeiten sind der Kern, nicht die Ausnahme.**
|
||||
{ref:kap:cpsat} modelliert Maschinenbelegung mit Intervallvariablen,
|
||||
{ref:kap:metaheuristiken} zeigt am selben Fall das Gesamtbild: Faustregel 2 497 Minuten
|
||||
Rüstzeit, CP-SAT allein 2 628, Simulated Annealing 2 343, Annealing plus LNS **2 289** —
|
||||
Rüstzeit{idx:Rüstzeit}, CP-SAT allein 2 628, Simulated Annealing{idx:Simulated Annealing} 2 343, Annealing plus LNS **2 289** —
|
||||
und die untere Schranke bei 1 768, damit sichtbar bleibt, wie viel Luft noch da ist.
|
||||
* **Wenn der Solver zu lange braucht, gibt es Zahlen statt Ratschläge.**
|
||||
{ref:sec:cpsat-parallele-suche} misst, was mehrere Suchstränge bringen (hier Faktor 12,3)
|
||||
|
|
@ -422,23 +422,23 @@ nachverhandelt, gewinnt nichts und hält das Verfahren für nutzlos.
|
|||
> Titel, null in fünf anderen. Und im nächsten Quartal sieht sie völlig anders aus.“*
|
||||
|
||||
* **Der Grund dafür steht in {ref:kap:finanzdaten}, nicht in {ref:kap:markowitz}.** Eine
|
||||
aus kurzen Zeitreihen geschätzte Kovarianzmatrix ist schlecht konditioniert; der
|
||||
aus kurzen Zeitreihen geschätzte Kovarianzmatrix{idx:Kovarianzmatrix} ist schlecht konditioniert; der
|
||||
Optimierer setzt dann auf Schätzrauschen. Shrinkage nach Ledoit-Wolf ist das Gegenmittel;
|
||||
ihre Wirkung wird an **Eigenwertspektrum und Konditionszahl** gemessen, nicht behauptet.
|
||||
ihre Wirkung wird an **Eigenwertspektrum und Konditionszahl**{idx:Konditionszahl} gemessen, nicht behauptet.
|
||||
* **Der VaR verschweigt genau das, worauf es ankommt.** In der Stichprobe aus
|
||||
{ref:kap:cvar} sagt der VaR: „an 95 % der Tage höchstens **1,86 %** Verlust“. Der CVaR
|
||||
sagt: „und wenn doch, dann im Mittel **2,99 %**“. Der schlechteste Tag der Stichprobe
|
||||
liegt bei **−23,0 %** — am VaR ändert dieser eine Tag **nichts**, am CVaR sehr wohl.
|
||||
Deshalb ist der CVaR die Größe, die man optimiert.
|
||||
* **Transaktionskosten und Rebalancing sind Teil des Modells, nicht ein Abzug danach.**
|
||||
{ref:kap:cvar} nimmt sie in die Zielfunktion, {ref:kap:handelsmaschine} setzt den
|
||||
* **Transaktionskosten{idx:Transaktionskosten} und Rebalancing sind Teil des Modells, nicht ein Abzug danach.**
|
||||
{ref:kap:cvar} nimmt sie in die Zielfunktion{idx:Zielfunktion}, {ref:kap:handelsmaschine} setzt den
|
||||
Backtest daneben — samt der Fallen, die einen guten Backtest wertlos machen.
|
||||
|
||||
**Ihr Weg.** Pfad D, und zwar **mit** {ref:kap:finanzdaten}. Danach Projekt **P6**
|
||||
(Portfolio-Rebalancer) oder **P7** (Risikoreport mit CVaR und Stresstests).
|
||||
|
||||
**Woran es scheitert.** An der Reihenfolge. Wer bei Markowitz einsteigt und die
|
||||
Datenkapitel überspringt, bekommt ein Modell, das seine eigenen Schätzfehler maximiert —
|
||||
Datenkapitel überspringt, bekommt ein Modell, das seine eigenen Schätzfehler{idx:Schätzfehler} maximiert —
|
||||
und merkt es erst im Echtgeldbetrieb.
|
||||
|
||||
### Für Studierende und Data Scientists — die Methodik {-}
|
||||
|
|
@ -540,43 +540,43 @@ Pfad E oder um gezielt nach einem Thema zu suchen:
|
|||
| --- | --- | --- |
|
||||
| `Installationstest.py` | Installationsprüfung | Vorspann |
|
||||
| `Bot_Allokation.py` | Erstes CP-SAT-Modell | {ref:kap:einfuehrung} |
|
||||
| `Brute_Force_Vergleich.py` | Kombinatorische Explosion | {ref:kap:einfuehrung} |
|
||||
| `Brute_Force_Vergleich.py` | Kombinatorische Explosion{idx:Kombinatorische Explosion} | {ref:kap:einfuehrung} |
|
||||
| `Bausteine_Vorlage.py` | Vorlage für eigene Modelle | {ref:kap:einfuehrung} |
|
||||
| `Excel_Bruecke.py` | Excel-Mappe lesen, lösen, zurückschreiben | {ref:kap:einfuehrung} |
|
||||
| `Matrixform.py` | Matrixform und Zulässigkeit | {ref:kap:fundament} |
|
||||
| `Matrixform.py` | Matrixform{idx:Matrixform} und Zulässigkeit | {ref:kap:fundament} |
|
||||
| `Konvexitaet_Demo.py` | Sehnen-Test, lokale Optima | {ref:kap:fundament} |
|
||||
| `Visualisierung_Loesungsraum.py` | Polyeder mit Ecken | {ref:kap:fundament} |
|
||||
| `Visualisierung_Loesungsraum.py` | Polyeder{idx:Polyeder} mit Ecken | {ref:kap:fundament} |
|
||||
| `Skalierung_Kondition.py` | Konditionszahl, Ruiz, Toleranzen | {ref:kap:fundament} |
|
||||
| `Solver_Wahl.py` | Entscheidungshilfe | {ref:kap:oekosystem} |
|
||||
| `Ein_System_Vier_Ansaetze.py` | Vier Bibliotheken | {ref:kap:oekosystem} |
|
||||
| `Modellierungsschichten.py` | Pyomo und Linopy | {ref:kap:oekosystem} |
|
||||
| `Modellierungsschichten.py` | Pyomo{idx:Pyomo} und Linopy{idx:Linopy} | {ref:kap:oekosystem} |
|
||||
| `Vektorisierte_Modellgenerierung.py` | Aufbauzeit vs. Lösezeit | {ref:kap:oekosystem} |
|
||||
| `Vom_Wunsch_zum_Modell.py` | Fünf Modelle auf denselben Daten | {ref:kap:modellierung} |
|
||||
| `Simplex_Tableau_LP.py` | Simplex von Grund auf | {ref:kap:lp} |
|
||||
| `Sensitivitaetsanalyse.py` | Schattenpreise | {ref:kap:lp} |
|
||||
| `Dualitaet_Nachweis.py` | Primal-dual, starke Dualität | {ref:kap:lp} |
|
||||
| `Toleranzen_und_Entartung.py` | Entartung, Toleranzen, Dualspannen | {ref:kap:lp} |
|
||||
| `Toleranzen_und_Entartung.py` | Entartung{idx:Entartung}, Toleranzen, Dualspannen | {ref:kap:lp} |
|
||||
| `Runden_Gegenbeispiel.py` | Warum Runden scheitert | {ref:kap:milp} |
|
||||
| `Rucksack.py` | Knapsack, LP-Schranke | {ref:kap:milp} |
|
||||
| `MILP_Portfolio_Fixgebuehren.py` | Fixkosten, Kardinalität | {ref:kap:milp} |
|
||||
| `Solverstatus_und_Gap.py` | MIP-Gap, Zeitlimit, Statusfälle | {ref:kap:milp} |
|
||||
| `Solverstatus_und_Gap.py` | MIP-Gap{idx:MIP-Gap}, Zeitlimit, Statusfälle | {ref:kap:milp} |
|
||||
| `Warmstart_Effekt.py` | LPT-Hinweis für CP-SAT | {ref:kap:milp} |
|
||||
| `Big_M_Falle.py` | Trickle Flow bei zu großem M | {ref:kap:milp} |
|
||||
| `Big_M_Falle.py` | Trickle Flow{idx:Trickle Flow} bei zu großem M | {ref:kap:milp} |
|
||||
| `Propagation_Demo.py` | Propagation messbar | {ref:kap:cpsat} |
|
||||
| `CP_SAT_Vertretungssystem.py` | Vertretungsplan | {ref:kap:cpsat} |
|
||||
| `JobShop_Intervalle.py` | Job-Shop-Scheduling | {ref:kap:cpsat} |
|
||||
| `JobShop_Intervalle.py` | Job-Shop-Scheduling{idx:Job-Shop-Scheduling} | {ref:kap:cpsat} |
|
||||
| `Parallele_Suche.py` | num_workers: Tempo gegen Reproduzierbarkeit | {ref:kap:cpsat} |
|
||||
| `CP_SAT_Statusfaelle.py` | Die fünf Solver-Antworten | {ref:kap:cpsat} |
|
||||
| `Strafgewichte.py` | Gewichte als Wechselkurse | {ref:kap:cpsat} |
|
||||
| `Min_Cost_Flow.py` | Netzwerkfluss | {ref:kap:graphen} |
|
||||
| `Zuordnung_Ungarisch.py` | Zuordnung, Unimodularität | {ref:kap:graphen} |
|
||||
| `VRP_Flotten_Routing.py` | CVRPTW | {ref:kap:graphen} |
|
||||
| `VRP_Flotten_Routing.py` | CVRPTW{idx:CVRPTW} | {ref:kap:graphen} |
|
||||
| `VRP_Kapazitaetsfalle.py` | Vergessene Dimension im Routing | {ref:kap:graphen} |
|
||||
| `Simulated_Annealing.py` | Lokale Suche, Temperatur kalibrieren | {ref:kap:metaheuristiken} |
|
||||
| `Metaheuristik_vs_Exakt.py` | Der Umschlagpunkt, und die Schranke | {ref:kap:metaheuristiken} |
|
||||
| `Large_Neighborhood_Search.py` | Zerstören und exakt reparieren | {ref:kap:metaheuristiken} |
|
||||
| `Spaltengenerierung.py` | Muster statt Stücke, Master und Pricing | {ref:kap:dekomposition} |
|
||||
| `QP_Grundlagen.py` | Konvexität, DCP-Check | {ref:kap:qp-nlp} |
|
||||
| `QP_Grundlagen.py` | Konvexität{idx:Konvexität}, DCP-Check | {ref:kap:qp-nlp} |
|
||||
| `KKT_Nachweis.py` | KKT numerisch prüfen | {ref:kap:qp-nlp} |
|
||||
| `Entropie_Maximierte_Allokation.py` | NLP mit Entropie | {ref:kap:qp-nlp} |
|
||||
| `Lokale_Optima_Multistart.py` | Lokale Optima, Multistart | {ref:kap:qp-nlp} |
|
||||
|
|
@ -585,8 +585,8 @@ Pfad E oder um gezielt nach einem Thema zu suchen:
|
|||
| `Stochastische_Optimierung.py` | Two-Stage mit Recourse | {ref:kap:unsicherheit} |
|
||||
| `Robuste_Optimierung.py` | Worst-Case-Absicherung | {ref:kap:unsicherheit} |
|
||||
| `Chance_Constraints.py` | Zusage „mit 95 % Sicherheit“, SOC und Big-M | {ref:kap:unsicherheit} |
|
||||
| `Bellman_Minimalbeispiel.py` | Rückwärtsinduktion | {ref:kap:dynamische-programmierung} |
|
||||
| `Mehrziel_Pareto.py` | Pareto-Front, ε-Constraint, Gewichtslücke | {ref:kap:mehrziel} |
|
||||
| `Bellman_Minimalbeispiel.py` | Rückwärtsinduktion{idx:Rückwärtsinduktion} | {ref:kap:dynamische-programmierung} |
|
||||
| `Mehrziel_Pareto.py` | Pareto-Front{idx:Pareto-Front}, ε-Constraint, Gewichtslücke | {ref:kap:mehrziel} |
|
||||
| `Predict_then_Optimize.py` | MSE gegen Entscheidungskosten | {ref:kap:prognose} |
|
||||
| `Strukturbruecke.py` | Derselbe Code über Werkstatt und Depot | {ref:kap:bruecke} |
|
||||
| `Kraftwerkseinsatz.py` | Unit Commitment unter Windunsicherheit | {ref:kap:supplychain} |
|
||||
|
|
@ -598,9 +598,9 @@ Pfad E oder um gezielt nach einem Thema zu suchen:
|
|||
| `Markowitz_CVXPY.py` | GMV, Max Sharpe, Frontier | {ref:kap:markowitz} |
|
||||
| `Diversifikation_Demo.py` | Korrelation und Portfoliorisiko | {ref:kap:markowitz} |
|
||||
| `Renditeschaetzung_Falle.py` | Schätzfehler in erwarteten Renditen | {ref:kap:markowitz} |
|
||||
| `VaR_CVaR_Demo.py` | Fat Tails, Subadditivität | {ref:kap:cvar} |
|
||||
| `VaR_CVaR_Demo.py` | Fat Tails{idx:Fat Tails}, Subadditivität{idx:Subadditivität} | {ref:kap:cvar} |
|
||||
| `CVaR_Portfolio.py` | CVaR mit Reibung | {ref:kap:cvar} |
|
||||
| `QuantitativeTradingEngine.py` | Walk-Forward-Backtest | {ref:kap:handelsmaschine} |
|
||||
| `QuantitativeTradingEngine.py` | Walk-Forward-Backtest{idx:Walk-Forward-Backtest} | {ref:kap:handelsmaschine} |
|
||||
| `Backtest_Fallen.py` | Fünf Selbsttäuschungen | {ref:kap:handelsmaschine} |
|
||||
| `Data_Snooping.py` | Bestes aus N Versuchen auf Rauschen | {ref:kap:handelsmaschine} |
|
||||
| `Infeasibility_Diagnose.py` | Notfallplan statt Fehler | {ref:kap:praxisfallen} |
|
||||
|
|
@ -613,7 +613,7 @@ Pfad E oder um gezielt nach einem Thema zu suchen:
|
|||
| `Mutationstest.py` | Findet die Lücken der eigenen Tests | {ref:kap:testing} |
|
||||
| `Benchmark_Skalierung.py` | Aufbau gegen Lösen, vier Bibliotheken | {ref:kap:testing} |
|
||||
| `Optimierungsdienst.py` | Das Modell als HTTP-Dienst | {ref:kap:testing} |
|
||||
| `Konfliktsuche.py` | Deletion Filter: den Widerspruch einkreisen | {ref:anhang:fehlerdiagnose} |
|
||||
| `Konfliktsuche.py` | Deletion Filter{idx:Deletion Filter}: den Widerspruch einkreisen | {ref:anhang:fehlerdiagnose} |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -621,7 +621,7 @@ Pfad E oder um gezielt nach einem Thema zu suchen:
|
|||
|
||||
Es ist **keine Anleitung zum Bau eigener Solver** — wir nutzen ausgereifte Implementierungen
|
||||
und investieren die Zeit stattdessen in die Modellierung. Die einzige Ausnahme ist der
|
||||
Simplex-Algorithmus in {ref:kap:lp}, den wir von Grund auf programmieren, weil man ihn
|
||||
Simplex-Algorithmus{idx:Simplex-Algorithmus} in {ref:kap:lp}, den wir von Grund auf programmieren, weil man ihn
|
||||
verstanden haben muss, um Dualität und Schattenpreise zu begreifen.
|
||||
|
||||
Es ist **kein Buch über maschinelles Lernen**. Prognosen kommen nur so weit vor, wie sie als
|
||||
|
|
|
|||
|
|
@ -11,21 +11,21 @@ sobald Ihnen ein Symbol oder ein Kürzel begegnet, das Sie nicht sicher zuordnen
|
|||
|
||||
| Symbol | Sprechweise | Bedeutung | Beispiel aus dem Buch |
|
||||
| --- | --- | --- | --- |
|
||||
| $x$ | „iks“ | **Entscheidungsvariable(n)** — das, was der Solver festlegen darf | Anzahl gestarteter Trading-Bots ({ref:kap:einfuehrung}) |
|
||||
| $x$ | „iks“ | **Entscheidungsvariable{idx:Entscheidungsvariable}(n)** — das, was der Solver festlegen darf | Anzahl gestarteter Trading-Bots ({ref:kap:einfuehrung}) |
|
||||
| $\mathbf{x}$ | „Vektor iks“ | Alle Entscheidungsvariablen als Spaltenvektor | $\mathbf{x} = (x_1, \dots, x_n)^\top$ |
|
||||
| $n$ | „en“ | Anzahl der Entscheidungsvariablen | 10 Aktien $\Rightarrow n = 10$ |
|
||||
| $m$ | „em“ | Anzahl der Nebenbedingungen | 3 Ressourcen $\Rightarrow m = 3$ |
|
||||
| $\mathbf{c}$ | „Vektor ze“ | **Kosten- bzw. Ertragsvektor** der Zielfunktion | Gewinn je Bot-Typ: $(150, 250)^\top$ |
|
||||
| $\mathbf{A}$ | „Matrix a“ | **Technologiematrix** — wie viel Ressource verbraucht welche Variable | Zeile „RAM“: $(4, 6)$ |
|
||||
| $\mathbf{b}$ | „Vektor be“ | **Kapazitätsvektor**, „rechte Seite“ der Ungleichungen | $(40, 60)^\top$ vCPU und GB |
|
||||
| $\mathbf{c}$ | „Vektor ze“ | **Kosten- bzw. Ertragsvektor** der Zielfunktion{idx:Zielfunktion} | Gewinn je Bot-Typ: $(150, 250)^\top$ |
|
||||
| $\mathbf{A}$ | „Matrix a“ | **Technologiematrix**{idx:Technologiematrix} — wie viel Ressource verbraucht welche Variable | Zeile „RAM“: $(4, 6)$ |
|
||||
| $\mathbf{b}$ | „Vektor be“ | **Kapazitätsvektor**{idx:Kapazitätsvektor}, „rechte Seite“ der Ungleichungen | $(40, 60)^\top$ vCPU und GB |
|
||||
| $f(\mathbf{x})$ | „ef von iks“ | **Zielfunktion** — die eine Zahl, die bewertet wird | Tagesgewinn in Euro |
|
||||
| $g_i(\mathbf{x})$ | „ge i von iks“ | $i$-te **Ungleichungs-Nebenbedingung**, Form $g_i(\mathbf{x}) \le 0$ | „RAM-Verbrauch minus 60 GB“ |
|
||||
| $h_j(\mathbf{x})$ | „ha j von iks“ | $j$-te **Gleichungs-Nebenbedingung**, Form $h_j(\mathbf{x}) = 0$ | „Summe der Gewichte minus 1“ |
|
||||
| $s_i$ | „es i“ | **Schlupfvariable** — ungenutzte Reserve der Ressource $i$ | 1 GB RAM übrig $\Rightarrow s_2 = 1$ |
|
||||
| $y_i,\ \lambda_i$ | „y i“, „lambda i“ | **Dualvariable / Schattenpreis** der Bedingung $i$ | 33,33 € je zusätzlicher Prüfstunde |
|
||||
| $s_i$ | „es i“ | **Schlupfvariable**{idx:Schlupfvariable} — ungenutzte Reserve der Ressource $i$ | 1 GB RAM übrig $\Rightarrow s_2 = 1$ |
|
||||
| $y_i,\ \lambda_i$ | „y i“, „lambda i“ | **Dualvariable / Schattenpreis**{idx:Schattenpreis} der Bedingung $i$ | 33,33 € je zusätzlicher Prüfstunde |
|
||||
| $M$ | „groß em“ | **Big-M** — hinreichend große Konstante zum Ein-/Ausschalten von Bedingungen | $x_j \le M \cdot y_j$ |
|
||||
| $z_i,\ y_i$ | | **Binärvariable** $\in \{0,1\}$ — Ja/Nein-Schalter | „Position $i$ wird eröffnet“ |
|
||||
| $\mathcal{F}$ | „kalligrafisches ef“ | **Zulässiger Bereich** — Menge aller erlaubten Lösungen | das Polyeder aus {ref:kap:fundament} |
|
||||
| $z_i,\ y_i$ | | **Binärvariable**{idx:Binärvariable} $\in \{0,1\}$ — Ja/Nein-Schalter | „Position $i$ wird eröffnet“ |
|
||||
| $\mathcal{F}$ | „kalligrafisches ef“ | **Zulässiger Bereich** — Menge{idx:Konvexität!Menge} aller erlaubten Lösungen | das Polyeder{idx:Polyeder} aus {ref:kap:fundament} |
|
||||
| $Z,\ Z^*$ | „zet“, „zet Stern“ | Zielfunktionswert bzw. **optimaler** Zielfunktionswert | $Z^* = 2300$ € |
|
||||
| $\mathbf{x}^*$ | „iks Stern“ | Die **optimale Lösung**. Der Stern markiert immer „im Optimum“ | $\mathbf{x}^* = (7, 5)^\top$ |
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ sobald Ihnen ein Symbol oder ein Kürzel begegnet, das Sie nicht sicher zuordnen
|
|||
| --- | --- | --- |
|
||||
| $\mathbb{R}$ | Reelle Zahlen (beliebig teilbar) | Variable darf 3,7 sein — **LP**, schnell lösbar |
|
||||
| $\mathbb{R}^n$ | $n$-Tupel reeller Zahlen | Der Raum, in dem $\mathbf{x}$ lebt |
|
||||
| $\mathbb{Z}$ | Ganze Zahlen | Variable muss 3 oder 4 sein — **MILP**, NP-schwer |
|
||||
| $\mathbb{Z}$ | Ganze Zahlen | Variable muss 3 oder 4 sein — **MILP**, NP-schwer{idx:NP-schwer} |
|
||||
| $\mathbb{N}_0$ | Natürliche Zahlen einschließlich 0 | Stückzahlen, nie negativ |
|
||||
| $\{0, 1\}$ | Nur zwei Werte | Ja/Nein-Entscheidung |
|
||||
| $\in$ | „ist Element von“ | $x \in \mathbb{Z}$: „$x$ ist ganzzahlig“ |
|
||||
|
|
@ -49,16 +49,16 @@ sobald Ihnen ein Symbol oder ein Kürzel begegnet, das Sie nicht sicher zuordnen
|
|||
| Symbol | Bedeutung | Lesehilfe |
|
||||
| --- | --- | --- |
|
||||
| $\sum_{i=1}^n a_i$ | Summe | „addiere $a_1$ bis $a_n$“ |
|
||||
| $\mathbf{c}^\top \mathbf{x}$ | Skalarprodukt | „$c_1 x_1 + c_2 x_2 + \dots$“ — eine einzige Zahl |
|
||||
| $\mathbf{c}^\top \mathbf{x}$ | Skalarprodukt{idx:Skalarprodukt} | „$c_1 x_1 + c_2 x_2 + \dots$“ — eine einzige Zahl |
|
||||
| $^\top$ | Transponiert | dreht Zeilen und Spalten; macht aus Spalten- einen Zeilenvektor |
|
||||
| $\mathbf{A}\mathbf{x}$ | Matrix-Vektor-Produkt | „berechne alle Ressourcenverbräuche auf einmal“ |
|
||||
| $\mathbf{A}\mathbf{x}$ | Matrix-Vektor-Produkt{idx:Matrix-Vektor-Produkt} | „berechne alle Ressourcenverbräuche auf einmal“ |
|
||||
| $\min_x,\ \max_x$ | Minimum/Maximum über $x$ | „wähle $x$ so, dass … kleinst-/größtmöglich wird“ |
|
||||
| $\arg\min$ | Argument des Minimums | nicht der *Wert*, sondern die *Stelle* des Minimums |
|
||||
| $\nabla f$ | „Nabla ef“, Gradient | Vektor aller partiellen Ableitungen — zeigt bergauf |
|
||||
| $\nabla f$ | „Nabla ef“, Gradient{idx:Gradient} | Vektor aller partiellen Ableitungen — zeigt bergauf |
|
||||
| $\partial Z / \partial b_i$ | Partielle Ableitung | „wie ändert sich $Z$, wenn nur $b_i$ sich ändert?“ |
|
||||
| $\Vert \mathbf{v} \Vert_1$ | $L_1$-Norm | Summe der Beträge: $\vert v_1\vert + \vert v_2\vert + \dots$ |
|
||||
| $\Vert \mathbf{v} \Vert_2$ | $L_2$-Norm (euklidisch) | die gewöhnliche Länge eines Pfeils |
|
||||
| $\mathbf{P} \succeq 0$ | positiv **semi**definit | alle Eigenwerte $\ge 0$; Funktion ist konvex |
|
||||
| $\mathbf{P} \succeq 0$ | positiv **semi**definit | alle Eigenwerte $\ge 0$; Funktion{idx:Konvexität!Funktion} ist konvex |
|
||||
| $\mathbf{P} \succ 0$ | positiv **definit** | alle Eigenwerte $> 0$; Funktion ist *streng* konvex |
|
||||
| $\mathbb{E}[\cdot]$ | Erwartungswert | gewichteter Mittelwert über alle Szenarien |
|
||||
| $\mathbb{1}$ oder $\mathbf{1}$ | Einsvektor | $(1,1,\dots,1)^\top$; $\mathbf{1}^\top\mathbf{w}$ ist die Summe aller $w_i$ |
|
||||
|
|
@ -72,15 +72,15 @@ sobald Ihnen ein Symbol oder ein Kürzel begegnet, das Sie nicht sicher zuordnen
|
|||
| $\mathbf{w}$ | **Portfoliogewichte** — Kapitalanteile je Titel | dimensionslos, Summe $= 1$ |
|
||||
| $w_i$ | Anteil von Titel $i$ | $0{,}15 \equiv 15\,\%$ |
|
||||
| $\boldsymbol{\mu}$ | „mü“ — Vektor der **erwarteten Renditen** | z. B. $0{,}11$ = 11 % p. a. |
|
||||
| $\boldsymbol{\Sigma}$ | „Sigma“ — **Kovarianzmatrix** der Renditen | $N \times N$, Einheit Rendite² |
|
||||
| $\sigma$ | „sigma“ — **Volatilität** (Standardabweichung) | $0{,}20$ = 20 % p. a. |
|
||||
| $\boldsymbol{\Sigma}$ | „Sigma“ — **Kovarianzmatrix**{idx:Kovarianzmatrix} der Renditen | $N \times N$, Einheit Rendite² |
|
||||
| $\sigma$ | „sigma“ — **Volatilität**{idx:Volatilität} (Standardabweichung) | $0{,}20$ = 20 % p. a. |
|
||||
| $\sigma^2$ | **Varianz** | Quadrat der Volatilität |
|
||||
| $\mathbf{S}$ | **Stichproben**-Kovarianzmatrix (aus Daten geschätzt) | verrauscht |
|
||||
| $\mathbf{F}$ | **Shrinkage-Target** — strukturierte Vergleichsmatrix | verzerrt, aber stabil |
|
||||
| $\delta$ | „delta“ — Shrinkage-Intensität | $\in [0,1]$, z. B. $0{,}18$ |
|
||||
| $r_f$ | *risk-free rate*, **risikoloser Zins** | z. B. $0{,}03$ = 3 % p. a. |
|
||||
| $R_{i,t}$ | **Diskrete Rendite** von Titel $i$ am Tag $t$ | $P_t/P_{t-1} - 1$ |
|
||||
| $r_{i,t}$ | **Logarithmische Rendite** (stetige Rendite) | $\ln(P_t/P_{t-1})$ |
|
||||
| $R_{i,t}$ | **Diskrete Rendite**{idx:Diskrete Rendite} von Titel $i$ am Tag $t$ | $P_t/P_{t-1} - 1$ |
|
||||
| $r_{i,t}$ | **Logarithmische Rendite**{idx:Logarithmische Rendite} (stetige Rendite) | $\ln(P_t/P_{t-1})$ |
|
||||
| $P_{i,t}$ | **Kurs** (bereinigter Schlusskurs) von Titel $i$ | in Währungseinheiten |
|
||||
| $\lambda$ | Risikoaversion / Gewichtung des Risikoterms | Modellparameter, frei wählbar |
|
||||
| $\alpha$ | Konfidenzniveau bei VaR/CVaR | $0{,}95$ = „schlechteste 5 % der Tage“ |
|
||||
|
|
@ -100,7 +100,7 @@ Diese Zeichen kommen erst in den Kapiteln vor, die über das klassische LP hinau
|
|||
| --- | --- | --- | --- |
|
||||
| $\pi$ | „pi“ | **Reihenfolge (Permutation)**: $\pi(k)$ ist der Auftrag, der als $k$-ter läuft | {ref:kap:metaheuristiken} |
|
||||
| $\Delta$ | „delta“ | **Zugbewertung** — um wie viel ein Nachbarschaftszug die Lösung verschlechtert ($\Delta > 0$) oder verbessert ($\Delta \le 0$) | {ref:kap:metaheuristiken} |
|
||||
| $T$ | „te“ | **Temperatur** im Simulated Annealing — steuert, wie oft eine Verschlechterung angenommen wird | {ref:kap:metaheuristiken} |
|
||||
| $T$ | „te“ | **Temperatur** im Simulated Annealing{idx:Simulated Annealing} — steuert, wie oft eine Verschlechterung angenommen wird | {ref:kap:metaheuristiken} |
|
||||
| $e^{-\Delta/T}$ | | **Annahmewahrscheinlichkeit** (Metropolis-Kriterium): kleine Verschlechterungen fast immer, große fast nie | {ref:kap:metaheuristiken} |
|
||||
| $\pi_i$ | „pi i“ | **Dualpreis** der Bedingung $i$ im Master-LP — der Preis, mit dem das Pricing rechnet | {ref:kap:dekomposition} |
|
||||
| $a_i$ | „a i“ | Wie oft Stück $i$ in einem **Schnittmuster** vorkommt (eine Spalte des Masters) | {ref:kap:dekomposition} |
|
||||
|
|
@ -115,7 +115,7 @@ Diese Zeichen kommen erst in den Kapiteln vor, die über das klassische LP hinau
|
|||
|
||||
> **⚠️ Achtung, Doppelbelegungen.** In der Literatur — und deshalb auch hier — tragen einige
|
||||
> Buchstaben je nach Kapitel verschiedene Bedeutungen. Die wichtigsten Fälle:
|
||||
> $\lambda$ ist in {ref:kap:lp} und {ref:kap:qp-nlp} ein **Lagrange-Multiplikator/Schattenpreis**, in {ref:kap:markowitz}
|
||||
> $\lambda$ ist in {ref:kap:lp} und {ref:kap:qp-nlp} ein **Lagrange-Multiplikator{idx:Lagrange-Multiplikator}/Schattenpreis**, in {ref:kap:markowitz}
|
||||
> und {ref:kap:cvar} ein **frei gewählter Risikoaversionsparameter**. $\gamma$ ist in {ref:kap:dynamische-programmierung} der
|
||||
> **Diskontfaktor**, in {ref:kap:cvar} die **VaR-Hilfsvariable**. $S$ bezeichnet als Matrix
|
||||
> $\mathbf{S}$ die Stichprobenkovarianz, als Skalar $S$ die Szenarienzahl. $\pi$ ist in
|
||||
|
|
@ -140,20 +140,20 @@ Diese Zeichen kommen erst in den Kapiteln vor, die über das klassische LP hinau
|
|||
| **QP** | Quadratic Program(ming) | Quadratische Optimierung | {ref:kap:qp-nlp} |
|
||||
| **MIQP** | Mixed-Integer Quadratic Program(ming) | Ganzzahlig-quadratische Optimierung | {ref:kap:markowitz} |
|
||||
| **NLP** | Nonlinear Program(ming) | Nichtlineare Optimierung | {ref:kap:qp-nlp} |
|
||||
| **MINLP** | Mixed-Integer Nonlinear Program(ming) | Ganzzahlig-nichtlineare Optimierung | {ref:kap:oekosystem} |
|
||||
| **MINLP**{idx:MINLP} | Mixed-Integer Nonlinear Program(ming) | Ganzzahlig-nichtlineare Optimierung | {ref:kap:oekosystem} |
|
||||
| **CP** | Constraint Programming | Bedingungsprogrammierung | {ref:kap:cpsat} |
|
||||
| **SAT** | Boolean **Sat**isfiability Problem | Erfüllbarkeitsproblem der Aussagenlogik | {ref:kap:cpsat} |
|
||||
| **CP-SAT** | Constraint Programming über SAT-Techniken | Solver-Name von Google OR-Tools | {ref:kap:cpsat} |
|
||||
| **CDCL** | Conflict-Driven Clause Learning | konfliktgetriebenes Klausellernen | {ref:kap:cpsat} |
|
||||
| **CP-SAT**{idx:CP-SAT} | Constraint Programming über SAT-Techniken | Solver-Name von Google OR-Tools{idx:OR-Tools} | {ref:kap:cpsat} |
|
||||
| **CDCL**{idx:CDCL} | Conflict-Driven Clause Learning | konfliktgetriebenes Klausellernen | {ref:kap:cpsat} |
|
||||
| **DP** | Dynamic Programming | Dynamische Programmierung | {ref:kap:dynamische-programmierung} |
|
||||
| **B&B** | Branch and Bound | Verzweigen und Beschränken | {ref:kap:milp} |
|
||||
| **B&C** | Branch and Cut | Verzweigen mit Schnittebenen | {ref:kap:milp} |
|
||||
| **KKT** | Karush–Kuhn–Tucker (Bedingungen) | Optimalitätsbedingungen bei Restriktionen | {ref:kap:qp-nlp} |
|
||||
| **SLSQP** | Sequential Least Squares Programming | sequentielle quadratische Optimierung | {ref:kap:qp-nlp} |
|
||||
| **RMT** | Random Matrix Theory | Zufallsmatrizentheorie | {ref:kap:finanzdaten} |
|
||||
| **SA** | Simulated Annealing | Simulierte Abkühlung — Metaheuristik, die Verschlechterungen mit fallender Wahrscheinlichkeit zulässt | {ref:kap:metaheuristiken} |
|
||||
| **SLSQP**{idx:SLSQP} | Sequential Least Squares Programming | sequentielle quadratische Optimierung | {ref:kap:qp-nlp} |
|
||||
| **RMT** | Random Matrix Theory | Zufallsmatrizentheorie{idx:Zufallsmatrizentheorie} | {ref:kap:finanzdaten} |
|
||||
| **SA** | Simulated Annealing | Simulierte Abkühlung — Metaheuristik{idx:Metaheuristik}, die Verschlechterungen mit fallender Wahrscheinlichkeit zulässt | {ref:kap:metaheuristiken} |
|
||||
| **LNS** | Large Neighborhood Search | Große Nachbarschaftssuche: Teil der Lösung verwerfen, Rest exakt neu bauen | {ref:kap:metaheuristiken} |
|
||||
| **CG** | Column Generation | Spaltengenerierung — Variablen erst erzeugen, wenn sie sich lohnen | {ref:kap:dekomposition} |
|
||||
| **CG** | Column Generation{idx:Column Generation} | Spaltengenerierung — Variablen erst erzeugen, wenn sie sich lohnen | {ref:kap:dekomposition} |
|
||||
| **IIS** | Irreducible Infeasible Subset | Kleinste widersprüchliche Teilmenge von Bedingungen | {ref:anhang:fehlerdiagnose} |
|
||||
| **MSE** | Mean Squared Error | Mittlerer quadratischer Fehler — das Standardmaß für Prognosegüte | {ref:kap:prognose} |
|
||||
|
||||
|
|
@ -165,9 +165,9 @@ Diese Zeichen kommen erst in den Kapiteln vor, die über das klassische LP hinau
|
|||
| **VRP** | Vehicle Routing Problem | Tourenplanungsproblem | {ref:kap:graphen} |
|
||||
| **CVRP** | **C**apacitated VRP | VRP mit Fahrzeugkapazitäten | {ref:kap:graphen} |
|
||||
| **VRPTW** | VRP with **T**ime **W**indows | VRP mit Zeitfenstern | {ref:kap:graphen} |
|
||||
| **CVRPTW** | Capacitated VRP with Time Windows | mit Kapazitäten *und* Zeitfenstern | {ref:kap:graphen} |
|
||||
| **CVRPTW**{idx:CVRPTW} | Capacitated VRP with Time Windows | mit Kapazitäten *und* Zeitfenstern | {ref:kap:graphen} |
|
||||
| **MCNFP** | Minimum-Cost Network Flow Problem | Kostenminimales Flussproblem | {ref:kap:graphen} |
|
||||
| **MTZ** | Miller–Tucker–Zemlin (Formulierung) | Kurzzyklus-Eliminierung | {ref:kap:graphen} |
|
||||
| **MTZ** | Miller–Tucker–Zemlin (Formulierung) | Kurzzyklus-Eliminierung{idx:Subtour!Eliminierung} | {ref:kap:graphen} |
|
||||
| **JSSP** | Job-Shop Scheduling Problem | Werkstattfertigungs-Reihenfolgeproblem | {ref:kap:cpsat} |
|
||||
|
||||
### 2.3 Finanz- und Risikokennzahlen
|
||||
|
|
@ -177,12 +177,12 @@ Diese Zeichen kommen erst in den Kapiteln vor, die über das klassische LP hinau
|
|||
| **MPT** | Modern Portfolio Theory | Moderne Portfoliotheorie (Markowitz) | {ref:kap:markowitz} |
|
||||
| **GMV** | Global Minimum Variance (Portfolio) | Portfolio kleinstmöglicher Varianz | {ref:kap:markowitz} |
|
||||
| **MVO** | Mean-Variance Optimization | Erwartungswert-Varianz-Optimierung | {ref:kap:markowitz} |
|
||||
| **SR** | Sharpe Ratio | Überrendite je Einheit Volatilität | {ref:kap:markowitz} |
|
||||
| **SR** | Sharpe Ratio{idx:Sharpe-Ratio} | Überrendite je Einheit Volatilität | {ref:kap:markowitz} |
|
||||
| **VaR** | Value at Risk | Verlustschwelle bei gegebener Wahrscheinlichkeit | {ref:kap:cvar} |
|
||||
| **CVaR** | Conditional Value at Risk | mittlerer Verlust jenseits des VaR | {ref:kap:cvar} |
|
||||
| **ES** | Expected Shortfall | anderes Wort für CVaR | {ref:kap:cvar} |
|
||||
| **ES** | Expected Shortfall{idx:Expected Shortfall} | anderes Wort für CVaR | {ref:kap:cvar} |
|
||||
| **CAGR** | Compound Annual Growth Rate | durchschnittliche jährliche Wachstumsrate | {ref:kap:handelsmaschine} |
|
||||
| **MDD** | Maximum Drawdown | größter Rückgang vom Höchststand | {ref:kap:handelsmaschine} |
|
||||
| **MDD** | Maximum Drawdown{idx:Maximum Drawdown} | größter Rückgang vom Höchststand | {ref:kap:handelsmaschine} |
|
||||
| **LW** | Ledoit–Wolf (Shrinkage) | Schrumpfungsverfahren für Kovarianzmatrizen | {ref:kap:finanzdaten} |
|
||||
| **p. a.** | *per annum* | pro Jahr | {ref:teil:anwendungen} |
|
||||
| **bp** | Basispunkt | 0,01 Prozentpunkt; 15 bp = 0,15 % | {ref:kap:cvar}, {ref:kap:handelsmaschine} |
|
||||
|
|
@ -191,19 +191,19 @@ Diese Zeichen kommen erst in den Kapiteln vor, die über das klassische LP hinau
|
|||
|
||||
| Kürzel | Ausgeschrieben | Was es ist | Lizenz |
|
||||
| --- | --- | --- | --- |
|
||||
| **HiGHS** | **Hi**gh Performance **G**eneral-purpose **S**olver | LP-, MILP- und QP-Solver in C++ | Open Source (MIT) |
|
||||
| **HiGHS**{idx:HiGHS} | **Hi**gh Performance **G**eneral-purpose **S**olver | LP-, MILP- und QP-Solver in C++ | Open Source (MIT) |
|
||||
| **OR-Tools** | Google Operations Research Tools | Solver-Sammlung (CP-SAT, Routing, Wrapper) | Open Source (Apache 2.0) |
|
||||
| **CVXPY** | **C**on**v**e**x** **Py**thon | Modellierungssprache für konvexe Optimierung | Open Source (Apache 2.0) |
|
||||
| **CVXPY**{idx:CVXPY} | **C**on**v**e**x** **Py**thon | Modellierungssprache für konvexe Optimierung | Open Source (Apache 2.0) |
|
||||
| **SciPy** | **Sci**entific **Py**thon | Wissenschaftliches Python-Paket; `scipy.optimize` liefert LP- (über HiGHS), Zuordnungs- (`linear_sum_assignment`) und NLP-Solver (`minimize`) | Open Source (BSD) |
|
||||
| **GLOP** | **G**oogle **L**inear **Op**timizer | LP-Solver in OR-Tools | Open Source |
|
||||
| **SCIP** | Solving Constraint Integer Programs | MILP/MINLP-Solver | akademisch frei |
|
||||
| **SCIP**{idx:SCIP} | Solving Constraint Integer Programs | MILP/MINLP-Solver | akademisch frei |
|
||||
| **CBC** | **C**oin-or **B**ranch and **C**ut | MILP-Solver des COIN-OR-Projekts | Open Source |
|
||||
| **GLPK** | GNU Linear Programming Kit | LP/MILP-Solver | Open Source (GPL) |
|
||||
| **OSQP** | **O**perator **S**plitting **Q**uadratic **P**rogram | QP-Solver | Open Source |
|
||||
| **ECOS** | Embedded Conic Solver | konischer Solver | Open Source |
|
||||
| **SCS** | Splitting Conic Solver | konischer Solver | Open Source |
|
||||
| **IPOPT** | **I**nterior **Po**int **Opt**imizer | NLP-Solver | Open Source (EPL) |
|
||||
| **Gurobi**, **CPLEX**, **Xpress** | — | kommerzielle Hochleistungs-Solver | kostenpflichtig |
|
||||
| **Gurobi**{idx:Gurobi}, **CPLEX**, **Xpress** | — | kommerzielle Hochleistungs-Solver | kostenpflichtig |
|
||||
| **API** | Application Programming Interface | Programmierschnittstelle | — |
|
||||
| **DSL** | Domain-Specific Language | fachspezifische Sprache (hier: Modellierungssprache) | — |
|
||||
| **CSR** | Compressed Sparse Row | Speicherformat für dünnbesetzte Matrizen | — |
|
||||
|
|
@ -220,12 +220,12 @@ Diese Zeichen kommen erst in den Kapiteln vor, die über das klassische LP hinau
|
|||
| **FEASIBLE** | Zulässige Lösung gefunden, Optimalität nicht bewiesen | Zeitlimit erhöhen oder Gap akzeptieren |
|
||||
| **INFEASIBLE** | Keine Lösung erfüllt alle Bedingungen | {ref:anhang:fehlerdiagnose}: Diagnose durchführen |
|
||||
| **UNBOUNDED** | Zielfunktion unbeschränkt verbesserbar | Fehlende Nebenbedingung — Modell prüfen |
|
||||
| **MIP-Gap** | Relativer Abstand beste Lösung ↔ beste Schranke | 1–2 % sind in der Praxis meist genug |
|
||||
| **Incumbent** | Beste bisher gefundene zulässige Lösung | Referenz für das Pruning |
|
||||
| **Relaxation** | Modell mit weggelassener Ganzzahligkeit | liefert die Schranke |
|
||||
| **MIP-Gap**{idx:MIP-Gap} | Relativer Abstand beste Lösung ↔ beste Schranke | 1–2 % sind in der Praxis meist genug |
|
||||
| **Incumbent**{idx:Branch-and-Bound!Incumbent} | Beste bisher gefundene zulässige Lösung | Referenz für das Pruning |
|
||||
| **Relaxation**{idx:Relaxation} | Modell mit weggelassener Ganzzahligkeit | liefert die Schranke |
|
||||
| **Warm Start** | Solver startet von bekannter Lösung | beschleunigt wiederholte Läufe |
|
||||
| **Slack** | Schlupf, ungenutzte Kapazität | Slack = 0 → Engpass |
|
||||
| **Lookahead-Bias** | Nutzung von Daten aus der Zukunft | Backtest ist wertlos — {ref:kap:praxisfallen} |
|
||||
| **Lookahead-Bias**{idx:Lookahead-Bias} | Nutzung von Daten aus der Zukunft | Backtest ist wertlos — {ref:kap:praxisfallen} |
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
>
|
||||
> **Voraussetzungen:** Keine. Dies ist der Einstieg.
|
||||
>
|
||||
> **Danach können Sie:** Ein Alltagsproblem in Entscheidungsvariablen, Parameter, Zielfunktion und Nebenbedingungen zerlegen, ein erstes Modell mit Google OR-Tools lösen — und die Daten dafür aus einer Excel-Mappe holen und das Ergebnis dorthin zurückschreiben.
|
||||
> **Danach können Sie:** Ein Alltagsproblem in Entscheidungsvariablen, Parameter{idx:Parameter (Modell)}, Zielfunktion{idx:Zielfunktion} und Nebenbedingungen zerlegen, ein erstes Modell mit Google OR-Tools{idx:OR-Tools} lösen — und die Daten dafür aus einer Excel-Mappe holen und das Ergebnis dorthin zurückschreiben.
|
||||
>
|
||||
> **Zeitbedarf:** ca. 3,5 Stunden inklusive Übungen.
|
||||
>
|
||||
|
|
@ -67,7 +67,7 @@ Block, führen Sie ihn aus, sehen Sie das Ergebnis — die Erklärung kommt dana
|
|||
geantwortet? Die naheliegende Antwort lautet „möglichst viele Tische“ — der Tisch bringt
|
||||
mit 240 € schließlich den vierfachen Deckungsbeitrag eines Stuhls. Rechnen wir das durch:
|
||||
|
||||
| Strategie | Menge | Deckungsbeitrag |
|
||||
| Strategie | Menge{idx:Konvexität!Menge} | Deckungsbeitrag |
|
||||
| --- | --- | ---: |
|
||||
| Nur Tische (Bauchgefühl) | 40 Tische (das Plattenmaterial ist zuerst leer) | 9 600 € |
|
||||
| Nur Stühle | 150 Stühle (die Montagezeit ist zuerst leer) | 9 000 € |
|
||||
|
|
@ -200,7 +200,7 @@ Und die Rechnung ist noch geschönt: Ein schnellerer Rechner hilft praktisch nic
|
|||
eine Beschleunigung um den Faktor **eine Million** verschiebt die Grenze von $n=20$ nur auf
|
||||
etwa $n=24$. Gegen kombinatorisches Wachstum ist Hardware machtlos.
|
||||
|
||||
Das folgende Programm macht diesen Effekt erfahrbar. Es löst dasselbe Zuordnungsproblem
|
||||
Das folgende Programm macht diesen Effekt erfahrbar. Es löst dasselbe Zuordnungsproblem{idx:Zuordnungsproblem (1:1)}
|
||||
zweimal — einmal durch vollständiges Durchprobieren, einmal mit einem OR-Solver — und
|
||||
vergleicht die Laufzeiten.
|
||||
|
||||
|
|
@ -343,7 +343,7 @@ zusätzlichen Element, die Solver-Zeit wächst kaum merklich.
|
|||
> | ----------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------ |
|
||||
> | `itertools.permutations(range(n))` | erzeugt nacheinander alle $n!$ Reihenfolgen | die Definition von „alles durchprobieren“ |
|
||||
> | `wert = sum(kosten[i][zuordnung[i]] ...)` | bewertet eine einzelne Kombination | das ist die **Zielfunktion**, nur eben von Hand ausgewertet |
|
||||
> | `modell.NewBoolVar(...)` | legt eine Ja/Nein-**Entscheidungsvariable** an | $n^2$ Variablen statt $n!$ Kombinationen |
|
||||
> | `modell.NewBoolVar(...)` | legt eine Ja/Nein-**Entscheidungsvariable**{idx:Entscheidungsvariable} an | $n^2$ Variablen statt $n!$ Kombinationen |
|
||||
> | `modell.AddExactlyOne(...)` | „genau eine davon ist wahr“ | die **Nebenbedingungen** |
|
||||
> | `modell.Minimize(...)` | die zu minimierende Summe | die **Zielfunktion**, jetzt deklariert statt ausgerechnet |
|
||||
> | `loeser.Solve(modell)` | der Solver sucht — aber nicht stur | er nutzt Struktur (Schranken, Propagation), statt abzuzählen |
|
||||
|
|
@ -419,7 +419,7 @@ Lagerkapazitäten, Steuerquoten, Entfernungen, Qualifikationen.
|
|||
|
||||
> **Die Leitfrage:** *Was ist gegeben und wird nicht entschieden?* Parameter sind der Ort,
|
||||
> an dem Datenqualität über Modellqualität entscheidet. {ref:kap:finanzdaten} zeigt am Beispiel der
|
||||
> Kovarianzmatrix, wie ein schlecht geschätzter Parameter ein mathematisch perfektes Modell
|
||||
> Kovarianzmatrix{idx:Kovarianzmatrix}, wie ein schlecht geschätzter Parameter ein mathematisch perfektes Modell
|
||||
> wertlos macht.
|
||||
|
||||
### Baustein 3 — Zielfunktion ($f(x)$)
|
||||
|
|
@ -862,8 +862,8 @@ Solver-Ergebnisse wo immer möglich gegen eine unabhängige Rechnung**, gerade a
|
|||
> | ---------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
> | Konstanten oben | alle Parameter an einer Stelle | Nie Zahlen im Modellcode verstreuen — sonst findet man sie beim Ändern nicht wieder |
|
||||
> | `NewIntVar(0, 100, ...)` | ganzzahlige Variable mit weiten Grenzen | Grenzen müssen endlich sein; 100 ist bewusst unkritisch groß |
|
||||
> | `modell.Add(x_a <= MAX_ARBITRAGE)` | Marktlimit als **Nebenbedingung** | Alternativ liesse sich dieses Limit auch in die Variablengrenze packen. Beides funktioniert — aber als Nebenbedingung bleibt das Modell zur mathematischen Formulierung deckungsgleich und man kann später den Schattenpreis abfragen |
|
||||
> | `loeser.StatusName(status)` | echter Status statt fester Text | Ein fest codierter Text wie „OPTIMAL“ würde unabhängig vom tatsächlichen Ergebnis ausgegeben — deshalb immer den echten Solver-Status auswerten |
|
||||
> | `modell.Add(x_a <= MAX_ARBITRAGE)` | Marktlimit als **Nebenbedingung** | Alternativ liesse sich dieses Limit auch in die Variablengrenze packen. Beides funktioniert — aber als Nebenbedingung bleibt das Modell zur mathematischen Formulierung deckungsgleich und man kann später den Schattenpreis{idx:Schattenpreis} abfragen |
|
||||
> | `loeser.StatusName(status)` | echter Status statt fester Text | Ein fest codierter Text wie „OPTIMAL“ würde unabhängig vom tatsächlichen Ergebnis ausgegeben — deshalb immer den echten Solver-Status{idx:Solver-Status} auswerten |
|
||||
> | `assert ...` | Selbstkontrolle nach dem Lösen | Kostet nichts und fängt Modellierungsfehler, die der Solver nicht bemerken kann |
|
||||
> | Vergleich mit naiver Strategie | quantifiziert den Nutzen | Die Frage „Was bringt die Optimierung überhaupt?“ kommt in jedem Projekt — beantworten Sie sie ungefragt |
|
||||
|
||||
|
|
@ -913,7 +913,7 @@ schlägt die Brücke — in beide Richtungen.
|
|||
> | „Zielzelle“ + Max/Min | `solver.Maximize(...)` | Statt einer Formel in einer Zelle ein Ausdruck im Code. |
|
||||
> | „Nebenbedingungen“-Liste | `solver.Add(...)` | Eine Zeile je Regel — oder eine Schleife für 10 000 Regeln. |
|
||||
> | „Ganzzahlig“ / „Binär“ | `NewIntVar(...)` / `NewBoolVar(...)` | Gleiche Bedeutung, gleiche Konsequenz für die Laufzeit. |
|
||||
> | Simplex-LP / GRG / Evolutionär | GLOP / SLSQP / CP-SAT | In Excel drei Auswahlpunkte, in Python drei Bibliotheken ({ref:kap:oekosystem}). |
|
||||
> | Simplex-LP / GRG / Evolutionär | GLOP / SLSQP{idx:SLSQP} / CP-SAT{idx:CP-SAT} | In Excel drei Auswahlpunkte, in Python drei Bibliotheken ({ref:kap:oekosystem}). |
|
||||
> | „Sensitivitätsbericht“ | `bedingung.dual_value()` | Der Schattenpreis — {ref:kap:lp} erklärt, was er bedeutet. |
|
||||
> | 200 Zeilen sind das Limit | keine praktische Grenze | Der Excel-Solver ist auf 200 veränderbare Zellen begrenzt. |
|
||||
|
||||
|
|
@ -1103,8 +1103,8 @@ zu und begründen Sie in einem Satz:
|
|||
(d) „Welche Kunden werden voraussichtlich kündigen?“
|
||||
(e) „Welchen dieser Kunden sollen wir mit unserem begrenzten Rabattbudget halten?“
|
||||
|
||||
**Aufgabe ⭐ — Hart oder weich?**
|
||||
Entscheiden Sie für jede Bedingung eines Klinik-Dienstplans, ob sie hart oder weich
|
||||
**Aufgabe ⭐ — Hart oder weich{idx:Nebenbedingung!weich}?**
|
||||
Entscheiden Sie für jede Bedingung eines Klinik-Dienstplans, ob sie hart{idx:Nebenbedingung!hart} oder weich
|
||||
modelliert werden sollte, und begründen Sie:
|
||||
(a) Gesetzliche Ruhezeit von 11 Stunden zwischen zwei Diensten.
|
||||
(b) Frau Meier möchte freitags nicht arbeiten.
|
||||
|
|
@ -1269,7 +1269,7 @@ eine Zahl liefern, die betriebswirtschaftlich Unsinn ist. Genau solche Fälle ü
|
|||
**Ausblick.** {ref:kap:fundament} liefert die Sprache, um Modelle mit hunderten Variablen kompakt
|
||||
aufzuschreiben: Vektoren, Matrizen und die geometrische Sicht auf den zulässigen Bereich.
|
||||
Dort lernen wir auch die Eigenschaft kennen, die darüber entscheidet, ob ein Problem
|
||||
verlässlich lösbar ist: **Konvexität**.
|
||||
verlässlich lösbar ist: **Konvexität**{idx:Konvexität}.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Kapitel: Das mathematische Fundament — Vektoren, Matrizen, Konvexität {#kap:fundament}
|
||||
# Kapitel: Das mathematische Fundament — Vektoren, Matrizen, Konvexität{idx:Konvexität} {#kap:fundament}
|
||||
|
||||
> **📌 Kapitel auf einen Blick**
|
||||
>
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
>
|
||||
> **Voraussetzungen:** {ref:kap:einfuehrung}. Lineare Algebra wird hier von Grund auf wiederholt.
|
||||
>
|
||||
> **Danach können Sie:** Ein Modell in Matrixform aufschreiben, den zulässigen Bereich
|
||||
> **Danach können Sie:** Ein Modell in Matrixform{idx:Matrixform} aufschreiben, den zulässigen Bereich
|
||||
> geometrisch deuten, beurteilen ob ein Problem konvex ist — und einschätzen, wie viele
|
||||
> Stellen Ihres Ergebnisses überhaupt belastbar sind.
|
||||
>
|
||||
|
|
@ -66,13 +66,13 @@ die zentrale Einsicht in Aktion — ganz ohne Solver, mit acht Zeilen NumPy.
|
|||
|
||||
**Das Optimum lautet $(0, 8)$ mit $Z = 40$** — und Sie haben es gefunden, ohne einen
|
||||
einzigen Solver zu starten. Vier Kandidaten statt unendlich vieler Punkte: Das ist der
|
||||
**Fundamentalsatz der linearen Optimierung**, und er ist der Grund, warum sich lineare
|
||||
**Fundamentalsatz der linearen Optimierung**{idx:Fundamentalsatz der linearen Optimierung}, und er ist der Grund, warum sich lineare
|
||||
Programme überhaupt zuverlässig lösen lassen.
|
||||
|
||||
**Warum funktioniert das?** Weil der zulässige Bereich ein **konvexes Polyeder** ist — ein
|
||||
Vielflächner ohne Diagonalen nach innen — und weil eine lineare Zielfunktion darauf ihren
|
||||
**Warum funktioniert das?** Weil der zulässige Bereich ein **konvexes Polyeder**{idx:Polyeder} ist — ein
|
||||
Vielflächner ohne Diagonalen nach innen — und weil eine lineare Zielfunktion{idx:Zielfunktion} darauf ihren
|
||||
größten Wert immer am Rand annimmt, genauer: in einer Ecke. Beides begründet dieses
|
||||
Kapitel. Der Simplex-Algorithmus in {ref:kap:lp} tut im Kern nichts anderes als das Programm
|
||||
Kapitel. Der Simplex-Algorithmus{idx:Simplex-Algorithmus} in {ref:kap:lp} tut im Kern nichts anderes als das Programm
|
||||
oben, nur klüger: Er probiert nicht alle Ecken durch, sondern läuft gezielt von Ecke zu
|
||||
Ecke bergauf.
|
||||
|
||||
|
|
@ -92,12 +92,12 @@ Nach diesem Kapitel können Sie …
|
|||
2. … erklären, warum der zulässige Bereich eines linearen Programms ein **Polyeder** ist.
|
||||
3. … den Fundamentalsatz der linearen Optimierung anwenden, um Kandidaten für das Optimum
|
||||
zu finden, ohne alles durchzuprobieren.
|
||||
4. … prüfen, ob eine Menge bzw. eine Funktion konvex ist, und begründen, warum das für die
|
||||
4. … prüfen, ob eine Menge{idx:Konvexität!Menge} bzw. eine Funktion{idx:Konvexität!Funktion} konvex ist, und begründen, warum das für die
|
||||
Lösbarkeit entscheidend ist.
|
||||
5. … einen zweidimensionalen Lösungsraum mit `matplotlib` zeichnen und daraus die optimale
|
||||
Ecke ablesen.
|
||||
6. … die **Konditionszahl** $\kappa(\mathbf{A})$ berechnen, ihren Wert deuten und ein
|
||||
schlecht skaliertes Modell mit Ruiz-Equilibrierung wieder rechenbar machen.
|
||||
6. … die **Konditionszahl**{idx:Konditionszahl} $\kappa(\mathbf{A})$ berechnen, ihren Wert deuten und ein
|
||||
schlecht skaliertes Modell mit Ruiz-Equilibrierung{idx:Ruiz-Equilibrierung} wieder rechenbar machen.
|
||||
7. … erklären, warum ein Solver-Ergebnis von `0.99999998` niemals mit `int()` in eine ganze
|
||||
Zahl verwandelt werden darf.
|
||||
|
||||
|
|
@ -129,7 +129,7 @@ $$
|
|||
\mathbf{c} = \begin{pmatrix} c_1 \\ c_2 \\ \vdots \\ c_n \end{pmatrix} \in \mathbb{R}^n
|
||||
$$
|
||||
|
||||
**Zielfunktion als Skalarprodukt:**
|
||||
**Zielfunktion als Skalarprodukt{idx:Skalarprodukt}:**
|
||||
|
||||
$$
|
||||
f(\mathbf{x}) = \mathbf{c}^\top \mathbf{x} = \sum_{j=1}^n c_j x_j
|
||||
|
|
@ -355,7 +355,7 @@ erzeugt von `bilder_04/erzeuge_polyeder.py`.](bilder_04/kap_fundament_polyeder.s
|
|||
### Der Fundamentalsatz der linearen Optimierung
|
||||
|
||||
> **Satz.** Besitzt ein lineares Optimierungsproblem eine optimale Lösung, dann liegt
|
||||
> mindestens ein optimaler Punkt auf einer **Ecke (Extrempunkt)** des Polyeders
|
||||
> mindestens ein optimaler Punkt auf einer **Ecke (Extrempunkt)**{idx:Ecke (Extrempunkt)} des Polyeders
|
||||
> $\mathcal{F}$.
|
||||
|
||||
**Warum das gilt — die Anschauung:** Die Zielfunktion $\mathbf{c}^\top\mathbf{x}$ hat
|
||||
|
|
@ -475,8 +475,8 @@ etwas falsch gemacht: Beide enden dort, wo es nicht mehr bergab geht.
|
|||
| --- | --- | --- |
|
||||
| Lineares Programm (LP) | **ja** | Globales Optimum, Sekunden bis Minuten selbst bei $10^6$ Variablen |
|
||||
| Quadratisches Programm mit $\mathbf{P} \succeq 0$ | **ja** | Globales Optimum, effizient ({ref:kap:qp-nlp}, {ref:kap:markowitz}) |
|
||||
| Ganzzahlige Variablen (MILP) | **nein** | Der zulässige Bereich ist ein Punktgitter, keine zusammenhängende Menge — NP-schwer ({ref:kap:milp}) |
|
||||
| Quadratisches Programm mit indefinitem $\mathbf{P}$ | **nein** | Nur lokale Optima; eine ungültige Kovarianzmatrix ist ein typischer Auslöser (siehe {ref:sec:qp-nlp-nichtlineare-optimierung-mit-scipy-optimize-minimize}) |
|
||||
| Ganzzahlige Variablen (MILP) | **nein** | Der zulässige Bereich ist ein Punktgitter, keine zusammenhängende Menge — NP-schwer{idx:NP-schwer} ({ref:kap:milp}) |
|
||||
| Quadratisches Programm mit indefinitem $\mathbf{P}$ | **nein** | Nur lokale Optima; eine ungültige Kovarianzmatrix{idx:Kovarianzmatrix} ist ein typischer Auslöser (siehe {ref:sec:qp-nlp-nichtlineare-optimierung-mit-scipy-optimize-minimize}) |
|
||||
| Allgemeines NLP mit beliebigen Funktionen | meist **nein** | `scipy.optimize` liefert nur ein lokales Optimum, abhängig vom Startpunkt |
|
||||
|
||||
### Konvexität sichtbar machen
|
||||
|
|
@ -893,7 +893,7 @@ Einheit messen“. Die Lösung rechnet man mit $\mathbf{x} = \mathbf{D}_c\,\tild
|
|||
zurück.
|
||||
|
||||
> **🎯 Merksatz**
|
||||
> Jeder ernsthafte Solver skaliert intern selbst — HiGHS, Gurobi, CP-SAT alle. Verlassen Sie
|
||||
> Jeder ernsthafte Solver skaliert intern selbst — HiGHS{idx:HiGHS}, Gurobi{idx:Gurobi}, CP-SAT{idx:CP-SAT} alle. Verlassen Sie
|
||||
> sich trotzdem nicht darauf: Die interne Skalierung repariert die Rechnung, nicht die
|
||||
> Modellierung. Wenn Ihre Koeffizienten zwölf Größenordnungen überspannen, sagt Ihnen das
|
||||
> etwas über Ihr Modell, nicht über den Solver.
|
||||
|
|
@ -902,7 +902,7 @@ zurück.
|
|||
|
||||
Das folgende Programm führt beides vor — die Fehlerverstärkung und ihre Behebung — und
|
||||
schließt mit der praktischen Konsequenz, die Sie in {ref:kap:milp} wieder brauchen werden:
|
||||
warum eine Binärvariable mit dem Wert `0.99999998` niemals mit `int()` gerundet werden darf.
|
||||
warum eine Binärvariable{idx:Binärvariable} mit dem Wert `0.99999998` niemals mit `int()` gerundet werden darf.
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@
|
|||
> Weizen 0.750 kg, Soja 0.250 kg -> 0.5350 EUR/kg
|
||||
> ```
|
||||
|
||||
**Sie haben soeben HiGHS benutzt** — denselben C++-Solver, der auch hinter `highspy`, hinter
|
||||
CVXPY und in vielen kommerziellen Systemen steckt. `scipy.optimize.linprog` ist nur die
|
||||
**Sie haben soeben HiGHS{idx:HiGHS} benutzt** — denselben C++-Solver, der auch hinter `highspy`, hinter
|
||||
CVXPY{idx:CVXPY} und in vielen kommerziellen Systemen steckt. `scipy.optimize.linprog` ist nur die
|
||||
dünnste denkbare Hülle darum.
|
||||
|
||||
Das ist die zentrale Botschaft dieses Kapitels: **Modellierungsschicht und Solver sind zwei
|
||||
|
|
@ -68,13 +68,13 @@ lassen sich unabhängig voneinander tauschen — und genau davon handelt der Res
|
|||
|
||||
> **⚠️ Zwei Stolpersteine stecken schon in diesen sechs Zeilen**
|
||||
>
|
||||
> * `linprog` **minimiert immer**. Wer maximieren will, negiert die Zielfunktion — und darf
|
||||
> * `linprog` **minimiert immer**. Wer maximieren will, negiert die Zielfunktion{idx:Zielfunktion} — und darf
|
||||
> nicht vergessen, das Ergebnis zurückzudrehen.
|
||||
> * `linprog` kennt **nur `<=`**. Ein Mindestgehalt „$\ge 20$“ wird zu „$-12x_1 - 44x_2 \le
|
||||
> -20$“. Ein Vorzeichenfehler an dieser Stelle liefert eine perfekt aussehende Lösung, die
|
||||
> das Gegenteil des Gewollten erfüllt.
|
||||
>
|
||||
> Beide Fallen verschwinden, sobald man eine Modellierungsschicht wie CVXPY oder Pyomo
|
||||
> Beide Fallen verschwinden, sobald man eine Modellierungsschicht wie CVXPY oder Pyomo{idx:Pyomo}
|
||||
> benutzt, in der `>=` einfach `>=` heißt. Das ist ein Hauptgrund, warum es sie gibt.
|
||||
|
||||
---
|
||||
|
|
@ -89,8 +89,8 @@ Nach diesem Kapitel können Sie …
|
|||
formulieren.
|
||||
4. … Ergebnisse verschiedener Solver gegeneinander validieren (*Cross-Check*).
|
||||
5. … einschätzen, wann sich der Aufwand einer Low-Level-Schnittstelle lohnt und wann nicht.
|
||||
6. … Pyomo und Linopy einordnen und begründen, wann sich der Umstieg auf sie lohnt.
|
||||
7. … Aufbau- und Lösezeit getrennt messen und einen Modellaufbau mit NumPy oder Polars
|
||||
6. … Pyomo und Linopy{idx:Linopy} einordnen und begründen, wann sich der Umstieg auf sie lohnt.
|
||||
7. … Aufbau- und Lösezeit getrennt messen und einen Modellaufbau mit NumPy oder Polars{idx:Polars}
|
||||
vektorisieren, statt ihn in Python-Schleifen zu erzeugen.
|
||||
|
||||
---
|
||||
|
|
@ -115,7 +115,7 @@ nutzt eine **zweischichtige Architektur**{idx:Zweischichtige Architektur}:
|
|||
> mit fünf verschiedenen Solvern lösen.
|
||||
|
||||
**Warum diese Trennung nützlich ist:** Ein CVXPY{idx:CVXPY}-Modell, das heute mit dem freien Solver
|
||||
Clarabel läuft, läuft morgen ohne Codeänderung mit dem kommerziellen Gurobi — man tauscht
|
||||
Clarabel läuft, läuft morgen ohne Codeänderung mit dem kommerziellen Gurobi{idx:Gurobi} — man tauscht
|
||||
ein Argument. Das schützt vor Herstellerbindung und erlaubt, im Projekt klein anzufangen.
|
||||
|
||||
---
|
||||
|
|
@ -125,10 +125,10 @@ ein Argument. Das schützt vor Herstellerbindung und erlaubt, im Projekt klein a
|
|||
| Bibliothek | Stärken & Problemklassen | Wann einsetzen? | Typische Backends |
|
||||
| --- | --- | --- | --- |
|
||||
| `scipy.optimize` | Standard-LPs, kontinuierliche nichtlineare Optimierung, Wurzelsuche | Für elementare LPs und schnelle Prototypen ohne zusätzliche schwere Abhängigkeiten | HiGHS (`highs-ds`, `highs-ipm`) |
|
||||
| `ortools` (Google) | Diskrete Planung, Schichten, Vertretungspläne, Routing (VRP/TSP), kombinatorische Logik | Wenn diskrete Ja/Nein-Entscheidungen, Zeitfenster und Wenn-Dann-Regeln dominieren | CP-SAT, GLOP, Routing Engine |
|
||||
| `cvxpy` | Konvexe Optimierung, quadratische Programme, Risikomodelle, Portfolios | **Erste Wahl für Finanzoptimierung**, Markowitz, CVaR, $L_1$-Transaktionskosten | Clarabel, OSQP, ECOS, SCS, HiGHS |
|
||||
| `ortools` (Google) | Diskrete Planung, Schichten, Vertretungspläne, Routing (VRP/TSP), kombinatorische Logik | Wenn diskrete Ja/Nein-Entscheidungen, Zeitfenster und Wenn-Dann-Regeln dominieren | CP-SAT{idx:CP-SAT}, GLOP, Routing Engine |
|
||||
| `cvxpy` | Konvexe Optimierung, quadratische Programme, Risikomodelle, Portfolios | **Erste Wahl für Finanzoptimierung**, Markowitz, CVaR, $L_1$-Transaktionskosten{idx:Transaktionskosten} | Clarabel, OSQP, ECOS, SCS, HiGHS |
|
||||
| `highspy` | Direkte Solver-Steuerung für LP/MILP, maximale Kontrolle | Wenn Sie Modelle wiederholt und schnell aufbauen oder Solver-Details steuern müssen | HiGHS |
|
||||
| `Pyomo` | Universelle Modellierungssprache (LP, MILP, MINLP) | Industrielle Großmodelle mit strikter Trennung von Daten und Modell | HiGHS, Gurobi, CPLEX, SCIP, IPOPT |
|
||||
| `Pyomo` | Universelle Modellierungssprache (LP, MILP, MINLP{idx:MINLP}) | Industrielle Großmodelle mit strikter Trennung von Daten und Modell | HiGHS, Gurobi, CPLEX, SCIP{idx:SCIP}, IPOPT |
|
||||
| `Linopy` | LP/MILP über beschriftete Arrays (`xarray`) | Modelle mit zehntausenden gleichartigen Nebenbedingungen (Energie, Netze, Zeitreihen) | HiGHS, GLPK, CBC, Gurobi |
|
||||
|
||||
### Die Entscheidung in drei Fragen
|
||||
|
|
@ -136,7 +136,7 @@ ein Argument. Das schützt vor Herstellerbindung und erlaubt, im Projekt klein a
|
|||
Statt die Tabelle auswendig zu lernen, beantworten Sie drei Fragen:
|
||||
|
||||
> **Frage 1: Gibt es Ja/Nein-Entscheidungen oder Reihenfolgen?**
|
||||
> → **Ja:** OR-Tools (CP-SAT) bei Zuweisung/Scheduling, oder MILP über HiGHS bei
|
||||
> → **Ja:** OR-Tools{idx:OR-Tools} (CP-SAT) bei Zuweisung/Scheduling, oder MILP über HiGHS bei
|
||||
> ökonomischen Fixkostenmodellen.
|
||||
> → **Nein:** weiter zu Frage 2.
|
||||
>
|
||||
|
|
@ -315,7 +315,7 @@ Zeichenkette an `python -c` übergeben — funktioniert und ist trotzdem die sch
|
|||
Der Schnipsel ist für Editor, Linter und Testwerkzeug unsichtbar, ein Tippfehler darin
|
||||
fällt erst zur Laufzeit auf, und übergeben lassen sich nur Zeichenketten.
|
||||
|
||||
Tragfähig ist stattdessen: **jeder Solver eine gewöhnliche Funktion mit lokalem Import**,
|
||||
Tragfähig ist stattdessen: **jeder Solver eine gewöhnliche Funktion{idx:Konvexität!Funktion} mit lokalem Import**,
|
||||
ausgeführt von einem `ProcessPoolExecutor` mit zwei Einstellungen, die zusammen die
|
||||
Garantie ergeben:
|
||||
|
||||
|
|
@ -517,8 +517,8 @@ Alle Wege fuehren zum selben, von Hand bestaetigten Optimum.
|
|||
>
|
||||
> | Ansatz | Zeilen für das Modell | Charakter |
|
||||
> | --- | --- | --- |
|
||||
> | `linprog` | 3 | Matrizen direkt übergeben. Kürzeste Variante, aber man muss selbst negieren und die Matrixform von Hand herstellen. |
|
||||
> | `highspy` | ~15 | Alles explizit, inklusive CSR-Format der dünnbesetzten Matrix. Aufwendig — dafür volle Kontrolle und kein Overhead beim wiederholten Lösen. |
|
||||
> | `linprog` | 3 | Matrizen direkt übergeben. Kürzeste Variante, aber man muss selbst negieren und die Matrixform{idx:Matrixform} von Hand herstellen. |
|
||||
> | `highspy` | ~15 | Alles explizit, inklusive CSR-Format{idx:CSR-Format} der dünnbesetzten Matrix. Aufwendig — dafür volle Kontrolle und kein Overhead beim wiederholten Lösen. |
|
||||
> | `cvxpy` | 4 | Liest sich wie die mathematische Formulierung. Prüft zusätzlich automatisch, ob das Problem konvex ist. Höchster Startaufwand pro Lauf (Kompilierung des Ausdrucksbaums). |
|
||||
> | `ortools`/GLOP | ~6 | Bedingungen einzeln mit `Add()` — gut lesbar bei wenigen, mühsam bei vielen Restriktionen. |
|
||||
>
|
||||
|
|
@ -569,7 +569,7 @@ große LPs überhaupt lösbar sind.
|
|||
| --- | --- | --- |
|
||||
| Einmaliges kleines LP, Prototyp | `scipy.optimize.linprog` | Keine zusätzliche Abhängigkeit, 3 Zeilen |
|
||||
| Portfolio, Risiko, alles Konvexe | **CVXPY** | Lesbarkeit + automatische Konvexitätsprüfung |
|
||||
| Dienstpläne, Zuordnung, Reihenfolge | **CP-SAT** | Globale Constraints, Konfliktlernen |
|
||||
| Dienstpläne, Zuordnung, Reihenfolge | **CP-SAT** | Globale Constraints{idx:Globale Constraints}, Konfliktlernen |
|
||||
| Fahrzeugtouren | **OR-Tools Routing** | Fertige Metaheuristiken, jahrzehntelang optimiert |
|
||||
| MILP mit Fixkosten, Kardinalität | `highspy` oder CP-SAT | Branch-and-Cut auf ökonomischer Struktur |
|
||||
| 50 000+ Variablen, wiederholte Läufe | `highspy` oder Pyomo | Modellaufbau wird sonst zum Engpass |
|
||||
|
|
@ -601,7 +601,7 @@ modell.kapazitaet = pyo.Constraint(modell.R, rule=kapazitaet)
|
|||
```
|
||||
|
||||
Das ist das $\forall i \in I$ aus {ref:kap:einfuehrung}, unmittelbar in Code übersetzt: eine
|
||||
Regel, angewandt auf jedes Element einer Menge. Pyomo kann außerdem, was CVXPY und OR-Tools
|
||||
Regel, angewandt auf jedes Element einer Menge{idx:Konvexität!Menge}. Pyomo kann außerdem, was CVXPY und OR-Tools
|
||||
nicht können — **nichtlineare und gemischt-ganzzahlig-nichtlineare** Modelle (MINLP) an
|
||||
Solver wie Ipopt oder BONMIN übergeben (siehe {ref:kap:qp-nlp}).
|
||||
|
||||
|
|
@ -1225,7 +1225,7 @@ passende Empfehlungen.
|
|||
|
||||
> **🐛 Finde den Denkfehler: Der Solver, der angeblich dreimal schneller ist**
|
||||
>
|
||||
> Ein Team vergleicht zwei Bibliotheken für sein Zuordnungsproblem und schreibt ins
|
||||
> Ein Team vergleicht zwei Bibliotheken für sein Zuordnungsproblem{idx:Zuordnungsproblem (1:1)} und schreibt ins
|
||||
> Protokoll: *„CVXPY braucht 1,9 s, SciPy nur 0,6 s — wir setzen auf SciPy.“* Gemessen
|
||||
> wurde so:
|
||||
>
|
||||
|
|
@ -1267,7 +1267,7 @@ passende Empfehlungen.
|
|||
>
|
||||
> **1. Sie sollen 300 Prüfungen auf 40 Räume und 12 Zeitfenster verteilen, mit Regeln wie
|
||||
> „diese beiden Klausuren nicht gleichzeitig“. Welches Werkzeug passt?**
|
||||
> (a) CVXPY — es prüft die Konvexität automatisch.
|
||||
> (a) CVXPY — es prüft die Konvexität{idx:Konvexität} automatisch.
|
||||
> (b) OR-Tools CP-SAT — diskrete Zuweisung mit logischen Regeln ist genau sein Gebiet.
|
||||
> (c) `scipy.optimize.minimize` — es kann beliebige Zielfunktionen.
|
||||
>
|
||||
|
|
@ -1280,7 +1280,7 @@ passende Empfehlungen.
|
|||
>
|
||||
> **3. Was haben `scipy.optimize.linprog`, `highspy`, CVXPY (mit Standardeinstellung) und
|
||||
> Pyomo (mit `appsi_highs`) gemeinsam?**
|
||||
> (a) Sie implementieren jeweils einen eigenen Simplex-Algorithmus in Python.
|
||||
> (a) Sie implementieren jeweils einen eigenen Simplex-Algorithmus{idx:Simplex-Algorithmus} in Python.
|
||||
> (b) Sie sind Modellierungsschichten über demselben C++-Solver HiGHS — die Rechenleistung
|
||||
> ist dieselbe, nur die Schreibweise unterscheidet sich.
|
||||
> (c) Sie können alle sowohl konvexe als auch nicht-konvexe Probleme global lösen.
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ Monatsbericht steht.
|
|||
> Ein Modell rechnet nicht aus, was man will, sondern was man aufgeschrieben hat. Die
|
||||
> Differenz zwischen beidem ist die eigentliche Arbeit dieses Kapitels.
|
||||
|
||||
**Warum funktioniert das?** Weil eine Zielfunktion eine **vollständige** Aussage darüber ist,
|
||||
**Warum funktioniert das?** Weil eine Zielfunktion{idx:Zielfunktion} eine **vollständige** Aussage darüber ist,
|
||||
was zählt. Alles, was nicht darin steht, ist dem Modell gleichgültig — nicht „weniger
|
||||
wichtig", sondern **wertlos**. Der Umsatzplan opfert den Deckungsbeitrag nicht aus Bosheit;
|
||||
er sieht ihn schlicht nicht.
|
||||
|
|
@ -96,7 +96,7 @@ Nach diesem Kapitel können Sie …
|
|||
2. … die vier Fragen stellen, die aus einer Anforderung ein Modell machen.
|
||||
3. … erkennen, dass ein Satz wie „Stammkunden dürfen wir nicht verlieren" mehrere Lesarten
|
||||
hat, und den Unterschied in Euro beziffern.
|
||||
4. … begründen, wann eine Regel hart und wann sie weich sein muss — und was eine harte Regel
|
||||
4. … begründen, wann eine Regel hart{idx:Nebenbedingung!hart} und wann sie weich{idx:Nebenbedingung!weich} sein muss — und was eine harte Regel
|
||||
im Betrieb anrichtet, wenn sie einmal nicht erfüllbar ist.
|
||||
5. … einen Kennzahlen-Fehlanreiz benennen, bevor er in die Zielfunktion gerät.
|
||||
6. … einen Satz aus einer Besprechung in den passenden Modellierungsbaustein
|
||||
|
|
@ -112,7 +112,7 @@ Was aus einer Besprechung mitkommt, klingt meist so:
|
|||
> *„Wir müssen die Maschinen besser auslasten. Und die Stammkunden dürfen wir nicht
|
||||
> verlieren."*
|
||||
|
||||
Zwei Sätze, aus denen ein Modell werden soll. Sie enthalten: keine Entscheidungsvariable,
|
||||
Zwei Sätze, aus denen ein Modell werden soll. Sie enthalten: keine Entscheidungsvariable{idx:Entscheidungsvariable},
|
||||
keine messbare Zielgröße, keine Nebenbedingung. Sie enthalten nicht einmal genug, um zu
|
||||
erkennen, *was* entschieden werden soll.
|
||||
|
||||
|
|
@ -142,7 +142,7 @@ sie übersprungen.
|
|||
Das Programm dieses Kapitels arbeitet die vier Fragen an einer Auftragsannahme ab: 14
|
||||
Anfragen verlangen 800 Maschinenstunden, verfügbar sind 300.
|
||||
|
||||
Es ist bewusst das **einfachste Modell des ganzen Buchs** — eine Binärvariable je Auftrag,
|
||||
Es ist bewusst das **einfachste Modell des ganzen Buchs** — eine Binärvariable{idx:Binärvariable} je Auftrag,
|
||||
eine Nebenbedingung. Alles, was sich zwischen den fünf Varianten ändert, ist die Frage.
|
||||
|
||||
```python
|
||||
|
|
@ -547,7 +547,7 @@ Wer sie nicht stellt, entscheidet sie trotzdem — nur unbewusst, beim Tippen.
|
|||
|
||||
### Teil 3: Hart oder weich
|
||||
|
||||
Dieselbe Regel als Strafkosten je abgelehntem Stammkundenauftrag:
|
||||
Dieselbe Regel als Strafkosten{idx:Strafkosten} je abgelehntem Stammkundenauftrag:
|
||||
|
||||
| Strafe je Auftrag | Deckungsbeitrag | abgelehnte Stammaufträge |
|
||||
| ---: | ---: | ---: |
|
||||
|
|
@ -639,26 +639,26 @@ es **bedeutet**, und welcher **Baustein** daraus wird. Die B-Nummern verweisen a
|
|||
| Was gesagt wird | Was gemeint ist | Baustein |
|
||||
| --- | --- | --- |
|
||||
| „Wir haben nur 400 Stunden." | eine Obergrenze, die nicht überschritten werden darf | harte Kapazitätsgrenze $\le b$ ({ref:kap:lp}) |
|
||||
| „Mehr als zwei Millionen gibt es nicht." | dasselbe, auf Geld | Budgetlimit (B27) |
|
||||
| „Mehr als zwei Millionen gibt es nicht." | dasselbe, auf Geld | Budgetlimit{idx:Budgetlimit} (B27) |
|
||||
| „Möglichst nicht über 40 Stunden." | eine Grenze, die im Notfall gebrochen werden darf | weiche Grenze mit Strafkosten (B8) |
|
||||
| „Wir können nur ganze Kisten liefern." | die Menge ist nicht teilbar | Ganzzahligkeitsbedingung ({ref:kap:milp}) |
|
||||
| „Wenn wir die Anlage nutzen, fallen Fixkosten an." | Kosten, die erst ab der ersten Einheit anfallen | Aktivierungsschalter (B1) |
|
||||
| „Wir können nur ganze Kisten liefern." | die Menge{idx:Konvexität!Menge} ist nicht teilbar | Ganzzahligkeitsbedingung ({ref:kap:milp}) |
|
||||
| „Wenn wir die Anlage nutzen, fallen Fixkosten an." | Kosten, die erst ab der ersten Einheit anfallen | Aktivierungsschalter{idx:Aktivierungsschalter (Modellierungsmuster)} (B1) |
|
||||
| „Entweder gar nicht oder mindestens 50." | kein Betrieb im Kleinen | semikontinuierliche Variable (B2) |
|
||||
| „Wenn wir A bauen, brauchen wir auch B." | eine Folgeverpflichtung | Implikation (B3) |
|
||||
| „Wenn wir A bauen, brauchen wir auch B." | eine Folgeverpflichtung | Implikation{idx:Implikation (Modellierungsmuster)} (B3) |
|
||||
| „Höchstens drei Positionen im Depot." | eine Obergrenze auf die **Anzahl**, nicht die Menge | Kardinalität (B6) |
|
||||
| „Der Anteil muss mindestens 30 % betragen." | eine Bedingung auf ein **Verhältnis** | Verhältnis-Bedingung (B12) |
|
||||
| „Der Anteil muss mindestens 30 % betragen." | eine Bedingung auf ein **Verhältnis** | Verhältnis-Bedingung{idx:Verhältnis-Bedingung} (B12) |
|
||||
| „Jeder Auftrag genau einem Mitarbeiter." | eine vollständige, eindeutige Zuordnung | Zuordnung 1:1 (B23) |
|
||||
| „Eine Maschine kann nur eines gleichzeitig." | zeitliche Ausschließlichkeit | Nichtüberlappung (B14) |
|
||||
| „B kann erst nach A." | eine Reihenfolge | Vorrangbeziehung (B13) |
|
||||
| „Eine Maschine kann nur eines gleichzeitig." | zeitliche Ausschließlichkeit | Nichtüberlappung{idx:Nichtüberlappung} (B14) |
|
||||
| „B kann erst nach A." | eine Reihenfolge | Vorrangbeziehung{idx:Vorrangbeziehung} (B13) |
|
||||
| „Höchstens fünf Tage am Stück." | eine Bedingung über ein **gleitendes Fenster** | gleitendes Fenster (B16) |
|
||||
| „Umstellen kostet uns eine halbe Stunde." | reihenfolgeabhängige Kosten | Umrüstkosten (B17), Rüstzeit als Kapazität (B26) |
|
||||
| „Was reinkommt, muss auch wieder raus." | Erhaltung an jedem Knoten | Flusserhaltung (B22) |
|
||||
| „Umstellen kostet uns eine halbe Stunde." | reihenfolgeabhängige Kosten | Umrüstkosten{idx:Umrüstkosten (Modellierungsmuster)} (B17), Rüstzeit{idx:Rüstzeit} als Kapazität (B26) |
|
||||
| „Was reinkommt, muss auch wieder raus." | Erhaltung an jedem Knoten | Flusserhaltung{idx:Flusserhaltung} (B22) |
|
||||
| „Notfalls brechen wir die Regel." | die Bedingung ist weich, aber teuer | Schlupfvariablen (B18) |
|
||||
| „Erst Termintreue, dann Kosten." | eine Rangfolge zwischen Zielen | hierarchische Ziele (B19) |
|
||||
| „Es soll gerecht zugehen." | den Schlechtestgestellten verbessern | Min/Max in der Zielfunktion (B11) |
|
||||
| „Was brächte uns eine zusätzliche Stunde?" | die Frage nach dem Grenzwert einer Ressource | Schattenpreis ({ref:kap:lp}, {ref:sec:praxisfallen-attribution}) |
|
||||
| „Mit 95 % Sicherheit muss es halten." | eine Zusage auf eine **Quote**, nicht auf einen Mittelwert | Chance Constraint ({ref:sec:unsicherheit-chance-constraints}) |
|
||||
| „Wir sichern uns gegen Schätzfehler ab." | gegen die ungünstigste Parameterlage planen | Worst-Case-Abzug (B21) |
|
||||
| „Was brächte uns eine zusätzliche Stunde?" | die Frage nach dem Grenzwert einer Ressource | Schattenpreis{idx:Schattenpreis} ({ref:kap:lp}, {ref:sec:praxisfallen-attribution}) |
|
||||
| „Mit 95 % Sicherheit muss es halten." | eine Zusage auf eine **Quote**, nicht auf einen Mittelwert | Chance Constraint{idx:Chance Constraint} ({ref:sec:unsicherheit-chance-constraints}) |
|
||||
| „Wir sichern uns gegen Schätzfehler{idx:Schätzfehler} ab." | gegen die ungünstigste Parameterlage planen | Worst-Case-Abzug{idx:Robuste Optimierung!Worst-Case-Abzug} (B21) |
|
||||
|
||||
### Fünf Wendungen, bei denen die Übersetzung eine Entscheidung erzwingt
|
||||
|
||||
|
|
@ -690,7 +690,7 @@ jemandem erklärt werden muss, der das Modell nicht kennt:
|
|||
| Optimalitätslücke von 2 % | „Besser als das hier geht es höchstens um 2 % — und die liegen unter unserer Datenungenauigkeit." |
|
||||
| CVaR | „Wenn es schiefgeht, verlieren wir im Mittel so viel." (Der VaR sagt nur, **ob** es schiefgeht.) |
|
||||
| EVPI | „Selbst eine perfekte Prognose wäre uns höchstens so viel wert." |
|
||||
| Relaxation | „Wir haben die Regel probeweise gelockert, um zu sehen, was sie kostet." |
|
||||
| Relaxation{idx:Relaxation} | „Wir haben die Regel probeweise gelockert, um zu sehen, was sie kostet." |
|
||||
| Chance Constraint | „Der Plan hält in 95 von 100 Fällen — und der nächste Prozentpunkt kostet …" |
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ Programmieren zu tun hat.
|
|||
|
||||
| Frage | Kapitel | Was Sie danach können |
|
||||
| --- | --- | --- |
|
||||
| Was ist überhaupt ein Optimierungsmodell? | {ref:kap:einfuehrung} | Die vier Bausteine benennen — Variablen, Zielfunktion, Nebenbedingungen, Daten — und sie in einem fremden Problem wiedererkennen |
|
||||
| Warum rechnet der Solver falsch, obwohl das Modell stimmt? | {ref:kap:fundament} | Konvexität beurteilen, den zulässigen Bereich als Polyeder sehen, schlechte Konditionierung erkennen und beheben |
|
||||
| Welche Bibliothek, und warum vertragen sie sich nicht? | {ref:kap:oekosystem} | Solver, Bindings und Modellierungsschichten unterscheiden — und den HiGHS-Symbolkonflikt zwischen `ortools` und `highspy` umgehen |
|
||||
| Was ist überhaupt ein Optimierungsmodell? | {ref:kap:einfuehrung} | Die vier Bausteine benennen — Variablen, Zielfunktion{idx:Zielfunktion}, Nebenbedingungen, Daten — und sie in einem fremden Problem wiedererkennen |
|
||||
| Warum rechnet der Solver falsch, obwohl das Modell stimmt? | {ref:kap:fundament} | Konvexität{idx:Konvexität} beurteilen, den zulässigen Bereich als Polyeder{idx:Polyeder} sehen, schlechte Konditionierung erkennen und beheben |
|
||||
| Welche Bibliothek, und warum vertragen sie sich nicht? | {ref:kap:oekosystem} | Solver, Bindings und Modellierungsschichten unterscheiden — und den HiGHS{idx:HiGHS}-Symbolkonflikt zwischen `ortools` und `highspy` umgehen |
|
||||
| Wie wird aus einem Satz ein Modell? | {ref:kap:modellierung} | Die vier Fragen stellen, harte von weichen Regeln trennen, einen Besprechungssatz übersetzen ({ref:sec:modellierung-glossar}) |
|
||||
|
||||
## Die Reihenfolge ist die Aussage
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ Fragen:
|
|||
|
||||
> **🎯 Merksatz zum Diagramm**
|
||||
> Die erste Frage ist die wichtigste — und sie lautet **nicht** „welcher Solver ist der
|
||||
> schnellste?“, sondern „welche **Struktur** hat mein Problem?“. Ein Zuordnungsproblem
|
||||
> schnellste?“, sondern „welche **Struktur** hat mein Problem?“. Ein Zuordnungsproblem{idx:Zuordnungsproblem (1:1)}
|
||||
> braucht keinen MILP-Solver, sondern eine Zeile `linear_sum_assignment`. Ein Dienstplan
|
||||
> gehört nicht in ein LP, sondern zu CP-SAT. Wer die Struktur erkennt, hat die halbe
|
||||
> gehört nicht in ein LP, sondern zu CP-SAT{idx:CP-SAT}. Wer die Struktur erkennt, hat die halbe
|
||||
> Laufzeit gespart, bevor die erste Zeile Code geschrieben ist.
|
||||
|
||||
Fällt Ihr Problem durch das Diagramm hindurch — nichtlineare Zielfunktion, unsichere Daten,
|
||||
Fällt Ihr Problem durch das Diagramm hindurch — nichtlineare Zielfunktion{idx:Zielfunktion}, unsichere Daten,
|
||||
Entscheidungen über mehrere Zeitstufen —, dann ist {ref:teil:nichtlinear} der richtige
|
||||
Ort. Dort steht ein zweites Diagramm für genau diese Fälle.
|
||||
|
||||
|
|
@ -27,14 +27,14 @@ Ort. Dort steht ein zweites Diagramm für genau diese Fälle.
|
|||
> **📌 Kapitel auf einen Blick**
|
||||
>
|
||||
> **Worum geht es?** Um das Kernverfahren des Operations Research. Wir bauen den
|
||||
> Simplex-Algorithmus selbst — nicht um ihn zu verwenden, sondern um zu verstehen, woher
|
||||
> Simplex-Algorithmus{idx:Simplex-Algorithmus} selbst — nicht um ihn zu verwenden, sondern um zu verstehen, woher
|
||||
> **Schattenpreise** kommen. Sie sind das wertvollste Nebenprodukt jeder Optimierung.
|
||||
>
|
||||
> **Voraussetzungen:** {ref:kap:fundament} (Matrixform, Polyeder, Ecken).
|
||||
> **Voraussetzungen:** {ref:kap:fundament} (Matrixform{idx:Matrixform}, Polyeder, Ecken).
|
||||
>
|
||||
> **Danach können Sie:** Ein LP in Standardform bringen, den Simplex von Hand rechnen,
|
||||
> Dualwerte interpretieren, daraus wirtschaftliche Handlungsempfehlungen ableiten — und
|
||||
> erkennen, wann ein Schattenpreis eine Entscheidung **nicht** tragen darf.
|
||||
> erkennen, wann ein Schattenpreis{idx:Schattenpreis} eine Entscheidung **nicht** tragen darf.
|
||||
>
|
||||
> **Zeitbedarf:** ca. 7 Stunden — das umfangreichste Kapitel von {ref:teil:kernverfahren}.
|
||||
>
|
||||
|
|
@ -124,13 +124,13 @@ Nach diesem Kapitel können Sie …
|
|||
|
||||
1. … Schlupfvariablen einführen und ein Ungleichungssystem in ein Gleichungssystem
|
||||
überführen.
|
||||
2. … eine Simplex-Iteration von Hand rechnen: Pivotspalte, Pivotzeile, Basistausch.
|
||||
2. … eine Simplex-Iteration von Hand rechnen: Pivotspalte{idx:Simplex-Algorithmus!Pivotspalte}, Pivotzeile, Basistausch.
|
||||
3. … erklären, warum das Verfahren terminiert und warum es das Optimum findet.
|
||||
4. … das duale Problem zu einem gegebenen primalen aufstellen.
|
||||
5. … **Schattenpreise**{idx:Schattenpreis} korrekt auslesen und interpretieren — inklusive der Vorzeichenfalle,
|
||||
die einer der häufigsten Fehler bei der Sensitivitätsanalyse ist.
|
||||
5. … **Schattenpreise**{idx:Schattenpreis} korrekt auslesen und interpretieren — inklusive der Vorzeichenfalle{idx:Schattenpreis!Vorzeichenfalle},
|
||||
die einer der häufigsten Fehler bei der Sensitivitätsanalyse{idx:Sensitivitätsanalyse} ist.
|
||||
6. … aus einer Sensitivitätsanalyse eine begründete Kaufentscheidung ableiten.
|
||||
7. … ein Modell auf **Entartung** prüfen und statt eines nicht eindeutigen Schattenpreises
|
||||
7. … ein Modell auf **Entartung**{idx:Entartung} prüfen und statt eines nicht eindeutigen Schattenpreises
|
||||
dessen belastbare Spanne berechnen.
|
||||
8. … erklären, warum Zulässigkeit immer gegen eine Toleranz und nie mit `== 0` geprüft wird.
|
||||
|
||||
|
|
@ -167,7 +167,7 @@ $$
|
|||
| $s_i > 0$ | Es sind $s_i$ Einheiten **übrig** | nicht-bindende Nebenbedingung, Reserve |
|
||||
|
||||
> **🎯 Merksatz**
|
||||
> Die Schlupfvariable ist kein Rechentrick, sondern eine Messgröße: Sie sagt Ihnen, welche
|
||||
> Die Schlupfvariable{idx:Schlupfvariable} ist kein Rechentrick, sondern eine Messgröße: Sie sagt Ihnen, welche
|
||||
> Ressource Ihr Geschäft begrenzt. Und nur wo sie null ist, kann es sich lohnen, Kapazität
|
||||
> nachzukaufen.
|
||||
|
||||
|
|
@ -182,12 +182,12 @@ Ecke zu Ecke — und zwar immer in Richtung Verbesserung.
|
|||

|
||||
|
||||
**Was Sie in der Abbildung sehen.** Durch jede besuchte Ecke läuft genau eine Niveaulinie —
|
||||
die Linien sind nicht gewählt, sondern die Zielwerte 0 €, 2.000 € und 2.375 € der drei Ecken.
|
||||
Der Simplex schiebt diese Linie in Richtung des Pfeils so weit hinaus, wie das Polyeder es
|
||||
Der Simplex schiebt diese Linie in Richtung des Pfeils so weit hinaus, wie das Polyeder{idx:Polyeder} es
|
||||
zulässt. Dass er dabei an einer Ecke anhält und nicht mittendrin, ist keine Eigenheit des
|
||||
Verfahrens, sondern der Fundamentalsatz: Weiter geht es nur noch hinaus.
|
||||
|
||||
|
|
@ -506,7 +506,7 @@ und 31,25 €.
|
|||
> theoretisch endlos kreisen. In der Praxis extrem selten; Bland's Regel verhindert es
|
||||
> beweisbar.
|
||||
> * **Den Simplex selbst produktiv einsetzen.** Diese Implementierung ist ein Lehrmodell.
|
||||
> HiGHS ist um Größenordnungen schneller und numerisch stabiler.
|
||||
> HiGHS{idx:HiGHS} ist um Größenordnungen schneller und numerisch stabiler.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -938,7 +938,7 @@ Deckungsbeitrag, also 15,33 € Reingewinn.
|
|||
> 2. **Numerische Gegenprobe:** Das Modell wird mit $b_3 + 1$ neu gelöst; der gemessene
|
||||
> Zuwachs muss dem Schattenpreis entsprechen. Diese Prüfung ist unabhängig von jeder
|
||||
> Vorzeichenkonvention und deshalb der zuverlässigste Test überhaupt.
|
||||
> 3. **Komplementärer Schlupf:** $s_i \cdot y_i = 0$ muss für alle $i$ gelten.
|
||||
> 3. **Komplementärer Schlupf{idx:Komplementärer Schlupf}:** $s_i \cdot y_i = 0$ muss für alle $i$ gelten.
|
||||
>
|
||||
> **Übernehmen Sie dieses Muster in eigene Projekte.** Der Aufwand ist eine Handvoll Zeilen,
|
||||
> der Nutzen ist die Gewissheit, dass Ihre Handlungsempfehlung nicht das Gegenteil des
|
||||
|
|
@ -992,7 +992,7 @@ Das ist keine theoretische Sorge. Dasselbe Modell, zwei Verfahren desselben Solv
|
|||
|
||||
| Verfahren | Schattenpreise | Was das Management daraus liest |
|
||||
| --- | --- | --- |
|
||||
| Dual Simplex | $(0{,}33;\ 0{,}33;\ 0)$ | „Fräse und Schleiferei sind die Engpässe, die Prüfung ist wertlos.“ |
|
||||
| Dual Simplex{idx:Dual Simplex} | $(0{,}33;\ 0{,}33;\ 0)$ | „Fräse und Schleiferei sind die Engpässe, die Prüfung ist wertlos.“ |
|
||||
| Innere-Punkte-Verfahren | $(0;\ 0;\ 1{,}00)$ | „Die Prüfung ist der Engpass, Fräse und Schleiferei sind wertlos.“ |
|
||||
|
||||
**Beide Zeilen sind mathematisch korrekt.** Sie widersprechen sich trotzdem vollständig.
|
||||
|
|
@ -1021,7 +1021,7 @@ nicht `== 0.0`. Wer exakt vergleicht, übersieht ausgerechnet die Engpässe, die
|
|||
### Die ehrliche Auskunft: Schattenpreis-Spannen
|
||||
|
||||
Was tut man also, wenn das Modell entartet ist? Man meldet keinen Einzelwert, sondern die
|
||||
**Spanne**. Die Menge aller optimalen Dualvektoren ist selbst ein Polyeder:
|
||||
**Spanne**. Die Menge{idx:Konvexität!Menge} aller optimalen Dualvektoren ist selbst ein Polyeder:
|
||||
|
||||
$$
|
||||
\mathbf{A}^\top\mathbf{y} \ge \mathbf{c},\qquad \mathbf{y} \ge \mathbf{0},
|
||||
|
|
@ -1318,7 +1318,7 @@ $$\max\ 5x_1 + 4x_2 \quad \text{u. d. N.}\quad 6x_1+4x_2 \le 24,\quad x_1+2x_2 \
|
|||
Geben Sie jedes Zwischentableau an und lesen Sie am Ende Lösung **und** Schattenpreise ab.
|
||||
Prüfen Sie mit `scipy.optimize.linprog`.
|
||||
|
||||
**Aufgabe ⭐⭐ — Duales Problem aufstellen.**
|
||||
**Aufgabe ⭐⭐ — Duales Problem{idx:Duales Problem} aufstellen.**
|
||||
Stellen Sie zum Modell aus der Aufgabe *Simplex von Hand* das duale Problem auf, lösen Sie es mit `linprog` und
|
||||
weisen Sie den starken Dualitätssatz numerisch nach.
|
||||
|
||||
|
|
@ -1367,7 +1367,7 @@ $$\max\ 3x_1+2x_2 \quad\text{u. d. N.}\quad x_1+x_2 \ge 4,\quad x_1+3x_2 \le 12,
|
|||
> (a) Der Schattenpreis ist $y_i = \partial Z^* / \partial b_i$. Welche Eigenschaft einer
|
||||
> Ableitung übersieht die Hochrechnung auf 2 000 Stunden?
|
||||
>
|
||||
> (b) Skizzieren Sie, wie der zusätzliche Deckungsbeitrag als Funktion der zusätzlichen
|
||||
> (b) Skizzieren Sie, wie der zusätzliche Deckungsbeitrag als Funktion{idx:Konvexität!Funktion} der zusätzlichen
|
||||
> Ofenstunden tatsächlich verläuft. Warum ist er nicht linear — und in welche Richtung
|
||||
> liegt der Fehler?
|
||||
>
|
||||
|
|
@ -1444,7 +1444,7 @@ $$\max\ 3x_1+2x_2 \quad\text{u. d. N.}\quad x_1+x_2 \ge 4,\quad x_1+3x_2 \le 12,
|
|||
|
||||
**Ausblick.** {ref:kap:milp} bricht mit der Annahme beliebiger Teilbarkeit: Was, wenn man nur
|
||||
ganze Maschinen kaufen kann? Wir werden sehen, dass Runden der LP-Lösung nicht nur ungenau,
|
||||
sondern grundsätzlich falsch ist — und lernen Branch-and-Bound kennen.
|
||||
sondern grundsätzlich falsch ist — und lernen Branch-and-Bound{idx:Branch-and-Bound} kennen.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Kapitel: Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound {#kap:milp}
|
||||
# Kapitel: Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound{idx:Branch-and-Bound} {#kap:milp}
|
||||
|
||||
> **📌 Kapitel auf einen Blick**
|
||||
>
|
||||
|
|
@ -7,10 +7,10 @@
|
|||
> **falsch** ist, und lernen die Modellierungstricks, mit denen sich logische Regeln in
|
||||
> lineare Ungleichungen übersetzen lassen.
|
||||
>
|
||||
> **Voraussetzungen:** {ref:kap:lp} (LP, Relaxation, Schranken).
|
||||
> **Voraussetzungen:** {ref:kap:lp} (LP, Relaxation{idx:Relaxation}, Schranken).
|
||||
>
|
||||
> **Danach können Sie:** Fixkosten, Entweder-Oder, Wenn-Dann und Kardinalitätsgrenzen
|
||||
> modellieren, ein MILP mit CP-SAT oder HiGHS lösen, den MIP-Gap als Zusage an den
|
||||
> modellieren, ein MILP mit CP-SAT{idx:CP-SAT} oder HiGHS lösen, den MIP-Gap{idx:MIP-Gap} als Zusage an den
|
||||
> Auftraggeber lesen — und ein Ergebnis erkennen, das nur deshalb gut aussieht, weil
|
||||
> das Big-M zu groß gewählt war.
|
||||
>
|
||||
|
|
@ -68,7 +68,7 @@
|
|||
> MILP 882.00 EUR Mengen [10. 0. 90.] Schalter [ 1. -0. 1. ]
|
||||
> ```
|
||||
|
||||
**Sehen Sie sich die Schalter der ersten Zeile an: 0,143.** Die LP-Relaxation eröffnet
|
||||
**Sehen Sie sich die Schalter der ersten Zeile an: 0,143.** Die LP-Relaxation{idx:LP-Relaxation} eröffnet
|
||||
Lager Mitte zu 14,3 % — und zahlt dafür nur 14,3 % der Fixkosten. So etwas gibt es in der
|
||||
Wirklichkeit nicht. Ein Lager ist offen oder zu.
|
||||
|
||||
|
|
@ -107,10 +107,10 @@ Nach diesem Kapitel können Sie …
|
|||
Kardinalität).
|
||||
4. … begründen, warum $M$ so klein wie möglich gewählt werden muss.
|
||||
5. … ein Portfolioproblem mit Ordergebühren und Höchstzahl an Positionen lösen.
|
||||
6. … **Incumbent, Schranke und MIP-Gap** unterscheiden und aus einem abgebrochenen
|
||||
6. … **Incumbent{idx:Branch-and-Bound!Incumbent}, Schranke und MIP-Gap** unterscheiden und aus einem abgebrochenen
|
||||
Solverlauf eine belastbare Aussage ableiten.
|
||||
7. … alle Solver-Statusfälle explizit behandeln, statt `OPTIMAL` vorauszusetzen.
|
||||
8. … einen **Warm-Start** setzen — und messen, ob er auf Ihrer Problemklasse überhaupt
|
||||
8. … einen **Warm-Start**{idx:Warm-Start} setzen — und messen, ob er auf Ihrer Problemklasse überhaupt
|
||||
etwas bringt.
|
||||
|
||||
---
|
||||
|
|
@ -130,7 +130,7 @@ Der verlockende Gedanke lautet: *„Wir lösen das Problem kontinuierlich und ru
|
|||
Eine verbreitete, aber unbelegte Behauptung dazu lautet, man verliere dadurch „oft
|
||||
20–50 % des Gewinns“. Rechnen wir es nach, statt es zu behaupten.
|
||||
|
||||

|
||||

|
||||
|
||||
> **✏️ Handrechnung: Propagation von Hand**
|
||||
>
|
||||
|
|
@ -246,7 +246,7 @@ if __name__ == "__main__":
|
|||
|
||||
---
|
||||
|
||||
## Globale Constraints — die Bausteine von CP-SAT {#sec:cpsat-globale-constraints-die-bausteine-von-cp}
|
||||
## Globale Constraints{idx:Globale Constraints} — die Bausteine von CP-SAT {#sec:cpsat-globale-constraints-die-bausteine-von-cp}
|
||||
|
||||
CP-SAT stellt mächtige Makros{idx:Globale Constraints} bereit, die in MILP hunderte Big-M-Ungleichungen erfordern
|
||||
würden. Jedes davon hat einen spezialisierten, hocheffizienten Propagator.
|
||||
|
|
@ -604,9 +604,9 @@ Suchstatistik: 113 Verzweigungen, 3 Konflikte, 0.006 s
|
|||
> CP-SAT-Konstrukte, die in MILP mehrere Big-M-Ungleichungen bräuchten. Die Spannweite
|
||||
> $\max - \min$ zu minimieren ist ein Standardrezept für „gleichmäßig verteilen“.
|
||||
>
|
||||
> **3. Kostenzerlegung.** Der Block „Woraus bestehen die Strafkosten?“ ist kein Beiwerk. In
|
||||
> **3. Kostenzerlegung{idx:Kostenzerlegung}.** Der Block „Woraus bestehen die Strafkosten?“ ist kein Beiwerk. In
|
||||
> der Praxis ist die erste Frage jedes Anwenders: *„Warum bekomme **ich** die Stunde?“* Wer
|
||||
> darauf keine Antwort hat, dessen System wird nicht benutzt ({ref:kap:praxisfallen}, *Explainable OR*).
|
||||
> darauf keine Antwort hat, dessen System wird nicht benutzt ({ref:kap:praxisfallen}, *Explainable OR*{idx:Explainable OR}).
|
||||
>
|
||||
> **4. Statusauswertung ohne CP-SAT-Vokabular.** Nach `Solve()` steht nur eine einzige Zeile
|
||||
> mit einer CP-SAT-Konstante darin:
|
||||
|
|
@ -615,7 +615,7 @@ Suchstatistik: 113 Verzweigungen, 3 Konflikte, 0.006 s
|
|||
> ```
|
||||
> Danach heißen die Fälle `status.modellfehler` (die Regeln widersprechen sich — das Modell
|
||||
> muss geändert werden) und `status.brauchbar` (es liegt etwas Ausführbares vor). Das ist
|
||||
> **dieselbe** Fallunterscheidung wie bei HiGHS in {ref:kap:milp} und bei GLOP in
|
||||
> **dieselbe** Fallunterscheidung wie bei HiGHS{idx:HiGHS} in {ref:kap:milp} und bei GLOP in
|
||||
> {ref:kap:lp}; nur die eine Übersetzerzeile weiß, welcher Solver gerechnet hat. Wer den
|
||||
> Auswertungscode direkt gegen `cp_model.INFEASIBLE` schreibt, kann ihn bei einem
|
||||
> Solverwechsel wegwerfen — {ref:sec:praxisfallen-solverwechsel} führt genau diesen Wechsel
|
||||
|
|
@ -625,7 +625,7 @@ Suchstatistik: 113 Verzweigungen, 3 Konflikte, 0.006 s
|
|||
>
|
||||
> * **Zu viele harte Regeln.** Jede zusätzliche harte Bedingung erhöht das Risiko von
|
||||
> `INFEASIBLE`. Faustregel: Hart ist nur, was rechtlich oder physikalisch unmöglich ist.
|
||||
> Alles andere wird weich mit hoher Strafe — dann liefert der Solver den „am wenigsten
|
||||
> Alles andere wird weich{idx:Nebenbedingung!weich} mit hoher Strafe — dann liefert der Solver den „am wenigsten
|
||||
> schlechten“ Plan statt einer Fehlermeldung.
|
||||
> * **Strafgewichte willkürlich wählen.** Die Gewichte (50, 80, 30) definieren implizit eine
|
||||
> Werteordnung: „Ein Freistundenloch ist so schlimm wie 1,6 Stunden Vorbelastung.“
|
||||
|
|
@ -834,7 +834,7 @@ theoretischen Ideal entfernt sein können, noch bevor der Solver fertig war.
|
|||
|
||||
> **💡 Warum Intervallvariablen so wertvoll sind**
|
||||
>
|
||||
> Eine Intervallvariable bündelt drei Größen (Start, Dauer, Ende) und garantiert intern
|
||||
> Eine Intervallvariable{idx:Intervallvariable} bündelt drei Größen (Start, Dauer, Ende) und garantiert intern
|
||||
> `start + dauer == ende`. Der eigentliche Gewinn ist aber `AddNoOverlap`: Diese eine Zeile
|
||||
> ersetzt für $k$ Gänge auf einer Maschine $\binom{k}{2}$ Entweder-Oder-Konstruktionen mit
|
||||
> je zwei Big-M-Ungleichungen und einer Binärvariablen. Bei 10 Gängen sind das 45
|
||||
|
|
@ -1123,7 +1123,7 @@ random_seed = 1 in JEDEM Lauf, 4 Wiederholungen je Arbeiterzahl.
|
|||
nicht achtmal, sondern **gut zwölfmal** schneller als einer. Das sieht nach Messfehler aus, ist aber die
|
||||
korrekte Beschreibung dessen, was CP-SAT tut: Es lässt **nicht** achtmal dieselbe Suche auf
|
||||
verschiedenen Kernen laufen, sondern **verschiedene Strategien nebeneinander** — Suche mit
|
||||
LP-Relaxation, Suche mit anderen Verzweigungsregeln, lokale Suche —, und die teilen
|
||||
LP-Relaxation{idx:LP-Relaxation}, Suche mit anderen Verzweigungsregeln, lokale Suche —, und die teilen
|
||||
einander ihre Schranken mit. Der zweite Arbeiter ist deshalb nicht „der zweite Kern“,
|
||||
sondern ein anderes Verfahren, das zufällig auch rechnet.
|
||||
|
||||
|
|
@ -1146,7 +1146,7 @@ entscheidet die Uhr, und die ist bei jedem Lauf anders.
|
|||
> **⚠️ `random_seed` allein macht nichts reproduzierbar**
|
||||
> Ein häufiger Irrtum: „Ich habe doch einen Seed gesetzt.“ Für einen Zufallsgenerator
|
||||
> stimmt das. Für einen **parallelen** Solver nicht — dort ist die zweite Zufallsquelle die
|
||||
> Ausführungsreihenfolge, und die lässt sich nicht mit einem Parameter festnageln.
|
||||
> Ausführungsreihenfolge, und die lässt sich nicht mit einem Parameter{idx:Parameter (Modell)} festnageln.
|
||||
> Reproduzierbar wird der Lauf erst mit `num_workers = 1` **und** Seed. Wer nur eines von
|
||||
> beidem setzt, hat einen Test, der gelegentlich grundlos rot wird.
|
||||
|
||||
|
|
@ -1485,7 +1485,7 @@ genau die Information, die zur Fehlersuche noetig waere.
|
|||
>
|
||||
> | Stelle | Was passiert | Warum es zählt |
|
||||
> | --- | --- | --- |
|
||||
> | `werte_aus()` | übersetzt Status in **Handlungsempfehlung** | Genau diese Funktion fehlt in den meisten Projekten. Sie ist kurz — und der Unterschied zwischen einem Prototyp und einem System, das nachts ohne Aufsicht läuft. |
|
||||
> | `werte_aus()` | übersetzt Status in **Handlungsempfehlung** | Genau diese Funktion{idx:Konvexität!Funktion} fehlt in den meisten Projekten. Sie ist kurz — und der Unterschied zwischen einem Prototyp und einem System, das nachts ohne Aufsicht läuft. |
|
||||
> | `hat_loesung = status in (OPTIMAL, FEASIBLE)` | die eigentliche Frage | Nicht „war der Solver erfolgreich?“, sondern „habe ich etwas in der Hand, das ich ausführen kann?“ |
|
||||
> | `BestObjectiveBound()` | die bewiesene Schranke | Ohne sie ist `FEASIBLE` eine nutzlose Angabe. Mit ihr wird daraus „höchstens 1,27 % vom Optimum“. |
|
||||
> | Läufe [2] und [3] | 0,5 s gegen 10 s | Der Gap fällt von 1,27 % auf 0,14 %. Zwanzigfache Rechenzeit für gut ein Prozent — die Entscheidung, ob sich das lohnt, trifft die Anwendung, nicht der Solver. |
|
||||
|
|
@ -1525,9 +1525,9 @@ Erweitern Sie das Vertretungssystem um:
|
|||
(b) Herr Bauer und Frau Koch sollen nicht beide am selben Tag eingesetzt werden.
|
||||
(c) Wer Slot 1 übernimmt, soll bevorzugt auch Slot 2 bekommen (Belohnung statt Strafe).
|
||||
|
||||
**Aufgabe ⭐⭐ — Infeasibility erzeugen und diagnostizieren.**
|
||||
**Aufgabe ⭐⭐ — Infeasibility{idx:Infeasibility} erzeugen und diagnostizieren.**
|
||||
Setzen Sie `MAX_VERTRETUNGEN = 0`. Was meldet das Programm? Bauen Sie anschließend eine
|
||||
**Schlupfvariable** je Slot ein („Stunde fällt aus“, Strafe 10 000) und beobachten Sie, wie
|
||||
**Schlupfvariable**{idx:Schlupfvariable} je Slot ein („Stunde fällt aus“, Strafe 10 000) und beobachten Sie, wie
|
||||
der Solver statt einer Fehlermeldung einen Notfallplan liefert. Welche Stunde lässt er
|
||||
ausfallen und warum?
|
||||
|
||||
|
|
@ -1785,7 +1785,7 @@ Nebenbedingungen. Alles, was einen Preis hat, wird irgendwann gekauft.
|
|||
> Der Plan ist mit dem vorhandenen Personal nicht zulässig zu machen.
|
||||
> * **Gewichte in verschiedenen Einheiten mischen.** Euro neben „Unzufriedenheitspunkten“
|
||||
> neben Minuten ergibt eine Zielfunktion, die niemand interpretieren kann — und deren
|
||||
> Konditionszahl obendrein leidet ({ref:sec:fundament-kondition}).
|
||||
> Konditionszahl{idx:Konditionszahl} obendrein leidet ({ref:sec:fundament-kondition}).
|
||||
> * **Nur ein Gewicht ausprobieren.** Ein einziger Lauf sagt nichts darüber, ob Sie nahe an
|
||||
> einem Kipppunkt stehen. Zwischen den Gewichten 5 und 10 ändert sich der Plan oben
|
||||
> erheblich.
|
||||
|
|
@ -1830,7 +1830,7 @@ Nebenbedingungen. Alles, was einen Preis hat, wird irgendwann gekauft.
|
|||
1. Was macht Constraint Propagation, und warum ist sie effizienter als Ausprobieren?
|
||||
2. Welchen Vorteil hat `AddAllDifferent(x)` gegenüber $\binom{n}{2}$ Einzelbedingungen?
|
||||
3. Was ist eine Intervallvariable, und welche Bedingung garantiert sie automatisch?
|
||||
4. Warum sollten möglichst wenige Bedingungen hart formuliert werden?
|
||||
4. Warum sollten möglichst wenige Bedingungen hart{idx:Nebenbedingung!hart} formuliert werden?
|
||||
5. Warum ist die Aufschlüsselung der Strafkosten in der Praxis wichtiger als der Zielwert
|
||||
6. Sie setzen `random_seed = 1`, bekommen aber trotzdem bei jedem Lauf einen anderen Plan.
|
||||
Woran liegt das, und was hilft?
|
||||
|
|
|
|||
|
|
@ -85,11 +85,11 @@ mehr.
|
|||
> nacheinander. Bei vier Monteuren kostet die gierige Regel 8 %; bei vierzig kostet sie
|
||||
> regelmäßig ein Vielfaches.
|
||||
|
||||
**Warum funktioniert das?** Weil das Zuordnungsproblem eine besondere Struktur hat: Seine
|
||||
**Warum funktioniert das?** Weil das Zuordnungsproblem{idx:Zuordnungsproblem (1:1)} eine besondere Struktur hat: Seine
|
||||
Nebenbedingungsmatrix ist **total unimodular**. Das bedeutet — wir kommen in
|
||||
{ref:sec:graphen-bipartites-matching-das-zuordnungsproblem} darauf zurück —, dass die
|
||||
LP-Relaxation von ganz allein ganzzahlige Lösungen liefert. Man braucht hier also weder
|
||||
Branch-and-Bound noch Binärvariablen. Dieselbe Eigenschaft macht auch Flussprobleme so
|
||||
LP-Relaxation{idx:LP-Relaxation} von ganz allein ganzzahlige Lösungen liefert. Man braucht hier also weder
|
||||
Branch-and-Bound{idx:Branch-and-Bound} noch Binärvariablen. Dieselbe Eigenschaft macht auch Flussprobleme so
|
||||
angenehm lösbar, und damit beginnt das Kapitel.
|
||||
|
||||
---
|
||||
|
|
@ -102,7 +102,7 @@ Nach diesem Kapitel können Sie …
|
|||
2. … den **Flusserhaltungssatz**{idx:Flusserhaltung} aufstellen und seine Bedeutung erklären.
|
||||
3. … begründen, warum Zuordnungsprobleme **ohne** Ganzzahligkeitsbedingung ganzzahlig lösbar
|
||||
sind (totale Unimodularität{idx:Totale Unimodularität}).
|
||||
4. … ein Vehicle Routing Problem mit Kapazitäten und Zeitfenstern mit OR-Tools lösen.
|
||||
4. … ein Vehicle Routing Problem mit Kapazitäten und Zeitfenstern mit OR-Tools{idx:OR-Tools} lösen.
|
||||
5. … einschätzen, wann ein spezialisierter Algorithmus einem allgemeinen MILP überlegen ist.
|
||||
6. … begründen, warum eine gierige Zuordnung systematisch schlechter ist als eine
|
||||
gemeinsame Optimierung.
|
||||
|
|
@ -128,7 +128,7 @@ mathematische Fundament für Transportketten, Liquiditätsrouting und Datenverte
|
|||
Route über den Umschlag läuft voll (dick, amber), die Kante Werk B → Umschlag bleibt
|
||||
ungenutzt (gestrichelt) — und trotzdem muss die teure Direktkante Werk B → Kunde 2 für 6 €
|
||||
bedient werden, weil der Umschlagweg dorthin schon ausgelastet ist. An den Knoten stehen die
|
||||
Dualwerte der Flusserhaltung. Erzeugt von
|
||||
Dualwerte der Flusserhaltung{idx:Flusserhaltung}. Erzeugt von
|
||||
`bilder_04/erzeuge_min_cost_flow.py`.](bilder_04/kap_graphen_min_cost_flow.svg)
|
||||
|
||||
Sei $x_{ij} \ge 0$ der Fluss über Kante $(i,j)$, $c_{ij}$ die Kosten je Einheit und
|
||||
|
|
@ -307,7 +307,7 @@ schon bei zehn Knoten den Überblick verliert.
|
|||
|
||||
---
|
||||
|
||||
## Bipartites Matching: das Zuordnungsproblem {#sec:graphen-bipartites-matching-das-zuordnungsproblem}
|
||||
## Bipartites Matching{idx:Bipartites Matching}: das Zuordnungsproblem {#sec:graphen-bipartites-matching-das-zuordnungsproblem}
|
||||
|
||||
Wenn $N$ Aufgaben auf $N$ Ressourcen **eins zu eins** verteilt werden — Orders auf Broker,
|
||||
Schichten auf Mitarbeitende, Aufträge auf Maschinen — spricht man von **bipartitem
|
||||
|
|
@ -319,9 +319,9 @@ $$
|
|||
\sum_j x_{ij} = 1\ \forall i,\qquad \sum_i x_{ij} = 1\ \forall j,\qquad x_{ij}\ge0
|
||||
$$
|
||||
|
||||
### Der Satz von Birkhoff und von Neumann
|
||||
### Der Satz von Birkhoff und von Neumann{idx:Satz von Birkhoff und von Neumann}
|
||||
|
||||
> **Satz.** Die Extrempunkte der Menge aller doppelt-stochastischen Matrizen (alle
|
||||
> **Satz.** Die Extrempunkte der Menge{idx:Konvexität!Menge} aller doppelt-stochastischen Matrizen (alle
|
||||
> Zeilensummen $= 1$, alle Spaltensummen $= 1$, $x_{ij} \ge 0$) sind **genau** die
|
||||
> Permutationsmatrizen (alle $x_{ij} \in \{0,1\}$).
|
||||
|
||||
|
|
@ -353,8 +353,8 @@ selbst“ ganzzahlig.
|
|||
>
|
||||
> **Und die Warnung dazu:** Diese Eigenschaft ist zerbrechlich. Eine einzige zusätzliche
|
||||
> Nebenbedingung, die nicht in das Schema passt — „höchstens drei Fahrzeuge insgesamt“,
|
||||
> eine Fixkostenkopplung, eine Mindestabnahmemenge — zerstört die totale Unimodularität.
|
||||
> Dann liefert die Relaxation wieder Brüche, und Sie brauchen doch ein MILP. Prüfen Sie
|
||||
> eine Fixkostenkopplung, eine Mindestabnahmemenge{idx:Mindestabnahmemenge} — zerstört die totale Unimodularität.
|
||||
> Dann liefert die Relaxation{idx:Relaxation} wieder Brüche, und Sie brauchen doch ein MILP. Prüfen Sie
|
||||
> das, bevor Sie sich auf die Struktur verlassen.
|
||||
|
||||
```python
|
||||
|
|
@ -539,9 +539,9 @@ $$
|
|||
> **💡 In der Praxis: nicht selbst modellieren**
|
||||
> Die MTZ-Formulierung ist didaktisch wertvoll, aber für reale Instanzen zu schwach — die
|
||||
> LP-Relaxation ist sehr locker, und Branch-and-Bound braucht sehr lange. Professionelle
|
||||
> Solver verwenden stattdessen dynamisch erzeugte Subtour-Eliminationsschnitte oder, wie
|
||||
> Solver verwenden stattdessen dynamisch erzeugte Subtour{idx:Subtour}-Eliminationsschnitte oder, wie
|
||||
> OR-Tools, **spezialisierte Metaheuristiken**. Nutzen Sie für Routing die
|
||||
> **Routing-Bibliothek**, nicht ein selbstgebautes MILP.
|
||||
> **Routing-Bibliothek**{idx:Routing-Bibliothek}, nicht ein selbstgebautes MILP.
|
||||
|
||||
### Praxisbeispiel: Flotten-Routing
|
||||
|
||||
|
|
@ -722,7 +722,7 @@ if __name__ == "__main__":
|
|||
> verschiebt sich der ganze Plan.
|
||||
> * **Zu enge Zeitfenster ohne Vorabprüfung.** Ist ein Kunde in seinem Fenster physisch nicht
|
||||
> erreichbar, meldet OR-Tools nur „keine Lösung“ — ohne zu sagen, welcher Kunde schuld ist.
|
||||
> Die Funktion `pruefe_daten()` fängt genau das ab.
|
||||
> Die Funktion{idx:Konvexität!Funktion} `pruefe_daten()` fängt genau das ab.
|
||||
> * **Ergebnisse als exakt betrachten.** Die Routing-Bibliothek nutzt **Metaheuristiken**.
|
||||
> Ein längeres Zeitlimit kann eine bessere Lösung liefern; „optimal“ wird hier in der Regel
|
||||
> nicht bewiesen. Für die Praxis genügt das fast immer — man sollte es aber wissen.
|
||||
|
|
@ -1032,7 +1032,7 @@ plausibel aussieht.
|
|||
> * **Die Prüfung aus denselben Bausteinen bauen wie das Modell.** Wer die Ladung mit
|
||||
> `loesung.Value(ladungs_dimension.CumulVar(...))` prüft, fragt das Modell, ob es sich an
|
||||
> sich selbst hält. Rechnen Sie stattdessen aus der **ausgegebenen Tour** neu nach.
|
||||
> * **Zwei Läufe nur an der Zielfunktion vergleichen.** 326 gegen 572 km sagt nichts,
|
||||
> * **Zwei Läufe nur an der Zielfunktion{idx:Zielfunktion} vergleichen.** 326 gegen 572 km sagt nichts,
|
||||
> solange nicht feststeht, dass beide Pläne überhaupt fahrbar sind.
|
||||
> * **Unbenutzte Fahrzeuge übersehen.** Drei Fahrzeuge, die im Depot stehen, während eines
|
||||
> alles fährt, sind fast immer ein Zeichen für eine fehlende Beschränkung.
|
||||
|
|
@ -1086,7 +1086,7 @@ plausibel aussieht.
|
|||
* **Graphen** sind die natürliche Sprache für Transport-, Zuordnungs- und Routenprobleme.
|
||||
* **Flusserhaltung** ist die Kirchhoff-Regel des Operations Research: Was hineingeht, kommt
|
||||
heraus — abzüglich des Knotensaldos.
|
||||
* **Totale Unimodularität** macht Fluss- und Zuordnungsprobleme „von selbst“ ganzzahlig. Wer
|
||||
* **Totale Unimodularität**{idx:Totale Unimodularität} macht Fluss- und Zuordnungsprobleme „von selbst“ ganzzahlig. Wer
|
||||
hier `integrality` setzt, verschenkt Laufzeit ohne Gegenwert.
|
||||
* **Spezialisierte Algorithmen schlagen allgemeine Solver** deutlich: Der Ungarische
|
||||
Algorithmus{idx:Ungarischer Algorithmus} löst in $O(n^3)$, wofür ein MILP-Solver Branch-and-Bound bräuchte.
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
> und eine Entscheidung muss trotzdem heute fallen.
|
||||
>
|
||||
> **Voraussetzungen:** {ref:kap:milp} und {ref:kap:cpsat}, insbesondere
|
||||
> {ref:sec:milp-gap} (MIP-Gap und Schranke).
|
||||
> {ref:sec:milp-gap} (MIP-Gap{idx:MIP-Gap} und Schranke).
|
||||
>
|
||||
> **Danach können Sie:** eine lokale Suche mit ihrer entscheidenden Zutat — der
|
||||
> Kostenänderung in O(1) — selbst schreiben, die Temperatur eines Simulated Annealing
|
||||
> Kostenänderung in O(1) — selbst schreiben, die Temperatur eines Simulated Annealing{idx:Simulated Annealing}
|
||||
> ausmessen statt raten, den Umschlagpunkt zwischen exakt und heuristisch für Ihr eigenes
|
||||
> Problem bestimmen, und mit Large Neighborhood Search beides kombinieren.
|
||||
>
|
||||
|
|
@ -99,7 +99,7 @@ Nach diesem Kapitel können Sie …
|
|||
1. … erklären, warum eine lokale Suche ohne **Kostenänderung in O(1)** praktisch wertlos ist.
|
||||
2. … Simulated Annealing implementieren und seine Starttemperatur **an der Zuggröße**
|
||||
kalibrieren statt am Zielfunktionswert.
|
||||
3. … den Beitrag der Metaheuristik gegen die einfachere Alternative abgrenzen — reines
|
||||
3. … den Beitrag der Metaheuristik{idx:Metaheuristik} gegen die einfachere Alternative abgrenzen — reines
|
||||
Bergsteigen — statt ihn ihr gutzuschreiben.
|
||||
4. … den **Umschlagpunkt** bestimmen, ab dem eine Metaheuristik den exakten Solver schlägt,
|
||||
und begründen, warum diese Zahl problemspezifisch ist.
|
||||
|
|
@ -136,7 +136,7 @@ $$
|
|||
Wer die Aufgabe als Graph liest, erkennt sie wieder: Es ist ein **asymmetrisches
|
||||
Rundreiseproblem** ({ref:kap:graphen}) mit offenem Ende. Das ist eine gute und eine
|
||||
schlechte Nachricht. Gut, weil damit alles bekannt ist, was man über das Problem wissen
|
||||
kann. Schlecht, weil dazu gehört, dass es NP-schwer ist.
|
||||
kann. Schlecht, weil dazu gehört, dass es NP-schwer{idx:NP-schwer} ist.
|
||||
|
||||
> **📖 Definition: Metaheuristik**{idx:Metaheuristik}
|
||||
>
|
||||
|
|
@ -151,7 +151,7 @@ kann. Schlecht, weil dazu gehört, dass es NP-schwer ist.
|
|||
|
||||
### Die Instanz
|
||||
|
||||
Alle Programme dieses Kapitels benutzen dieselbe Aufgabe. Die Rüstzeit setzt sich aus zwei
|
||||
Alle Programme dieses Kapitels benutzen dieselbe Aufgabe. Die Rüstzeit{idx:Rüstzeit} setzt sich aus zwei
|
||||
Teilen zusammen: einem unregelmäßigen Reinigungsaufwand zwischen den Produktfamilien und
|
||||
einem Zuschlag für den Wechsel von Dunkel nach Hell.
|
||||
|
||||
|
|
@ -895,7 +895,7 @@ if __name__ == "__main__":
|
|||
print("=" * 88)
|
||||
```
|
||||
|
||||
**Erwartete Ausgabe** (die CP-SAT-Spalten sind hardwareabhängig, siehe Programmkopf):
|
||||
**Erwartete Ausgabe** (die CP-SAT{idx:CP-SAT}-Spalten sind hardwareabhängig, siehe Programmkopf):
|
||||
|
||||
```
|
||||
========================================================================================
|
||||
|
|
@ -1428,7 +1428,7 @@ Starttemperatur würde eine Verschlechterung von genau 70 Minuten in 37 % der F
|
|||
angenommen? Vergleichen Sie das mit den Temperaturen in der Tabelle.
|
||||
|
||||
**Aufgabe ⭐⭐ — Die teure Bewertung.**
|
||||
Ersetzen Sie in `Simulated_Annealing.py` die Funktion `delta_verschieben` durch eine
|
||||
Ersetzen Sie in `Simulated_Annealing.py` die Funktion{idx:Konvexität!Funktion} `delta_verschieben` durch eine
|
||||
Variante, die den Zug ausführt und `gesamtruestzeit()` neu berechnet. Wie viele Züge schafft
|
||||
das Programm dann in derselben Zeit, und wie verändert sich das Ergebnis bei gleichem
|
||||
Zeitbudget?
|
||||
|
|
@ -1510,7 +1510,7 @@ liegt es an der Strategie oder an der Zahl der Runden, die sie schafft?
|
|||
* Eine **Faustregel** ist selten dumm, aber immer kurzsichtig: Sie bewertet einen Schritt
|
||||
danach, was er kostet, nicht danach, was er übrig lässt.
|
||||
* **Lokale Suche** steht und fällt mit der Kostenänderung in $O(1)$. Wer den Zug über die
|
||||
volle Zielfunktion bewertet, misst am Ende seine Implementierung statt des Verfahrens.
|
||||
volle Zielfunktion{idx:Zielfunktion} bewertet, misst am Ende seine Implementierung statt des Verfahrens.
|
||||
* **Simulated Annealing** nimmt Verschlechterungen mit $e^{-\Delta/T}$ an. $T$ und $\Delta$
|
||||
haben dieselbe Einheit — die Temperatur gehört an der **Zuggröße** kalibriert, nicht am
|
||||
Zielfunktionswert. Die verbreitete Regel „20 bis 50 % Annahmequote“ war auf dieser Aufgabe
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ je Stück-und-Rolle, und es kennt gar keine einzelnen Rollen mehr. Damit verschw
|
|||
Problem, das das naheliegende Modell praktisch unlösbar macht — dazu gleich mehr.
|
||||
|
||||
> **🎯 Merksatz**
|
||||
> Die schwierigste Arbeit an einem Optimierungsmodell ist selten die Zielfunktion. Es ist die
|
||||
> Die schwierigste Arbeit an einem Optimierungsmodell ist selten die Zielfunktion{idx:Zielfunktion}. Es ist die
|
||||
> Frage, **worüber** die Variablen laufen.
|
||||
|
||||
**Warum funktioniert das?** Weil hier alle 16 möglichen Muster aufzählbar waren. Bei drei
|
||||
|
|
@ -98,7 +98,7 @@ Nach diesem Kapitel können Sie …
|
|||
|
||||
## Warum das naheliegende Modell scheitert {#sec:dekomposition-symmetrie}
|
||||
|
||||
Der erste Entwurf eines Zuschnittmodells sieht fast immer so aus: eine Binärvariable
|
||||
Der erste Entwurf eines Zuschnittmodells sieht fast immer so aus: eine Binärvariable{idx:Binärvariable}
|
||||
$z_{jr}$ für „Stück $j$ liegt auf Rolle $r$", dazu $y_r$ für „Rolle $r$ wird benutzt".
|
||||
|
||||
Zwei Dinge gehen dabei schief.
|
||||
|
|
@ -108,14 +108,14 @@ Binärvariablen — unangenehm, aber allein noch kein Hindernis.
|
|||
|
||||
**Die Symmetrie.** Das ist das eigentliche Problem. Alle Mutterrollen sind **gleich**. Jede
|
||||
Lösung existiert deshalb in unzähligen Umbenennungen: Vertauscht man Rolle 3 und Rolle 47,
|
||||
entsteht eine formal andere, inhaltlich identische Lösung. Branch-and-Bound weiß das nicht
|
||||
entsteht eine formal andere, inhaltlich identische Lösung. Branch-and-Bound{idx:Branch-and-Bound} weiß das nicht
|
||||
und arbeitet sie einzeln ab.
|
||||
|
||||
> **⚠️ Woran man ein Symmetrieproblem erkennt**
|
||||
>
|
||||
> Der Suchbaum wächst, aber die **Schranke bewegt sich nicht.** Im Protokoll aus
|
||||
> {ref:sec:milp-gap} sieht das so aus: Die Zahl der Knoten steigt in die Hunderttausende,
|
||||
> der Incumbent verbessert sich hin und wieder, und der Dual Bound steht praktisch still.
|
||||
> der Incumbent{idx:Branch-and-Bound!Incumbent} verbessert sich hin und wieder, und der Dual Bound steht praktisch still.
|
||||
>
|
||||
> Das ist ein anderes Bild als „das Problem ist einfach zu groß". Bei einem großen, aber
|
||||
> unsymmetrischen Problem nähern sich beide Werte einander an, nur langsam.
|
||||
|
|
@ -134,7 +134,7 @@ $$
|
|||
>
|
||||
> | Mathematik | Alltagssprache |
|
||||
> | --- | --- |
|
||||
> | $P$ | die Menge aller zulässigen Schnittmuster |
|
||||
> | $P$ | die Menge{idx:Konvexität!Menge} aller zulässigen Schnittmuster |
|
||||
> | $a_{ip}$ | „Wie viele Stücke der Breite $i$ liefert Muster $p$?" |
|
||||
> | $x_p$ | „Wie oft schneide ich Muster $p$?" — die einzige Entscheidung |
|
||||
> | $d_i$ | die bestellte Stückzahl der Breite $i$ |
|
||||
|
|
@ -156,7 +156,7 @@ Die Idee ist alt (Gilmore und Gomory, 1961) und in einem Satz gesagt:
|
|||
> Muster gibt, das sich lohnen würde — und wenn ja, nimm nur dieses eine dazu.
|
||||
|
||||
Die Frage „lohnt sich noch ein Muster?" beantworten die **Dualwerte** des Master-LPs. Der
|
||||
Dualwert $\pi_i$ zur Bedarfszeile $i$ ist genau der Schattenpreis aus
|
||||
Dualwert $\pi_i$ zur Bedarfszeile $i$ ist genau der Schattenpreis{idx:Schattenpreis} aus
|
||||
{ref:sec:lp-dualitaet-und-schattenpreise}: Er sagt, wie viele Rollen ein zusätzliches Stück
|
||||
der Breite $i$ kostet.
|
||||
|
||||
|
|
@ -189,7 +189,7 @@ $$
|
|||
> Mustern optimal — auch über den nie erzeugten.
|
||||
|
||||
**Und wie findet man das beste neue Muster?** Man sucht die Zusammenstellung von Stücken mit
|
||||
dem größten Gesamtwert, die noch in die Rolle passt. Das ist ein **Rucksackproblem**:
|
||||
dem größten Gesamtwert, die noch in die Rolle passt. Das ist ein **Rucksackproblem**{idx:Rucksackproblem}:
|
||||
|
||||
| Rucksack ({ref:kap:milp}) | hier |
|
||||
| --- | --- |
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ ist: Welches nehme ich, und was bekomme ich dafür?
|
|||
| --- | --- | --- | --- | --- |
|
||||
| **LP** | teilbare Mengen, lineare Zusammenhänge | beweisbares Optimum **plus Schattenpreise** | sobald etwas ganzzahlig sein muss | {ref:kap:lp} |
|
||||
| **MILP** | Ja/Nein-Entscheidungen, Fixkosten, Logik | beweisbares Optimum, Gap als Fortschrittsmaß | Laufzeit wächst mit der Zahl der Binärvariablen | {ref:kap:milp} |
|
||||
| **CP-SAT** | Zuweisung, Reihenfolge, Kalender, harte Logik | beweisbares Optimum, sehr ausdrucksstarke Bedingungen | keine Schattenpreise, keine stetigen Größen | {ref:kap:cpsat} |
|
||||
| **CP-SAT**{idx:CP-SAT} | Zuweisung, Reihenfolge, Kalender, harte Logik | beweisbares Optimum, sehr ausdrucksstarke Bedingungen | keine Schattenpreise, keine stetigen Größen | {ref:kap:cpsat} |
|
||||
| **Graphenalgorithmen** | Flüsse, Zuordnung, Touren | oft **polynomiell** statt exponentiell | nur, wenn die Struktur wirklich passt | {ref:kap:graphen} |
|
||||
| **Metaheuristiken** | wenn der exakte Solver aussteigt | eine gute Lösung in **fester Zeit** | keine Garantie, kein Beweis, keine Schranke | {ref:kap:metaheuristiken} |
|
||||
| **Spaltengenerierung** | Modelle mit astronomisch vielen Variablen | beweisbares Optimum über nie erzeugte Spalten | lohnt nur bei bestimmter Instanzstruktur | {ref:kap:dekomposition} |
|
||||
|
|
@ -23,7 +23,7 @@ wissen, wo es aufhört — nicht, wofür es gedacht ist.
|
|||
| Behauptung | Gemessen | Wo |
|
||||
| --- | --- | --- |
|
||||
| „Der exakte Solver ist immer besser." | Bei 500 Aufträgen liefert CP-SAT eine Lösung, die **5,2 % schlechter** ist als die Faustregel eines Meisters | {ref:kap:metaheuristiken} |
|
||||
| „Metaheuristiken sind ungenau." | Faustregel 2 497 → Annealing 2 343 → Annealing plus LNS **2 289** Minuten Rüstzeit; untere Schranke 1 768 | {ref:kap:metaheuristiken} |
|
||||
| „Metaheuristiken sind ungenau." | Faustregel 2 497 → Annealing 2 343 → Annealing plus LNS **2 289** Minuten Rüstzeit{idx:Rüstzeit}; untere Schranke 1 768 | {ref:kap:metaheuristiken} |
|
||||
| „Man muss alle Variablen aufschreiben." | 28 erzeugte Muster von **46 408** möglichen — und die Lösung ist beweisbar optimal | {ref:kap:dekomposition} |
|
||||
| „Dekomposition lohnt sich immer." | Bei drei Stücken je Rolle **11 %** Ersparnis, bei sechs **nichts** | {ref:kap:dekomposition} |
|
||||
| „Mit Seed ist der Lauf reproduzierbar." | Schon **zwei** Arbeiter liefern bei identischem Seed drei verschiedene Pläne zum selben Zielwert | {ref:sec:cpsat-parallele-suche} |
|
||||
|
|
@ -34,7 +34,7 @@ wissen, wo es aufhört — nicht, wofür es gedacht ist.
|
|||
weit danebenliegen, und gerundet sogar unzulässig werden.
|
||||
2. **Ein zu großes Big-M.** Es macht das Modell nicht falsch, sondern die Suche langsam und
|
||||
die Schranken wertlos. So klein wie zulässig, nie „sicherheitshalber groß".
|
||||
3. **Zu früh heuristisch werden.** Der Umschlagpunkt, ab dem eine Metaheuristik den exakten
|
||||
3. **Zu früh heuristisch werden.** Der Umschlagpunkt, ab dem eine Metaheuristik{idx:Metaheuristik} den exakten
|
||||
Solver schlägt, ist eine Eigenschaft **des Problems** und lässt sich messen. Wer ihn
|
||||
nicht misst, verzichtet auf Optimalitätsgarantien, die er hätte haben können.
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ brauchen, hängt davon ab, **welche** davon bei Ihnen vorliegt:
|
|||
|
||||
> **🎯 Merksatz zum Diagramm**
|
||||
> Die erste Frage trennt zwei Welten, die man nicht vermischen darf. Ist die
|
||||
> **Nichtlinearität** das Problem, geht es um Konvexität — und damit darum, ob Sie eine
|
||||
> **Nichtlinearität** das Problem, geht es um Konvexität{idx:Konvexität} — und damit darum, ob Sie eine
|
||||
> Optimalitätsgarantie bekommen oder nur ein lokales Optimum. Ist die **Unsicherheit** das
|
||||
> Problem, geht es um etwas ganz anderes: Nicht der Solver ist die Schwierigkeit, sondern
|
||||
> die Frage, was „optimal“ überhaupt heißen soll, wenn man die Daten nicht kennt.
|
||||
|
|
@ -33,15 +33,15 @@ insgesamt leistet, fasst die Synthese an seinem Ende zusammen.
|
|||
> **📌 Kapitel auf einen Blick**
|
||||
>
|
||||
> **Worum geht es?** Risiko ist quadratisch. Sobald Varianz ins Spiel kommt, verlässt man
|
||||
> die Welt der Polyeder. Dieses Kapitel liefert das mathematische Fundament für die gesamte
|
||||
> die Welt der Polyeder{idx:Polyeder}. Dieses Kapitel liefert das mathematische Fundament für die gesamte
|
||||
> Portfoliooptimierung in {ref:teil:anwendungen}.
|
||||
>
|
||||
> **Voraussetzungen:** {ref:kap:fundament} (Konvexität, Eigenwerte), {ref:kap:lp} (Dualität,
|
||||
> Schattenpreise). Gradienten werden in {ref:sec:qp-nlp-lernziele} wiederholt.
|
||||
>
|
||||
> **Danach können Sie:** Ein quadratisches Programm aufstellen, die KKT-Bedingungen
|
||||
> anwenden, den Zusammenhang zwischen Lagrange-Multiplikator und Schattenpreis erklären,
|
||||
> eine gültige Kovarianzmatrix konstruieren — und mit nicht-konvexen Problemen umgehen,
|
||||
> anwenden, den Zusammenhang zwischen Lagrange-Multiplikator{idx:Lagrange-Multiplikator} und Schattenpreis erklären,
|
||||
> eine gültige Kovarianzmatrix{idx:Kovarianzmatrix} konstruieren — und mit nicht-konvexen Problemen umgehen,
|
||||
> ohne ein lokales Optimum für das Optimum zu halten.
|
||||
>
|
||||
> **Zeitbedarf:** ca. 6,5 Stunden.
|
||||
|
|
@ -120,8 +120,8 @@ $$
|
|||
|
||||
Der letzte Term ist der entscheidende: Bei negativer Korrelation ist er **negativ** und
|
||||
zieht das Gesamtrisiko herunter. Deshalb verlässt man mit Risiko die Welt der Polyeder aus
|
||||
{ref:teil:kernverfahren} — die Zielfunktion ist kein Skalarprodukt mehr, sondern eine
|
||||
quadratische Form. Was das für die Lösbarkeit bedeutet und warum CVXPY das trotzdem mit
|
||||
{ref:teil:kernverfahren} — die Zielfunktion{idx:Zielfunktion} ist kein Skalarprodukt{idx:Skalarprodukt} mehr, sondern eine
|
||||
quadratische Form. Was das für die Lösbarkeit bedeutet und warum CVXPY{idx:CVXPY} das trotzdem mit
|
||||
Optimalitätsgarantie löst, klärt der Rest des Kapitels.
|
||||
|
||||
> **🎯 Merksatz**
|
||||
|
|
@ -139,7 +139,7 @@ Nach diesem Kapitel können Sie …
|
|||
1. … ein **quadratisches Programm (QP)** aufstellen und von einem allgemeinen nichtlinearen
|
||||
Programm abgrenzen.
|
||||
2. … die **KKT-Bedingungen** herleiten und auf ein Optimierungsproblem anwenden.
|
||||
3. … den Zusammenhang zwischen **Lagrange-Multiplikator** und **Schattenpreis** erklären.
|
||||
3. … den Zusammenhang zwischen **Lagrange-Multiplikator** und **Schattenpreis**{idx:Schattenpreis} erklären.
|
||||
4. … zwischen **konvex**{idx:Konvexität} und **streng konvex**{idx:Konvexität!streng konvex}
|
||||
unterscheiden und eine gültige, positiv semidefinite **Kovarianzmatrix**{idx:Kovarianzmatrix}
|
||||
konstruieren.
|
||||
|
|
@ -204,11 +204,11 @@ Minimum.“* Korrekt gilt:
|
|||
|
||||
| Voraussetzung | Bedeutung | Folgerung |
|
||||
| --- | --- | --- |
|
||||
| $\mathbf{P} \succeq 0$ — **positiv semidefinit**, alle Eigenwerte $\lambda_i \ge 0$ | Die Funktion ist eine „Schüssel“, die eine flache Rinne haben darf | Problem ist **konvex**. Jedes lokale Minimum ist global. Es kann aber **mehrere Minimalstellen** geben — mit demselben Zielwert |
|
||||
| $\mathbf{P} \succeq 0$ — **positiv semidefinit**, alle Eigenwerte $\lambda_i \ge 0$ | Die Funktion{idx:Konvexität!Funktion} ist eine „Schüssel“, die eine flache Rinne haben darf | Problem ist **konvex**. Jedes lokale Minimum ist global. Es kann aber **mehrere Minimalstellen** geben — mit demselben Zielwert |
|
||||
| $\mathbf{P} \succ 0$ — **positiv definit**, alle $\lambda_i > 0$ | Echte Schüssel ohne flache Richtung | Problem ist **streng konvex**. Die Minimalstelle ist **eindeutig** |
|
||||
| $\mathbf{P}$ hat einen negativen Eigenwert | Sattel oder Rinne nach unten | Problem ist **nicht konvex**. Lokale Optima möglich, keine Garantie |
|
||||
|
||||
**Warum das praktisch zählt:** Eine Stichproben-Kovarianzmatrix mit mehr Titeln als
|
||||
**Warum das praktisch zählt:** Eine Stichproben-Kovarianzmatrix{idx:Stichproben-Kovarianzmatrix} mit mehr Titeln als
|
||||
Beobachtungen ($N > T$) ist **singulär** — also nur semidefinit. Dann gibt es unendlich viele
|
||||
Portfolios mit exakt demselben minimalen Risiko, und der Solver liefert eines davon,
|
||||
scheinbar willkürlich. Kleine Datenänderungen führen zu völlig anderen Gewichten. Genau
|
||||
|
|
@ -547,7 +547,7 @@ if __name__ == "__main__":
|
|||
## Nichtlineare Optimierung mit `scipy.optimize.minimize` {#sec:qp-nlp-nichtlineare-optimierung-mit-scipy-optimize-minimize}
|
||||
|
||||
Wenn Zielfunktion oder Nebenbedingungen weder linear noch quadratisch sind — Logarithmen,
|
||||
Wurzeln, Exponentialfunktionen — nutzt man gradientenbasierte Verfahren wie **SLSQP**
|
||||
Wurzeln, Exponentialfunktionen — nutzt man gradientenbasierte Verfahren wie **SLSQP**{idx:SLSQP}
|
||||
(*Sequential Least Squares Programming*).
|
||||
|
||||
> **⚠️ Der entscheidende Unterschied zu CVXPY**
|
||||
|
|
@ -564,7 +564,7 @@ Wir optimieren ein Portfolio nicht nur nach Varianz, sondern maximieren zusätzl
|
|||
$$
|
||||
\min_{\mathbf{w}}\quad \underbrace{\tfrac12\mathbf{w}^\top\boldsymbol{\Sigma}\mathbf{w}}_{\text{Risiko}}
|
||||
\;-\;\underbrace{\alpha\,\boldsymbol{\mu}^\top\mathbf{w}}_{\text{Ertrag}}
|
||||
\;-\;\underbrace{\beta\Big(-\textstyle\sum_i w_i\ln w_i\Big)}_{\text{Diversifikation}}
|
||||
\;-\;\underbrace{\beta\Big(-\textstyle\sum_i w_i\ln w_i\Big)}_{\text{Diversifikation{idx:Diversifikation}}}
|
||||
$$
|
||||
|
||||
> **📐 Formel-Lesehilfe zur Entropie**
|
||||
|
|
@ -575,7 +575,7 @@ $$
|
|||
> **Ohne Formel gesagt:** Die Entropie misst, wie „breit verteilt“ das Portfolio ist. Weil
|
||||
> sie mit einem Minuszeichen in die zu minimierende Zielfunktion eingeht, wird breite
|
||||
> Streuung **belohnt** — und zwar mathematisch glatt, ohne harte Obergrenzen. Der Vorteil
|
||||
> gegenüber einer Schranke wie $w_i \le 0{,}2$: Der Übergang ist weich, das Ergebnis
|
||||
> gegenüber einer Schranke wie $w_i \le 0{,}2$: Der Übergang ist weich{idx:Nebenbedingung!weich}, das Ergebnis
|
||||
> reagiert nicht sprunghaft auf kleine Datenänderungen.
|
||||
|
||||
```python
|
||||
|
|
@ -789,7 +789,7 @@ unverändert gelassen. **Der weiche Term verteilt, die harte Schranke kappt.**
|
|||
|
||||
---
|
||||
|
||||
## Jenseits der Konvexität: lokale Optima, Multistart und MINLP {#sec:qp-nlp-nichtkonvex}
|
||||
## Jenseits der Konvexität: lokale Optima, Multistart und MINLP{idx:MINLP} {#sec:qp-nlp-nichtkonvex}
|
||||
|
||||
Alles bisher in diesem Kapitel stand unter einer Bedingung: **Konvexität**. Sie ist der
|
||||
Grund, warum CVXPY eine Optimalitätsgarantie geben kann und warum die KKT-Bedingungen nicht
|
||||
|
|
@ -807,7 +807,7 @@ Effekten:
|
|||
| --- | --- | --- |
|
||||
| **Mengenrabatte** | Stückpreis fällt mit der Bestellmenge | Kostenfunktion wird konkav — Sprünge nach unten belohnen große Lose |
|
||||
| **Skaleneffekte** | Stückkosten sinken mit der Losgröße | dasselbe Muster in der Produktion |
|
||||
| **Produkte von Variablen** | „Menge mal Preis“, wenn beide entschieden werden | $x \cdot y$ ist weder konvex noch konkav |
|
||||
| **Produkte von Variablen** | „Menge{idx:Konvexität!Menge} mal Preis“, wenn beide entschieden werden | $x \cdot y$ ist weder konvex noch konkav |
|
||||
| **Ja/Nein mal Menge** | Anlage läuft *und* wie stark | ganzzahlig + nichtlinear = MINLP |
|
||||
| **Verhältnisse** | Auslastungsgrad, Rendite je eingesetztem Euro | Quotienten sind selten konvex |
|
||||
|
||||
|
|
@ -1124,9 +1124,9 @@ schwierigste der in diesem Buch behandelten Klassen. Dafür gibt es eigene Werkz
|
|||
|
||||
| Werkzeug | Art | Was es leistet |
|
||||
| --- | --- | --- |
|
||||
| **Ipopt** (über `cyipopt` oder Pyomo) | lokaler NLP-Solver | Innere-Punkte-Verfahren für große, glatte NLPs mit tausenden Variablen — deutlich leistungsfähiger als `scipy`, aber ebenfalls **nur lokal** |
|
||||
| **Ipopt** (über `cyipopt` oder Pyomo{idx:Pyomo}) | lokaler NLP-Solver | Innere-Punkte-Verfahren für große, glatte NLPs mit tausenden Variablen — deutlich leistungsfähiger als `scipy`, aber ebenfalls **nur lokal** |
|
||||
| **Bonmin**, **Couenne** | MINLP | Bonmin lokal, Couenne mit globaler Garantie für viele Klassen |
|
||||
| **SCIP**, **BARON**, **Gurobi** | global | Beweisbar globales Optimum, mit entsprechendem Rechenaufwand |
|
||||
| **SCIP**{idx:SCIP}, **BARON**, **Gurobi**{idx:Gurobi} | global | Beweisbar globales Optimum, mit entsprechendem Rechenaufwand |
|
||||
| **Pyomo** ({ref:sec:oekosystem-pyomo-linopy}) | Modellierungsschicht | Bindet alle oben genannten an, ohne dass das Modell umgeschrieben werden muss |
|
||||
|
||||
> **⚠️ Zu diesem Abschnitt gehört kein lauffähiges Programm.** Ipopt, Bonmin und Couenne
|
||||
|
|
@ -1200,7 +1200,7 @@ korrelieren?)
|
|||
**Aufgabe ⭐⭐⭐ — Effekt der Gewichtung untersuchen.**
|
||||
Variieren Sie in `Entropie_Maximierte_Allokation.py` systematisch $\alpha \in
|
||||
\{0{,}1;\ 0{,}5;\ 1;\ 5\}$ und $\beta \in \{0;\ 0{,}005;\ 0{,}015;\ 0{,}05\}$. Stellen Sie
|
||||
für jede Kombination Rendite, Volatilität und Entropie in einer Tabelle dar.
|
||||
für jede Kombination Rendite, Volatilität{idx:Volatilität} und Entropie in einer Tabelle dar.
|
||||
(a) Wie verändert $\beta$ die Konzentration im Krypto-Titel?
|
||||
(b) Ab welchem $\beta$ nähert sich die Lösung der Gleichgewichtung?
|
||||
(c) Was ist Ihre Empfehlung — und mit welcher Begründung würden Sie sie einem
|
||||
|
|
@ -1349,7 +1349,7 @@ groß ist der Unterschied zwischen bestem und schlechtestem Ergebnis? Kann die
|
|||
Nachkommastelle. „Bester Wert aus 200 Startpunkten, Spanne bis …“ ist belastbar, ein
|
||||
einzelner Wert ist es nicht.
|
||||
|
||||
**Ausblick.** {ref:kap:unsicherheit} gibt die Annahme auf, dass die Parameter überhaupt bekannt sind. Wir
|
||||
**Ausblick.** {ref:kap:unsicherheit} gibt die Annahme auf, dass die Parameter{idx:Parameter (Modell)} überhaupt bekannt sind. Wir
|
||||
lernen, mit Szenarien, Erwartungswerten und Worst Cases umzugehen.
|
||||
|
||||
---
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
> **📌 Kapitel auf einen Blick**
|
||||
>
|
||||
> **Worum geht es?** Bisher waren alle Parameter bekannt. In der Realität sind Nachfrage,
|
||||
> **Worum geht es?** Bisher waren alle Parameter{idx:Parameter (Modell)} bekannt. In der Realität sind Nachfrage,
|
||||
> Rendite und Fahrzeit **Zufallsgrößen**. Dieses Kapitel zeigt vier Wege, damit umzugehen —
|
||||
> und warum „einfach den Mittelwert einsetzen“ der schlechteste davon ist.
|
||||
>
|
||||
|
|
@ -114,8 +114,8 @@ Nach diesem Kapitel können Sie …
|
|||
1. … den **Fluch des Durchschnitts**{idx:Fluch des Durchschnitts} (*Flaw of Averages*) an einem Beispiel erklären.
|
||||
2. … ein **zweistufiges stochastisches Programm** mit Recourse formulieren.
|
||||
3. … Monte-Carlo einsetzen, um Verteilungen statt Punktschätzungen zu bewerten.
|
||||
4. … ein **robustes** Modell mit Unsicherheitsmenge aufstellen und seinen Preis beziffern.
|
||||
5. … eine **Wahrscheinlichkeitszusage** („mit 95 % Sicherheit“) als Chance Constraint
|
||||
4. … ein **robustes** Modell mit Unsicherheitsmenge{idx:Unsicherheitsmenge} aufstellen und seinen Preis beziffern.
|
||||
5. … eine **Wahrscheinlichkeitszusage** („mit 95 % Sicherheit“) als Chance Constraint{idx:Chance Constraint}
|
||||
schreiben — analytisch als Kegelbedingung oder szenariobasiert mit Big-M — und den Preis
|
||||
eines Prozentpunkts Sicherheit beziffern.
|
||||
6. … begründen, welcher der vier Ansätze für ein gegebenes Problem passt.
|
||||
|
|
@ -274,9 +274,9 @@ Erwartungswert der Kosten ist größer als die Kosten des Erwartungswerts.
|
|||
|
||||

|
||||
|
||||
| | **Monte-Carlo** | **Stochastische Programmierung** | **Robuste Optimierung** | **Chance Constraints** |
|
||||
| | **Monte-Carlo** | **Stochastische Programmierung**{idx:Stochastische Programmierung} | **Robuste Optimierung**{idx:Robuste Optimierung} | **Chance Constraints** |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Braucht | Verteilung | Szenarien **mit Wahrscheinlichkeiten** | nur eine **Menge** möglicher Werte | Verteilung **oder** Szenarien |
|
||||
| Braucht | Verteilung | Szenarien **mit Wahrscheinlichkeiten** | nur eine **Menge**{idx:Konvexität!Menge} möglicher Werte | Verteilung **oder** Szenarien |
|
||||
| Optimiert | nichts (bewertet nur) | **Erwartungswert** über Szenarien | **Worst Case** in der Menge | Kosten bei **zugesicherter Quote** |
|
||||
| Typische Frage | „Wie riskant ist dieser Plan?“ | „Was ist im Mittel am besten?“ | „Was hält auch im schlimmsten Fall?“ | „Was hält in 95 % der Fälle?“ |
|
||||
| Stärke | beliebige Kennzahlen, sehr flexibel | nutzt Wahrscheinlichkeiten voll aus | keine Verteilungsannahme nötig | die Zusage steht **im Modell** |
|
||||
|
|
@ -290,7 +290,7 @@ macht damit verhandelbar, was die Sicherheit kosten darf.
|
|||
|
||||
---
|
||||
|
||||
## Monte-Carlo-Simulation {#sec:unsicherheit-monte-carlo-simulation}
|
||||
## Monte-Carlo-Simulation{idx:Monte-Carlo-Simulation} {#sec:unsicherheit-monte-carlo-simulation}
|
||||
|
||||
**Monte-Carlo**{idx:Monte-Carlo-Simulation} heißt schlicht: Ziehe sehr viele Zufallsszenarien, werte für jedes den Plan
|
||||
aus, und betrachte die **Verteilung** der Ergebnisse statt eines einzigen Werts.
|
||||
|
|
@ -662,7 +662,7 @@ Prognosen tatsächlich — anders als in dem Beispiel aus der Aufgabe *EVPI inte
|
|||
|
||||
---
|
||||
|
||||
## Robuste Optimierung: gegen den Worst Case absichern {#sec:unsicherheit-robuste-optimierung-gegen-den-worst-case}
|
||||
## Robuste Optimierung{idx:Robuste Optimierung}: gegen den Worst Case absichern {#sec:unsicherheit-robuste-optimierung-gegen-den-worst-case}
|
||||
|
||||
Wenn Wahrscheinlichkeiten unbekannt oder instabil sind — Marktcrashs, Lieferkettenabrisse,
|
||||
Pandemien —, hilft die **robuste Optimierung**{idx:Robuste Optimierung}. Sie fragt nicht nach dem Mittel, sondern
|
||||
|
|
@ -856,19 +856,19 @@ z_{1-\alpha} = \Phi^{-1}(1-\alpha)
|
|||
$$
|
||||
|
||||
Das ist eine **Second-Order-Cone-Bedingung**{idx:Konische Optimierung (SOCP, SDP)} — dieselbe
|
||||
Bauform, die {ref:kap:qp-nlp} eingeführt hat, und CVXPY löst sie ohne Umstände.
|
||||
Bauform, die {ref:kap:qp-nlp} eingeführt hat, und CVXPY{idx:CVXPY} löst sie ohne Umstände.
|
||||
|
||||
> **🎯 Warum eine Norm und keine Summe**
|
||||
> Der Sicherheitszuschlag $\lVert\mathbf{L}^\top\mathbf{x}\rVert_2$ ist **keine** Summe von
|
||||
> Einzelzuschlägen je Anlage. Genau darin steckt der Nutzen der Mischung: Zwei gegenläufige
|
||||
> Quellen schwanken **gemeinsam** weniger als jede für sich, und die Norm rechnet das
|
||||
> automatisch mit. Ein fester Aufschlag je Anlage könnte das nicht — er wäre linear und
|
||||
> würde Diversifikation nicht belohnen.
|
||||
> würde Diversifikation{idx:Diversifikation} nicht belohnen.
|
||||
|
||||
### Weg 2: Szenarien — Big-M ohne Verteilungsannahme
|
||||
|
||||
Liegen statt einer Verteilung nur $S$ beobachtete Szenarien vor, bekommt jedes eine
|
||||
Binärvariable $z_s$, die sagt, ob es verletzt werden **darf**:
|
||||
Binärvariable{idx:Binärvariable} $z_s$, die sagt, ob es verletzt werden **darf**:
|
||||
|
||||
$$
|
||||
\begin{aligned}
|
||||
|
|
@ -1203,11 +1203,11 @@ Verteilung.** Der Plan verspricht 95 % und hält **87,4 %**. Nicht weil das Verf
|
|||
rechnet: In einer reinen Normalwelt liefert derselbe Plan exakt seine 95,0 %. Sondern weil
|
||||
die Normalverteilung eine Kältewelle mit Dunkelflaute nicht kennt. In der bricht **alles
|
||||
zugleich** ein — auch das Gaskraftwerk, weil bei Frost der Netzdruck fällt. Eine
|
||||
Kovarianzmatrix mit Korrelationen um null kann so etwas nicht ausdrücken.
|
||||
Kovarianzmatrix{idx:Kovarianzmatrix} mit Korrelationen um null kann so etwas nicht ausdrücken.
|
||||
|
||||
Der szenariobasierte Weg kennt diese Fälle, weil sie in den Daten stehen. Er kommt auf
|
||||
94,8 %, kostet dafür 16,7 % mehr — und kauft **keine Windkraft mehr**. Die Logik dahinter ist
|
||||
hart und richtig: Was im Ernstfall ausfällt, hilft der Zusage nicht.
|
||||
hart{idx:Nebenbedingung!hart} und richtig: Was im Ernstfall ausfällt, hilft der Zusage nicht.
|
||||
|
||||
> **⚠️ Die Szenariomethode überanpasst — und mehr Szenarien helfen nicht verlässlich**
|
||||
> Bei $S$ Szenarien und $\alpha = 5\,\%$ darf das Modell genau $0{,}05 \cdot S$ davon
|
||||
|
|
@ -1336,7 +1336,7 @@ das lässt sich in CVXPY mit `cp.sum_largest` formulieren.)
|
|||
> {ref:sec:unsicherheit-schnellstart} führt der Mittelwert in die Irre, weil die **Kosten**
|
||||
> asymmetrisch sind. Hier führt er in die Irre, weil die **Verknüpfung** asymmetrisch ist:
|
||||
> Ein Gewerk, das früher fertig wird, hilft niemandem — ein Gewerk, das sich verspätet,
|
||||
> verzögert alles. Beide Male gilt: *Der Mittelwert einer Funktion ist nicht die Funktion
|
||||
> verzögert alles. Beide Male gilt: *Der Mittelwert einer Funktion{idx:Konvexität!Funktion} ist nicht die Funktion
|
||||
> des Mittelwerts.*
|
||||
|
||||
---
|
||||
|
|
@ -1368,7 +1368,7 @@ das lässt sich in CVXPY mit `cp.sum_largest` formulieren.)
|
|||
> und rechnet deterministisch. Wann ist das unproblematisch?**
|
||||
> (a) Immer — der Erwartungswert ist die beste Einzelschätzung.
|
||||
> (b) Nie.
|
||||
> (c) Wenn Zielfunktion und Nebenbedingungen in den unsicheren Größen **linear** sind und
|
||||
> (c) Wenn Zielfunktion{idx:Zielfunktion} und Nebenbedingungen in den unsicheren Größen **linear** sind und
|
||||
> keine Entscheidung erst nach Beobachtung fällt. Sobald Minimum, Maximum, Betrag oder eine
|
||||
> Nachbesserungsentscheidung im Spiel ist, gilt es nicht mehr.
|
||||
|
||||
|
|
@ -1421,7 +1421,7 @@ das lässt sich in CVXPY mit `cp.sum_largest` formulieren.)
|
|||
Entscheidung nicht begründbar.
|
||||
|
||||
**Ausblick.** {ref:kap:dynamische-programmierung} fügt die Zeitdimension hinzu: Entscheidungen, die über viele
|
||||
Perioden aufeinander aufbauen — gelöst mit der Bellman-Gleichung.
|
||||
Perioden aufeinander aufbauen — gelöst mit der Bellman-Gleichung{idx:Bellman-Gleichung}.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Kapitel: Dynamische Programmierung — Die Bellman-Gleichung und Order-Execution {#kap:dynamische-programmierung}
|
||||
# Kapitel: Dynamische Programmierung — Die Bellman-Gleichung{idx:Bellman-Gleichung} und Order-Execution {#kap:dynamische-programmierung}
|
||||
|
||||
> **📌 Kapitel auf einen Blick**
|
||||
>
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
> **Voraussetzungen:** {ref:kap:unsicherheit} (Erwartungswerte). Rekursion in Python.
|
||||
>
|
||||
> **Danach können Sie:** Ein mehrperiodiges Problem in Zustände und Stufen zerlegen, die
|
||||
> Wertfunktion durch Rückwärtsinduktion berechnen, die optimale Strategie ableiten — und
|
||||
> Wertfunktion durch Rückwärtsinduktion{idx:Rückwärtsinduktion} berechnen, die optimale Strategie ableiten — und
|
||||
> prüfen, ob Ihr Zustand vollständig genug ist.
|
||||
>
|
||||
> **Zeitbedarf:** ca. 5 Stunden.
|
||||
|
|
@ -85,7 +85,7 @@ zusätzlichen bezahlt.
|
|||
|
||||
**Warum funktioniert das?** Weil man den Rest des Weges nicht neu durchdenken muss, sobald
|
||||
man einmal an einem Ort steht: Wie man dorthin gekommen ist, ist für die Zukunft egal. Diese
|
||||
Eigenschaft heißt **Bellmansches Optimalitätsprinzip** und ist der Grund, warum aus einem
|
||||
Eigenschaft heißt **Bellmansches Optimalitätsprinzip**{idx:Optimalitätsprinzip} und ist der Grund, warum aus einem
|
||||
Problem mit exponentiell vielen Wegen eine Rechnung mit wenigen Zeilen wird. Bei fünf Orten
|
||||
fällt das kaum auf — bei fünfzig ist es der Unterschied zwischen Sekunden und Jahren.
|
||||
|
||||
|
|
@ -99,10 +99,10 @@ Nach diesem Kapitel können Sie …
|
|||
2. … Zustand, Stufe, Aktion und Wertfunktion für ein gegebenes Problem benennen.
|
||||
3. … eine Rückwärtsinduktion{idx:Rückwärtsinduktion} von Hand für ein kleines Problem durchführen.
|
||||
4. … das Almgren-Chriss-Ausführungsproblem lösen und die Lösung interpretieren.
|
||||
5. … einschätzen, wann DP funktioniert und wann der „Fluch der Dimensionalität“ zuschlägt.
|
||||
5. … einschätzen, wann DP funktioniert und wann der „Fluch der Dimensionalität{idx:Fluch der Dimensionalität}“ zuschlägt.
|
||||
6. … die Wertfunktion als **Nachschlagetabelle** lesen: Sie liefert keine Planfolge, sondern
|
||||
eine Regel, die auch bei Abweichungen gilt.
|
||||
7. … einen Zustandsraum auf Vollständigkeit prüfen und erkennen, wann eine Kostenart
|
||||
7. … einen Zustandsraum{idx:Zustandsraum} auf Vollständigkeit prüfen und erkennen, wann eine Kostenart
|
||||
Vorgeschichte erfordert.
|
||||
|
||||
---
|
||||
|
|
@ -328,13 +328,13 @@ C(n_t, X_t) = \underbrace{\eta\,n_t^2}_{\text{Marktauswirkung}} \;+\; \underbrac
|
|||
$$
|
||||
|
||||
> **📐 Formel-Lesehilfe**
|
||||
> * $n_t$ — in Periode $t$ verkaufte Stückzahl. Quadriert, weil doppelte Menge mehr als
|
||||
> * $n_t$ — in Periode $t$ verkaufte Stückzahl. Quadriert, weil doppelte Menge{idx:Konvexität!Menge} mehr als
|
||||
> doppelten Preisdruck erzeugt.
|
||||
> * $\eta$ („eta“) — Slippage-Koeffizient. Wie stark reagiert der Markt auf Volumen?
|
||||
> * $X_t$ — Restbestand **nach** dem Verkauf. Quadriert, weil Varianz quadratisch mit der
|
||||
> Positionsgröße wächst.
|
||||
> * $\lambda$ — Risikoaversion: Wie sehr stört mich Schwankung im Vergleich zu Slippage?
|
||||
> * $\sigma$ — Volatilität je Periode.
|
||||
> * $\sigma$ — Volatilität{idx:Volatilität} je Periode.
|
||||
>
|
||||
> **Ohne Formel gesagt:** „Schnell verkaufen kostet Preisabschlag. Langsam verkaufen kostet
|
||||
> Nervenkitzel. Finde die Mitte.“
|
||||
|
|
@ -352,7 +352,7 @@ $$
|
|||
> holding_risk = risk_aversion * (sigma_period ** 2) * (remaining ** 2) * 1e5
|
||||
> ```
|
||||
> Woher eine solche Zahl kommt, bleibt dann unklar. Faktisch wirkt sie als versteckte
|
||||
> Erhöhung der Risikoaversion um fünf Größenordnungen — ein Parameter wie
|
||||
> Erhöhung der Risikoaversion um fünf Größenordnungen — ein Parameter{idx:Parameter (Modell)} wie
|
||||
> `risk_aversion = 1e-6` würde dann in Wahrheit $0{,}1$ bedeuten. Solche „magischen
|
||||
> Zahlen“ machen ein Modell unkalibrierbar: Niemand kann sagen, ob 1e-6 viel oder wenig
|
||||
> ist.
|
||||
|
|
@ -693,7 +693,7 @@ Zustandsvariable **multipliziert** den Aufwand.
|
|||
|
||||
**Gegenmittel:**
|
||||
* **Zustandsraum**{idx:Zustandsraum} **verkleinern:** gröber diskretisieren, irrelevante Variablen weglassen.
|
||||
* **Approximate Dynamic Programming**{idx:Dynamische Programmierung!Approximate Dynamic Programming}**:** $V_t$ durch eine parametrische Funktion annähern
|
||||
* **Approximate Dynamic Programming**{idx:Dynamische Programmierung!Approximate Dynamic Programming}**:** $V_t$ durch eine parametrische Funktion{idx:Konvexität!Funktion} annähern
|
||||
statt tabellarisch zu speichern.
|
||||
* **Reinforcement Learning**{idx:Reinforcement Learning}**:** dieselbe Bellman-Gleichung{idx:Bellman-Gleichung}, aber $V$ wird aus Erfahrung
|
||||
gelernt (Q-Learning{idx:Q-Learning}) statt vollständig berechnet.
|
||||
|
|
@ -720,7 +720,7 @@ nicht nur vom aktuellen Zustand)?
|
|||
Wertfunktionstabelle und bestimmen Sie den optimalen Pfad. Prüfen Sie mit
|
||||
`Bellman_Minimalbeispiel.py` (angepasst).
|
||||
|
||||
**Aufgabe ⭐⭐ — Rucksackproblem als DP.**
|
||||
**Aufgabe ⭐⭐ — Rucksackproblem{idx:Rucksackproblem} als DP.**
|
||||
Lösen Sie das Rucksackproblem aus {ref:kap:milp} mit dynamischer Programmierung statt MILP.
|
||||
(Zustand: verbleibende Kapazität; Stufe: betrachteter Gegenstand.) Vergleichen Sie
|
||||
Laufzeit und Ergebnis mit dem MILP-Solver.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
> {ref:kap:milp}. Für den Denkfehler hilft {ref:kap:markowitz}.
|
||||
>
|
||||
> **Danach können Sie:** begründen, warum eine gewichtete Summe bei ganzzahligen Modellen
|
||||
> Kompromisse **grundsätzlich** nicht erreichen kann; eine vollständige Pareto-Front mit dem
|
||||
> Kompromisse **grundsätzlich** nicht erreichen kann; eine vollständige Pareto-Front{idx:Pareto-Front} mit dem
|
||||
> ε-Constraint-Verfahren berechnen; und einer Geschäftsführung eine Entscheidung vorlegen,
|
||||
> die sie tatsächlich treffen kann.
|
||||
>
|
||||
|
|
@ -128,7 +128,7 @@ $$
|
|||
|
||||
> **📖 Definition: Pareto-Front**{idx:Pareto-Front}
|
||||
>
|
||||
> Die Menge aller nicht dominierten Lösungen. Sie ist das vollständige Ergebnis eines
|
||||
> Die Menge{idx:Konvexität!Menge} aller nicht dominierten Lösungen. Sie ist das vollständige Ergebnis eines
|
||||
> Mehrzielproblems — nicht ein Punkt, sondern eine Liste.
|
||||
>
|
||||
> Wer daraus einen einzelnen Punkt macht, trifft eine Entscheidung. Die Frage ist nur, ob er
|
||||
|
|
@ -645,7 +645,7 @@ Eine Front mit zehn Punkten ist kein Ergebnis, sondern eine Speisekarte. Damit s
|
|||
entscheidbar wird, gehört eine Spalte dazu, die im Programm `EUR je kg` heißt:
|
||||
|
||||
$$
|
||||
\text{Schattenpreis} = \frac{\text{Aufpreis gegenüber dem Kostenminimum}}
|
||||
\text{Schattenpreis{idx:Schattenpreis}} = \frac{\text{Aufpreis gegenüber dem Kostenminimum}}
|
||||
{\text{eingesparte Kilogramm}}
|
||||
$$
|
||||
|
||||
|
|
@ -657,7 +657,7 @@ kaufmännisch schon getroffen.
|
|||
>
|
||||
> | Stelle | Was sie tut |
|
||||
> | --- | --- |
|
||||
> | `plane(ziel, co2_grenze, kosten_grenze)` | **eine** Funktion für alle Varianten. Welches Ziel und welche Schranke — mehr Unterschied gibt es zwischen den fünf Teilen des Programms nicht |
|
||||
> | `plane(ziel, co2_grenze, kosten_grenze)` | **eine** Funktion{idx:Konvexität!Funktion} für alle Varianten. Welches Ziel und welche Schranke — mehr Unterschied gibt es zwischen den fünf Teilen des Programms nicht |
|
||||
> | `pareto_front()` | das ε-Verfahren: Grenze jeweils um 1 kg unter den zuletzt erreichten Wert drücken, bis nichts mehr geht |
|
||||
> | `untere_huelle()` | rechnet die Hülle **unabhängig** aus, damit die Aussage „unerreichbar“ nicht auf dem Gewichtsraster beruht, sondern auf Geometrie |
|
||||
>
|
||||
|
|
@ -683,7 +683,7 @@ würden Sie empfehlen — und wie begründen Sie ihn in einem Satz?
|
|||
Erhöhen Sie `BAHN_TRASSEN` von 5 auf 8. Was passiert mit der Länge der Front und mit der
|
||||
Zahl der unerreichbaren Punkte? Erklären Sie den Zusammenhang.
|
||||
|
||||
**Aufgabe ⭐⭐ — Die Front der Relaxation.**
|
||||
**Aufgabe ⭐⭐ — Die Front der Relaxation{idx:Relaxation}.**
|
||||
Lassen Sie `integrality` weg, sodass Anteile erlaubt sind. Berechnen Sie die Front erneut
|
||||
(mit einem ε-Raster, da es nun unendlich viele Punkte gibt). Wie viele Punkte liegen jetzt
|
||||
oberhalb der konvexen Hülle — und warum?
|
||||
|
|
@ -771,4 +771,4 @@ einer Fläche. Wie ändert sich das ε-Verfahren, und warum wächst der Aufwand
|
|||
|
||||
---
|
||||
|
||||
*Weiter mit:* [{ref:kap:prognose} — Predict-then-Optimize](34_Predict_then_Optimize.md)
|
||||
*Weiter mit:* [{ref:kap:prognose} — Predict-then-Optimize{idx:Predict-then-Optimize}](34_Predict_then_Optimize.md)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Kapitel: Predict-then-Optimize — die bessere Prognose, die schlechtere Entscheidung {#kap:prognose}
|
||||
# Kapitel: Predict-then-Optimize{idx:Predict-then-Optimize} — die bessere Prognose, die schlechtere Entscheidung {#kap:prognose}
|
||||
|
||||
> **📌 Kapitel auf einen Blick**
|
||||
>
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
> Ein Modell **prognostiziert**, ein anderes **entscheidet**. Beide arbeiten sauber — und
|
||||
> genau an der Naht entsteht ein Fehler, den keine der beiden Seiten sieht.
|
||||
>
|
||||
> **Voraussetzungen:** {ref:kap:unsicherheit}, insbesondere das Newsvendor-Problem und das
|
||||
> **Voraussetzungen:** {ref:kap:unsicherheit}, insbesondere das Newsvendor-Problem{idx:Newsvendor-Problem} und das
|
||||
> kritische Verhältnis. Etwas Regression hilft, ist aber nicht nötig.
|
||||
>
|
||||
> **Danach können Sie:** begründen, warum ein Prognosemodell mit kleinerem MSE teurere
|
||||
|
|
@ -61,7 +61,7 @@ derselben Daten, aus denen auch das Quantil kommt. Trotzdem kostet er **7,20 €
|
|||
gut 10 %.
|
||||
|
||||
Der Grund steht in den Preisen: Ein fehlendes Brot kostet doppelt so viel wie ein übriges.
|
||||
Bei asymmetrischen Kosten liegt die optimale Menge nicht in der Mitte der Verteilung,
|
||||
Bei asymmetrischen Kosten liegt die optimale Menge{idx:Konvexität!Menge} nicht in der Mitte der Verteilung,
|
||||
sondern beim **kritischen Verhältnis** $c_-/(c_- + c_+) = 6/9 = 66{,}7\,\%$ — das kennen Sie
|
||||
aus {ref:kap:unsicherheit}.
|
||||
|
||||
|
|
@ -578,7 +578,7 @@ Die dritte Zeile der Ergebnistabelle — „Zuschlag auf Kosten trainiert" — i
|
|||
denkbare Form einer Idee, die derzeit erforscht wird: **das Prognosemodell direkt auf die
|
||||
Entscheidungskosten zu trainieren** statt auf ein Fehlermaß.
|
||||
|
||||
Hier war es ein einziger Parameter, mit einer Rasterschleife bestimmt. Der allgemeine Fall
|
||||
Hier war es ein einziger Parameter{idx:Parameter (Modell)}, mit einer Rasterschleife bestimmt. Der allgemeine Fall
|
||||
ist schwieriger, weil die Optimierung zwischen Modell und Kosten steht: Um den Gradienten
|
||||
der Kosten nach den Modellparametern zu bilden, muss man **durch das Optimierungsproblem
|
||||
hindurch ableiten**.
|
||||
|
|
@ -631,7 +631,7 @@ und zwar **in unterschiedlichem Ausmaß**? Was sagt das über den Wert eines Mer
|
|||
>
|
||||
> Ein Data-Science-Team stellt sein Quartalsergebnis vor:
|
||||
>
|
||||
> > *„Wir haben das alte lineare Modell durch ein Gradient-Boosting-Modell ersetzt. Der MSE
|
||||
> > *„Wir haben das alte lineare Modell durch ein Gradient{idx:Gradient}-Boosting-Modell ersetzt. Der MSE
|
||||
> > auf den Testdaten ist um 18 % gesunken, der MAPE um 14 %. Das ist die größte
|
||||
> > Prognoseverbesserung, die wir je erreicht haben. Die Disposition bekommt ab nächstem
|
||||
> > Monat die neuen Werte."*
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ Er hat drei Abschnitte, und Sie können nach jedem aufhören:
|
|||
> ersten beiden Kapitel dieses Teils und kann den Rest überspringen, ohne dass etwas
|
||||
> fehlt — die Methoden sind dieselben.
|
||||
>
|
||||
> **Lesen Sie ihn trotzdem, wenn Sie eines der folgenden Themen brauchen:** Schätzfehler in
|
||||
> **Lesen Sie ihn trotzdem, wenn Sie eines der folgenden Themen brauchen:** Schätzfehler{idx:Schätzfehler} in
|
||||
> Kovarianzmatrizen (das Problem tritt bei jeder Korrelationsschätzung auf, auch bei
|
||||
> Lieferzeiten), Risikomaße jenseits der Standardabweichung, oder rollierende Auswertung
|
||||
> mit sauberer Trennung von Trainings- und Testzeitraum.
|
||||
|
|
@ -114,7 +114,7 @@ Der interessanteste Teil steht in der zweiten Zeile der Ausgabe. **60,26 € je
|
|||
Risikobudget** — das ist der Dualwert derselben Nebenbedingung, die in der Werkstatt sagt,
|
||||
was eine zusätzliche Montagestunde wert wäre. In der Finanzwelt hat diese Zahl einen eigenen
|
||||
Namen: der **Preis des Risikos**. Es ist nicht bloß eine Analogie, es ist derselbe
|
||||
Schattenpreis aus {ref:kap:lp}.
|
||||
Schattenpreis{idx:Schattenpreis} aus {ref:kap:lp}.
|
||||
|
||||
> **🎯 Merksatz**
|
||||
> Wenn zwei Probleme dieselbe Struktur haben, brauchen sie nicht zwei Modelle, sondern zwei
|
||||
|
|
@ -122,7 +122,7 @@ Schattenpreis aus {ref:kap:lp}.
|
|||
> — nicht daran, dass eine Tabelle es behauptet.
|
||||
|
||||
**Warum funktioniert das?** Weil ein LP nichts über die Bedeutung seiner Zahlen weiß. Es
|
||||
sieht eine Matrix, einen Kapazitätsvektor und einen Zielvektor. Ob in der Matrix Stunden,
|
||||
sieht eine Matrix, einen Kapazitätsvektor{idx:Kapazitätsvektor} und einen Zielvektor. Ob in der Matrix Stunden,
|
||||
Kilogramm oder Risikobeiträge stehen, kommt darin nicht vor.
|
||||
|
||||
---
|
||||
|
|
@ -646,7 +646,7 @@ Gebühr um 10 Einheiten zu erhöhen. Bis zu welcher Gebühr lohnt sich das — u
|
|||
Einschränkung dieser Aussage kennen Sie aus {ref:sec:lp-entartung}?
|
||||
|
||||
**Aufgabe ⭐⭐ — Die Brücke rückwärts.**
|
||||
Übertragen Sie die Ledoit-Wolf-Shrinkage aus {ref:kap:finanzdaten} auf Lieferzeiten:
|
||||
Übertragen Sie die Ledoit-Wolf-Shrinkage{idx:Ledoit-Wolf-Shrinkage} aus {ref:kap:finanzdaten} auf Lieferzeiten:
|
||||
Wo genau träte dort dasselbe Problem auf, und welche Daten bräuchten Sie?
|
||||
|
||||
**Aufgabe ⭐⭐ — CVaR mit Ganzzahligkeit.**
|
||||
|
|
@ -670,7 +670,7 @@ trägt — und schreiben Sie auf, welche der drei Zeilen im Weg steht.
|
|||
> geht vor wie im Portfoliomanagement:
|
||||
>
|
||||
> > *„Ich habe für jeden Lieferanten aus den letzten drei Jahren die mittlere Lieferzeit und
|
||||
> > die Kovarianzmatrix der Lieferzeiten geschätzt. Dann habe ich das Markowitz-Modell
|
||||
> > die Kovarianzmatrix{idx:Kovarianzmatrix} der Lieferzeiten geschätzt. Dann habe ich das Markowitz-Modell
|
||||
> > angewendet: minimiere die Varianz der Gesamtlieferzeit bei vorgegebener mittlerer
|
||||
> > Lieferzeit. Das Ergebnis ist ein sauber diversifiziertes Lieferantenportfolio."*
|
||||
>
|
||||
|
|
@ -723,7 +723,7 @@ trägt — und schreiben Sie auf, welche der drei Zeilen im Weg steht.
|
|||
## Zusammenfassung {#sec:bruecke-zusammenfassung}
|
||||
|
||||
* Die Behauptung „dieselben Methoden, andere Domäne" ist prüfbar — und hier geprüft: Ein
|
||||
Depot passt unverändert in die Klasse `Produktionsproblem`, und **eine** CVaR-Funktion
|
||||
Depot passt unverändert in die Klasse `Produktionsproblem`, und **eine** CVaR-Funktion{idx:Konvexität!Funktion}
|
||||
bearbeitet Kursverluste wie Lieferverzüge.
|
||||
* Der **Schattenpreis** einer Ressource heißt in der Finanzwelt *Preis des Risikos*. Es ist
|
||||
derselbe Dualwert derselben Nebenbedingung.
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ hinaus:
|
|||
| **1** | Welcher Block läuft in welcher Stunde? | **binär**, für alle Szenarien gleich | am Vorabend, bevor der Wind bekannt ist |
|
||||
| **2** | Wie viel liefert jeder laufende Block? | kontinuierlich, je Szenario verschieden | am Tag selbst, laufend anpassbar |
|
||||
|
||||
Im Kapitel Unsicherheit war die erste Stufe kontinuierlich (Kapazität kaufen, Menge
|
||||
Im Kapitel Unsicherheit war die erste Stufe kontinuierlich (Kapazität kaufen, Menge{idx:Konvexität!Menge}
|
||||
festlegen). Hier ist sie **ganzzahlig** — und das ändert die Sache grundlegend: Eine
|
||||
Kapazität lässt sich anteilig erhöhen, ein Kraftwerk nicht zu 30 % anfahren.
|
||||
|
||||
|
|
@ -710,7 +710,7 @@ Ergänzen Sie einen Batteriespeicher (100 MW, 400 MWh, Wirkungsgrad 90 %). Um wi
|
|||
die erwarteten Kosten — und was ist der Speicher damit je MWh Kapazität wert?
|
||||
|
||||
**Aufgabe ⭐⭐⭐ — Wenn es größer wird.**
|
||||
Erhöhen Sie auf 20 Blöcke und 168 Stunden (eine Woche). Beobachten Sie MIP-Gap und
|
||||
Erhöhen Sie auf 20 Blöcke und 168 Stunden (eine Woche). Beobachten Sie MIP-Gap{idx:MIP-Gap} und
|
||||
Rechenzeit ({ref:sec:milp-gap}). Ab wann wird das Problem für den exakten Solver zu groß —
|
||||
und welches Verfahren aus {ref:kap:metaheuristiken} würden Sie einsetzen?
|
||||
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ die Kapitel danach, **welche** Voraussetzung bei Ihnen verletzt ist.
|
|||
| --- | --- | --- | --- |
|
||||
| **Linearität** | Risiko wächst quadratisch, Kosten degressiv, Sättigung | QP, konvexe Optimierung, KKT | {ref:kap:qp-nlp} |
|
||||
| **Feste Daten** | Nachfrage, Wind, Rendite stehen erst morgen fest | Monte-Carlo, Zweistufigkeit, Robustheit, Chance Constraints | {ref:kap:unsicherheit} |
|
||||
| **Eine Periode** | die Entscheidung heute verändert, was übermorgen möglich ist | Bellman-Gleichung, Rückwärtsinduktion | {ref:kap:dynamische-programmierung} |
|
||||
| **Ein Ziel** | zwei Kennzahlen sollen gleichzeitig stimmen | Pareto-Front, ε-Constraint | {ref:kap:mehrziel} |
|
||||
| **Daten sind gegeben** | die Eingabe ist selbst eine Prognose | Predict-then-Optimize, entscheidungsorientiertes Lernen | {ref:kap:prognose} |
|
||||
| **Eine Periode** | die Entscheidung heute verändert, was übermorgen möglich ist | Bellman-Gleichung{idx:Bellman-Gleichung}, Rückwärtsinduktion{idx:Rückwärtsinduktion} | {ref:kap:dynamische-programmierung} |
|
||||
| **Ein Ziel** | zwei Kennzahlen sollen gleichzeitig stimmen | Pareto-Front{idx:Pareto-Front}, ε-Constraint | {ref:kap:mehrziel} |
|
||||
| **Daten sind gegeben** | die Eingabe ist selbst eine Prognose | Predict-then-Optimize{idx:Predict-then-Optimize}, entscheidungsorientiertes Lernen | {ref:kap:prognose} |
|
||||
|
||||
Die letzte Zeile ist die unbequemste: Dort ist nicht das Modell unsicher, sondern seine
|
||||
**Eingabe** — und die kommt aus einem zweiten Modell, das nach anderen Kriterien gebaut
|
||||
|
|
@ -32,7 +32,7 @@ wurde.
|
|||
1. **Unsicherheit durch Mittelwerte ersetzen.** Der Durchschnittskunde kauft nie. Bei
|
||||
asymmetrischen Kosten liegt das Optimum systematisch neben dem Mittelwert, und eine
|
||||
Terminzusage ist ein **Quantil**, kein Erwartungswert.
|
||||
2. **Konvexität voraussetzen, ohne sie zu prüfen.** Ohne sie gibt es keine
|
||||
2. **Konvexität{idx:Konvexität} voraussetzen, ohne sie zu prüfen.** Ohne sie gibt es keine
|
||||
Optimalitätsgarantie, sondern nur ein lokales Ergebnis — und der Solver sagt das nicht
|
||||
von selbst.
|
||||
3. **Zwei Ziele mit einem Gewicht verrechnen, bevor die Front bekannt ist.** Ein Gewicht
|
||||
|
|
@ -43,7 +43,7 @@ wurde.
|
|||
|
||||
> **🎯** Jede der vier Annahmen lässt sich einzeln aufgeben — aber jede kostet etwas
|
||||
> Bestimmtes: Linearität kostet die Optimalitätsgarantie, feste Daten kosten Rechenzeit
|
||||
> oder Vorsicht, eine Periode kostet Zustandsraum, ein Ziel kostet eine Entscheidung, die
|
||||
> oder Vorsicht, eine Periode kostet Zustandsraum{idx:Zustandsraum}, ein Ziel kostet eine Entscheidung, die
|
||||
> nicht der Modellierer treffen darf. Wer weiß, **welche** Annahme bei ihm fällt, weiß
|
||||
> auch, welchen Preis er zahlt.
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@
|
|||
> Statistik.
|
||||
>
|
||||
> **Danach können Sie:** Kursdaten korrekt laden, diskrete und logarithmische Renditen
|
||||
> unterscheiden, das Schätzfehlerproblem erklären, Ledoit-Wolf-Shrinkage anwenden — und
|
||||
> erkennen, wann eine Kovarianzmatrix aus zu wenigen Beobachtungen stammt.
|
||||
> unterscheiden, das Schätzfehlerproblem erklären, Ledoit-Wolf-Shrinkage{idx:Ledoit-Wolf-Shrinkage} anwenden — und
|
||||
> erkennen, wann eine Kovarianzmatrix{idx:Kovarianzmatrix} aus zu wenigen Beobachtungen stammt.
|
||||
>
|
||||
> **Zeitbedarf:** ca. 5 Stunden.
|
||||
>
|
||||
|
|
@ -73,7 +73,7 @@ $100 \cdot e^{0{,}1823} = 120{,}00$ — exakt der beobachtete Endkurs.
|
|||
| Verknüpfung über die Zeit | multiplikativ: $\prod(1+r_t)$ | **additiv**: $\sum \ln(1+r_t)$ |
|
||||
| Mitteln zulässig? | nein — führt systematisch zu hoch | ja |
|
||||
| Verknüpfung über Anlagen | **additiv**: $\sum w_i r_i$ | nein (Summe von Logs ≠ Log der Summe) |
|
||||
| Wofür also | Portfoliogewichtung, Kennzahlen je Periode | Zeitreihenanalyse, Volatilität, Modelle |
|
||||
| Wofür also | Portfoliogewichtung, Kennzahlen je Periode | Zeitreihenanalyse, Volatilität{idx:Volatilität}, Modelle |
|
||||
|
||||
> **🎯 Merksatz**
|
||||
> Beide Renditearten sind richtig — für **verschiedene Richtungen**. Diskrete Renditen
|
||||
|
|
@ -94,9 +94,9 @@ Rest dieses Kapitels behandelt die zweite große Fehlerquelle bei Finanzdaten
|
|||
Nach diesem Kapitel können Sie …
|
||||
|
||||
1. … erklären, wann man diskrete und wann logarithmische Renditen verwendet.
|
||||
2. … beschreiben, warum die Stichproben-Kovarianzmatrix bei vielen Titeln unbrauchbar wird.
|
||||
2. … beschreiben, warum die Stichproben-Kovarianzmatrix{idx:Stichproben-Kovarianzmatrix} bei vielen Titeln unbrauchbar wird.
|
||||
3. … den **Error-Maximizer-Effekt**{idx:Error-Maximizer-Effekt} an einem Experiment nachweisen.
|
||||
4. … Ledoit-Wolf-Shrinkage anwenden und ihre Wirkung an Eigenwerten und Konditionszahl
|
||||
4. … Ledoit-Wolf-Shrinkage anwenden und ihre Wirkung an Eigenwerten und Konditionszahl{idx:Konditionszahl}
|
||||
messen.
|
||||
5. … Kursdaten so laden, dass die Spaltenreihenfolge garantiert stimmt.
|
||||
6. … begründen, warum eine Schätzung aus $T < N$ Beobachtungen dem Optimierer risikofreie
|
||||
|
|
@ -111,7 +111,7 @@ Sei $P_{i,t}$ der **bereinigte** Schlusskurs (*adjusted close*){idx:Adjusted Clo
|
|||
$t$. „Bereinigt“ heißt: um Dividenden und Aktiensplits korrigiert — sonst erscheint jede
|
||||
Dividendenzahlung als Kurssturz.
|
||||
|
||||
### Diskrete Rendite
|
||||
### Diskrete Rendite{idx:Diskrete Rendite}
|
||||
|
||||
$$
|
||||
R_{i,t} = \frac{P_{i,t} - P_{i,t-1}}{P_{i,t-1}} = \frac{P_{i,t}}{P_{i,t-1}} - 1
|
||||
|
|
@ -123,7 +123,7 @@ $$
|
|||
R_{p,t} = \sum_{i=1}^n w_i R_{i,t} = \mathbf{w}^\top\mathbf{R}_t
|
||||
$$
|
||||
|
||||
### Logarithmische Rendite
|
||||
### Logarithmische Rendite{idx:Logarithmische Rendite}
|
||||
|
||||
$$
|
||||
r_{i,t} = \ln\!\left(\frac{P_{i,t}}{P_{i,t-1}}\right) = \ln P_{i,t} - \ln P_{i,t-1}
|
||||
|
|
@ -234,7 +234,7 @@ if __name__ == "__main__":
|
|||
|
||||
---
|
||||
|
||||
## Das Schätzfehler-Problem {#sec:finanzdaten-das-schaetzfehler-problem}
|
||||
## Das Schätzfehler{idx:Schätzfehler}-Problem {#sec:finanzdaten-das-schaetzfehler-problem}
|
||||
|
||||
Sei $\mathbf{X}\in\mathbb{R}^{T\times N}$ die Matrix zentrierter Renditen von $N$ Titeln über
|
||||
$T$ Handelstage. Die **Stichproben-Kovarianzmatrix**{idx:Stichproben-Kovarianzmatrix} lautet:
|
||||
|
|
@ -243,7 +243,7 @@ $$
|
|||
\mathbf{S} = \frac{1}{T-1}\mathbf{X}^\top\mathbf{X}
|
||||
$$
|
||||
|
||||
Das Problem: $\mathbf{S}$ hat $\frac{N(N+1)}{2}$ zu schätzende Parameter, aber nur
|
||||
Das Problem: $\mathbf{S}$ hat $\frac{N(N+1)}{2}$ zu schätzende Parameter{idx:Parameter (Modell)}, aber nur
|
||||
$T \cdot N$ Datenpunkte. Bei $N = 50$ Titeln sind das **1275 Parameter** — geschätzt aus
|
||||
einem Jahr Daten ($T = 252$).
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
> **Voraussetzungen:** {ref:kap:qp-nlp} (QP, KKT), {ref:kap:finanzdaten} (Kovarianz, Shrinkage).
|
||||
>
|
||||
> **Danach können Sie:** Die Effizienzgrenze berechnen, das Maximum-Sharpe-Portfolio über
|
||||
> die Korn-Transformation bestimmen, institutionelle Nebenbedingungen einbauen — und
|
||||
> die Korn-Transformation{idx:Korn-Transformation} bestimmen, institutionelle Nebenbedingungen einbauen — und
|
||||
> beurteilen, wann eine Renditeschätzung das Ergebnis wertlos macht.
|
||||
>
|
||||
> **Zeitbedarf:** ca. 6 Stunden.
|
||||
|
|
@ -78,7 +78,7 @@ Lesen Sie die dritte Spalte: Sie zeigt, wie viel Rendite je Einheit Risiko herau
|
|||
* Bei **4 %**: **0,75** — das beste Verhältnis.
|
||||
* Bei 8 %: 0,44 — das renditestärkste Portfolio ist das **schlechteste** je Risikoeinheit.
|
||||
Und es besteht zu 100 % aus Aktien: Wer die höchste Rendite fordert, bekommt zwangsläufig
|
||||
gar keine Diversifikation mehr.
|
||||
gar keine Diversifikation{idx:Diversifikation} mehr.
|
||||
|
||||
Von 3 % auf 8 % Rendite ist ein Zuwachs um Faktor 2,7 — das Risiko steigt dabei um Faktor
|
||||
3,7. Die letzten Prozentpunkte Rendite sind die teuersten.
|
||||
|
|
@ -90,7 +90,7 @@ Von 3 % auf 8 % Rendite ist ein Zuwachs um Faktor 2,7 — das Risiko steigt dabe
|
|||
> sondern eine unternehmerische Frage.
|
||||
|
||||
**Warum funktioniert das?** Weil `cp.Parameter` das Modell nur **einmal** aufbaut und dann
|
||||
sechsmal mit verschiedenen Zielwerten löst. Genau dafür gibt es Parameter in CVXPY: Bei 200
|
||||
sechsmal mit verschiedenen Zielwerten löst. Genau dafür gibt es Parameter{idx:Parameter (Modell)} in CVXPY: Bei 200
|
||||
Punkten auf der Linie spart das den 200-fachen Kompilierungsaufwand
|
||||
({ref:sec:oekosystem-vektorisierung}). Der Rest dieses Kapitels führt die Effizienzlinie
|
||||
sauber aus, zeigt, wie man das beste Verhältnis direkt berechnet statt es abzulesen — und
|
||||
|
|
@ -315,7 +315,7 @@ $$
|
|||
$$
|
||||
|
||||
> **📐 Formel-Lesehilfe**
|
||||
> Zähler: **Überrendite** über den risikolosen Zins $r_f$. Nenner: die Volatilität.
|
||||
> Zähler: **Überrendite** über den risikolosen Zins $r_f$. Nenner: die Volatilität{idx:Volatilität}.
|
||||
>
|
||||
> **Ohne Formel gesagt:** „Wie viel Mehrertrag bekomme ich je Einheit Risiko, die ich
|
||||
> eingehe?“ Eine Sharpe Ratio von 0,8 heißt: Für jeden Prozentpunkt Volatilität gibt es
|
||||
|
|
@ -323,7 +323,7 @@ $$
|
|||
|
||||
### Die Korn-Transformation
|
||||
|
||||
Die Sharpe Ratio ist ein **Bruch** — und damit **nicht konvex**. CVXPY würde sie ablehnen.
|
||||
Die Sharpe Ratio ist ein **Bruch** — und damit **nicht konvex**. CVXPY{idx:CVXPY} würde sie ablehnen.
|
||||
Der Ausweg ist ein eleganter Trick, der die Homogenität des Problems ausnutzt:
|
||||
|
||||
$$
|
||||
|
|
@ -362,7 +362,7 @@ In der Praxis gelten regulatorische und interne Regeln:
|
|||
| **Sektorlimit** | $\sum_{i\in\text{Tech}} w_i \le 0{,}35$ | Branchenkonzentration begrenzen |
|
||||
| **Mindestposition** | $w_i = 0$ oder $w_i \ge w_{\min}$ | Streuverluste vermeiden |
|
||||
| **Kardinalität** | $\sum_i z_i \le K$, $w_i \le M z_i$ | Verwaltungsaufwand begrenzen |
|
||||
| **Turnover-Grenze** | $\|\mathbf{w}-\mathbf{w}_{\text{alt}}\|_1 \le \tau$ | Transaktionskosten dämpfen |
|
||||
| **Turnover-Grenze** | $\|\mathbf{w}-\mathbf{w}_{\text{alt}}\|_1 \le \tau$ | Transaktionskosten{idx:Transaktionskosten} dämpfen |
|
||||
|
||||
### Was diese Regeln kosten
|
||||
|
||||
|
|
@ -703,7 +703,7 @@ if __name__ == "__main__":
|
|||
> Das Programm vergleicht immer mit dem **1/N-Portfolio**. Das ist kein Scherz: DeMiguel,
|
||||
> Garlappi und Uppal zeigten 2009 in einer viel beachteten Studie, dass die naive
|
||||
> Gleichgewichtung viele optimierte Strategien out of sample schlägt — weil sie keinerlei
|
||||
> Schätzung benötigt und damit auch keinen Schätzfehler enthält. **Wenn Ihre Optimierung
|
||||
> Schätzung benötigt und damit auch keinen Schätzfehler{idx:Schätzfehler} enthält. **Wenn Ihre Optimierung
|
||||
> 1/N nicht schlägt, ist sie ihren Aufwand nicht wert.** Diese Messlatte sollte in jedem
|
||||
> Portfolioprojekt stehen.
|
||||
|
||||
|
|
@ -759,9 +759,9 @@ zweiten. Vergleichen Sie GMV, Max Sharpe und 1/N.
|
|||
|
||||
## Finde den Denkfehler {#sec:markowitz-denkfehler}
|
||||
|
||||
{ref:kap:finanzdaten} hat gezeigt, was eine schlecht geschätzte **Kovarianzmatrix**
|
||||
{ref:kap:finanzdaten} hat gezeigt, was eine schlecht geschätzte **Kovarianzmatrix**{idx:Kovarianzmatrix}
|
||||
anrichtet. Bei den erwarteten **Renditen** ist es schlimmer — und weil sie in der
|
||||
Zielfunktion stehen statt in der Nebenbedingung, fällt es schwerer auf.
|
||||
Zielfunktion{idx:Zielfunktion} stehen statt in der Nebenbedingung, fällt es schwerer auf.
|
||||
|
||||
> **🐛 Finde den Denkfehler: Zwölf gleiche Anlagen, ein sehr ungleiches Portfolio**
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Kapitel: Tail-Risiko, CVaR und Transaktionskosten {#kap:cvar}
|
||||
# Kapitel: Tail-Risiko, CVaR und Transaktionskosten{idx:Transaktionskosten} {#kap:cvar}
|
||||
|
||||
> **📌 Kapitel auf einen Blick**
|
||||
>
|
||||
|
|
@ -86,12 +86,12 @@ Nach diesem Kapitel können Sie …
|
|||
|
||||
1. … erklären, warum Marktrenditen keine Normalverteilung haben und was daraus folgt.
|
||||
2. … VaR und CVaR definieren und begründen, warum nur der CVaR kohärent ist.
|
||||
3. … das Rockafellar-Uryasev-Theorem anwenden, um den CVaR linear zu formulieren.
|
||||
3. … das Rockafellar-Uryasev-Theorem{idx:Rockafellar-Uryasev-Theorem} anwenden, um den CVaR linear zu formulieren.
|
||||
4. … Transaktionskosten über die $L_1$-Norm modellieren.
|
||||
5. … Einheiten konsistent halten und Nebenbedingungen vektorisieren.
|
||||
6. … erklären, warum zwei Anlagen mit identischem VaR völlig verschiedene Extremverluste
|
||||
haben können.
|
||||
7. … die Folgen fehlender Subadditivität für die Verteilung von Risikobudgets benennen.
|
||||
7. … die Folgen fehlender Subadditivität{idx:Subadditivität} für die Verteilung von Risikobudgets benennen.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -250,7 +250,7 @@ alle **zwei Jahre**. Der Faktor beträgt fast **eine Million**.
|
|||
|
||||
Und Teil 2 zeigt das Grundproblem des VaR an einem Beispiel, das Sie von Hand nachrechnen
|
||||
können: Einzeln meldet er für jede Anleihe einen *Gewinn* von 2 €, im Portfolio einen
|
||||
*Verlust* von 98 €. Diversifikation hätte demnach das Risiko um 102 € erhöht. Der CVaR
|
||||
*Verlust* von 98 €. Diversifikation{idx:Diversifikation} hätte demnach das Risiko um 102 € erhöht. Der CVaR
|
||||
dagegen verhält sich korrekt: 101,33 € im Portfolio gegenüber 159,24 € bei getrennter
|
||||
Betrachtung — die Streuung **senkt** das Risiko, wie es sein muss.
|
||||
|
||||
|
|
@ -305,7 +305,7 @@ nicht überschritten wird.
|
|||
| --- | --- | --- |
|
||||
| Berücksichtigt Verlusthöhe im Rand | ✗ nein | ✓ ja |
|
||||
| **Subadditiv**{idx:Subadditivität} ($\rho(A+B) \le \rho(A)+\rho(B)$) | ✗ nein | ✓ ja |
|
||||
| Kohärentes Risikomaß | ✗ nein | ✓ ja |
|
||||
| Kohärentes Risikomaß{idx:Kohärentes Risikomaß} | ✗ nein | ✓ ja |
|
||||
| Konvex und optimierbar | ✗ nein | ✓ ja |
|
||||
| Regulatorischer Standard | bis Basel II | **ab Basel III** |
|
||||
|
||||
|
|
@ -343,7 +343,7 @@ $$
|
|||
> der Verlust darüber hinausgeht. Der CVaR ist die Schwelle plus der gemittelte Überschuss
|
||||
> — und zwar für diejenige Schwelle, bei der diese Summe minimal wird.“
|
||||
>
|
||||
> **Warum $u_s$ automatisch das Maximum wird:** Die Zielfunktion minimiert die Summe der
|
||||
> **Warum $u_s$ automatisch das Maximum wird:** Die Zielfunktion{idx:Zielfunktion} minimiert die Summe der
|
||||
> $u_s$. Jedes $u_s$ wird also so klein wie möglich gedrückt — bis an die Grenze, die die
|
||||
> beiden Ungleichungen erlauben. Das ist genau das Maximum der beiden Untergrenzen.
|
||||
|
||||
|
|
@ -367,8 +367,8 @@ $$
|
|||
>
|
||||
> > **⚠️ Die teuerste Verwechslung des Kapitels**
|
||||
> > $\alpha$ und $1-\alpha$ zu vertauschen führt zu **keiner Fehlermeldung**. Das Modell
|
||||
> > rechnet weiter, nur eben über die falsche Menge. An 2 000 simulierten Tagesrenditen mit
|
||||
> > Fat Tails gemessen:
|
||||
> > rechnet weiter, nur eben über die falsche Menge{idx:Konvexität!Menge}. An 2 000 simulierten Tagesrenditen mit
|
||||
> > Fat Tails{idx:Fat Tails} gemessen:
|
||||
> >
|
||||
> > | Rechnung | gemittelt über | CVaR |
|
||||
> > | --- | --- | --- |
|
||||
|
|
@ -408,7 +408,7 @@ $$
|
|||
> gegenüber vielen kleinen. Das entspricht genau dem, was man in der Praxis will — nicht 50
|
||||
> Kleinstorders mit je 3 € Mindestgebühr.
|
||||
|
||||
In CVXPY schreibt man einfach `cp.norm1(w - w_alt)`; intern wird das in lineare
|
||||
In CVXPY{idx:CVXPY} schreibt man einfach `cp.norm1(w - w_alt)`; intern wird das in lineare
|
||||
Hilfsvariablen zerlegt.
|
||||
|
||||
---
|
||||
|
|
@ -425,7 +425,7 @@ Hilfsvariablen zerlegt.
|
|||
> ```
|
||||
> Der Risikoterm ist dadurch faktisch um Faktor 252 zu schwach gewichtet:
|
||||
> `lambda_risk = 1.5` bedeutet dann effektiv eine Risikoaversion von $1{,}5/252 \approx 0{,}006$.
|
||||
> Das Modell ist nicht falsch im Sinne von unlösbar — aber der Parameter bedeutet nicht,
|
||||
> Das Modell ist nicht falsch im Sinne von unlösbar — aber der Parameter{idx:Parameter (Modell)} bedeutet nicht,
|
||||
> was er zu bedeuten scheint, und lässt sich daher nicht sinnvoll einstellen.
|
||||
>
|
||||
> **Dieses Programm rechnet deshalb durchgehend auf Tagesbasis** und annualisiert erst in
|
||||
|
|
@ -655,7 +655,7 @@ if __name__ == "__main__":
|
|||
> und **nicht** als das Naheliegende, `cp.sqrt(cp.quad_form(w, sigma))`. Der naheliegende
|
||||
> Ausdruck ist nicht DCP und wird von CVXPY mit einem `DCPError` abgelehnt: `cp.sqrt` ist
|
||||
> konkav und verlangt deshalb ein **konkaves** Argument, `quad_form` ist aber konvex. Die
|
||||
> Regel wird verletzt, obwohl die Funktion als ganze mathematisch völlig harmlos ist —
|
||||
> Regel wird verletzt, obwohl die Funktion{idx:Konvexität!Funktion} als ganze mathematisch völlig harmlos ist —
|
||||
> $\sqrt{w^\top \Sigma w}$ ist konvex, DCP kann es nur nicht *sehen*.
|
||||
>
|
||||
> Wichtig ist die Fehlerdiagnose dahinter, weil sie leicht in die Irre geht:
|
||||
|
|
@ -673,7 +673,7 @@ if __name__ == "__main__":
|
|||
|
||||
> **💡 Zur Annualisierung von VaR und CVaR**
|
||||
> Ein häufiger Fehler skaliert den täglichen CVaR mit $\sqrt{252}$. Diese
|
||||
> **Wurzel-Zeit-Regel** gilt streng nur für **Standardabweichungen** unabhängig identisch
|
||||
> **Wurzel-Zeit-Regel**{idx:Wurzel-Zeit-Regel} gilt streng nur für **Standardabweichungen** unabhängig identisch
|
||||
> verteilter Größen ohne Drift. Der CVaR ist ein Erwartungswert über einen Verteilungsrand
|
||||
> — für ihn ist die Regel eine grobe Näherung, die bei fetten Rändern und Autokorrelation
|
||||
> systematisch danebenliegt.
|
||||
|
|
@ -711,7 +711,7 @@ Angenommen, ein Modell verrechnet Jahresrendite gegen Tages-CVaR (siehe die Warn
|
|||
Wirkung wie `RISIKOAVERSION = 1.5` im konsistenten Tagesmodell zu erzielen?
|
||||
|
||||
**Aufgabe ⭐⭐⭐ — Risikoaversion kalibrieren.**
|
||||
Variieren Sie `RISIKOAVERSION` von 0 bis 20 und tragen Sie Rendite, Volatilität, CVaR und
|
||||
Variieren Sie `RISIKOAVERSION` von 0 bis 20 und tragen Sie Rendite, Volatilität{idx:Volatilität}, CVaR und
|
||||
Turnover gegeneinander auf.
|
||||
(a) Wie sieht die „Effizienzgrenze“ im Rendite-CVaR-Raum aus?
|
||||
(b) Bei welchem Wert entspricht das CVaR-Portfolio ungefähr dem Varianz-Portfolio?
|
||||
|
|
@ -822,7 +822,7 @@ $\tau \in \{0{,}05;\ 0{,}1;\ 0{,}25;\ 0{,}5;\ 1{,}0\}$.
|
|||
> Antworten: [Anhang A](90_Anhang_Loesungen.md#selbsttest-loesung-cvar).
|
||||
|
||||
1. Was misst der CVaR, was der VaR nicht misst?
|
||||
2. Warum ist der CVaR konvex, aber nicht streng konvex?
|
||||
2. Warum ist der CVaR konvex, aber nicht streng konvex{idx:Konvexität!streng konvex}?
|
||||
3. Welche Rolle spielt die Hilfsvariable $\gamma$ bei Rockafellar/Uryasev?
|
||||
4. Warum bevorzugt die $L_1$-Strafe wenige große statt vieler kleiner Umschichtungen?
|
||||
5. Warum sollte man tägliche und annualisierte Größen nicht in einer Zielfunktion mischen?
|
||||
|
|
@ -852,7 +852,7 @@ $\tau \in \{0{,}05;\ 0{,}1;\ 0{,}25;\ 0{,}5;\ 1{,}0\}$.
|
|||
Zeit.
|
||||
|
||||
**Ausblick.** {ref:kap:handelsmaschine} fügt alles zusammen: Datenpipeline, Signal, Optimierung,
|
||||
Rebalancing und ein Walk-Forward-Backtest ohne Lookahead-Bias.
|
||||
Rebalancing{idx:Rebalancing} und ein Walk-Forward-Backtest{idx:Walk-Forward-Backtest} ohne Lookahead-Bias.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@
|
|||
> **📌 Kapitel auf einen Blick**
|
||||
>
|
||||
> **Worum geht es?** Um das Zusammenführen von allem: Datenpipeline, Signal, Optimierung,
|
||||
> Rebalancing, Kostenverbuchung und ein Backtest, der nicht lügt.
|
||||
> Rebalancing{idx:Rebalancing}, Kostenverbuchung und ein Backtest, der nicht lügt.
|
||||
>
|
||||
> **Voraussetzungen:** {ref:kap:finanzdaten} bis {ref:kap:cvar}.
|
||||
>
|
||||
> **Danach können Sie:** Eine Walk-Forward-Backtest-Architektur bauen, Lookahead-Bias
|
||||
> **Danach können Sie:** Eine Walk-Forward-Backtest{idx:Walk-Forward-Backtest}-Architektur bauen, Lookahead-Bias{idx:Lookahead-Bias}
|
||||
> vermeiden, Ergebnisse gegen eine Benchmark bewerten und typische Backtest-Fallen erkennen.
|
||||
>
|
||||
> **Zeitbedarf:** ca. 6 Stunden.
|
||||
|
|
@ -93,7 +93,7 @@ Nach diesem Kapitel können Sie …
|
|||
1. … die sechs Bausteine einer quantitativen Engine benennen und ihre Reihenfolge begründen.
|
||||
2. … einen Walk-Forward-Backtest{idx:Walk-Forward-Backtest} ohne Lookahead-Bias{idx:Lookahead-Bias} implementieren.
|
||||
3. … Rebalancing-Termine korrekt auf Handelstage abbilden.
|
||||
4. … Transaktionskosten und Gewichtsdrift realistisch verbuchen.
|
||||
4. … Transaktionskosten{idx:Transaktionskosten} und Gewichtsdrift realistisch verbuchen.
|
||||
5. … Backtest-Ergebnisse kritisch prüfen und die typischen Selbsttäuschungen erkennen.
|
||||
6. … den maximalen Rückschlag als eigenständige Kennzahl berichten und begründen, warum
|
||||
Rendite und Sharpe allein nichts über den Verlauf aussagen.
|
||||
|
|
@ -646,7 +646,7 @@ FEHLER 1+2+3 kombiniert 25.41 % +19.80 %
|
|||
* **Lookahead** erzeugt eine scheinbare Überrendite von **15,4 Prozentpunkten pro Jahr**.
|
||||
Ein einziger falscher Index — `iloc[t+1]` statt `iloc[t]` — verwandelt Rauschen in eine
|
||||
scheinbar brillante Strategie.
|
||||
* **Survivorship-Bias** liefert **13,1 Prozentpunkte** allein dadurch, dass man das
|
||||
* **Survivorship-Bias**{idx:Survivorship-Bias} liefert **13,1 Prozentpunkte** allein dadurch, dass man das
|
||||
Universum im Nachhinein auf die Gewinner beschränkt.
|
||||
* Selbst die **ehrliche** Variante zeigt noch +1,1 Prozentpunkte — reines Rauschen, das
|
||||
aber ohne Weiteres als „leichte Outperformance“ verkauft werden könnte.
|
||||
|
|
@ -664,7 +664,7 @@ Die fünf Fallen im Einzelnen:
|
|||
| 2 | **Survivorship-Bias**{idx:Survivorship-Bias} | Nur heute existierende Titel im Universum | Historische Indexzusammensetzung verwenden |
|
||||
| 3 | **Kostenblindheit** | Gebühren, Spread, Slippage ignoriert | Kosten im Modell **und** in der Verbuchung |
|
||||
| 4 | **Overfitting**{idx:Overfitting} | Parameter auf die Vergangenheit getrimmt | Out-of-Sample-Zeitraum strikt zurückhalten |
|
||||
| 5 | **Data Snooping**{idx:Data Snooping} | Viele Varianten getestet, beste berichtet | Zahl der Versuche protokollieren; Deflated Sharpe Ratio |
|
||||
| 5 | **Data Snooping**{idx:Data Snooping} | Viele Varianten getestet, beste berichtet | Zahl der Versuche protokollieren; Deflated Sharpe Ratio{idx:Sharpe-Ratio} |
|
||||
|
||||
> **🎯 Die unbequeme Wahrheit**
|
||||
> Falle 5 ist die gefährlichste, weil sie sich nicht im Code zeigt, sondern im
|
||||
|
|
@ -686,7 +686,7 @@ Backtest und echtem Einsatz liegt:
|
|||
| **Papierhandel** | Funktioniert es auf Live-Daten ohne Geld? | 3–6 Monate, oft schlechter als der Backtest |
|
||||
| **Kapazitätsanalyse** | Bewegt meine eigene Order den Markt? | Begrenzt das einsetzbare Volumen |
|
||||
| **Regimewechsel-Test** | Hält es in Krisen? | Backtest über 2008, 2020 separat auswerten |
|
||||
| **Betriebsrisiken** | Was, wenn der Datenfeed ausfällt? | Fallback-Strategie, Monitoring |
|
||||
| **Betriebsrisiken** | Was, wenn der Datenfeed ausfällt? | Fallback-Strategie{idx:Fallback-Strategie}, Monitoring |
|
||||
| **Regulatorik** | MiFID II, Best Execution, Dokumentation | Protokollpflichten |
|
||||
|
||||
> **⚠️ Der Realitätsabschlag**
|
||||
|
|
@ -777,7 +777,7 @@ der beim ersten Versuch funktioniert hat.
|
|||
Das folgende Programm macht den Effekt messbar. Es testet Strategien, die
|
||||
**nachweislich** keinerlei Vorteil haben — ihre Tagesergebnisse sind Zufallszahlen mit
|
||||
Erwartungswert exakt null — und zeigt, wie gut die jeweils beste davon aussieht, allein
|
||||
als Funktion der Anzahl der Versuche.
|
||||
als Funktion{idx:Konvexität!Funktion} der Anzahl der Versuche.
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ konkurrierende Verwendungen verteilen, unter Unsicherheit.**
|
|||
|
||||
| Werkstatt und Kraftwerk | Depot und Handel | Was mathematisch dahintersteht |
|
||||
| --- | --- | --- |
|
||||
| Produkt, Maschinenstunde | Titel, Kapital | Entscheidungsvariable |
|
||||
| Produkt, Maschinenstunde | Titel, Kapital | Entscheidungsvariable{idx:Entscheidungsvariable} |
|
||||
| Deckungsbeitrag | erwartete Rendite | linearer Zielterm |
|
||||
| Kapazität, Liefervertrag | Positionsgrenze, Sektorlimit | Nebenbedingung |
|
||||
| Rüstkosten, Anfahrkosten | Transaktionskosten | Fixkosten mit Binärvariable (B1) |
|
||||
| Rüstkosten, Anfahrkosten | Transaktionskosten{idx:Transaktionskosten} | Fixkosten mit Binärvariable{idx:Binärvariable} (B1) |
|
||||
| Lastabwurf, Konventionalstrafe | Tail-Verlust | Straf- bzw. Risikoterm |
|
||||
| Wind- und Nachfrageszenarien | Renditeszenarien | Szenariomenge |
|
||||
|
||||
|
|
@ -26,12 +26,12 @@ sondern eine Redewendung.
|
|||
| „Planen mit der Prognose ist gut genug." | Der Erwartungswert-Plan kostet **149 % mehr** (874 870 € statt 351 356 €) und wirft in **28 von 40** Szenarien Last ab | {ref:kap:supplychain} |
|
||||
| „Dann sparen wir eben beim Brennstoff." | Genau das tut er: 12 725 € gespart, **536 239 €** Lastabwurf bezahlt — das 42-fache. Die Anfahrkosten sind in beiden Plänen gleich | {ref:kap:supplychain} |
|
||||
| „Der VaR sagt, wie riskant es ist." | VaR **1,86 %**, CVaR **2,99 %** — und der schlechteste Tag der Stichprobe (**−23,0 %**) ändert am VaR **nichts** | {ref:kap:cvar} |
|
||||
| „Die Kovarianzmatrix ist eine Eingabe wie jede andere." | Aus kurzen Reihen geschätzt ist sie schlecht konditioniert; die Optimierung setzt dann auf Schätzrauschen | {ref:kap:finanzdaten} |
|
||||
| „Die Kovarianzmatrix{idx:Kovarianzmatrix} ist eine Eingabe wie jede andere." | Aus kurzen Reihen geschätzt ist sie schlecht konditioniert; die Optimierung setzt dann auf Schätzrauschen | {ref:kap:finanzdaten} |
|
||||
|
||||
## Drei Fehler, die dieser Teil verhindert
|
||||
|
||||
1. **Bei Markowitz einsteigen.** Wer {ref:kap:finanzdaten} überspringt, optimiert seine
|
||||
eigenen Schätzfehler und wundert sich über Gewichte, die niemand halten würde.
|
||||
eigenen Schätzfehler{idx:Schätzfehler} und wundert sich über Gewichte, die niemand halten würde.
|
||||
2. **Den VaR für ein Risikomaß halten.** Er sagt, **ob** die Schwelle gerissen wird, nicht
|
||||
**wie schlimm** es dahinter aussieht — und er ist nicht kohärent. Optimiert wird der
|
||||
CVaR.
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ gefunden:**
|
|||
| Zielwert nachrechnen | Fixkosten, die im Modell nicht verbucht wurden | {ref:sec:milp-denkfehler} |
|
||||
|
||||
> **🎯 Merksatz**
|
||||
> Entscheidend ist, was diese Funktion **nicht** benutzt: kein Solver-Objekt, keine
|
||||
> Entscheidend ist, was diese Funktion{idx:Konvexität!Funktion} **nicht** benutzt: kein Solver-Objekt, keine
|
||||
> Modellvariable, keine Dimension aus der Bibliothek. Sie bekommt nur die ausgegebene
|
||||
> Lösung und die Anforderungen — und rechnet unabhängig nach. Eine Prüfung, die dieselben
|
||||
> Bausteine verwendet wie das Modell, prüft das Modell gegen sich selbst und findet
|
||||
|
|
@ -89,9 +89,9 @@ Nach diesem Kapitel können Sie …
|
|||
|
||||
1. … die fünf typischen Praxisfallen benennen und je ein Gegenmittel nennen.
|
||||
2. … ein unlösbares Modell in einen „am wenigsten schlechten“ Plan verwandeln.
|
||||
3. … Solver-Ergebnisse erklärbar machen (*Explainable OR*).
|
||||
3. … Solver-Ergebnisse erklärbar machen (*Explainable OR*{idx:Explainable OR}).
|
||||
4. … für jede Nebenbedingung beziffern, was sie den Plan kostet — und begründen, warum
|
||||
der Schattenpreis diese Frage nur für die *nächste* Einheit beantwortet.
|
||||
der Schattenpreis{idx:Schattenpreis} diese Frage nur für die *nächste* Einheit beantwortet.
|
||||
5. … Zeitlimits und Optimalitätslücken sinnvoll setzen.
|
||||
6. … die Architektur einer produktionsreifen OR-Plattform skizzieren.
|
||||
7. … eine **modellunabhängige Abnahmeprüfung** schreiben, die eine Lösung gegen die
|
||||
|
|
@ -109,14 +109,14 @@ Nach diesem Kapitel können Sie …
|
|||
|
||||

|
||||
|
||||
### Falle 1 — Infeasibility
|
||||
### Falle 1 — Infeasibility{idx:Infeasibility}
|
||||
|
||||
Wenn Parameter unglücklich zusammentreffen — drei Mitarbeitende gleichzeitig krank, kein
|
||||
qualifizierter Ersatz —, meldet der Solver schlicht `INFEASIBLE`.
|
||||
|
||||
* **Falsch:** Das System stürzt ab oder zeigt „Fehler“. Der Disponent steht ohne Plan da.
|
||||
* **Richtig:** **Hierarchische Relaxation.**{idx:Hierarchische Relaxation} Jede harte Bedingung, die im Notfall gebrochen
|
||||
werden darf, erhält eine teure Schlupfvariable. So liefert der Solver immer einen Plan —
|
||||
werden darf, erhält eine teure Schlupfvariable{idx:Schlupfvariable}. So liefert der Solver immer einen Plan —
|
||||
und zeigt zugleich präzise, **wo** es klemmt.
|
||||
|
||||
```python
|
||||
|
|
@ -380,30 +380,30 @@ Derselbe Unterschied kehrt auf Modellebene wieder, und dort lässt er sich in Eu
|
|||
beziffern: {ref:sec:praxisfallen-attribution} misst für jede Bedingung, was sie den
|
||||
ganzen Plan kostet — und baut daraus einen Bericht, den man vorlegen kann.
|
||||
|
||||
### Falle 3 — Regimewechsel und Schätzfehler
|
||||
### Falle 3 — Regimewechsel und Schätzfehler{idx:Schätzfehler}
|
||||
|
||||
Ein Modell, das auf einer mehrjährigen Aufwärtsphase kalibriert wurde, kennt keine
|
||||
Liquiditätskrise und keine Zinswende.
|
||||
|
||||
* **Robuste Schätzung** statt roher Historie: Ledoit-Wolf-Shrinkage ({ref:kap:finanzdaten}),
|
||||
* **Robuste Schätzung** statt roher Historie: Ledoit-Wolf-Shrinkage{idx:Ledoit-Wolf-Shrinkage} ({ref:kap:finanzdaten}),
|
||||
Szenarien ({ref:kap:unsicherheit}).
|
||||
* **Harte Obergrenzen** für Einzelpositionen und Sektoren — auch dann, wenn der Solver
|
||||
rechnerisch alles in einen Titel legen möchte. Die Grenze kostet Ertrag im Normalfall und
|
||||
rettet im Ernstfall.
|
||||
* **Rollierende Neuschätzung** statt einmaliger Kalibrierung.
|
||||
|
||||
### Falle 4 — Lookahead- und Survivorship-Bias
|
||||
### Falle 4 — Lookahead- und Survivorship-Bias{idx:Survivorship-Bias}
|
||||
|
||||
Ausführlich in {ref:kap:handelsmaschine} behandelt. Die Kurzfassung: Beide Fehler machen Backtests
|
||||
systematisch zu gut, ohne eine Fehlermeldung zu erzeugen. Der Lookahead-Selbsttest aus
|
||||
{ref:sec:handelsmaschine-die-engine} findet den ersten automatisch.
|
||||
|
||||
### Falle 5 — Laufzeitexplosion
|
||||
### Falle 5 — Laufzeitexplosion{idx:Laufzeitexplosion (Fehlerbild)}
|
||||
|
||||
Exakte Optimalität kann bei MILP oder CP-SAT Minuten bis Stunden dauern — und die Laufzeit
|
||||
Exakte Optimalität kann bei MILP oder CP-SAT{idx:CP-SAT} Minuten bis Stunden dauern — und die Laufzeit
|
||||
wächst nicht linear mit der Problemgröße.
|
||||
|
||||
| Einsatzszenario | Empfohlenes Zeitlimit | Akzeptabler MIP-Gap |
|
||||
| Einsatzszenario | Empfohlenes Zeitlimit | Akzeptabler MIP-Gap{idx:MIP-Gap} |
|
||||
| --- | --- | --- |
|
||||
| Interaktive Oberfläche | 5–10 Sekunden | 2–5 % |
|
||||
| Batch tagsüber | 1–5 Minuten | 1–2 % |
|
||||
|
|
@ -422,9 +422,9 @@ wächst nicht linear mit der Problemgröße.
|
|||
|
||||
---
|
||||
|
||||
## Constraint Attribution: welche Bedingung kostet wie viel? {#sec:praxisfallen-attribution}
|
||||
## Constraint Attribution{idx:Constraint Attribution}: welche Bedingung kostet wie viel? {#sec:praxisfallen-attribution}
|
||||
|
||||
Der Constraint-Trace beantwortet „warum **diese** Zuweisung?“. Der Deletion Filter in
|
||||
Der Constraint-Trace beantwortet „warum **diese** Zuweisung?“. Der Deletion Filter{idx:Deletion Filter} in
|
||||
{ref:anhang:fehlerdiagnose} beantwortet „warum geht es **gar nicht**?“. Der häufigste Fall
|
||||
in der Praxis liegt dazwischen, und für ihn hat bisher niemand ein Werkzeug bekommen:
|
||||
|
||||
|
|
@ -880,7 +880,7 @@ weg, ist er erfüllbar, keine allein ist „der“ Grund. Genau die Struktur, di
|
|||
angewandt.
|
||||
|
||||
Die Pointe steht am Ende: Mit +15 Stunden Lackierkapazität wird der Wunsch erfüllbar — und
|
||||
kostet dann **nichts**. Der Plan wählt diese Menge von sich aus, sobald der Engpass weg ist.
|
||||
kostet dann **nichts**. Der Plan wählt diese Menge{idx:Konvexität!Menge} von sich aus, sobald der Engpass weg ist.
|
||||
Der Konflikt bestand nie zwischen Vertrieb und Produktion. Er bestand zwischen dem Vertrieb
|
||||
und der Lackiererei, und niemand wusste das.
|
||||
|
||||
|
|
@ -929,7 +929,7 @@ In einer professionellen Umgebung ist der Optimierer kein Skript, sondern ein
|
|||
| --- | --- | --- |
|
||||
| **Quellsysteme** | ERP, Personalplanung, Marktdaten-Feeds | REST, Datenbanken, Broker-APIs |
|
||||
| **Datenqualität** | Validierung, Plausibilität, unveränderlicher Snapshot | Pydantic, Pandera, Great Expectations |
|
||||
| **Optimierungs-Worker** | Modell bauen, lösen, Timeout, Fallback | Celery/Redis, OR-Tools, HiGHS, CVXPY |
|
||||
| **Optimierungs-Worker** | Modell bauen, lösen, Timeout, Fallback | Celery/Redis, OR-Tools{idx:OR-Tools}, HiGHS, CVXPY |
|
||||
| **Disposition** | Ergebnis prüfen, ändern, freigeben | Web-UI, Dashboard, Freigabeworkflow |
|
||||
| **Ausführung** | Kalender-Sync, Benachrichtigung, Order-Routing | Kalender-APIs, Messaging, Broker |
|
||||
| **Betrieb** | Monitoring, Audit-Trail, Alarme | Logging, Metriken, Versionierung |
|
||||
|
|
@ -1007,7 +1007,7 @@ zeigt nach innen auf die Domäne, und die Domäne zeigt auf nichts. Erzeugt von
|
|||
Der unscheinbarste, aber wirksamste Teil ist die Statusübersetzung. Dieselbe Aussage heißt
|
||||
in den fünf im Buch verwendeten Bibliotheken:
|
||||
|
||||
| Bedeutung | pywraplp | CP-SAT | HiGHS | SciPy | CVXPY |
|
||||
| Bedeutung | pywraplp | CP-SAT | HiGHS{idx:HiGHS} | SciPy | CVXPY{idx:CVXPY} |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| beweisbar optimal | `Solver.OPTIMAL` | `cp_model.OPTIMAL` | `"Optimal"` | `status == 0` | `"optimal"` |
|
||||
| zulässig, nicht bewiesen | `Solver.FEASIBLE` | `cp_model.FEASIBLE` | `"Time limit reached"` | — | `"optimal_inaccurate"` |
|
||||
|
|
@ -1595,7 +1595,7 @@ deshalb nicht glauben sollte, bevor sie jemand vorgeführt hat.
|
|||
Also führen wir sie vor — und zwar am unbequemsten Paar, das dieses Buch zu bieten hat:
|
||||
**CP-SAT gegen HiGHS**. Die beiden sind grundverschieden. CP-SAT ist ein
|
||||
Constraint-Programming-Solver, der ausschließlich ganzzahlig rechnet und Restriktionen als
|
||||
Ausdrücke entgegennimmt. HiGHS ist ein klassischer Branch-and-Bound-Löser, der eine
|
||||
Ausdrücke entgegennimmt. HiGHS ist ein klassischer Branch-and-Bound{idx:Branch-and-Bound}-Löser, der eine
|
||||
Koeffizientenmatrix erwartet. Und sie lassen sich nicht einmal gemeinsam importieren
|
||||
({ref:kap:oekosystem}).
|
||||
|
||||
|
|
@ -2044,10 +2044,10 @@ Arbeiten Sie diese Liste ab, bevor ein OR-System in Betrieb geht:
|
|||
|
||||
**Modell**
|
||||
- [ ] Alle Nebenbedingungen sind dokumentiert — mit fachlicher Begründung, nicht nur als Code.
|
||||
- [ ] Für jede harte Bedingung ist geprüft: Muss sie wirklich hart sein?
|
||||
- [ ] Für jede harte Bedingung ist geprüft: Muss sie wirklich hart{idx:Nebenbedingung!hart} sein?
|
||||
- [ ] Es gibt eine Relaxationsstrategie für den Infeasible-Fall.
|
||||
- [ ] Big-M-Werte sind so klein wie möglich gewählt.
|
||||
- [ ] Die Zielfunktion ist in konsistenten Einheiten formuliert.
|
||||
- [ ] Die Zielfunktion{idx:Zielfunktion} ist in konsistenten Einheiten formuliert.
|
||||
|
||||
**Daten**
|
||||
- [ ] Spaltenreihenfolge und Datentypen werden nach jedem Import geprüft.
|
||||
|
|
@ -2074,7 +2074,7 @@ Arbeiten Sie diese Liste ab, bevor ein OR-System in Betrieb geht:
|
|||
**Grundlagen und lineare/ganzzahlige Optimierung**
|
||||
* Bertsimas & Tsitsiklis: *Introduction to Linear Optimization* — Standardwerk zu Simplex,
|
||||
Dualität, Polyedertheorie.
|
||||
* Wolsey: *Integer Programming* — Branch-and-Cut, Schnittebenen, Formulierungsstärke.
|
||||
* Wolsey: *Integer Programming* — Branch-and-Cut{idx:Branch-and-Cut}, Schnittebenen, Formulierungsstärke.
|
||||
|
||||
**Konvexe Optimierung**
|
||||
* Boyd & Vandenberghe: *Convex Optimization* — Pflichtlektüre; frei verfügbar. Die
|
||||
|
|
@ -2084,8 +2084,8 @@ Arbeiten Sie diese Liste ab, bevor ein OR-System in Betrieb geht:
|
|||
* Google OR-Tools Dokumentation und das CP-SAT-Primer von Laurent Perron.
|
||||
|
||||
**Quantitative Finanzmathematik**
|
||||
* López de Prado: *Advances in Financial Machine Learning* — Backtest-Overfitting,
|
||||
Denoising, Deflated Sharpe Ratio.
|
||||
* López de Prado: *Advances in Financial Machine Learning* — Backtest-Overfitting{idx:Overfitting},
|
||||
Denoising, Deflated Sharpe Ratio{idx:Sharpe-Ratio}.
|
||||
* Cornuéjols, Peña & Tütüncü: *Optimization Methods in Finance*.
|
||||
|
||||
**Wie es weitergeht**
|
||||
|
|
@ -2100,7 +2100,7 @@ Wenn Sie doch tiefer in die Methodik wollen, sind das die lohnendsten Richtungen
|
|||
| --- | --- | --- |
|
||||
| **Column Generation / Branch-and-Price**{idx:Column Generation} | sehr große Zuschnitt- und Dienstplanprobleme | {ref:kap:dekomposition}, Wolsey |
|
||||
| **Benders-Zerlegung**{idx:Benders-Zerlegung} | zweistufige stochastische Modelle mit vielen Szenarien | Birge & Louveaux |
|
||||
| **Approximate Dynamic Programming / RL**{idx:Approximate Dynamic Programming} | hochdimensionale Zustandsräume | Powell: *Reinforcement Learning and Stochastic Optimization* |
|
||||
| **Approximate Dynamic Programming / RL**{idx:Approximate Dynamic Programming} | hochdimensionale Zustandsräume | Powell: *Reinforcement Learning{idx:Reinforcement Learning} and Stochastic Optimization* |
|
||||
| **Konische Optimierung (SOCP, SDP)**{idx:Konische Optimierung (SOCP, SDP)} | robuste Portfolios, Ellipsoid-Unsicherheit | Boyd & Vandenberghe, {ref:kap:lp} |
|
||||
| **Multi-Objective Optimization**{idx:Multi-Objective Optimization} | echte Zielkonflikte ohne Gewichtung | Ehrgott: *Multicriteria Optimization* |
|
||||
|
||||
|
|
@ -2110,16 +2110,16 @@ Wenn Sie doch tiefer in die Methodik wollen, sind das die lohnendsten Richtungen
|
|||
|
||||
> Lösungen: {ref:sec:loesungen-praxisfallen}.
|
||||
|
||||
**Aufgabe ⭐ — Hart oder weich, revisited.**
|
||||
**Aufgabe ⭐ — Hart oder weich{idx:Nebenbedingung!weich}, revisited.**
|
||||
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.
|
||||
|
||||
**Aufgabe ⭐ — 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.
|
||||
(d) Portfolio-Rebalancing{idx:Rebalancing} monatlich.
|
||||
|
||||
**Aufgabe ⭐⭐ — Relaxation einbauen.**
|
||||
**Aufgabe ⭐⭐ — Relaxation{idx:Relaxation} einbauen.**
|
||||
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
|
||||
|
|
@ -2146,8 +2146,8 @@ 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.
|
||||
|
||||
**Aufgabe ⭐⭐⭐ — Post-Mortem schreiben.**
|
||||
Suchen Sie sich einen der im Buch besprochenen Fehler aus (z. B. die Vorzeichenfalle in
|
||||
{ref:sec:lp-die-vorzeichenfalle-bei-schattenpreisen}, die ungültige Kovarianzmatrix in
|
||||
Suchen Sie sich einen der im Buch besprochenen Fehler aus (z. B. die Vorzeichenfalle{idx:Schattenpreis!Vorzeichenfalle} in
|
||||
{ref:sec:lp-die-vorzeichenfalle-bei-schattenpreisen}, die ungültige Kovarianzmatrix{idx:Kovarianzmatrix} in
|
||||
{ref:kap:qp-nlp}, die Sektor-Positionsindizes in {ref:kap:markowitz}, die vermischten
|
||||
Einheiten in {ref:sec:cvar-implementierung-cvar-portfolio-mit-reibung} oder die
|
||||
Rebalancing-Termine in {ref:sec:handelsmaschine-rebalancing-termine-richtig-bestimmen})
|
||||
|
|
@ -2472,7 +2472,7 @@ sichtbar wird, und gibt Zeit zum Handeln.
|
|||
> der produktivste erste Schritt?**
|
||||
> (a) Das Zeitlimit erhöhen.
|
||||
> (b) Die neue Regel wieder entfernen und in Ruhe abwarten.
|
||||
> (c) Die harten Regeln hierarchisch lockern — mit teuren Strafkosten statt Verboten —,
|
||||
> (c) Die harten Regeln hierarchisch lockern — mit teuren Strafkosten{idx:Strafkosten} statt Verboten —,
|
||||
> damit der Solver benennt, **welche** Regel den Widerspruch erzeugt, statt nur zu sagen,
|
||||
> dass es einen gibt.
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ Nach diesem Kapitel können Sie …
|
|||
|
||||
## Warum Optimierungsmodelle schwer zu testen sind {#sec:testing-warum-schwer}
|
||||
|
||||
Bei einer gewöhnlichen Funktion schreibt man den erwarteten Wert hin:
|
||||
Bei einer gewöhnlichen Funktion{idx:Konvexität!Funktion} schreibt man den erwarteten Wert hin:
|
||||
|
||||
```python
|
||||
assert steuer(50_000) == 12_345.60
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ werden. Was dabei schiefgeht, hat selten mit Mathematik zu tun.
|
|||
|
||||
| Was in Produktion passiert | Gegenmittel | Wo |
|
||||
| --- | --- | --- |
|
||||
| `INFEASIBLE` um 3 Uhr nachts, niemand weiß warum | Relaxation mit gestaffelten Strafkosten (B18); Deletion Filter für die Diagnose | {ref:kap:praxisfallen}, {ref:anhang:fehlerdiagnose} |
|
||||
| Der Disponent lehnt den Plan ab, weil er ihn nicht versteht | Constraint-Trace für die einzelne Zuweisung; Kostenzurechnung für den ganzen Plan | {ref:kap:praxisfallen}, {ref:sec:praxisfallen-attribution} |
|
||||
| `INFEASIBLE` um 3 Uhr nachts, niemand weiß warum | Relaxation{idx:Relaxation} mit gestaffelten Strafkosten{idx:Strafkosten} (B18); Deletion Filter{idx:Deletion Filter} für die Diagnose | {ref:kap:praxisfallen}, {ref:anhang:fehlerdiagnose} |
|
||||
| Der Disponent lehnt den Plan ab, weil er ihn nicht versteht | Constraint-Trace{idx:Constraint-Trace} für die einzelne Zuweisung; Kostenzurechnung für den ganzen Plan | {ref:kap:praxisfallen}, {ref:sec:praxisfallen-attribution} |
|
||||
| Der Solver läuft ins Zeitlimit und keiner merkt es | Status, Gap und Zeitausschöpfung protokollieren — konstante Laufzeit ist ein Warnsignal | {ref:kap:praxisfallen} |
|
||||
| Ein Test wird grundlos mal rot, mal grün | auf Zielwert und Regeln prüfen, nicht auf die Gestalt der Lösung; `num_workers = 1` **und** Seed | {ref:sec:cpsat-parallele-suche}, {ref:kap:testing} |
|
||||
| Ein Ergebnis lässt sich später nicht mehr nachvollziehen | Snapshot-Prinzip: unveränderlicher Datenstand mit ID je Lauf | {ref:kap:praxisfallen} |
|
||||
| Ein Ergebnis lässt sich später nicht mehr nachvollziehen | Snapshot-Prinzip{idx:Snapshot-Prinzip}: unveränderlicher Datenstand mit ID je Lauf | {ref:kap:praxisfallen} |
|
||||
| Das Modell prüft sich selbst | Abnahmeprüfung als eigener Baustein, ohne Solver und ohne Modellvariable | {ref:sec:praxisfallen-or-kern} |
|
||||
|
||||
## Was dieser Teil gemessen hat
|
||||
|
|
@ -20,12 +20,12 @@ werden. Was dabei schiefgeht, hat selten mit Mathematik zu tun.
|
|||
| --- | --- | --- |
|
||||
| „Der Solver nennt schon den Grund für `INFEASIBLE`." | Er nennt gar nichts. Der Deletion Filter findet einen kleinsten Konflikt — dieses Modell enthält **neun** verschiedene, und welchen man sieht, steuert die Prüfreihenfolge | {ref:anhang:fehlerdiagnose} |
|
||||
| „Bindende Bedingungen sind die teuren." | Von fünf bindenden Bedingungen kostet eine **0,00 €** | {ref:sec:praxisfallen-attribution} |
|
||||
| „Der Schattenpreis sagt, was der Hebel bringt." | Hochgerechnet 120 €, gemessen **60 €** — er gilt nur bis +15 Stunden. Die Ranglisten nach Preis und nach Wirkung drehen sich um | {ref:sec:praxisfallen-attribution} |
|
||||
| „Der Schattenpreis{idx:Schattenpreis} sagt, was der Hebel bringt." | Hochgerechnet 120 €, gemessen **60 €** — er gilt nur bis +15 Stunden. Die Ranglisten nach Preis und nach Wirkung drehen sich um | {ref:sec:praxisfallen-attribution} |
|
||||
| „Mehr Arbeiter sind proportional schneller." | **12,3-fach** bei acht Arbeitern — überlinear, weil verschiedene Strategien statt derselben Suche laufen | {ref:sec:cpsat-parallele-suche} |
|
||||
|
||||
## Drei Fehler, die dieser Teil verhindert
|
||||
|
||||
1. **Alles hart formulieren.** Wer keine Regel brechen lässt, bekommt irgendwann eine
|
||||
1. **Alles hart{idx:Nebenbedingung!hart} formulieren.** Wer keine Regel brechen lässt, bekommt irgendwann eine
|
||||
Fehlermeldung statt eines Plans — und zwar nachts, im Batchlauf.
|
||||
2. **Genauer optimieren als die Daten sind.** Ein Gap von 2 % ist bei ±10 %
|
||||
Datenunsicherheit bedeutungslos. Die Rechenzeit dafür ist verschenkt.
|
||||
|
|
|
|||
|
|
@ -54,11 +54,11 @@ Abwesenheitsmeldungen.
|
|||
* 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.
|
||||
* Solver: CP-SAT{idx:CP-SAT}.
|
||||
|
||||
**Abnahmekriterien.**
|
||||
- [ ] Läuft in unter 10 Sekunden für eine ganze Schule (60 Lehrkräfte, 30 Slots).
|
||||
- [ ] Liefert **immer** einen Plan — auch wenn nicht alle Slots besetzbar sind (Relaxation).
|
||||
- [ ] Liefert **immer** einen Plan — auch wenn nicht alle Slots besetzbar sind (Relaxation{idx:Relaxation}).
|
||||
- [ ] Weist je Zuweisung eine Begründung aus.
|
||||
- [ ] Ausgabe als CSV **und** als lesbare Tagestabelle.
|
||||
- [ ] Vergleich gegen die manuelle Lösung: Wie viele Wünsche werden erfüllt?
|
||||
|
|
@ -96,7 +96,7 @@ Arbeitszeitgesetz, Tarifvertrag, Qualifikationsmix und individuelle Wünsche.
|
|||
- [ ] Bei Unlösbarkeit: Notfallplan plus benannte Ursache.
|
||||
|
||||
**Stolperfallen.** Der 28-Tage-Zyklus erzeugt viele Variablen (25 × 28 × 3 = 2100) —
|
||||
Symmetriebrechung und gute Suchheuristiken werden wichtig. Fairness über einen Monat ist
|
||||
Symmetriebrechung{idx:Symmetriebrechung} und gute Suchheuristiken werden wichtig. Fairness über einen Monat ist
|
||||
etwas anderes als Fairness über eine Woche.
|
||||
|
||||
---
|
||||
|
|
@ -111,8 +111,8 @@ an. Kunden haben Zeitfenster, Fahrzeuge Kapazitäten, Fahrer Arbeitszeiten.
|
|||
**Daten.** Adressen aus einer CSV; Entfernungen über OpenStreetMap (`osmnx`, `openrouteservice`)
|
||||
oder als Luftlinie mit Umwegfaktor 1,3 als Näherung.
|
||||
|
||||
**Modellskizze.** OR-Tools Routing-Bibliothek mit Kapazitäts- und Zeitdimension;
|
||||
Metaheuristik `GUIDED_LOCAL_SEARCH`, Zeitlimit 30 Sekunden.
|
||||
**Modellskizze.** OR-Tools{idx:OR-Tools} Routing-Bibliothek{idx:Routing-Bibliothek} mit Kapazitäts- und Zeitdimension;
|
||||
Metaheuristik{idx:Metaheuristik} `GUIDED_LOCAL_SEARCH`, Zeitlimit 30 Sekunden.
|
||||
|
||||
**Abnahmekriterien.**
|
||||
- [ ] Alle Kunden werden innerhalb ihrer Zeitfenster beliefert.
|
||||
|
|
@ -136,12 +136,12 @@ eröffnet werden sollen, um 60 Filialen zu versorgen.
|
|||
|
||||
**Modellskizze.** Kombiniertes Standort- und Transportproblem:
|
||||
* $y_j \in \{0,1\}$ — Lager $j$ eröffnen (Fixkosten).
|
||||
* $x_{ij} \ge 0$ — Menge von Lager $j$ zu Filiale $i$.
|
||||
* $x_{ij} \ge 0$ — Menge{idx:Konvexität!Menge} von Lager $j$ zu Filiale $i$.
|
||||
* Kopplung: $x_{ij} \le M\,y_j$; Kapazität je Lager; Bedarfsdeckung je Filiale.
|
||||
* Ziel: Fixkosten + Transportkosten minimieren.
|
||||
|
||||
**Abnahmekriterien.**
|
||||
- [ ] Sensitivitätsanalyse: Wie verändert sich die Lösung bei ±20 % Transportkosten?
|
||||
- [ ] Sensitivitätsanalyse{idx: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.
|
||||
|
|
@ -157,7 +157,7 @@ nicht einfach addieren.
|
|||
> **Schwierigkeit:** ⭐⭐⭐ · **Kapitel:** {ref:kap:lp}, {ref:kap:milp}, {ref:kap:cpsat} · **Zeit:** ca. 18 Stunden
|
||||
|
||||
**Ausgangslage.** Eine Fertigung produziert 15 Varianten auf 4 Maschinen. Jeder
|
||||
Produktwechsel kostet Rüstzeit; die Rüstzeit hängt von der Reihenfolge ab.
|
||||
Produktwechsel kostet Rüstzeit{idx:Rüstzeit}; die Rüstzeit hängt von der Reihenfolge ab.
|
||||
|
||||
**Modellskizze.** Los- und Reihenfolgeplanung:
|
||||
* Variablen: Produktionsmengen, Rüstentscheidungen, Reihenfolge (Intervallvariablen).
|
||||
|
|
@ -187,9 +187,9 @@ Steuerfreibetragsnutzung.
|
|||
**Modellskizze.**
|
||||
* Variablen: Zielgewichte $w_i$; Binärvariablen für „Position wird gehandelt“.
|
||||
* Hart: Vollinvestition, keine Leerverkäufe, Positionsobergrenzen, Mindestordergröße
|
||||
(semikontinuierlich, {ref:kap:milp}), höchstens $K$ Transaktionen je Rebalancing.
|
||||
* Ziel: erwartete Rendite − Risikoterm − Transaktionskosten − Steuerwirkung.
|
||||
* Solver: CVXPY (konvexer Teil) oder MIQP für die Kardinalität.
|
||||
(semikontinuierlich, {ref:kap:milp}), höchstens $K$ Transaktionen je Rebalancing{idx:Rebalancing}.
|
||||
* Ziel: erwartete Rendite − Risikoterm − Transaktionskosten{idx:Transaktionskosten} − Steuerwirkung.
|
||||
* Solver: CVXPY{idx:CVXPY} (konvexer Teil) oder MIQP für die Kardinalität.
|
||||
|
||||
**Abnahmekriterien.**
|
||||
- [ ] Toleranzband: Es wird nur gehandelt, wenn die Abweichung > 5 Prozentpunkte beträgt.
|
||||
|
|
@ -224,7 +224,7 @@ Ihre Strategie die Gleichgewichtung nicht schlägt, ist das ein Ergebnis, kein M
|
|||
- [ ] Klartext-Zusammenfassung: „Im schlechtesten Prozent der Monate verlieren Sie
|
||||
typischerweise X €.“
|
||||
|
||||
**Stolperfallen.** Die Wurzel-Zeit-Regel bei CVaR ({ref:kap:cvar}) — nicht blind anwenden.
|
||||
**Stolperfallen.** Die Wurzel-Zeit-Regel{idx:Wurzel-Zeit-Regel} bei CVaR ({ref:kap:cvar}) — nicht blind anwenden.
|
||||
Korrelationen sind in Krisen andere als im Mittel: Stresstest mit erhöhten Korrelationen
|
||||
rechnen.
|
||||
|
||||
|
|
@ -276,7 +276,7 @@ genau die Frage, um die es geht.
|
|||
Kilogramm CO₂ an Mehrkosten bedeutet.
|
||||
|
||||
**Abnahmekriterien.**
|
||||
- [ ] Die Pareto-Front ist berechnet und gezeichnet, nicht nur beschrieben.
|
||||
- [ ] Die Pareto-Front{idx: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 **gewichtete Summe
|
||||
niemals** finden würde — und warum.
|
||||
|
|
@ -296,7 +296,7 @@ Modell, sondern der Schritt danach.
|
|||
**Modellskizze.** Vier Schichten, jede einzeln abnehmbar:
|
||||
* **Domäne:** Eingabedaten als validierte Objekte (Pydantic), nicht als lose Dictionaries —
|
||||
ein falscher Wert soll beim Einlesen auffallen, nicht im Solver ({ref:kap:praxisfallen}).
|
||||
* **Kern:** Modellaufbau und Lösung hinter einer Funktion, die ein `Loesung`-Objekt
|
||||
* **Kern:** Modellaufbau und Lösung hinter einer Funktion{idx:Konvexität!Funktion}, die ein `Loesung`-Objekt
|
||||
zurückgibt und **alle** Statusfälle behandelt.
|
||||
* **Tests:** eine Suite, die auch die Fälle abdeckt, in denen es *keine* Lösung gibt
|
||||
({ref:kap:testing}).
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@
|
|||
(d)/(e): Die Prognose sagt, *wer* kündigen wird; die Optimierung sagt, *wen* man mit dem
|
||||
vorhandenen Geld halten kann.
|
||||
|
||||
**{loesung} — Hart oder weich?**
|
||||
(a) **hart** — gesetzlich zwingend. (b) **weich** — Wunsch, mit Strafkosten. (c) **hart** —
|
||||
**{loesung} — Hart oder weich{idx:Nebenbedingung!weich}?**
|
||||
(a) **hart** — gesetzlich zwingend. (b) **weich** — Wunsch, mit Strafkosten{idx:Strafkosten}. (c) **hart** —
|
||||
Patientensicherheit, rechtlich vorgeschrieben. (d) **weich** — Fairnessziel, über
|
||||
Strafterme. (e) **hart**, falls tariflich/gesetzlich fixiert, sonst weich mit sehr hoher
|
||||
Strafterme. (e) **hart**{idx:Nebenbedingung!hart}, falls tariflich/gesetzlich fixiert, sonst weich mit sehr hoher
|
||||
Strafe. Faustregel: Hart ist nur, was rechtlich oder physikalisch unmöglich zu verletzen
|
||||
ist.
|
||||
|
||||
|
|
@ -33,8 +33,8 @@ Jeder weitere Auftrag multipliziert die Zeit mit der neuen Anzahl.
|
|||
$14! = 8{,}7\cdot10^{10}$ ✗. Also **13 Aufträge**.
|
||||
|
||||
**{loesung} — Modell lesen.**
|
||||
(a) Variablen $x_1, x_2 \ge 0$; Parameter $(3,5)$ und die Kapazitäten $(4,12,18)$;
|
||||
Zielfunktion $\max 3x_1+5x_2$; vier Nebenbedingungen inkl. Nichtnegativität.
|
||||
(a) Variablen $x_1, x_2 \ge 0$; Parameter{idx:Parameter (Modell)} $(3,5)$ und die Kapazitäten $(4,12,18)$;
|
||||
Zielfunktion{idx:Zielfunktion} $\max 3x_1+5x_2$; vier Nebenbedingungen inkl. Nichtnegativität.
|
||||
(b) $(2,6)$: $2\le4$ ✓, $12\le12$ ✓, $6+12=18\le18$ ✓ → zulässig, $Z=36$.
|
||||
$(4,3)$: $4\le4$ ✓, $6\le12$ ✓, $12+6=18\le18$ ✓ → zulässig, $Z=27$.
|
||||
(c) Beste ganzzahlige Lösung ist $(2,6)$ mit $Z=36$ — sie ist hier bereits ganzzahlig, weil
|
||||
|
|
@ -73,7 +73,7 @@ $Z = 2{,}5\cdot96 + 3\cdot70 = 240 + 210 = 450$ ✓.
|
|||
Schleife über `RAM_GESAMT in range(54, 73, 2)`, jeweils Modell neu lösen.
|
||||
(a) Ab 62 GB steigt der Gewinn nicht mehr — dann bindet die **vCPU**-Grenze, RAM ist nicht
|
||||
mehr der Engpass.
|
||||
(b) Der Zuwachs je GB ist der **Schattenpreis** ({ref:kap:lp}). Solange RAM bindet, liegt er
|
||||
(b) Der Zuwachs je GB ist der **Schattenpreis**{idx:Schattenpreis} ({ref:kap:lp}). Solange RAM bindet, liegt er
|
||||
bei 31,25 €/GB; danach fällt er auf 0.
|
||||
|
||||
**{loesung} — Eigenes Problem.** Individuell. Prüfkriterien: Sind die Variablen wirklich
|
||||
|
|
@ -150,9 +150,9 @@ Grund für die Rechenzeit.
|
|||
|
||||
---
|
||||
|
||||
## Lösungen zu Kapitel „Das mathematische Fundament — Vektoren, Matrizen, Konvexität“ {#sec:loesungen-fundament}
|
||||
## Lösungen zu Kapitel „Das mathematische Fundament — Vektoren, Matrizen, Konvexität{idx:Konvexität}“ {#sec:loesungen-fundament}
|
||||
|
||||
**{loesung} — Matrixform lesen.**
|
||||
**{loesung} — Matrixform{idx:Matrixform} lesen.**
|
||||
$\max 4x_1 + x_2 + 6x_3$ u. d. N. $x_1 + 2x_2 \le 10$, $x_2 + 3x_3 \le 12$, $x \ge 0$.
|
||||
**3 Variablen, 2 Nebenbedingungen** (plus Nichtnegativität).
|
||||
|
||||
|
|
@ -175,9 +175,9 @@ aber weiterhin mindestens eine in einer Ecke — der Fundamentalsatz bleibt gül
|
|||
(c) **nicht** konvex, sondern **konkav** ($f'' = -\tfrac14 x^{-3/2} < 0$).
|
||||
(d) **nicht** konvex, konkav ($f'' = -1/x^2 < 0$).
|
||||
(e) konvex (Summe konvexer Funktionen; Hesse-Matrix $2\mathbf{I} \succ 0$).
|
||||
(f) konvexe Menge (Kreisscheibe).
|
||||
(f) konvexe Menge{idx:Konvexität!Menge} (Kreisscheibe).
|
||||
(g) **konvexe Menge** — der Bereich oberhalb der Hyperbel im positiven Quadranten ist
|
||||
konvex (Achtung, überraschend: die *Funktion* $1/x$ ist konvex, und die Menge
|
||||
konvex (Achtung, überraschend: die *Funktion*{idx:Konvexität!Funktion} $1/x$ ist konvex, und die Menge
|
||||
$\{x_2 \ge 1/x_1\}$ ist der Epigraph einer konvexen Funktion, also konvex).
|
||||
|
||||
**{loesung} — Positive Semidefinitheit.**
|
||||
|
|
@ -256,7 +256,7 @@ sagt, *wo* man suchen muss, nicht dass die Suche billig ist.
|
|||
**2 — (b).** Faustregel $\kappa = 10^{k}$ ⟹ etwa $k$ signifikante Stellen verloren; bei
|
||||
$10^{11}$ bleiben von 16 rund 5. Das Modell ist deshalb nicht unlösbar (a) — es rechnet nur
|
||||
mit einer Genauigkeit, die den Ergebnissen nicht mehr anzusehen ist. (c) verwechselt die
|
||||
Konditionszahl mit einem Aufwandsmaß; sie sagt nichts über die Iterationszahl.
|
||||
Konditionszahl{idx:Konditionszahl} mit einem Aufwandsmaß; sie sagt nichts über die Iterationszahl.
|
||||
|
||||
**3 — (c).** `int()` schneidet ab: `int(0.99999998) == 0` macht aus einer Ja- eine
|
||||
Nein-Entscheidung (a). Den Wert unverändert weiterzureichen (b) verschiebt das Problem nur
|
||||
|
|
@ -281,9 +281,9 @@ ist die Prüfung gegen die Toleranz mit Fehlermeldung im Zweifelsfall — die Fu
|
|||
## Lösungen zu Kapitel „Das Python-Ökosystem für OR — Solver, Bindings und Modellierungsschichten“ {#sec:loesungen-oekosystem}
|
||||
|
||||
**{loesung} — Solverwahl.**
|
||||
(a) CP-SAT (diskrete Zuordnung mit Zeitfenstern).
|
||||
(a) CP-SAT{idx:CP-SAT} (diskrete Zuordnung mit Zeitfenstern).
|
||||
(b) `scipy.optimize.linprog` (klassisches Mischungs-LP, klein).
|
||||
(c) CVXPY (konvexes QP).
|
||||
(c) CVXPY{idx:CVXPY} (konvexes QP).
|
||||
(d) MIQP — CVXPY mit Binärvariablen und MIQP-fähigem Solver, oder Heuristik.
|
||||
(e) MILP über `highspy` oder CP-SAT (Standortproblem mit Fixkosten).
|
||||
(f) `scipy.optimize.minimize` mit Multistart (nicht konvex).
|
||||
|
|
@ -292,7 +292,7 @@ ist die Prüfung gegen die Toleranz mit Fehlermeldung im Zweifelsfall — die Fu
|
|||
(kontinuierlich) liefern. Denken Sie an die Prozesstrennung, falls `ortools` und `highspy`
|
||||
kollidieren.
|
||||
|
||||
**{loesung} — CSR-Format.**
|
||||
**{loesung} — CSR-Format{idx:CSR-Format}.**
|
||||
`values = [3, 1, 2, 5, 4, 6]`, `indices = [0, 3, 2, 0, 1, 3]`, `starts = [0, 2, 3]`.
|
||||
CSR speichert 6 Werte + 6 Indizes + 3 Startpositionen = 15 Zahlen; die volle Matrix hätte
|
||||
$3\times4 = 12$. **Bei dieser winzigen, dicht besetzten Matrix lohnt CSR nicht** — der
|
||||
|
|
@ -311,8 +311,8 @@ der Modellaufbau effizienter ist. CVXPY hat den größten festen Aufwand
|
|||
(Ausdrucksbaum-Kompilierung), der bei wiederholten Läufen mit `cp.Parameter` teilweise
|
||||
entfällt.
|
||||
|
||||
**{loesung} — Eigene Entscheidungshilfe.** Ergänzungen: Bei kommerzieller Lizenz Gurobi/CPLEX
|
||||
über Pyomo oder CVXPY empfehlen; bei Lesbarkeitsanforderung Pyomo (algebraische Notation,
|
||||
**{loesung} — Eigene Entscheidungshilfe.** Ergänzungen: Bei kommerzieller Lizenz Gurobi{idx:Gurobi}/CPLEX
|
||||
über Pyomo{idx:Pyomo} oder CVXPY empfehlen; bei Lesbarkeitsanforderung Pyomo{idx:Pyomo} (algebraische Notation,
|
||||
Trennung von Daten und Modell).
|
||||
|
||||
### Finde den Denkfehler — Der Solver, der angeblich dreimal schneller ist
|
||||
|
|
@ -377,7 +377,7 @@ Sekunden — selbst bei Faktor 4 gewinnen Sie 6 der 40 Sekunden. Das Zeitlimit (
|
|||
den Abbruch, nicht die Geschwindigkeit. Die Regel dahinter: **erst messen, wo die Zeit
|
||||
hingeht, dann optimieren.**
|
||||
|
||||
**3 — (b).** Alle vier sind Modellierungsschichten über HiGHS. Deshalb liefern sie
|
||||
**3 — (b).** Alle vier sind Modellierungsschichten über HiGHS{idx:HiGHS}. Deshalb liefern sie
|
||||
denselben Zielwert (bis auf Toleranz) und unterscheiden sich in der reinen Rechenzeit kaum
|
||||
— wohl aber im Aufbauaufwand und in der Lesbarkeit. (a) ist falsch: Niemand von ihnen
|
||||
implementiert den Simplex in Python, das wäre um Größenordnungen zu langsam. (c) ist
|
||||
|
|
@ -394,7 +394,7 @@ es spezialisierte globale Solver ({ref:kap:qp-nlp}).
|
|||
4. Wegen des Kompilierungsaufwands des Ausdrucksbaums. Kein Argument dagegen, weil dieser
|
||||
Aufwand einmalig ist, die Lesbarkeit hoch und die Konvexitätsprüfung wertvoll.
|
||||
5. Bei rein kontinuierlichen Problemen (CP-SAT kennt nur ganze Zahlen) und bei reinen
|
||||
Routing-Problemen (dort ist die Routing-Bibliothek überlegen).
|
||||
Routing-Problemen (dort ist die Routing-Bibliothek{idx:Routing-Bibliothek} überlegen).
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -577,13 +577,13 @@ Ressource 3 — der höchste Schattenpreis (9,8) bedeutet den größten Grenznut
|
|||
zurückgedreht. Der korrekte Schattenpreis ist **+45 €**.
|
||||
|
||||
**{loesung} — Simplex von Hand.**
|
||||
Starttableau mit $s_1, s_2$ in der Basis. Erste Iteration: Pivotspalte $x_1$ ($-5$),
|
||||
Quotienten $24/6 = 4$ und $6/1 = 6$ → Pivotzeile 1. Nach dem Tausch: $x_1 = 4$, $Z = 20$.
|
||||
Starttableau mit $s_1, s_2$ in der Basis. Erste Iteration: Pivotspalte{idx:Simplex-Algorithmus!Pivotspalte} $x_1$ ($-5$),
|
||||
Quotienten $24/6 = 4$ und $6/1 = 6$ → Pivotzeile{idx:Simplex-Algorithmus!Pivotzeile} 1. Nach dem Tausch: $x_1 = 4$, $Z = 20$.
|
||||
Zweite Iteration: Pivotspalte $x_2$, Pivotzeile 2 → $x_1 = 3$, $x_2 = 1{,}5$, $Z = 21$.
|
||||
**Optimum:** $\mathbf{x}^* = (3;\ 1{,}5)$, $Z^* = 21$, Schattenpreise
|
||||
$y^* = (0{,}75;\ 0{,}50)$.
|
||||
|
||||
**{loesung} — Duales Problem.**
|
||||
**{loesung} — Duales Problem{idx:Duales Problem}.**
|
||||
$\min 24y_1 + 6y_2$ u. d. N. $6y_1 + y_2 \ge 5$, $4y_1 + 2y_2 \ge 4$, $y \ge 0$.
|
||||
Lösung $y^* = (0{,}75;\ 0{,}50)$. Probe der Restriktionen:
|
||||
$6\cdot0{,}75 + 0{,}5 = 5$ ✓ (mit Gleichheit, weil $x_1 > 0$),
|
||||
|
|
@ -672,7 +672,7 @@ vorhanden, muss der Dualwert null sein. (a) hat die Aussage in ihr Gegenteil ver
|
|||
verwechselt Schlupf mit Auslastung — $s_i = 12$ heißt gerade, dass 12 Einheiten *übrig*
|
||||
sind.
|
||||
|
||||
**2 — (b) Entartung.** 7 aktive Bedingungen bei 5 Variablen bedeuten: Die Ecke ist
|
||||
**2 — (b) Entartung{idx:Entartung}.** 7 aktive Bedingungen bei 5 Variablen bedeuten: Die Ecke ist
|
||||
überbestimmt, es gibt mehrere optimale Dualvektoren, und welchen der Solver zeigt, hängt
|
||||
vom gewählten Verfahren ab. (a) verharmlost genau den Fall, der Fehlentscheidungen
|
||||
produziert; (c) verwechselt Entartung mit Unlösbarkeit — der Plan selbst ist völlig in
|
||||
|
|
@ -697,7 +697,7 @@ abgesehen von genau diesem Rauschen.
|
|||
|
||||
---
|
||||
|
||||
## Lösungen zu Kapitel „Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound“ {#sec:loesungen-milp}
|
||||
## Lösungen zu Kapitel „Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound{idx:Branch-and-Bound}“ {#sec:loesungen-milp}
|
||||
|
||||
**{loesung} — Runden widerlegen.**
|
||||
Beispiel: $\max x_1 + x_2$ u. d. N. $10x_1 + 10x_2 \le 15$, ganzzahlig. LP-Optimum
|
||||
|
|
@ -706,7 +706,7 @@ Optimum ist $(1,0)$ mit $Z = 1$. Prinzip: kleine Zahlen plus knappe Kapazität.
|
|||
|
||||
**{loesung} — Big-M wählen.**
|
||||
$M = 250$ (die bekannte Kapazität). Bei $M = 10^6$ bleibt das Modell korrekt, aber die
|
||||
LP-Relaxation wird extrem schwach: $y_j$ darf schon bei $x_j/10^6$ liegen, die Schranke ist
|
||||
LP-Relaxation{idx:LP-Relaxation} wird extrem schwach: $y_j$ darf schon bei $x_j/10^6$ liegen, die Schranke ist
|
||||
praktisch wertlos, und Branch-and-Bound muss weit mehr Knoten durchsuchen.
|
||||
|
||||
**{loesung} — Regeln übersetzen.**
|
||||
|
|
@ -717,7 +717,7 @@ praktisch wertlos, und Branch-and-Bound muss weit mehr Knoten durchsuchen.
|
|||
(e) $\sum_{j=1}^3 y_j = 1$.
|
||||
|
||||
**{loesung} — Branch-and-Bound.**
|
||||
LP-Relaxation der Wurzel: nach Nutzen/Gewicht sortieren ($8/5=1{,}6$; $11/7=1{,}57$;
|
||||
LP-Relaxation{idx:Relaxation} der Wurzel: nach Nutzen/Gewicht sortieren ($8/5=1{,}6$; $11/7=1{,}57$;
|
||||
$6/4=1{,}5$; $4/3=1{,}33$). Gierig füllen: $x_1=1$ (Rest 9), $x_2=1$ (Rest 2),
|
||||
$x_3 = 0{,}5$ → $Z_{LP} = 8+11+3 = 22$. Verzweigen über $x_3$.
|
||||
Ast $x_3=0$: $x_1=1,x_2=1,x_4=2/3$ → $Z = 21{,}67$; weiter verzweigen → beste ganzzahlige
|
||||
|
|
@ -810,7 +810,7 @@ Schranke mit einem erreichbaren Wert: 47 100 € ist eine *untere* Schranke, es
|
|||
offen, ob ein Plan mit diesen Kosten überhaupt existiert.
|
||||
|
||||
**2 — (b).** Die Laufzeit (a) ist ein realer, aber beherrschbarer Nachteil — man merkt ihn
|
||||
und kann reagieren. Der Trickle Flow dagegen ist **still**: Das Modell meldet `Optimal`,
|
||||
und kann reagieren. Der Trickle Flow{idx:Trickle Flow} dagegen ist **still**: Das Modell meldet `Optimal`,
|
||||
liefert eine Zahl, und niemand sieht, dass die Fixkosten verschwunden sind. Ein Fehler, den
|
||||
man bemerkt, ist immer harmloser als einer, den man nicht bemerkt. (c) ist frei erfunden —
|
||||
negative Kosten entstehen dabei nicht.
|
||||
|
|
@ -819,12 +819,12 @@ negative Kosten entstehen dabei nicht.
|
|||
und verworfen, wenn er nicht zulässig ist. Das Ergebnis bleibt in jedem Fall korrekt (b ist
|
||||
also falsch), und `INFEASIBLE` bezieht sich immer auf das Modell, nie auf einen Hinweis (a
|
||||
ist falsch). Praktische Konsequenz: Prüfen Sie Ihre Startlösung selbst auf Zulässigkeit —
|
||||
sonst messen Sie einen Warm-Start-Effekt, den es gar nicht gibt.
|
||||
sonst messen Sie einen Warm-Start{idx:Warm-Start}-Effekt, den es gar nicht gibt.
|
||||
|
||||
### Selbsttest {#selbsttest-loesung-milp}
|
||||
1. Weil die Relaxation **mehr** Lösungen zulässt (alle ganzzahligen plus gebrochene) — das
|
||||
Maximum über einer größeren Menge ist mindestens so groß.
|
||||
2. Teilproblem unzulässig; Schranke schlechter als der Incumbent; LP-Lösung bereits
|
||||
2. Teilproblem unzulässig; Schranke schlechter als der Incumbent{idx:Branch-and-Bound!Incumbent}; LP-Lösung bereits
|
||||
ganzzahlig.
|
||||
3. $L\,y \le x \le U\,y$ mit binärem $y$.
|
||||
4. Weil die LP-Relaxation dadurch schwächer wird: Die berechnete Schranke liegt weiter vom
|
||||
|
|
@ -852,7 +852,7 @@ Zuweisungssummen koppeln, dann `modell.Add(arbeitet_bauer + arbeitet_koch <= 1)`
|
|||
(c) Belohnung = negative Strafe: `strafterme.append(-30 * folge_var)`, wobei `folge_var`
|
||||
per `AddBoolAnd`/`OnlyEnforceIf` an $x_{p,0} \wedge x_{p,1}$ gekoppelt wird.
|
||||
|
||||
**{loesung} — Infeasibility.**
|
||||
**{loesung} — Infeasibility{idx:Infeasibility}.**
|
||||
Mit `MAX_VERTRETUNGEN = 0` meldet der Solver `INFEASIBLE`. Nach Einbau der Schlupfvariablen
|
||||
lässt der Solver **alle vier** Stunden ausfallen (4 × 10 000 = 40 000 Strafpunkte) — es geht
|
||||
nicht anders. Interessanter wird es bei `MAX_VERTRETUNGEN = 1`: Dann fällt genau die Stunde
|
||||
|
|
@ -892,7 +892,7 @@ Reproduzierbarkeit:
|
|||
|
||||
Nur die Kombination trägt.
|
||||
(c) Bei **15 Aufträgen** (60 s Zeitlimit): Ein Arbeiter läuft ins Limit und meldet
|
||||
`FEASIBLE` mit Makespan 200; acht Arbeiter melden `OPTIMAL` mit **demselben** Makespan 200
|
||||
`FEASIBLE` mit Makespan{idx:Makespan} 200; acht Arbeiter melden `OPTIMAL` mit **demselben** Makespan 200
|
||||
nach 26,4 s. Bei 13 Aufträgen sind es 11,2 s gegen 2,8 s, bei 14 schon 21,4 s gegen 3,7 s.
|
||||
Bemerkenswert ist, dass beide denselben Wert finden — der Unterschied liegt nicht in der
|
||||
Lösung, sondern im **Beweis**, dass es keine bessere gibt. Genau diese Arbeit teilen sich
|
||||
|
|
@ -1012,7 +1012,7 @@ Regeln. Wer eine reproduzierbare Ausgabe braucht — etwa für ein Buch —, fix
|
|||
|
||||
## Lösungen zu Kapitel „Graphen, Flüsse und Touren — Min-Cost-Flow, Matching und VRP“ {#sec:loesungen-graphen}
|
||||
|
||||
**{loesung} — Flusserhaltung.** $b_i = (15+3) - (12+8) = -2$ → **Senke** (Nettobedarf 2).
|
||||
**{loesung} — Flusserhaltung{idx:Flusserhaltung}.** $b_i = (15+3) - (12+8) = -2$ → **Senke** (Nettobedarf 2).
|
||||
|
||||
**{loesung} — Unlösbarkeit.** Die Summe aller Flusserhaltungsgleichungen ergibt $\sum_i b_i = 0$
|
||||
(jede Kante taucht einmal mit $+1$ und einmal mit $-1$ auf). Ist die Summe ungleich null,
|
||||
|
|
@ -1051,12 +1051,12 @@ Weg).
|
|||
Auslastung deutlich. (b) Unlösbar, sobald $\text{Kapazität} \times \text{Fahrzeuge} <
|
||||
\text{Gesamtbedarf}$ (hier: bei 3 Fahrzeugen à 10 sind 30 < 37 → unlösbar) **oder** wenn
|
||||
Zeitfenster nicht mehr eingehalten werden können. (c) 1 s liefert meist eine brauchbare,
|
||||
30 s eine spürbar bessere Lösung — die Metaheuristik verbessert kontinuierlich.
|
||||
30 s eine spürbar bessere Lösung — die Metaheuristik{idx:Metaheuristik} verbessert kontinuierlich.
|
||||
(d) Doppelte Servicezeit kann Zeitfenster verletzen → möglicherweise unlösbar.
|
||||
|
||||
**{loesung} — TSP mit MTZ.** Erwartetes Ergebnis: Bei 8 Städten löst das MILP in Sekunden. Ab
|
||||
etwa 12–15 Städten wird die schwache MTZ-Relaxation zum Problem, und die Laufzeit steigt
|
||||
stark — während OR-Tools weiterhin in Sekundenbruchteilen sehr gute Touren liefert.
|
||||
stark — während OR-Tools{idx:OR-Tools} weiterhin in Sekundenbruchteilen sehr gute Touren liefert.
|
||||
|
||||
### Finde den Denkfehler — Die vergessene Dimension
|
||||
|
||||
|
|
@ -1345,7 +1345,7 @@ kostet bis zu eine Rolle, und in der Summe sind es sechs.
|
|||
|
||||
Die Schranke sagt: *Weniger als 73 Rollen sind unmöglich.* Sie sagt **nicht**: *Jede
|
||||
zulässige Lösung liegt höchstens eine Rolle darüber.* Das ist die Verwechslung von unterer
|
||||
Schranke und Gütegarantie — dieselbe Verwechslung wie beim MIP-Gap in {ref:sec:milp-gap},
|
||||
Schranke und Gütegarantie — dieselbe Verwechslung wie beim MIP-Gap{idx:MIP-Gap} in {ref:sec:milp-gap},
|
||||
nur in die andere Richtung.
|
||||
|
||||
**Was der Kollege stattdessen hätte tun müssen:** das Master ein zweites Mal lösen, diesmal
|
||||
|
|
@ -1362,7 +1362,7 @@ Zeile, dauert Millisekunden und liefert 73 statt 79. Er hatte alles dafür berei
|
|||
Objekte — die Symmetrie verschwindet. (a) trifft zufällig auch zu, ist aber nicht der Grund;
|
||||
(c) ist falsch, die LP-Lösung ist hier gerade **nicht** ganzzahlig (72,92).
|
||||
|
||||
**2. b)** Ein Rucksackproblem: Nutzen sind die Schattenpreise, Gewichte die Breiten,
|
||||
**2. b)** Ein Rucksackproblem{idx:Rucksackproblem}: Nutzen sind die Schattenpreise, Gewichte die Breiten,
|
||||
Kapazität die Rollenbreite. (c) beschreibt eine Heuristik — dann wäre das Verfahren nicht mehr
|
||||
exakt, weil man nie sicher wüsste, ob es wirklich kein lohnendes Muster mehr gibt.
|
||||
|
||||
|
|
@ -1396,7 +1396,7 @@ konvex; die Lösung ist **nicht notwendig eindeutig**. Der Eigenwert 0 bedeutet
|
|||
**flache Richtung**: Entlang des zugehörigen Eigenvektors ändert sich der quadratische Term
|
||||
nicht — es gibt eine Rinne statt eines Punktes.
|
||||
|
||||
**{loesung} — Komplementärer Schlupf.** Ja, verträglich: $\lambda_i w_i = 0$ gilt für alle $i$
|
||||
**{loesung} — Komplementärer Schlupf{idx:Komplementärer Schlupf}.** Ja, verträglich: $\lambda_i w_i = 0$ gilt für alle $i$
|
||||
($w_2 = 0$ mit $\lambda_2 > 0$; die anderen mit $\lambda = 0$). $\lambda_2 = 0{,}03$
|
||||
bedeutet: Würde man Titel 2 zwingen, ein kleines positives Gewicht zu tragen, verschlechterte
|
||||
sich der Zielwert um 0,03 je Einheit — die Nichtnegativitätsschranke ist dort **bindend**.
|
||||
|
|
@ -1431,7 +1431,7 @@ Gewichten negativ werden (der zugehörige Eigenvektor liegt allerdings teilweise
|
|||
des zulässigen Bereichs $w \ge 0{,}001$, $\sum w = 1$ — deshalb fällt der Fehler bei
|
||||
naiver Prüfung nicht auf).
|
||||
|
||||
### Finde den Denkfehler — Die Kovarianzmatrix aus dem Controlling
|
||||
### Finde den Denkfehler — Die Kovarianzmatrix{idx:Kovarianzmatrix} aus dem Controlling
|
||||
|
||||
(a) **Ohne zu rechnen.** Stellen Sie sich die drei Anlagen als drei Personen vor, die
|
||||
nebeneinander gehen. A und B gehen fast im Gleichschritt ($0{,}9$). B und C gehen fast im
|
||||
|
|
@ -1515,7 +1515,7 @@ das im Bericht kenntlich machen.
|
|||
nicht die Qualität des Ergebnisses. Bei Mengenrabatten ist die Zielfunktion nicht konvex,
|
||||
also kann es mehrere lokale Minima geben — im Kapitelbeispiel fünf, mit 8 % Spanne. (a) wäre
|
||||
nur bei einem konvexen Problem richtig. (c) ist zu pessimistisch: Ein lokales Minimum ist es
|
||||
sehr wohl, die Zulässigkeit wird von SLSQP eingehalten.
|
||||
sehr wohl, die Zulässigkeit wird von SLSQP{idx:SLSQP} eingehalten.
|
||||
|
||||
**3 — (c) Schattenpreis.** $\lambda^*$ ist die Ableitung des optimalen Zielwerts nach der
|
||||
rechten Seite der Nebenbedingung — dieselbe Bedeutung wie der Dualwert im LP
|
||||
|
|
@ -1550,7 +1550,7 @@ Projektkosten mit Nachträgen.
|
|||
(b) stochastisch (Verteilung bekannt).
|
||||
(c) robust bzw. Extremwertstatistik (seltene Ereignisse, katastrophale Folgen).
|
||||
(d) stochastisch (Szenarien mit Wahrscheinlichkeiten liegen vor).
|
||||
(e) Chance Constraint — die Zusage ist bereits als Quote formuliert („an 99 % aller
|
||||
(e) Chance Constraint{idx:Chance Constraint} — die Zusage ist bereits als Quote formuliert („an 99 % aller
|
||||
Wintertage“). Robust wäre hier zu teuer (es gibt immer einen kälteren Tag), der
|
||||
Erwartungswert zu schwach (er sagt nichts über die Zusage).
|
||||
|
||||
|
|
@ -1595,7 +1595,7 @@ Prozentpunkt ist bereits 4,5-mal so teuer wie der erste. Sagen Sie mir, was ein
|
|||
das Unternehmen kostet, dann rechne ich aus, welche Quote sich lohnt. Und die Zusage gilt
|
||||
nur für die Wetterlagen, die wir modelliert haben — die Kältewelle gehört hinein.“
|
||||
|
||||
**{loesung} — Budgeted Uncertainty.**
|
||||
**{loesung} — Budgeted Uncertainty{idx:Budgeted Uncertainty}.**
|
||||
```python
|
||||
abzug = cp.sum_largest(cp.multiply(UNSICHERHEIT, w), Gamma)
|
||||
ziel = cp.Maximize(MU_SCHAETZUNG @ w - abzug - 0.5*LAMBDA*cp.quad_form(w, SIGMA))
|
||||
|
|
@ -1620,7 +1620,7 @@ Gewerk, das 17 Tage braucht, hält alle auf. Die guten Ausreißer verpuffen, die
|
|||
schlagen voll durch.
|
||||
|
||||
Damit gilt für das Maximum immer $\mathbb{E}[\max] \ge \max(\mathbb{E})$. Die Differenz ist
|
||||
kein Schätzfehler, sondern eine **systematische Verzerrung** — sie geht immer in dieselbe
|
||||
kein Schätzfehler{idx:Schätzfehler}, sondern eine **systematische Verzerrung** — sie geht immer in dieselbe
|
||||
Richtung, und sie wächst mit der Streuung der Einzelschätzungen.
|
||||
|
||||
(b) **Warum 95,5 %.** Damit das Projekt die geplanten 11,33 Tage hält, müssen **alle fünf**
|
||||
|
|
@ -1683,7 +1683,7 @@ hier 38 Stück. (a) ignoriert die Kostenasymmetrie und kostet im Kapitelbeispiel
|
|||
setzt eine Wahrscheinlichkeitsverteilung voraus und minimiert den Erwartungswert; robuste
|
||||
Optimierung kommt mit einer bloßen Bandbreite aus und sichert den ungünstigsten Fall darin
|
||||
ab. Keines ist „genauer“ (a) — sie beantworten verschiedene Fragen. (c) trifft es nicht:
|
||||
Robuste Optimierung betrachtet nicht mehr Szenarien, sondern eine ganze Menge auf einmal,
|
||||
Robuste Optimierung{idx:Robuste Optimierung} betrachtet nicht mehr Szenarien, sondern eine ganze Menge auf einmal,
|
||||
und interessiert sich darin nur für den schlechtesten Punkt.
|
||||
|
||||
**3 — (c).** Bei durchgehender Linearität und ohne nachgelagerte Entscheidung gilt
|
||||
|
|
@ -1719,20 +1719,20 @@ Fall, in dem es tatsächlich zulässig ist.
|
|||
|
||||
---
|
||||
|
||||
## Lösungen zu Kapitel „Dynamische Programmierung — Die Bellman-Gleichung und Order-Execution“ {#sec:loesungen-dynamische-programmierung}
|
||||
## Lösungen zu Kapitel „Dynamische Programmierung — Die Bellman-Gleichung{idx:Bellman-Gleichung} und Order-Execution“ {#sec:loesungen-dynamische-programmierung}
|
||||
|
||||
**{loesung} — Bausteine.** Stufe = Tag 1–5; Zustand = verbleibende Distanz (ggf. plus
|
||||
Erschöpfungsgrad); Aktion = heutige Tagesetappe; Wertfunktion = minimale Restanstrengung.
|
||||
**Nicht** in den Zustand gehören: bereits gelaufene Kilometer (redundant, wenn die
|
||||
Restdistanz bekannt ist) und das Wetter von gestern (ohne Einfluss auf die Zukunft).
|
||||
|
||||
**{loesung} — Optimalitätsprinzip.** Weil der Wert eines Zustands nur von den *künftigen*
|
||||
**{loesung} — Optimalitätsprinzip{idx:Optimalitätsprinzip}.** Weil der Wert eines Zustands nur von den *künftigen*
|
||||
Entscheidungen abhängt, kann man ihn ab dem Ende rekursiv berechnen. Hängen die Kosten
|
||||
zusätzlich von **früheren** Aktionen ab, ist die Markov-Eigenschaft verletzt — die Lösung:
|
||||
die relevante Vergangenheit **in den Zustand aufnehmen** (dann wächst allerdings der
|
||||
Zustandsraum).
|
||||
Zustandsraum{idx:Zustandsraum}).
|
||||
|
||||
**{loesung} — Rückwärtsinduktion.** Mit $C(n) = n^2 + 2n$ und 5 Einheiten in 3 Perioden ergibt
|
||||
**{loesung} — Rückwärtsinduktion{idx:Rückwärtsinduktion}.** Mit $C(n) = n^2 + 2n$ und 5 Einheiten in 3 Perioden ergibt
|
||||
sich als optimaler Pfad $2 \to 2 \to 1$ (oder eine Permutation davon) mit Gesamtkosten
|
||||
$8 + 8 + 3 = 19$. Alles auf einmal kostet $25 + 10 = 35$.
|
||||
|
||||
|
|
@ -1807,7 +1807,7 @@ def V(t, lager, lief_vorher):
|
|||
Damit findet die Rückwärtsinduktion $(3, 1, 4, 2)$ für 70 € — das nachgerechnete Optimum.
|
||||
Der Zustandsraum **verdoppelt** sich (je Lagerstand zwei Varianten, „lief“ und „lief
|
||||
nicht“). Das ist der übliche Preis: Vollständigkeit des Zustands kostet Größe, und genau
|
||||
hier beginnt der Fluch der Dimensionalität.
|
||||
hier beginnt der Fluch der Dimensionalität{idx:Fluch der Dimensionalität}.
|
||||
|
||||
(d) **Warum der richtige Betrag das Tückische ist.** Man würde erwarten, dass ein falsches
|
||||
Modell auch einen falschen Kostenbetrag ausgibt — dann fiele es beim Nachrechnen auf. Hier
|
||||
|
|
@ -1855,7 +1855,7 @@ Eignung.
|
|||
3. Alles, was die Zukunft beeinflusst, und nichts weiter. Unvollständig ist er, wenn die
|
||||
Kosten oder Übergänge zusätzlich von der Vorgeschichte abhängen.
|
||||
4. Der Aufwand wächst multiplikativ mit jeder Zustandsdimension. Gegenmittel: gröbere
|
||||
Diskretisierung/Zustandsreduktion, Funktionsapproximation (ADP), Reinforcement Learning.
|
||||
Diskretisierung/Zustandsreduktion, Funktionsapproximation (ADP), Reinforcement Learning{idx:Reinforcement Learning}.
|
||||
5. Weil sie eine **unabhängige** Prüfung ermöglicht — Größenordnungsfehler und
|
||||
Vorzeichenfehler fallen sofort auf.
|
||||
|
||||
|
|
@ -1898,7 +1898,7 @@ Wer ihn auflösen will, sollte zuerst prüfen, ob sich die Ressource vermehren l
|
|||
über Gewichte zu verhandeln.
|
||||
|
||||
**{loesung} — Die Front der Relaxation.**
|
||||
Ohne `integrality` ist der zulässige Bereich konvex, und die Pareto-Front liegt vollständig
|
||||
Ohne `integrality` ist der zulässige Bereich konvex, und die Pareto-Front{idx:Pareto-Front} liegt vollständig
|
||||
auf ihrer eigenen unteren konvexen Hülle. Es gibt also **keinen** Punkt oberhalb — jeder
|
||||
Punkt der Front ist durch ein passendes Gewicht erreichbar.
|
||||
|
||||
|
|
@ -1986,7 +1986,7 @@ aber nicht zu: Auch bei exakt gleichem Budget bliebe der Effekt.
|
|||
|
||||
---
|
||||
|
||||
## Lösungen zu Kapitel „Predict-then-Optimize“ {#sec:loesungen-prognose}
|
||||
## Lösungen zu Kapitel „Predict-then-Optimize{idx:Predict-then-Optimize}“ {#sec:loesungen-prognose}
|
||||
|
||||
**{loesung} — Andere Preise.**
|
||||
Der Überhang kostet nur noch 1,50 €, die Fehlmenge weiterhin 6 €. Das kritische Verhältnis
|
||||
|
|
@ -2206,7 +2206,7 @@ der Methode.
|
|||
1. Montagestunden ↔ Kapital; Plattenmaterial ↔ Risikobudget; Deckungsbeitrag je Stück ↔
|
||||
erwarteter Ertrag je 1 000 €. (Weitere: Mindestlosgröße ↔ Mindestordergröße,
|
||||
Rüstkosten ↔ Ordergebühr, Sortimentsbreite ↔ Kardinalitätsgrenze.)
|
||||
2. Ein LP sieht eine Matrix, einen Kapazitätsvektor und einen Zielvektor — Bedeutung kommt
|
||||
2. Ein LP sieht eine Matrix, einen Kapazitätsvektor{idx:Kapazitätsvektor} und einen Zielvektor — Bedeutung kommt
|
||||
darin nicht vor. Das ist hier ein Vorteil, weil derselbe geprüfte, getestete Code beide
|
||||
Domänen bedient; man erbt die Verlässlichkeit mit.
|
||||
3. „Stellen Sie sich vor, Ihre Engpassmaschine wäre nicht die Fräse, sondern eine Vorschrift:
|
||||
|
|
@ -2506,16 +2506,16 @@ $\sigma_p^2 = 0{,}25\cdot0{,}0625 + 0{,}25\cdot0{,}0144
|
|||
+ 2\cdot0{,}25\cdot(-0{,}2)\cdot0{,}25\cdot0{,}12
|
||||
= 0{,}015625 + 0{,}0036 - 0{,}003 = 0{,}016225$, also $\sigma_p = 12{,}74\,\%$.
|
||||
|
||||
Beste Sharpe Ratio unter den vier Kandidaten: $(0{,}3;\ 0{,}7)$. Das exakte Optimum liegt
|
||||
Beste Sharpe Ratio{idx:Sharpe-Ratio} unter den vier Kandidaten: $(0{,}3;\ 0{,}7)$. Das exakte Optimum liegt
|
||||
bei $w_1 = 0{,}318$. **Bemerkenswert:** Die Mischung $(0{,}3;\ 0{,}7)$ hat mit 10,08 % eine
|
||||
**geringere** Volatilität als *beide* Einzeltitel (25 % und 12 %) — genau der
|
||||
**geringere** Volatilität{idx:Volatilität} als *beide* Einzeltitel (25 % und 12 %) — genau der
|
||||
Diversifikationseffekt, den die negative Korrelation ermöglicht.
|
||||
|
||||
**{loesung} — Lambda deuten.** Von $\lambda=0$ (GMV, linker unterer Punkt der Kurve) wandert die
|
||||
Lösung entlang der Effizienzgrenze nach rechts oben, bis sie bei $\lambda\to\infty$ im Titel
|
||||
mit der höchsten Rendite endet (bzw. an der Positionsobergrenze).
|
||||
|
||||
**{loesung} — Korn-Transformation.**
|
||||
**{loesung} — Korn-Transformation{idx:Korn-Transformation}.**
|
||||
$\text{SR}(c\mathbf{w}) = \frac{c\mathbf{w}^\top\boldsymbol{\mu}-r_f}{\sqrt{c^2\mathbf{w}^\top\boldsymbol{\Sigma}\mathbf{w}}}$
|
||||
— bei einem Portfolio mit $\sum w_i = 1$ und Überrenditen geschrieben als
|
||||
$\mathbf{w}^\top(\boldsymbol{\mu}-r_f\mathbf{1})$ kürzt sich $c$ heraus. Mit der Bedingung
|
||||
|
|
@ -2611,7 +2611,7 @@ aussehen.
|
|||
|
||||
**1 — (b).** Das renditestärkste Portfolio auf der Effizienzlinie hat notwendig das
|
||||
schlechteste Rendite-Risiko-Verhältnis (im Kapitelbeispiel 0,44 gegenüber 0,75 beim
|
||||
Optimum) und besteht vollständig aus der renditestärksten Einzelanlage — Diversifikation
|
||||
Optimum) und besteht vollständig aus der renditestärksten Einzelanlage — Diversifikation{idx:Diversifikation}
|
||||
findet dort gar nicht mehr statt. (a) und (c) sind sachlich falsch: Der Punkt ist numerisch
|
||||
völlig unproblematisch und wird von CVXPY ohne Weiteres gefunden.
|
||||
|
||||
|
|
@ -2642,14 +2642,14 @@ Risikowerten, nicht zu Konzentration.
|
|||
|
||||
---
|
||||
|
||||
## Lösungen zu Kapitel „Tail-Risiko, CVaR und Transaktionskosten“ {#sec:loesungen-cvar}
|
||||
## Lösungen zu Kapitel „Tail-Risiko, CVaR und Transaktionskosten{idx:Transaktionskosten}“ {#sec:loesungen-cvar}
|
||||
|
||||
**{loesung} — VaR und CVaR von Hand.**
|
||||
Sortierte Verluste: $-2{,}0; -1{,}2; -0{,}8; -0{,}4; 0{,}3; 0{,}6; 1{,}1; 2{,}1; 5{,}4;
|
||||
8{,}9$. Das 80 %-Quantil ist der 8. Wert: $\text{VaR}_{80\%} = 2{,}1$.
|
||||
$\text{CVaR}_{80\%} = $ Mittel der schlechtesten 20 % $= (5{,}4+8{,}9)/2 = \mathbf{7{,}15}$.
|
||||
|
||||
**{loesung} — Subadditivität.** Ein Risikomaß sollte Diversifikation nie bestrafen: Das Risiko
|
||||
**{loesung} — Subadditivität{idx:Subadditivität}.** Ein Risikomaß sollte Diversifikation nie bestrafen: Das Risiko
|
||||
eines zusammengelegten Portfolios darf nicht größer sein als die Summe der Einzelrisiken.
|
||||
Wird das verletzt, hätte eine Bank einen Anreiz, Portfolios künstlich aufzuspalten, um
|
||||
Eigenkapitalanforderungen zu senken — ökonomisch unsinnig.
|
||||
|
|
@ -2741,7 +2741,7 @@ wenn man Mengen zusammenlegt; ein Quantil nicht — es kann springen, sobald sic
|
|||
Reihenfolge der Szenarien ändert.
|
||||
|
||||
**Die praktische Konsequenz** ist die Umstellung der Bankenaufsicht mit Basel III vom VaR auf
|
||||
den *Expected Shortfall* — dieselbe Größe, die hier CVaR heißt. Und für Ihre eigenen
|
||||
den *Expected Shortfall*{idx:Expected Shortfall} — dieselbe Größe, die hier CVaR heißt. Und für Ihre eigenen
|
||||
Modelle, auch außerhalb der Finanzwelt: Wo immer Sie eine Risikokennzahl über Einheiten
|
||||
aggregieren wollen, prüfen Sie zuerst, ob das Maß das überhaupt zulässt.
|
||||
|
||||
|
|
@ -2785,7 +2785,7 @@ Anleihen dort sind **gerade unabhängig**, und genau deshalb tritt die Verletzun
|
|||
**{loesung} — Lookahead erkennen.**
|
||||
(a) sauber (`:heute`). (b) **Lookahead** — gesamter Zeitraum. (c) **Lookahead** —
|
||||
Volatilität über den ganzen Zeitraum enthält Zukunft. (d) sauber — Gewichte aus Daten bis
|
||||
heute, angewendet auf heute (idealerweise auf morgen). (e) **Survivorship-Bias** — das
|
||||
heute, angewendet auf heute (idealerweise auf morgen). (e) **Survivorship-Bias**{idx:Survivorship-Bias} — das
|
||||
Universum wird danach gefiltert, wer über den gesamten Zeitraum Daten hat.
|
||||
|
||||
**{loesung} — Kennzahlen deuten.**
|
||||
|
|
@ -2795,7 +2795,7 @@ B: Sharpe $= (8-2)/9 = 0{,}67$, Calmar $= 8/12 = 0{,}67$.
|
|||
Auszahlungen in einer Verlustphase Substanz vernichten. B ist in beiden risikoadjustierten
|
||||
Maßen besser.
|
||||
|
||||
**{loesung} — Rebalancing-Kalender.** Etwa 25–30 % der Termine fallen aus. Die Kennzahlen ändern
|
||||
**{loesung} — Rebalancing{idx:Rebalancing}-Kalender.** Etwa 25–30 % der Termine fallen aus. Die Kennzahlen ändern
|
||||
sich messbar — in welche Richtung, ist zufällig. Genau das ist der Punkt: Der Fehler
|
||||
verzerrt, ohne aufzufallen.
|
||||
|
||||
|
|
@ -2808,7 +2808,7 @@ Gebühren ist monatlich meist vertretbar, bei 0,5 % eher quartalsweise. Ein **To
|
|||
wenigen Perioden. Folgerung: Eine gute Gesamtkennzahl kann von einer einzigen glücklichen
|
||||
Phase getragen sein — **immer** nach Teilzeiträumen aufschlüsseln.
|
||||
|
||||
**{loesung} — Data Snooping messen.** Erwartetes Ergebnis: Die beste In-Sample-Sharpe-Ratio liegt
|
||||
**{loesung} — Data Snooping{idx:Data Snooping} messen.** Erwartetes Ergebnis: Die beste In-Sample-Sharpe-Ratio liegt
|
||||
deutlich über dem Mittelwert aller Varianten; auf dem zurückgehaltenen Zeitraum fällt sie
|
||||
Richtung Mittelwert zurück. Die **Differenz zwischen (a) und (c) ist der Selektionseffekt**
|
||||
— genau das, was die Deflated Sharpe Ratio korrigieren soll.
|
||||
|
|
@ -2927,7 +2927,7 @@ Wochenendverteilung.
|
|||
(d) 30–60 s, Gap 1 % — die Datenunsicherheit ist ohnehin größer.
|
||||
|
||||
**{loesung} — Relaxation einbauen.** Muster wie in `Infeasibility_Diagnose.py`:
|
||||
Schlupfvariable je Mindestbesetzung, Strafe deutlich über allen weichen Zielen, aber
|
||||
Schlupfvariable{idx:Schlupfvariable} je Mindestbesetzung, Strafe deutlich über allen weichen Zielen, aber
|
||||
endlich. Wichtig: **gestaffelte** Strafen, damit der Solver die *am wenigsten schmerzhafte*
|
||||
Verletzung wählt.
|
||||
|
||||
|
|
@ -3039,7 +3039,7 @@ Zielfunktion bepreist ist, sagt nichts darüber, ob sie eingehalten wurde.
|
|||
**3 — (c) hierarchisch lockern.** `INFEASIBLE` sagt nur, *dass* ein Widerspruch existiert,
|
||||
nicht *welche* Regeln ihn erzeugen. Ersetzt man harte Verbote durch sehr teure Strafkosten,
|
||||
liefert der Solver wieder eine Lösung — und die verletzten Regeln stehen benannt in der
|
||||
Kostenzerlegung. Genau das tut `Infeasibility_Diagnose.py`. (a) hilft nicht: `INFEASIBLE`
|
||||
Kostenzerlegung{idx:Kostenzerlegung}. Genau das tut `Infeasibility_Diagnose.py`. (a) hilft nicht: `INFEASIBLE`
|
||||
ist ein Beweis, kein Abbruch. (b) verschiebt das Problem und verliert die Gelegenheit, die
|
||||
Ursache zu finden, solange sie noch frisch ist.
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue