diff --git a/.gitignore b/.gitignore index e4f9760..6da6577 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ __pycache__/ venv/ .venv/ +# pip install -e . legt dieses Verzeichnis an (Metadaten des editierbaren Pakets) +or_mit_python.egg-info/ + # LaTeX/xelatex-Nebenprodukte des PDF-Baus (build_version_04.py --pdf) build_v04.log build_v04.tex diff --git a/CLAUDE.md b/CLAUDE.md index c7975c1..cda9bf3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -174,6 +174,31 @@ Auch das `README.md` im Programme-Verzeichnis wird erzeugt — aus der Vorlage **`or_kern.py` ist der gemeinsame Unterbau** aller Programme (Domänenmodell, `SolverStatus`, `Loesung`-DTO, Abnahmeprüfung). Abgedruckt im Kapitel Praxisfallen. +**Notebook-Tests (`nbmake`).** Seit September 2026 sind die 25 Notebooks ebenso +getestet wie die Programme. `pyproject.toml` hat `nbmake>=1.5` in der `dev`-Gruppe; +`PLAN.md` Abschnitt 10 enthält den zusätzlichen Verifikationsschritt +`pytest --nbmake --nbmake-timeout=900 Notebooks_04/ -q`. Dafür müssen die Notebooks im +Build drei Dinge mitbringen, die ein Programmskript nicht braucht: +* **Zweite Setup-Zelle** (`NOTEBOOK_SETUP_2` in `build_version_04.py`): definiert + `__file__` (Programme nutzen es für `OUTPUT_DIR`), erweitert `sys.path` um das + Programmverzeichnis (`from or_kern import …`) und stellt multiprocessing auf `fork` + (der Spawn-Modus findet Kernel-Funktionen nicht). +* **Subprocess-Zellen** für Programme, die nicht direkt im Kernel laufen: + `import highspy` (Solver-Konflikt mit ortools), `import pytest` (`SystemExit`), + `get_context("spawn")` (multiprocessing), `import subprocess` + `__file__` (sucht + andere .py-Dateien), `sys.exit(` (`SystemExit` im Kernel). Diese Programme erscheinen + als Markdown-Codeblock (sichtbar, nicht ausführbar) plus einer Subprocess-Zelle, die + das Programm mit `NO_COLOR=1` aufruft (sonst gibt pytest ANSI-Codes aus, die der + Ausgabe-Parser von `Mutationstest.py` nicht verarbeitet). +* **`%pip`-Setup-Zelle** trägt das Tag `nbmake-skip` (wird von nbmake aktuell noch + ignoriert, aber als Dokumentation gedacht — die Zelle ist schnell, wenn Pakete schon + installiert sind). +* **Inkrementeller Test** (`teste_code_04.py`): testet nur Programme und Notebooks, + die sich seit dem letzten Commit geändert haben (via `git status`). Netzabhängige + Dateien (yfinance) werden automatisch erkannt und nur getestet, wenn Internet + verfügbar ist. Aufruf: `python3 …/teste_code_04.py` (geänderte), `--alles` + (alle), `--check` (nur anzeigen). + **`ortools` und `highspy` lassen sich nicht im selben Prozess importieren** (beide bringen eine eigene HiGHS-Kopie mit). Deshalb lädt `or_kern.py` Solverbibliotheken erst in der aufrufenden Funktion, und Programme, die beide brauchen, starten getrennte Prozesse (Muster: diff --git a/Notebooks_04/anhang-fehlerdiagnose.ipynb b/Notebooks_04/anhang-fehlerdiagnose.ipynb index 9a10276..e69d310 100644 --- a/Notebooks_04/anhang-fehlerdiagnose.ipynb +++ b/Notebooks_04/anhang-fehlerdiagnose.ipynb @@ -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": {}, diff --git a/Notebooks_04/bruecke.ipynb b/Notebooks_04/bruecke.ipynb index 08a2fd8..b54ab56 100644 --- a/Notebooks_04/bruecke.ipynb +++ b/Notebooks_04/bruecke.ipynb @@ -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": {}, diff --git a/Notebooks_04/cpsat.ipynb b/Notebooks_04/cpsat.ipynb index 765a79b..dd73a5d 100644 --- a/Notebooks_04/cpsat.ipynb +++ b/Notebooks_04/cpsat.ipynb @@ -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, diff --git a/Notebooks_04/cvar.ipynb b/Notebooks_04/cvar.ipynb index f581980..c4e7564 100644 --- a/Notebooks_04/cvar.ipynb +++ b/Notebooks_04/cvar.ipynb @@ -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, diff --git a/Notebooks_04/dekomposition.ipynb b/Notebooks_04/dekomposition.ipynb index 321bd40..8ac622c 100644 --- a/Notebooks_04/dekomposition.ipynb +++ b/Notebooks_04/dekomposition.ipynb @@ -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": {}, diff --git a/Notebooks_04/dynamische-programmierung.ipynb b/Notebooks_04/dynamische-programmierung.ipynb index 2662789..e3c4be0 100644 --- a/Notebooks_04/dynamische-programmierung.ipynb +++ b/Notebooks_04/dynamische-programmierung.ipynb @@ -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, diff --git a/Notebooks_04/einfuehrung.ipynb b/Notebooks_04/einfuehrung.ipynb index 0531984..778fa0a 100644 --- a/Notebooks_04/einfuehrung.ipynb +++ b/Notebooks_04/einfuehrung.ipynb @@ -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, diff --git a/Notebooks_04/finanzdaten.ipynb b/Notebooks_04/finanzdaten.ipynb index 324b2cf..86d86cd 100644 --- a/Notebooks_04/finanzdaten.ipynb +++ b/Notebooks_04/finanzdaten.ipynb @@ -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, diff --git a/Notebooks_04/fundament.ipynb b/Notebooks_04/fundament.ipynb index 37b2294..71ddefe 100644 --- a/Notebooks_04/fundament.ipynb +++ b/Notebooks_04/fundament.ipynb @@ -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, diff --git a/Notebooks_04/graphen.ipynb b/Notebooks_04/graphen.ipynb index a9f3047..8c5b1cc 100644 --- a/Notebooks_04/graphen.ipynb +++ b/Notebooks_04/graphen.ipynb @@ -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, diff --git a/Notebooks_04/handelsmaschine.ipynb b/Notebooks_04/handelsmaschine.ipynb index 3d7b425..0a3441e 100644 --- a/Notebooks_04/handelsmaschine.ipynb +++ b/Notebooks_04/handelsmaschine.ipynb @@ -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, diff --git a/Notebooks_04/lp.ipynb b/Notebooks_04/lp.ipynb index de95953..a30cdc4 100644 --- a/Notebooks_04/lp.ipynb +++ b/Notebooks_04/lp.ipynb @@ -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, diff --git a/Notebooks_04/markowitz.ipynb b/Notebooks_04/markowitz.ipynb index d8f490a..c793463 100644 --- a/Notebooks_04/markowitz.ipynb +++ b/Notebooks_04/markowitz.ipynb @@ -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, diff --git a/Notebooks_04/mehrziel.ipynb b/Notebooks_04/mehrziel.ipynb index e1cb7ca..cc98354 100644 --- a/Notebooks_04/mehrziel.ipynb +++ b/Notebooks_04/mehrziel.ipynb @@ -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": {}, diff --git a/Notebooks_04/metaheuristiken.ipynb b/Notebooks_04/metaheuristiken.ipynb index 9be40f6..99b8048 100644 --- a/Notebooks_04/metaheuristiken.ipynb +++ b/Notebooks_04/metaheuristiken.ipynb @@ -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, diff --git a/Notebooks_04/milp.ipynb b/Notebooks_04/milp.ipynb index 8f5ed61..ffbf18d 100644 --- a/Notebooks_04/milp.ipynb +++ b/Notebooks_04/milp.ipynb @@ -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')" ] } ], diff --git a/Notebooks_04/modellierung.ipynb b/Notebooks_04/modellierung.ipynb index df7ab93..c44b88d 100644 --- a/Notebooks_04/modellierung.ipynb +++ b/Notebooks_04/modellierung.ipynb @@ -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": {}, diff --git a/Notebooks_04/oekosystem.ipynb b/Notebooks_04/oekosystem.ipynb index ae42071..6518796 100644 --- a/Notebooks_04/oekosystem.ipynb +++ b/Notebooks_04/oekosystem.ipynb @@ -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')" ] } ], diff --git a/Notebooks_04/output/feasible_region_2d.png b/Notebooks_04/output/feasible_region_2d.png new file mode 100644 index 0000000..ff86ad3 Binary files /dev/null and b/Notebooks_04/output/feasible_region_2d.png differ diff --git a/Notebooks_04/output/markowitz_efficient_frontier.png b/Notebooks_04/output/markowitz_efficient_frontier.png new file mode 100644 index 0000000..15e2d8d Binary files /dev/null and b/Notebooks_04/output/markowitz_efficient_frontier.png differ diff --git a/Notebooks_04/output/optimal_execution_dp.png b/Notebooks_04/output/optimal_execution_dp.png new file mode 100644 index 0000000..8c44182 Binary files /dev/null and b/Notebooks_04/output/optimal_execution_dp.png differ diff --git a/Notebooks_04/output/trading_engine_backtest.png b/Notebooks_04/output/trading_engine_backtest.png new file mode 100644 index 0000000..e5d84d4 Binary files /dev/null and b/Notebooks_04/output/trading_engine_backtest.png differ diff --git a/Notebooks_04/praxisfallen.ipynb b/Notebooks_04/praxisfallen.ipynb index 802e3be..9489dd9 100644 --- a/Notebooks_04/praxisfallen.ipynb +++ b/Notebooks_04/praxisfallen.ipynb @@ -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')" ] } ], diff --git a/Notebooks_04/prognose.ipynb b/Notebooks_04/prognose.ipynb index cf10cf6..3f44049 100644 --- a/Notebooks_04/prognose.ipynb +++ b/Notebooks_04/prognose.ipynb @@ -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": {}, diff --git a/Notebooks_04/qp-nlp.ipynb b/Notebooks_04/qp-nlp.ipynb index 92f9c40..21a6fb3 100644 --- a/Notebooks_04/qp-nlp.ipynb +++ b/Notebooks_04/qp-nlp.ipynb @@ -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, diff --git a/Notebooks_04/supplychain.ipynb b/Notebooks_04/supplychain.ipynb index b5842f0..e3419cc 100644 --- a/Notebooks_04/supplychain.ipynb +++ b/Notebooks_04/supplychain.ipynb @@ -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": {}, diff --git a/Notebooks_04/testing.ipynb b/Notebooks_04/testing.ipynb index 7ce275c..37cefa1 100644 --- a/Notebooks_04/testing.ipynb +++ b/Notebooks_04/testing.ipynb @@ -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')" ] } ], diff --git a/Notebooks_04/unsicherheit.ipynb b/Notebooks_04/unsicherheit.ipynb index 2e2a12b..0b4ca21 100644 --- a/Notebooks_04/unsicherheit.ipynb +++ b/Notebooks_04/unsicherheit.ipynb @@ -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, diff --git a/Notebooks_04/vorwort.ipynb b/Notebooks_04/vorwort.ipynb index 66c47aa..b9a4ced 100644 --- a/Notebooks_04/vorwort.ipynb +++ b/Notebooks_04/vorwort.ipynb @@ -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')" ] } ], diff --git a/OR_HTML_04/Notebooks_04.zip b/OR_HTML_04/Notebooks_04.zip index 67ded28..e9fdbef 100644 Binary files a/OR_HTML_04/Notebooks_04.zip and b/OR_HTML_04/Notebooks_04.zip differ diff --git a/OR_HTML_04/Notebooks_04/anhang-fehlerdiagnose.ipynb b/OR_HTML_04/Notebooks_04/anhang-fehlerdiagnose.ipynb index 9a10276..e69d310 100644 --- a/OR_HTML_04/Notebooks_04/anhang-fehlerdiagnose.ipynb +++ b/OR_HTML_04/Notebooks_04/anhang-fehlerdiagnose.ipynb @@ -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": {}, diff --git a/OR_HTML_04/Notebooks_04/bruecke.ipynb b/OR_HTML_04/Notebooks_04/bruecke.ipynb index 08a2fd8..b54ab56 100644 --- a/OR_HTML_04/Notebooks_04/bruecke.ipynb +++ b/OR_HTML_04/Notebooks_04/bruecke.ipynb @@ -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": {}, diff --git a/OR_HTML_04/Notebooks_04/cpsat.ipynb b/OR_HTML_04/Notebooks_04/cpsat.ipynb index 765a79b..dd73a5d 100644 --- a/OR_HTML_04/Notebooks_04/cpsat.ipynb +++ b/OR_HTML_04/Notebooks_04/cpsat.ipynb @@ -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, diff --git a/OR_HTML_04/Notebooks_04/cvar.ipynb b/OR_HTML_04/Notebooks_04/cvar.ipynb index f581980..c4e7564 100644 --- a/OR_HTML_04/Notebooks_04/cvar.ipynb +++ b/OR_HTML_04/Notebooks_04/cvar.ipynb @@ -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, diff --git a/OR_HTML_04/Notebooks_04/dekomposition.ipynb b/OR_HTML_04/Notebooks_04/dekomposition.ipynb index 321bd40..8ac622c 100644 --- a/OR_HTML_04/Notebooks_04/dekomposition.ipynb +++ b/OR_HTML_04/Notebooks_04/dekomposition.ipynb @@ -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": {}, diff --git a/OR_HTML_04/Notebooks_04/dynamische-programmierung.ipynb b/OR_HTML_04/Notebooks_04/dynamische-programmierung.ipynb index 2662789..e3c4be0 100644 --- a/OR_HTML_04/Notebooks_04/dynamische-programmierung.ipynb +++ b/OR_HTML_04/Notebooks_04/dynamische-programmierung.ipynb @@ -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, diff --git a/OR_HTML_04/Notebooks_04/einfuehrung.ipynb b/OR_HTML_04/Notebooks_04/einfuehrung.ipynb index 0531984..778fa0a 100644 --- a/OR_HTML_04/Notebooks_04/einfuehrung.ipynb +++ b/OR_HTML_04/Notebooks_04/einfuehrung.ipynb @@ -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, diff --git a/OR_HTML_04/Notebooks_04/finanzdaten.ipynb b/OR_HTML_04/Notebooks_04/finanzdaten.ipynb index 324b2cf..86d86cd 100644 --- a/OR_HTML_04/Notebooks_04/finanzdaten.ipynb +++ b/OR_HTML_04/Notebooks_04/finanzdaten.ipynb @@ -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, diff --git a/OR_HTML_04/Notebooks_04/fundament.ipynb b/OR_HTML_04/Notebooks_04/fundament.ipynb index 37b2294..71ddefe 100644 --- a/OR_HTML_04/Notebooks_04/fundament.ipynb +++ b/OR_HTML_04/Notebooks_04/fundament.ipynb @@ -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, diff --git a/OR_HTML_04/Notebooks_04/graphen.ipynb b/OR_HTML_04/Notebooks_04/graphen.ipynb index a9f3047..8c5b1cc 100644 --- a/OR_HTML_04/Notebooks_04/graphen.ipynb +++ b/OR_HTML_04/Notebooks_04/graphen.ipynb @@ -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, diff --git a/OR_HTML_04/Notebooks_04/handelsmaschine.ipynb b/OR_HTML_04/Notebooks_04/handelsmaschine.ipynb index 3d7b425..0a3441e 100644 --- a/OR_HTML_04/Notebooks_04/handelsmaschine.ipynb +++ b/OR_HTML_04/Notebooks_04/handelsmaschine.ipynb @@ -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, diff --git a/OR_HTML_04/Notebooks_04/lp.ipynb b/OR_HTML_04/Notebooks_04/lp.ipynb index de95953..a30cdc4 100644 --- a/OR_HTML_04/Notebooks_04/lp.ipynb +++ b/OR_HTML_04/Notebooks_04/lp.ipynb @@ -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, diff --git a/OR_HTML_04/Notebooks_04/markowitz.ipynb b/OR_HTML_04/Notebooks_04/markowitz.ipynb index d8f490a..c793463 100644 --- a/OR_HTML_04/Notebooks_04/markowitz.ipynb +++ b/OR_HTML_04/Notebooks_04/markowitz.ipynb @@ -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, diff --git a/OR_HTML_04/Notebooks_04/mehrziel.ipynb b/OR_HTML_04/Notebooks_04/mehrziel.ipynb index e1cb7ca..cc98354 100644 --- a/OR_HTML_04/Notebooks_04/mehrziel.ipynb +++ b/OR_HTML_04/Notebooks_04/mehrziel.ipynb @@ -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": {}, diff --git a/OR_HTML_04/Notebooks_04/metaheuristiken.ipynb b/OR_HTML_04/Notebooks_04/metaheuristiken.ipynb index 9be40f6..99b8048 100644 --- a/OR_HTML_04/Notebooks_04/metaheuristiken.ipynb +++ b/OR_HTML_04/Notebooks_04/metaheuristiken.ipynb @@ -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, diff --git a/OR_HTML_04/Notebooks_04/milp.ipynb b/OR_HTML_04/Notebooks_04/milp.ipynb index 8f5ed61..ffbf18d 100644 --- a/OR_HTML_04/Notebooks_04/milp.ipynb +++ b/OR_HTML_04/Notebooks_04/milp.ipynb @@ -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')" ] } ], diff --git a/OR_HTML_04/Notebooks_04/modellierung.ipynb b/OR_HTML_04/Notebooks_04/modellierung.ipynb index df7ab93..c44b88d 100644 --- a/OR_HTML_04/Notebooks_04/modellierung.ipynb +++ b/OR_HTML_04/Notebooks_04/modellierung.ipynb @@ -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": {}, diff --git a/OR_HTML_04/Notebooks_04/oekosystem.ipynb b/OR_HTML_04/Notebooks_04/oekosystem.ipynb index ae42071..6518796 100644 --- a/OR_HTML_04/Notebooks_04/oekosystem.ipynb +++ b/OR_HTML_04/Notebooks_04/oekosystem.ipynb @@ -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')" ] } ], diff --git a/OR_HTML_04/Notebooks_04/praxisfallen.ipynb b/OR_HTML_04/Notebooks_04/praxisfallen.ipynb index 802e3be..9489dd9 100644 --- a/OR_HTML_04/Notebooks_04/praxisfallen.ipynb +++ b/OR_HTML_04/Notebooks_04/praxisfallen.ipynb @@ -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')" ] } ], diff --git a/OR_HTML_04/Notebooks_04/prognose.ipynb b/OR_HTML_04/Notebooks_04/prognose.ipynb index cf10cf6..3f44049 100644 --- a/OR_HTML_04/Notebooks_04/prognose.ipynb +++ b/OR_HTML_04/Notebooks_04/prognose.ipynb @@ -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": {}, diff --git a/OR_HTML_04/Notebooks_04/qp-nlp.ipynb b/OR_HTML_04/Notebooks_04/qp-nlp.ipynb index 92f9c40..21a6fb3 100644 --- a/OR_HTML_04/Notebooks_04/qp-nlp.ipynb +++ b/OR_HTML_04/Notebooks_04/qp-nlp.ipynb @@ -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, diff --git a/OR_HTML_04/Notebooks_04/supplychain.ipynb b/OR_HTML_04/Notebooks_04/supplychain.ipynb index b5842f0..e3419cc 100644 --- a/OR_HTML_04/Notebooks_04/supplychain.ipynb +++ b/OR_HTML_04/Notebooks_04/supplychain.ipynb @@ -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": {}, diff --git a/OR_HTML_04/Notebooks_04/testing.ipynb b/OR_HTML_04/Notebooks_04/testing.ipynb index 7ce275c..37cefa1 100644 --- a/OR_HTML_04/Notebooks_04/testing.ipynb +++ b/OR_HTML_04/Notebooks_04/testing.ipynb @@ -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')" ] } ], diff --git a/OR_HTML_04/Notebooks_04/unsicherheit.ipynb b/OR_HTML_04/Notebooks_04/unsicherheit.ipynb index 2e2a12b..0b4ca21 100644 --- a/OR_HTML_04/Notebooks_04/unsicherheit.ipynb +++ b/OR_HTML_04/Notebooks_04/unsicherheit.ipynb @@ -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, diff --git a/OR_HTML_04/Notebooks_04/vorwort.ipynb b/OR_HTML_04/Notebooks_04/vorwort.ipynb index 66c47aa..b9a4ced 100644 --- a/OR_HTML_04/Notebooks_04/vorwort.ipynb +++ b/OR_HTML_04/Notebooks_04/vorwort.ipynb @@ -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')" ] } ], diff --git a/OR_HTML_04/bilder_04/titelseite.svg b/OR_HTML_04/bilder_04/titelseite.svg index 2872aed..2ed7226 100644 --- a/OR_HTML_04/bilder_04/titelseite.svg +++ b/OR_HTML_04/bilder_04/titelseite.svg @@ -2444,7 +2444,7 @@ z - + - + - - @@ -2580,7 +2616,7 @@ z - + @@ -2600,11 +2636,11 @@ z - - + + - - + + diff --git a/OR_HTML_04/gesamtdokument.html b/OR_HTML_04/gesamtdokument.html index 3df8e00..23654df 100644 --- a/OR_HTML_04/gesamtdokument.html +++ b/OR_HTML_04/gesamtdokument.html @@ -381,7 +381,7 @@

Mit Python planen, optimieren und entscheiden: von Personal, Schichten und Logistik über Energie, Ressourcen und Netzwerke bis zur Portfoliooptimierung an den Finanzmärkten.

Autor / Herausgeber: Dieter Schlüter

<dieter(dot)schlueter(atsign)linix(dot)de>

-

Stand: 10. September 2026 v17.50

+

Stand: 11. September 2026 v22.37