Notebook-Tests: nbmake + Subprocess-Zellen + inkrementeller Test

Alle 25 Notebooks sind nun fehlerfrei testbar (25 passed). Dafür drei
Änderungen im Build und eine neue Test-Infrastruktur:

1. pyproject.toml: nbmake>=1.5 in der dev-Gruppe.

2. build_version_04.py: Notebooks bekommen zwei Setup-Zellen und
   Subprocess-Zellen für Programme, die nicht direkt im Kernel laufen:
   - NOTEBOOK_SETUP_2: __file__ definieren, sys.path für or_kern,
     multiprocessing auf fork (Spawn findet Kernel-Funktionen nicht).
   - _braucht_subprocess: erkennt highspy (Solver-Konflikt), pytest
     (SystemExit), get_context('spawn'), subprocess+__file__ (sucht
     .py-Dateien), sys.exit (SystemExit). Diese Programme erscheinen
     als Markdown-Codeblock (sichtbar, nicht ausführbar) plus einer
     Subprocess-Zelle mit NO_COLOR=1 (verhindert ANSI-Codes, die der
     Parser von Mutationstest.py nicht verarbeitet).
   - Solver-Konflikt-Erkennung: wenn ein Kapitel sowohl ortools als
     auch highspy importiert, laufen auch reine ortools-Programme als
     Subprocess (highspy schon im Kernel).

3. teste_code_04.py: inkrementeller Test — nur geänderte/neue Programme
   und Notebooks (via git status). Netzabhängige Dateien (yfinance)
   werden automatisch erkannt und nur getestet, wenn Internet verfügbar.

4. PLAN.md Abschnitt 10: neuer Verifikationsschritt 4 (pytest --nbmake).
   PROGRESS.md und CLAUDE.md aktualisiert.

Gefundene und behobene Probleme:
- or_kern-Import: sys.path im Notebook erweitert.
- __file__ nicht definiert: zweite Setup-Zelle setzt es.
- multiprocessing spawn: fork erzwungen (Ein_System_Vier_Ansaetze.py).
- ortools/highspy-Konflikt: Subprocess für beide Solver.
- pytest SystemExit: Subprocess für test_or_kern.py und Mutationstest.py.
- sys.exit(0): Subprocess für Installationstest.py.
- ANSI-Codes in pytest-Ausgabe: NO_COLOR=1 in Subprocess-Zelle.
This commit is contained in:
dschlueter 2026-09-11 22:38:59 +02:00
commit a4fc247116
70 changed files with 4073 additions and 305 deletions

Binary file not shown.

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Wenn die fünf Schritte nicht reichen: den Konflikt einkreisen\n",
"\n",
"`Konfliktsuche.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Das Programm\n",
"\n",
"`Strukturbruecke.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Was Propagation leistet\n",
"\n",
"`Propagation_Demo.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -116,6 +150,15 @@
"`CP_SAT_Vertretungssystem.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Praxisfall: Dynamisches Vertretungssystem\n",
"\n",
"`CP_SAT_Vertretungssystem.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -375,6 +418,15 @@
"`JobShop_Intervalle.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Intervallvariablen: Job-Shop-Scheduling\n",
"\n",
"`JobShop_Intervalle.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -505,6 +557,15 @@
"`Parallele_Suche.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Parallele Suche: was `num_workers` wirklich bewirkt\n",
"\n",
"`Parallele_Suche.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -717,6 +778,15 @@
"`CP_SAT_Statusfaelle.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Die fünf Antworten von CP-SAT\n",
"\n",
"`CP_SAT_Statusfaelle.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -957,6 +1027,15 @@
"`Strafgewichte.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Finde den Denkfehler\n",
"\n",
"`Strafgewichte.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Die zwei Schwächen des Markowitz-Modells\n",
"\n",
"`VaR_CVaR_Demo.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -152,6 +186,15 @@
"`CVaR_Portfolio.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Implementierung: CVaR-Portfolio mit Reibung\n",
"\n",
"`CVaR_Portfolio.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Das Programm\n",
"\n",
"`Spaltengenerierung.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Die Bellman-Gleichung\n",
"\n",
"`Bellman_Minimalbeispiel.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -132,6 +166,15 @@
"`Mehrperiodige_Order_Execution.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Das Almgren-Chriss-Problem: optimale Orderausführung\n",
"\n",
"`Mehrperiodige_Order_Execution.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Warum Ausprobieren scheitert — mit eigener Rechnung\n",
"\n",
"`Brute_Force_Vergleich.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -150,6 +184,15 @@
"`Bausteine_Vorlage.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Die Bausteine in der Praxis: eine Vorlage\n",
"\n",
"`Bausteine_Vorlage.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -250,6 +293,15 @@
"`Bot_Allokation.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Umsetzung mit Google OR-Tools\n",
"\n",
"`Bot_Allokation.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -363,6 +415,15 @@
"`Excel_Bruecke.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Von Excel zu Python: Ihre Daten liegen schon da\n",
"\n",
"`Excel_Bruecke.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Logarithmische Rendite{idx:Logarithmische Rendite}\n",
"\n",
"`Renditen_Vergleich.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -115,6 +149,15 @@
"`Schaetzrauschen_Demo.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Das Schätzfehler{idx:Schätzfehler}-Problem\n",
"\n",
"`Schaetzrauschen_Demo.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -228,6 +271,15 @@
"`Finanzdaten_Ledoit_Wolf.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Praxis: Datenpipeline mit korrekter Spaltenreihenfolge\n",
"\n",
"`Finanzdaten_Ledoit_Wolf.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -392,6 +444,15 @@
"`Kovarianz_Falle.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Finde den Denkfehler\n",
"\n",
"`Kovarianz_Falle.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Dasselbe in Python\n",
"\n",
"`Matrixform.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -101,6 +135,15 @@
"`Konvexitaet_Demo.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Konvexität sichtbar machen\n",
"\n",
"`Konvexitaet_Demo.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -191,6 +234,15 @@
"`Visualisierung_Loesungsraum.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Geometrische Visualisierung des Lösungsraums\n",
"\n",
"`Visualisierung_Loesungsraum.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -348,6 +400,15 @@
"`Skalierung_Kondition.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Das Experiment\n",
"\n",
"`Skalierung_Kondition.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Das Minimum-Cost-Flow-Problem (MCNFP)\n",
"\n",
"`Min_Cost_Flow.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -144,6 +178,15 @@
"`Zuordnung_Ungarisch.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Der Satz von Birkhoff und von Neumann{idx:Satz von Birkhoff und von Neumann}\n",
"\n",
"`Zuordnung_Ungarisch.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -266,6 +309,15 @@
"`VRP_Flotten_Routing.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Praxisbeispiel: Flotten-Routing\n",
"\n",
"`VRP_Flotten_Routing.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -448,6 +500,15 @@
"`VRP_Kapazitaetsfalle.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Finde den Denkfehler\n",
"\n",
"`VRP_Kapazitaetsfalle.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Die Engine\n",
"\n",
"`QuantitativeTradingEngine.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -352,6 +386,15 @@
"`Backtest_Fallen.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Die fünf Selbsttäuschungen des Backtestens\n",
"\n",
"`Backtest_Fallen.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -465,6 +508,15 @@
"`Data_Snooping.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Finde den Denkfehler\n",
"\n",
"`Data_Snooping.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Das Simplex-Tableau in Python\n",
"\n",
"`Simplex_Tableau_LP.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -207,6 +241,15 @@
"`Dualitaet_Nachweis.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Der starke Dualitätssatz\n",
"\n",
"`Dualitaet_Nachweis.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -302,6 +345,15 @@
"`Sensitivitaetsanalyse.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Praxisfall: Sensitivitätsanalyse mit korrekten Schattenpreisen\n",
"\n",
"`Sensitivitaetsanalyse.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -429,6 +481,15 @@
"`Toleranzen_und_Entartung.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Die ehrliche Auskunft: Schattenpreis-Spannen\n",
"\n",
"`Toleranzen_und_Entartung.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Warum Diversifikation funktioniert\n",
"\n",
"`Diversifikation_Demo.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -94,6 +128,15 @@
"`Markowitz_CVXPY.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Vollimplementierung mit CVXPY\n",
"\n",
"`Markowitz_CVXPY.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -374,6 +417,15 @@
"`Renditeschaetzung_Falle.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Finde den Denkfehler\n",
"\n",
"`Renditeschaetzung_Falle.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Das Programm\n",
"\n",
"`Mehrziel_Pareto.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Simulated Annealing\n",
"\n",
"`Simulated_Annealing.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -346,6 +380,15 @@
"`Metaheuristik_vs_Exakt.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Ab wann lohnt es sich?\n",
"\n",
"`Metaheuristik_vs_Exakt.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -595,6 +638,15 @@
"`Large_Neighborhood_Search.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Large Neighborhood Search\n",
"\n",
"`Large_Neighborhood_Search.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Warum Runden fundamental scheitert\n",
"\n",
"`Runden_Gegenbeispiel.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -138,6 +172,15 @@
"`Rucksack.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Beispiel: Das Rucksackproblem{idx:Rucksackproblem}\n",
"\n",
"`Rucksack.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -213,6 +256,15 @@
"`MILP_Portfolio_Fixgebuehren.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Praxisfall: Portfolio mit Ordergebühren und Kardinalitätsgrenze\n",
"\n",
"`MILP_Portfolio_Fixgebuehren.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -434,11 +486,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Alle Statusfälle behandeln\n",
"\n",
"`Solverstatus_und_Gap.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# Solverstatus_und_Gap.py\n",
@ -654,7 +709,36 @@
" print(\" Warmstart_Effekt.py - dort halbiert ein Heuristik-Hinweis die Zeit).\")\n",
" print(\" * Sie planen laufend neu und der gestrige Plan ist fast noch gueltig.\")\n",
" print(\"In beiden Faellen gilt: MESSEN, nicht glauben.\")\n",
" print(\"=\" * 78)"
" print(\"=\" * 78)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'Solverstatus_und_Gap.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'Solverstatus_und_Gap.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('Solverstatus_und_Gap.py nicht gefunden')"
]
},
{
@ -667,11 +751,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Warm-Starts: was sie können und was nicht\n",
"\n",
"`Warmstart_Effekt.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# Warmstart_Effekt.py\n",
@ -819,7 +906,36 @@
" print(\" davon ab, wie schnell der Solver von allein eine vergleichbar gute\")\n",
" print(\" Loesung findet. Das ist die eigentliche Lehre: Ein Warm-Start ist\")\n",
" print(\" eine Messung wert, keine Glaubensfrage.\")\n",
" print(\"=\" * 78)"
" print(\"=\" * 78)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'Warmstart_Effekt.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'Warmstart_Effekt.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('Warmstart_Effekt.py nicht gefunden')"
]
},
{
@ -832,11 +948,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Finde den Denkfehler\n",
"\n",
"`Big_M_Falle.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# Big_M_Falle.py\n",
@ -1030,7 +1149,36 @@
" print(\"nicht darauf: Presolve kann das nur, wenn eine implizite Schranke\")\n",
" print(\"herleitbar ist. Die Pruefung aus pruefe() kostet Millisekunden und\")\n",
" print(\"funktioniert immer.\")\n",
" print(\"=\" * 78)"
" print(\"=\" * 78)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'Big_M_Falle.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'Big_M_Falle.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('Big_M_Falle.py nicht gefunden')"
]
}
],

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Derselbe Datensatz, fünf Modelle\n",
"\n",
"`Vom_Wunsch_zum_Modell.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Die Entscheidung in drei Fragen\n",
"\n",
"`Solver_Wahl.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -121,11 +155,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Wie die Isolation aussieht, wenn sie tragen soll\n",
"\n",
"`Ein_System_Vier_Ansaetze.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# Ein_System_Vier_Ansaetze.py\n",
@ -270,7 +307,45 @@
" print(\"Alle Wege fuehren zum selben, von Hand bestaetigten Optimum.\")\n",
" print(\"(Die Zeiten enthalten Prozessstart und Import - sie messen NICHT die\")\n",
" print(\" reine Solverleistung. Die Uebungsaufgabe 'Laufzeitvergleich' trennt beides.)\")\n",
" print(\"=\" * 78)"
" print(\"=\" * 78)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'Ein_System_Vier_Ansaetze.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'Ein_System_Vier_Ansaetze.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('Ein_System_Vier_Ansaetze.py nicht gefunden')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Die Schichten im Überblick\n",
"\n",
"`Modellierungsschichten.py`\n"
]
},
{
@ -470,11 +545,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Vier Stufen an einem Transportproblem\n",
"\n",
"`Vektorisierte_Modellgenerierung.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# Vektorisierte_Modellgenerierung.py\n",
@ -714,7 +792,36 @@
" print(\" Schreibweise derselben Matrix - Schleife gegen Kronecker-Produkt.\")\n",
" print(\"\\nDie Lesbarkeit von Variante A ist trotzdem viel wert: Fangen Sie dort an,\")\n",
" print(\"und vektorisieren Sie erst, wenn die Messung es verlangt.\")\n",
" print(\"=\" * 88)"
" print(\"=\" * 88)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'Vektorisierte_Modellgenerierung.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'Vektorisierte_Modellgenerierung.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('Vektorisierte_Modellgenerierung.py nicht gefunden')"
]
}
],

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,27 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -31,11 +56,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Falle 1 — Infeasibility{idx:Infeasibility}\n",
"\n",
"`Infeasibility_Diagnose.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# Infeasibility_Diagnose.py\n",
@ -147,7 +175,36 @@
" print(\"\\nDer Anwender bekommt jetzt einen Plan PLUS eine konkrete Ursache -\")\n",
" print(\"und kann handeln: Vertretung von aussen holen, Stunde verlegen,\")\n",
" print(\"oder die Klasse zusammenlegen.\")\n",
" print(\"=\" * 78)"
" print(\"=\" * 78)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'Infeasibility_Diagnose.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'Infeasibility_Diagnose.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('Infeasibility_Diagnose.py nicht gefunden')"
]
},
{
@ -160,11 +217,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Falle 2 — Der Black-Box-Effekt\n",
"\n",
"`Erklaerbarkeit.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# Erklaerbarkeit.py\n",
@ -249,7 +309,45 @@
" print(f\" -> Die Obergrenze blockiert zwar {blockiert}, kostet aber gerade NICHTS:\")\n",
" print(\" Selbst ohne sie waere die Loesung dieselbe.\")\n",
" print(\" Blockierend und kostenrelevant sind zwei verschiedene Dinge.\")\n",
" print(\"=\" * 78)"
" print(\"=\" * 78)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'Erklaerbarkeit.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'Erklaerbarkeit.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('Erklaerbarkeit.py nicht gefunden')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Constraint Attribution{idx:Constraint Attribution}: welche Bedingung kostet wie viel?\n",
"\n",
"`Constraint_Attribution.py`\n"
]
},
{
@ -584,11 +682,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Ein Enum für fünf Bibliotheken\n",
"\n",
"`or_kern.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# or_kern.py\n",
@ -1092,7 +1193,36 @@
" print(\"\\nAlle drei scheitern beim EINLESEN - nicht erst beim Loesen und\")\n",
" print(\"schon gar nicht erst im Bericht. Das ist der ganze Zweck der\")\n",
" print(\"Domaenenschicht.\")\n",
" print(\"=\" * 78)"
" print(\"=\" * 78)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'or_kern.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'or_kern.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('or_kern.py nicht gefunden')"
]
},
{
@ -1105,11 +1235,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Der Solverwechsel in der Praxis\n",
"\n",
"`Solverwechsel_CPSAT_HiGHS.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# Solverwechsel_CPSAT_HiGHS.py\n",
@ -1433,7 +1566,36 @@
" print(\"gleich teure Loesungen, darf jeder Solver eine andere davon liefern.\")\n",
" print(\"Hier stimmen sie zufaellig ueberein - darauf zu testen waere trotzdem\")\n",
" print(\"ein unzuverlaessiger Test (siehe JobShop_Intervalle.py).\")\n",
" print(\"=\" * 82)"
" print(\"=\" * 82)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'Solverwechsel_CPSAT_HiGHS.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'Solverwechsel_CPSAT_HiGHS.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('Solverwechsel_CPSAT_HiGHS.py nicht gefunden')"
]
},
{
@ -1446,11 +1608,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Finde den Denkfehler\n",
"\n",
"`Betriebsueberwachung.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# Betriebsueberwachung.py\n",
@ -1630,7 +1795,36 @@
" print()\n",
" print(\"Die dritte ist die frueheste Warnung: Sie steigt, lange bevor der Gap\")\n",
" print(\"sichtbar wird, und gibt Zeit zum Handeln.\")\n",
" print(\"=\" * 84)"
" print(\"=\" * 84)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'Betriebsueberwachung.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'Betriebsueberwachung.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('Betriebsueberwachung.py nicht gefunden')"
]
}
],

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Das Programm\n",
"\n",
"`Predict_then_Optimize.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Konvexität: die präzise Aussage\n",
"\n",
"`QP_Grundlagen.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -102,6 +136,15 @@
"`KKT_Nachweis.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Die vier KKT-Bedingungen\n",
"\n",
"`KKT_Nachweis.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -229,6 +272,15 @@
"`Entropie_Maximierte_Allokation.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Praxisfall: Entropie-maximierte Kapitalallokation\n",
"\n",
"`Entropie_Maximierte_Allokation.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -384,6 +436,15 @@
"`Lokale_Optima_Multistart.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Was ein lokales Optimum praktisch bedeutet\n",
"\n",
"`Lokale_Optima_Multistart.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Das Programm\n",
"\n",
"`Kraftwerkseinsatz.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,27 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -31,11 +56,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Die Testsuite\n",
"\n",
"`test_or_kern.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# test_or_kern.py\n",
@ -344,7 +372,36 @@
"\n",
"if __name__ == \"__main__\":\n",
" import sys\n",
" sys.exit(pytest.main([__file__, \"-v\", \"--tb=short\", \"-p\", \"no:cacheprovider\"]))"
" sys.exit(pytest.main([__file__, \"-v\", \"--tb=short\", \"-p\", \"no:cacheprovider\"]))\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'test_or_kern.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'test_or_kern.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('test_or_kern.py nicht gefunden')"
]
},
{
@ -357,11 +414,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Wer testet die Tests?\n",
"\n",
"`Mutationstest.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# Mutationstest.py\n",
@ -540,7 +600,36 @@
" print(\"Die Quote selbst ist keine Kennzahl fuer ein Dashboard. Zehn von Hand\")\n",
" print(\"gewaehlte Mutationen sind keine Stichprobe aus der Menge aller\")\n",
" print(\"moeglichen Fehler. Was zaehlt, ist die LISTE der Ueberlebenden.\")\n",
" print(\"=\" * 84)"
" print(\"=\" * 84)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'Mutationstest.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'Mutationstest.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('Mutationstest.py nicht gefunden')"
]
},
{
@ -553,11 +642,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Ein Vergleich, dem man glauben kann\n",
"\n",
"`Benchmark_Skalierung.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# Benchmark_Skalierung.py\n",
@ -770,7 +862,36 @@
" print(\" * Etwas ueber Ihre Maschine. Diese Zahlen stammen von einer\")\n",
" print(\" anderen. Der Sinn des Programms ist, dass Sie es auf Ihrer\")\n",
" print(\" laufen lassen.\")\n",
" print(\"=\" * 92)"
" print(\"=\" * 92)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'Benchmark_Skalierung.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'Benchmark_Skalierung.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('Benchmark_Skalierung.py nicht gefunden')"
]
},
{
@ -783,11 +904,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Das Modell als Dienst\n",
"\n",
"`Optimierungsdienst.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# Optimierungsdienst.py\n",
@ -1102,7 +1226,36 @@
" print()\n",
" print(\"(Es wird hier nicht gebaut - das Buch setzt keine laufende\")\n",
" print(\" Docker-Installation voraus.)\")\n",
" print(\"=\" * 80)"
" print(\"=\" * 80)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'Optimierungsdienst.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'Optimierungsdienst.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('Optimierungsdienst.py nicht gefunden')"
]
}
],

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,36 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Der Fluch des Durchschnitts\n",
"\n",
"`Fluch_des_Durchschnitts.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -100,6 +134,15 @@
"`Monte_Carlo.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Monte-Carlo-Simulation{idx:Monte-Carlo-Simulation}\n",
"\n",
"`Monte_Carlo.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -209,6 +252,15 @@
"`Stochastische_Optimierung.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Zweistufige stochastische Programmierung\n",
"\n",
"`Stochastische_Optimierung.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -345,6 +397,15 @@
"`Robuste_Optimierung.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Robuste Optimierung{idx:Robuste Optimierung}: gegen den Worst Case absichern\n",
"\n",
"`Robuste_Optimierung.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,
@ -461,6 +522,15 @@
"`Chance_Constraints.py`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Der Fall: ein Kraftwerkspark mit 500 MW Zusage\n",
"\n",
"`Chance_Constraints.py`\n"
]
},
{
"cell_type": "code",
"execution_count": null,

View file

@ -12,7 +12,11 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": [
"nbmake-skip"
]
},
"outputs": [],
"source": [
"# Einmalig ausfuehren: installiert alle im Buch verwendeten Pakete.\n",
@ -21,6 +25,27 @@
" scikit-learn matplotlib plotly pyomo linopy pymoo pydantic openpyxl"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Notebook-spezifisches Setup: __file__ definieren (Programme nutzen es\n",
"# fuer OUTPUT_DIR), Programmverzeichnis in den Suchpfad aufnehmen (or_kern)\n",
"# und multiprocessing auf 'fork' stellen (Spawn findet Kernel-Funktionen nicht).\n",
"import os, sys\n",
"__file__ = os.path.join(os.getcwd(), '_notebook.py')\n",
"for _p in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" if os.path.isfile(os.path.join(_p, 'or_kern.py')):\n",
" sys.path.insert(0, _p); break\n",
"import multiprocessing as _mp\n",
"try: _mp.set_start_method('fork', force=True)\n",
"except (RuntimeError, ValueError): pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -31,11 +56,14 @@
]
},
{
"cell_type": "code",
"execution_count": null,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Installationstest {-}\n",
"\n",
"`Installationstest.py`\n",
"\n",
"```python\n",
"#!/usr/bin/env python3\n",
"\n",
"# Installationstest.py\n",
@ -154,7 +182,36 @@
" print(\"-\" * 78)\n",
" print(\"Alles bereit — Sie können mit dem ersten Kapitel beginnen.\"\n",
" if alle_ok else \"Mindestens ein Solver arbeitet fehlerhaft.\")\n",
" sys.exit(0 if alle_ok else 1)"
" sys.exit(0 if alle_ok else 1)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# In einem Notebook kann 'Installationstest.py' nicht direkt ausgefuehrt werden\n",
"# (ortools/highspy-Konflikt im selben Kernel, pytest oder multiprocessing).\n",
"# Deshalb als Subprocess — so laeuft es genauso wie im Terminal.\n",
"import subprocess, sys, os\n",
"# NO_COLOR/TERM=dumb verhindern ANSI-Codes in der Ausgabe (pytest\n",
"# im Jupyter-Kernel wuerde sonst farbige Escape-Sequenzen ausgeben).\n",
"_env = dict(os.environ, NO_COLOR='1', TERM='dumb')\n",
"for _d in [os.path.join(os.path.dirname(os.getcwd()),\n",
" 'Operations_Research_mit_Python_Version_04_Programme'),\n",
" os.path.dirname(os.getcwd()), os.getcwd()]:\n",
" _p = os.path.join(_d, 'Installationstest.py')\n",
" if os.path.isfile(_p):\n",
" _r = subprocess.run([sys.executable, _p], cwd=_d, env=_env,\n",
" capture_output=True, text=True)\n",
" if _r.stdout: print(_r.stdout)\n",
" if _r.stderr: print(_r.stderr)\n",
" _r.check_returncode()\n",
" break\n",
"else:\n",
" print('Installationstest.py nicht gefunden')"
]
}
],

View file

@ -2444,7 +2444,7 @@ z
</g>
</g>
<g id="text_14">
<!-- Stand: 10. September 2026 v17.51 -->
<!-- Stand: 11. September 2026 v22.38 -->
<g style="fill: #c7d2fe" transform="translate(71.4528 818.05749) scale(0.12 -0.12)">
<defs>
<path id="DejaVuSans-31" d="M 794 531
@ -2460,27 +2460,6 @@ L 3481 0
L 794 0
L 794 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-32" d="M 1228 531
L 3431 531
@ -2505,6 +2484,27 @@ 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
@ -2536,39 +2536,75 @@ Q 2619 4750 2861 4703
Q 3103 4656 3366 4563
z
" transform="scale(0.015625)"/>
<path id="DejaVuSans-37" d="M 525 4666
L 3525 4666
L 3525 4397
L 1831 0
L 1172 0
L 2766 4134
L 525 4134
L 525 4666
<path id="DejaVuSans-33" d="M 2597 2516
Q 3050 2419 3304 2112
Q 3559 1806 3559 1356
Q 3559 666 3084 287
Q 2609 -91 1734 -91
Q 1441 -91 1130 -33
Q 819 25 488 141
L 488 750
Q 750 597 1062 519
Q 1375 441 1716 441
Q 2309 441 2620 675
Q 2931 909 2931 1356
Q 2931 1769 2642 2001
Q 2353 2234 1838 2234
L 1294 2234
L 1294 2753
L 1863 2753
Q 2328 2753 2575 2939
Q 2822 3125 2822 3475
Q 2822 3834 2567 4026
Q 2313 4219 1838 4219
Q 1578 4219 1281 4162
Q 984 4106 628 3988
L 628 4550
Q 988 4650 1302 4700
Q 1616 4750 1894 4750
Q 2613 4750 3031 4423
Q 3450 4097 3450 3541
Q 3450 3153 3228 2886
Q 3006 2619 2597 2516
z
" transform="scale(0.015625)"/>
<path id="DejaVuSans-35" d="M 691 4666
L 3169 4666
L 3169 4134
L 1269 4134
L 1269 2991
Q 1406 3038 1543 3061
Q 1681 3084 1819 3084
Q 2600 3084 3056 2656
Q 3513 2228 3513 1497
Q 3513 744 3044 326
Q 2575 -91 1722 -91
Q 1428 -91 1123 -41
Q 819 9 494 109
L 494 744
Q 775 591 1075 516
Q 1375 441 1709 441
Q 2250 441 2565 725
Q 2881 1009 2881 1497
Q 2881 1984 2565 2268
Q 2250 2553 1709 2553
Q 1456 2553 1204 2497
Q 953 2441 691 2322
L 691 4666
<path id="DejaVuSans-38" d="M 2034 2216
Q 1584 2216 1326 1975
Q 1069 1734 1069 1313
Q 1069 891 1326 650
Q 1584 409 2034 409
Q 2484 409 2743 651
Q 3003 894 3003 1313
Q 3003 1734 2745 1975
Q 2488 2216 2034 2216
z
M 1403 2484
Q 997 2584 770 2862
Q 544 3141 544 3541
Q 544 4100 942 4425
Q 1341 4750 2034 4750
Q 2731 4750 3128 4425
Q 3525 4100 3525 3541
Q 3525 3141 3298 2862
Q 3072 2584 2669 2484
Q 3125 2378 3379 2068
Q 3634 1759 3634 1313
Q 3634 634 3220 271
Q 2806 -91 2034 -91
Q 1263 -91 848 271
Q 434 634 434 1313
Q 434 1759 690 2068
Q 947 2378 1403 2484
z
M 1172 3481
Q 1172 3119 1398 2916
Q 1625 2713 2034 2713
Q 2441 2713 2670 2916
Q 2900 3119 2900 3481
Q 2900 3844 2670 4047
Q 2441 4250 2034 4250
Q 1625 4250 1398 4047
Q 1172 3844 1172 3481
z
" transform="scale(0.015625)"/>
</defs>
@ -2580,7 +2616,7 @@ z
<use xlink:href="#DejaVuSans-3a" transform="translate(290.820312 0)"/>
<use xlink:href="#DejaVuSans-20" transform="translate(324.511719 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-31" 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)"/>
@ -2600,11 +2636,11 @@ z
<use xlink:href="#DejaVuSans-20" transform="translate(1386.132812 0)"/>
<use xlink:href="#DejaVuSans-20" transform="translate(1417.919922 0)"/>
<use xlink:href="#DejaVuSans-76" transform="translate(1449.707031 0)"/>
<use xlink:href="#DejaVuSans-31" transform="translate(1508.886719 0)"/>
<use xlink:href="#DejaVuSans-37" transform="translate(1572.509766 0)"/>
<use xlink:href="#DejaVuSans-32" transform="translate(1508.886719 0)"/>
<use xlink:href="#DejaVuSans-32" transform="translate(1572.509766 0)"/>
<use xlink:href="#DejaVuSans-2e" transform="translate(1636.132812 0)"/>
<use xlink:href="#DejaVuSans-35" transform="translate(1667.919922 0)"/>
<use xlink:href="#DejaVuSans-31" transform="translate(1731.542969 0)"/>
<use xlink:href="#DejaVuSans-33" transform="translate(1667.919922 0)"/>
<use xlink:href="#DejaVuSans-38" transform="translate(1731.542969 0)"/>
</g>
</g>
<g id="text_15">

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Before After
Before After

View file

@ -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>&lt;dieter(dot)schlueter(atsign)linix(dot)de&gt;</p>
<p>Stand: 10. September 2026 v17.50</p>
<p>Stand: 11. September 2026 v22.37</p>
<hr />
<nav id="TOC" role="doc-toc">
<ul>

2
OR_HTML_04/index.html generated
View file

@ -115,7 +115,7 @@
<p class="hero-anwendungen">Mit Python planen, optimieren und entscheiden: von Personal, Schichten und Logistik über Energie, Ressourcen und Netzwerke bis zur Portfoliooptimierung an den Finanzmärkten.</p>
<p class="hero-autor">Autor / Herausgeber: Dieter Schlüter<br>
&lt;dieter(dot)schlueter(atsign)linix(dot)de&gt;<br>
Stand: 10. September 2026 v17.52</p>
Stand: 11. September 2026 v22.38</p>
</div>
</section>
<section class="einstieg">

File diff suppressed because one or more lines are too long

View file

@ -110,7 +110,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>&lt;dieter(dot)schlueter(atsign)linix(dot)de&gt;</p>
<p>Stand: 10. September 2026 v17.52</p>
<p>Stand: 11. September 2026 v22.38</p>
<hr />
<h1 class="unnumbered" id="über-den-kurs">Über den Kurs</h1>
<h2 class="unnumbered" id="vorwort">Vorwort</h2>