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

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

|
||||

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

|
||||
|
||||
| | **Monte-Carlo** | **Stochastische Programmierung** | **Robuste Optimierung** | **Chance Constraints** |
|
||||
| | **Monte-Carlo** | **Stochastische Programmierung**{idx:Stochastische Programmierung} | **Robuste Optimierung**{idx:Robuste Optimierung} | **Chance Constraints** |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Braucht | Verteilung | Szenarien **mit Wahrscheinlichkeiten** | nur eine **Menge** möglicher Werte | Verteilung **oder** Szenarien |
|
||||
| Braucht | Verteilung | Szenarien **mit Wahrscheinlichkeiten** | nur eine **Menge**{idx:Konvexität!Menge} möglicher Werte | Verteilung **oder** Szenarien |
|
||||
| Optimiert | nichts (bewertet nur) | **Erwartungswert** über Szenarien | **Worst Case** in der Menge | Kosten bei **zugesicherter Quote** |
|
||||
| Typische Frage | „Wie riskant ist dieser Plan?“ | „Was ist im Mittel am besten?“ | „Was hält auch im schlimmsten Fall?“ | „Was hält in 95 % der Fälle?“ |
|
||||
| Stärke | beliebige Kennzahlen, sehr flexibel | nutzt Wahrscheinlichkeiten voll aus | keine Verteilungsannahme nötig | die Zusage steht **im Modell** |
|
||||
|
|
@ -290,7 +290,7 @@ macht damit verhandelbar, was die Sicherheit kosten darf.
|
|||
|
||||
---
|
||||
|
||||
## Monte-Carlo-Simulation {#sec:unsicherheit-monte-carlo-simulation}
|
||||
## Monte-Carlo-Simulation{idx:Monte-Carlo-Simulation} {#sec:unsicherheit-monte-carlo-simulation}
|
||||
|
||||
**Monte-Carlo**{idx:Monte-Carlo-Simulation} heißt schlicht: Ziehe sehr viele Zufallsszenarien, werte für jedes den Plan
|
||||
aus, und betrachte die **Verteilung** der Ergebnisse statt eines einzigen Werts.
|
||||
|
|
@ -662,7 +662,7 @@ Prognosen tatsächlich — anders als in dem Beispiel aus der Aufgabe *EVPI inte
|
|||
|
||||
---
|
||||
|
||||
## Robuste Optimierung: gegen den Worst Case absichern {#sec:unsicherheit-robuste-optimierung-gegen-den-worst-case}
|
||||
## Robuste Optimierung{idx:Robuste Optimierung}: gegen den Worst Case absichern {#sec:unsicherheit-robuste-optimierung-gegen-den-worst-case}
|
||||
|
||||
Wenn Wahrscheinlichkeiten unbekannt oder instabil sind — Marktcrashs, Lieferkettenabrisse,
|
||||
Pandemien —, hilft die **robuste Optimierung**{idx:Robuste Optimierung}. Sie fragt nicht nach dem Mittel, sondern
|
||||
|
|
@ -856,19 +856,19 @@ z_{1-\alpha} = \Phi^{-1}(1-\alpha)
|
|||
$$
|
||||
|
||||
Das ist eine **Second-Order-Cone-Bedingung**{idx:Konische Optimierung (SOCP, SDP)} — dieselbe
|
||||
Bauform, die {ref:kap:qp-nlp} eingeführt hat, und CVXPY löst sie ohne Umstände.
|
||||
Bauform, die {ref:kap:qp-nlp} eingeführt hat, und CVXPY{idx:CVXPY} löst sie ohne Umstände.
|
||||
|
||||
> **🎯 Warum eine Norm und keine Summe**
|
||||
> Der Sicherheitszuschlag $\lVert\mathbf{L}^\top\mathbf{x}\rVert_2$ ist **keine** Summe von
|
||||
> Einzelzuschlägen je Anlage. Genau darin steckt der Nutzen der Mischung: Zwei gegenläufige
|
||||
> Quellen schwanken **gemeinsam** weniger als jede für sich, und die Norm rechnet das
|
||||
> automatisch mit. Ein fester Aufschlag je Anlage könnte das nicht — er wäre linear und
|
||||
> würde Diversifikation nicht belohnen.
|
||||
> würde Diversifikation{idx:Diversifikation} nicht belohnen.
|
||||
|
||||
### Weg 2: Szenarien — Big-M ohne Verteilungsannahme
|
||||
|
||||
Liegen statt einer Verteilung nur $S$ beobachtete Szenarien vor, bekommt jedes eine
|
||||
Binärvariable $z_s$, die sagt, ob es verletzt werden **darf**:
|
||||
Binärvariable{idx:Binärvariable} $z_s$, die sagt, ob es verletzt werden **darf**:
|
||||
|
||||
$$
|
||||
\begin{aligned}
|
||||
|
|
@ -1203,11 +1203,11 @@ Verteilung.** Der Plan verspricht 95 % und hält **87,4 %**. Nicht weil das Verf
|
|||
rechnet: In einer reinen Normalwelt liefert derselbe Plan exakt seine 95,0 %. Sondern weil
|
||||
die Normalverteilung eine Kältewelle mit Dunkelflaute nicht kennt. In der bricht **alles
|
||||
zugleich** ein — auch das Gaskraftwerk, weil bei Frost der Netzdruck fällt. Eine
|
||||
Kovarianzmatrix mit Korrelationen um null kann so etwas nicht ausdrücken.
|
||||
Kovarianzmatrix{idx:Kovarianzmatrix} mit Korrelationen um null kann so etwas nicht ausdrücken.
|
||||
|
||||
Der szenariobasierte Weg kennt diese Fälle, weil sie in den Daten stehen. Er kommt auf
|
||||
94,8 %, kostet dafür 16,7 % mehr — und kauft **keine Windkraft mehr**. Die Logik dahinter ist
|
||||
hart und richtig: Was im Ernstfall ausfällt, hilft der Zusage nicht.
|
||||
hart{idx:Nebenbedingung!hart} und richtig: Was im Ernstfall ausfällt, hilft der Zusage nicht.
|
||||
|
||||
> **⚠️ Die Szenariomethode überanpasst — und mehr Szenarien helfen nicht verlässlich**
|
||||
> Bei $S$ Szenarien und $\alpha = 5\,\%$ darf das Modell genau $0{,}05 \cdot S$ davon
|
||||
|
|
@ -1336,7 +1336,7 @@ das lässt sich in CVXPY mit `cp.sum_largest` formulieren.)
|
|||
> {ref:sec:unsicherheit-schnellstart} führt der Mittelwert in die Irre, weil die **Kosten**
|
||||
> asymmetrisch sind. Hier führt er in die Irre, weil die **Verknüpfung** asymmetrisch ist:
|
||||
> Ein Gewerk, das früher fertig wird, hilft niemandem — ein Gewerk, das sich verspätet,
|
||||
> verzögert alles. Beide Male gilt: *Der Mittelwert einer Funktion ist nicht die Funktion
|
||||
> verzögert alles. Beide Male gilt: *Der Mittelwert einer Funktion{idx:Konvexität!Funktion} ist nicht die Funktion
|
||||
> des Mittelwerts.*
|
||||
|
||||
---
|
||||
|
|
@ -1368,7 +1368,7 @@ das lässt sich in CVXPY mit `cp.sum_largest` formulieren.)
|
|||
> und rechnet deterministisch. Wann ist das unproblematisch?**
|
||||
> (a) Immer — der Erwartungswert ist die beste Einzelschätzung.
|
||||
> (b) Nie.
|
||||
> (c) Wenn Zielfunktion und Nebenbedingungen in den unsicheren Größen **linear** sind und
|
||||
> (c) Wenn Zielfunktion{idx:Zielfunktion} und Nebenbedingungen in den unsicheren Größen **linear** sind und
|
||||
> keine Entscheidung erst nach Beobachtung fällt. Sobald Minimum, Maximum, Betrag oder eine
|
||||
> Nachbesserungsentscheidung im Spiel ist, gilt es nicht mehr.
|
||||
|
||||
|
|
@ -1421,7 +1421,7 @@ das lässt sich in CVXPY mit `cp.sum_largest` formulieren.)
|
|||
Entscheidung nicht begründbar.
|
||||
|
||||
**Ausblick.** {ref:kap:dynamische-programmierung} fügt die Zeitdimension hinzu: Entscheidungen, die über viele
|
||||
Perioden aufeinander aufbauen — gelöst mit der Bellman-Gleichung.
|
||||
Perioden aufeinander aufbauen — gelöst mit der Bellman-Gleichung{idx:Bellman-Gleichung}.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Kapitel: Dynamische Programmierung — Die Bellman-Gleichung und Order-Execution {#kap:dynamische-programmierung}
|
||||
# Kapitel: Dynamische Programmierung — Die Bellman-Gleichung{idx:Bellman-Gleichung} und Order-Execution {#kap:dynamische-programmierung}
|
||||
|
||||
> **📌 Kapitel auf einen Blick**
|
||||
>
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
> **Voraussetzungen:** {ref:kap:unsicherheit} (Erwartungswerte). Rekursion in Python.
|
||||
>
|
||||
> **Danach können Sie:** Ein mehrperiodiges Problem in Zustände und Stufen zerlegen, die
|
||||
> Wertfunktion durch Rückwärtsinduktion berechnen, die optimale Strategie ableiten — und
|
||||
> Wertfunktion durch Rückwärtsinduktion{idx:Rückwärtsinduktion} berechnen, die optimale Strategie ableiten — und
|
||||
> prüfen, ob Ihr Zustand vollständig genug ist.
|
||||
>
|
||||
> **Zeitbedarf:** ca. 5 Stunden.
|
||||
|
|
@ -85,7 +85,7 @@ zusätzlichen bezahlt.
|
|||
|
||||
**Warum funktioniert das?** Weil man den Rest des Weges nicht neu durchdenken muss, sobald
|
||||
man einmal an einem Ort steht: Wie man dorthin gekommen ist, ist für die Zukunft egal. Diese
|
||||
Eigenschaft heißt **Bellmansches Optimalitätsprinzip** und ist der Grund, warum aus einem
|
||||
Eigenschaft heißt **Bellmansches Optimalitätsprinzip**{idx:Optimalitätsprinzip} und ist der Grund, warum aus einem
|
||||
Problem mit exponentiell vielen Wegen eine Rechnung mit wenigen Zeilen wird. Bei fünf Orten
|
||||
fällt das kaum auf — bei fünfzig ist es der Unterschied zwischen Sekunden und Jahren.
|
||||
|
||||
|
|
@ -99,10 +99,10 @@ Nach diesem Kapitel können Sie …
|
|||
2. … Zustand, Stufe, Aktion und Wertfunktion für ein gegebenes Problem benennen.
|
||||
3. … eine Rückwärtsinduktion{idx:Rückwärtsinduktion} von Hand für ein kleines Problem durchführen.
|
||||
4. … das Almgren-Chriss-Ausführungsproblem lösen und die Lösung interpretieren.
|
||||
5. … einschätzen, wann DP funktioniert und wann der „Fluch der Dimensionalität“ zuschlägt.
|
||||
5. … einschätzen, wann DP funktioniert und wann der „Fluch der Dimensionalität{idx:Fluch der Dimensionalität}“ zuschlägt.
|
||||
6. … die Wertfunktion als **Nachschlagetabelle** lesen: Sie liefert keine Planfolge, sondern
|
||||
eine Regel, die auch bei Abweichungen gilt.
|
||||
7. … einen Zustandsraum auf Vollständigkeit prüfen und erkennen, wann eine Kostenart
|
||||
7. … einen Zustandsraum{idx:Zustandsraum} auf Vollständigkeit prüfen und erkennen, wann eine Kostenart
|
||||
Vorgeschichte erfordert.
|
||||
|
||||
---
|
||||
|
|
@ -328,13 +328,13 @@ C(n_t, X_t) = \underbrace{\eta\,n_t^2}_{\text{Marktauswirkung}} \;+\; \underbrac
|
|||
$$
|
||||
|
||||
> **📐 Formel-Lesehilfe**
|
||||
> * $n_t$ — in Periode $t$ verkaufte Stückzahl. Quadriert, weil doppelte Menge mehr als
|
||||
> * $n_t$ — in Periode $t$ verkaufte Stückzahl. Quadriert, weil doppelte Menge{idx:Konvexität!Menge} mehr als
|
||||
> doppelten Preisdruck erzeugt.
|
||||
> * $\eta$ („eta“) — Slippage-Koeffizient. Wie stark reagiert der Markt auf Volumen?
|
||||
> * $X_t$ — Restbestand **nach** dem Verkauf. Quadriert, weil Varianz quadratisch mit der
|
||||
> Positionsgröße wächst.
|
||||
> * $\lambda$ — Risikoaversion: Wie sehr stört mich Schwankung im Vergleich zu Slippage?
|
||||
> * $\sigma$ — Volatilität je Periode.
|
||||
> * $\sigma$ — Volatilität{idx:Volatilität} je Periode.
|
||||
>
|
||||
> **Ohne Formel gesagt:** „Schnell verkaufen kostet Preisabschlag. Langsam verkaufen kostet
|
||||
> Nervenkitzel. Finde die Mitte.“
|
||||
|
|
@ -352,7 +352,7 @@ $$
|
|||
> holding_risk = risk_aversion * (sigma_period ** 2) * (remaining ** 2) * 1e5
|
||||
> ```
|
||||
> Woher eine solche Zahl kommt, bleibt dann unklar. Faktisch wirkt sie als versteckte
|
||||
> Erhöhung der Risikoaversion um fünf Größenordnungen — ein Parameter wie
|
||||
> Erhöhung der Risikoaversion um fünf Größenordnungen — ein Parameter{idx:Parameter (Modell)} wie
|
||||
> `risk_aversion = 1e-6` würde dann in Wahrheit $0{,}1$ bedeuten. Solche „magischen
|
||||
> Zahlen“ machen ein Modell unkalibrierbar: Niemand kann sagen, ob 1e-6 viel oder wenig
|
||||
> ist.
|
||||
|
|
@ -693,7 +693,7 @@ Zustandsvariable **multipliziert** den Aufwand.
|
|||
|
||||
**Gegenmittel:**
|
||||
* **Zustandsraum**{idx:Zustandsraum} **verkleinern:** gröber diskretisieren, irrelevante Variablen weglassen.
|
||||
* **Approximate Dynamic Programming**{idx:Dynamische Programmierung!Approximate Dynamic Programming}**:** $V_t$ durch eine parametrische Funktion annähern
|
||||
* **Approximate Dynamic Programming**{idx:Dynamische Programmierung!Approximate Dynamic Programming}**:** $V_t$ durch eine parametrische Funktion{idx:Konvexität!Funktion} annähern
|
||||
statt tabellarisch zu speichern.
|
||||
* **Reinforcement Learning**{idx:Reinforcement Learning}**:** dieselbe Bellman-Gleichung{idx:Bellman-Gleichung}, aber $V$ wird aus Erfahrung
|
||||
gelernt (Q-Learning{idx:Q-Learning}) statt vollständig berechnet.
|
||||
|
|
@ -720,7 +720,7 @@ nicht nur vom aktuellen Zustand)?
|
|||
Wertfunktionstabelle und bestimmen Sie den optimalen Pfad. Prüfen Sie mit
|
||||
`Bellman_Minimalbeispiel.py` (angepasst).
|
||||
|
||||
**Aufgabe ⭐⭐ — Rucksackproblem als DP.**
|
||||
**Aufgabe ⭐⭐ — Rucksackproblem{idx:Rucksackproblem} als DP.**
|
||||
Lösen Sie das Rucksackproblem aus {ref:kap:milp} mit dynamischer Programmierung statt MILP.
|
||||
(Zustand: verbleibende Kapazität; Stufe: betrachteter Gegenstand.) Vergleichen Sie
|
||||
Laufzeit und Ergebnis mit dem MILP-Solver.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
> {ref:kap:milp}. Für den Denkfehler hilft {ref:kap:markowitz}.
|
||||
>
|
||||
> **Danach können Sie:** begründen, warum eine gewichtete Summe bei ganzzahligen Modellen
|
||||
> Kompromisse **grundsätzlich** nicht erreichen kann; eine vollständige Pareto-Front mit dem
|
||||
> Kompromisse **grundsätzlich** nicht erreichen kann; eine vollständige Pareto-Front{idx:Pareto-Front} mit dem
|
||||
> ε-Constraint-Verfahren berechnen; und einer Geschäftsführung eine Entscheidung vorlegen,
|
||||
> die sie tatsächlich treffen kann.
|
||||
>
|
||||
|
|
@ -128,7 +128,7 @@ $$
|
|||
|
||||
> **📖 Definition: Pareto-Front**{idx:Pareto-Front}
|
||||
>
|
||||
> Die Menge aller nicht dominierten Lösungen. Sie ist das vollständige Ergebnis eines
|
||||
> Die Menge{idx:Konvexität!Menge} aller nicht dominierten Lösungen. Sie ist das vollständige Ergebnis eines
|
||||
> Mehrzielproblems — nicht ein Punkt, sondern eine Liste.
|
||||
>
|
||||
> Wer daraus einen einzelnen Punkt macht, trifft eine Entscheidung. Die Frage ist nur, ob er
|
||||
|
|
@ -645,7 +645,7 @@ Eine Front mit zehn Punkten ist kein Ergebnis, sondern eine Speisekarte. Damit s
|
|||
entscheidbar wird, gehört eine Spalte dazu, die im Programm `EUR je kg` heißt:
|
||||
|
||||
$$
|
||||
\text{Schattenpreis} = \frac{\text{Aufpreis gegenüber dem Kostenminimum}}
|
||||
\text{Schattenpreis{idx:Schattenpreis}} = \frac{\text{Aufpreis gegenüber dem Kostenminimum}}
|
||||
{\text{eingesparte Kilogramm}}
|
||||
$$
|
||||
|
||||
|
|
@ -657,7 +657,7 @@ kaufmännisch schon getroffen.
|
|||
>
|
||||
> | Stelle | Was sie tut |
|
||||
> | --- | --- |
|
||||
> | `plane(ziel, co2_grenze, kosten_grenze)` | **eine** Funktion für alle Varianten. Welches Ziel und welche Schranke — mehr Unterschied gibt es zwischen den fünf Teilen des Programms nicht |
|
||||
> | `plane(ziel, co2_grenze, kosten_grenze)` | **eine** Funktion{idx:Konvexität!Funktion} für alle Varianten. Welches Ziel und welche Schranke — mehr Unterschied gibt es zwischen den fünf Teilen des Programms nicht |
|
||||
> | `pareto_front()` | das ε-Verfahren: Grenze jeweils um 1 kg unter den zuletzt erreichten Wert drücken, bis nichts mehr geht |
|
||||
> | `untere_huelle()` | rechnet die Hülle **unabhängig** aus, damit die Aussage „unerreichbar“ nicht auf dem Gewichtsraster beruht, sondern auf Geometrie |
|
||||
>
|
||||
|
|
@ -683,7 +683,7 @@ würden Sie empfehlen — und wie begründen Sie ihn in einem Satz?
|
|||
Erhöhen Sie `BAHN_TRASSEN` von 5 auf 8. Was passiert mit der Länge der Front und mit der
|
||||
Zahl der unerreichbaren Punkte? Erklären Sie den Zusammenhang.
|
||||
|
||||
**Aufgabe ⭐⭐ — Die Front der Relaxation.**
|
||||
**Aufgabe ⭐⭐ — Die Front der Relaxation{idx:Relaxation}.**
|
||||
Lassen Sie `integrality` weg, sodass Anteile erlaubt sind. Berechnen Sie die Front erneut
|
||||
(mit einem ε-Raster, da es nun unendlich viele Punkte gibt). Wie viele Punkte liegen jetzt
|
||||
oberhalb der konvexen Hülle — und warum?
|
||||
|
|
@ -771,4 +771,4 @@ einer Fläche. Wie ändert sich das ε-Verfahren, und warum wächst der Aufwand
|
|||
|
||||
---
|
||||
|
||||
*Weiter mit:* [{ref:kap:prognose} — Predict-then-Optimize](34_Predict_then_Optimize.md)
|
||||
*Weiter mit:* [{ref:kap:prognose} — Predict-then-Optimize{idx:Predict-then-Optimize}](34_Predict_then_Optimize.md)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Kapitel: Predict-then-Optimize — die bessere Prognose, die schlechtere Entscheidung {#kap:prognose}
|
||||
# Kapitel: Predict-then-Optimize{idx:Predict-then-Optimize} — die bessere Prognose, die schlechtere Entscheidung {#kap:prognose}
|
||||
|
||||
> **📌 Kapitel auf einen Blick**
|
||||
>
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
> Ein Modell **prognostiziert**, ein anderes **entscheidet**. Beide arbeiten sauber — und
|
||||
> genau an der Naht entsteht ein Fehler, den keine der beiden Seiten sieht.
|
||||
>
|
||||
> **Voraussetzungen:** {ref:kap:unsicherheit}, insbesondere das Newsvendor-Problem und das
|
||||
> **Voraussetzungen:** {ref:kap:unsicherheit}, insbesondere das Newsvendor-Problem{idx:Newsvendor-Problem} und das
|
||||
> kritische Verhältnis. Etwas Regression hilft, ist aber nicht nötig.
|
||||
>
|
||||
> **Danach können Sie:** begründen, warum ein Prognosemodell mit kleinerem MSE teurere
|
||||
|
|
@ -61,7 +61,7 @@ derselben Daten, aus denen auch das Quantil kommt. Trotzdem kostet er **7,20 €
|
|||
gut 10 %.
|
||||
|
||||
Der Grund steht in den Preisen: Ein fehlendes Brot kostet doppelt so viel wie ein übriges.
|
||||
Bei asymmetrischen Kosten liegt die optimale Menge nicht in der Mitte der Verteilung,
|
||||
Bei asymmetrischen Kosten liegt die optimale Menge{idx:Konvexität!Menge} nicht in der Mitte der Verteilung,
|
||||
sondern beim **kritischen Verhältnis** $c_-/(c_- + c_+) = 6/9 = 66{,}7\,\%$ — das kennen Sie
|
||||
aus {ref:kap:unsicherheit}.
|
||||
|
||||
|
|
@ -578,7 +578,7 @@ Die dritte Zeile der Ergebnistabelle — „Zuschlag auf Kosten trainiert" — i
|
|||
denkbare Form einer Idee, die derzeit erforscht wird: **das Prognosemodell direkt auf die
|
||||
Entscheidungskosten zu trainieren** statt auf ein Fehlermaß.
|
||||
|
||||
Hier war es ein einziger Parameter, mit einer Rasterschleife bestimmt. Der allgemeine Fall
|
||||
Hier war es ein einziger Parameter{idx:Parameter (Modell)}, mit einer Rasterschleife bestimmt. Der allgemeine Fall
|
||||
ist schwieriger, weil die Optimierung zwischen Modell und Kosten steht: Um den Gradienten
|
||||
der Kosten nach den Modellparametern zu bilden, muss man **durch das Optimierungsproblem
|
||||
hindurch ableiten**.
|
||||
|
|
@ -631,7 +631,7 @@ und zwar **in unterschiedlichem Ausmaß**? Was sagt das über den Wert eines Mer
|
|||
>
|
||||
> Ein Data-Science-Team stellt sein Quartalsergebnis vor:
|
||||
>
|
||||
> > *„Wir haben das alte lineare Modell durch ein Gradient-Boosting-Modell ersetzt. Der MSE
|
||||
> > *„Wir haben das alte lineare Modell durch ein Gradient{idx:Gradient}-Boosting-Modell ersetzt. Der MSE
|
||||
> > auf den Testdaten ist um 18 % gesunken, der MAPE um 14 %. Das ist die größte
|
||||
> > Prognoseverbesserung, die wir je erreicht haben. Die Disposition bekommt ab nächstem
|
||||
> > Monat die neuen Werte."*
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ Er hat drei Abschnitte, und Sie können nach jedem aufhören:
|
|||
> ersten beiden Kapitel dieses Teils und kann den Rest überspringen, ohne dass etwas
|
||||
> fehlt — die Methoden sind dieselben.
|
||||
>
|
||||
> **Lesen Sie ihn trotzdem, wenn Sie eines der folgenden Themen brauchen:** Schätzfehler in
|
||||
> **Lesen Sie ihn trotzdem, wenn Sie eines der folgenden Themen brauchen:** Schätzfehler{idx:Schätzfehler} in
|
||||
> Kovarianzmatrizen (das Problem tritt bei jeder Korrelationsschätzung auf, auch bei
|
||||
> Lieferzeiten), Risikomaße jenseits der Standardabweichung, oder rollierende Auswertung
|
||||
> mit sauberer Trennung von Trainings- und Testzeitraum.
|
||||
|
|
@ -114,7 +114,7 @@ Der interessanteste Teil steht in der zweiten Zeile der Ausgabe. **60,26 € je
|
|||
Risikobudget** — das ist der Dualwert derselben Nebenbedingung, die in der Werkstatt sagt,
|
||||
was eine zusätzliche Montagestunde wert wäre. In der Finanzwelt hat diese Zahl einen eigenen
|
||||
Namen: der **Preis des Risikos**. Es ist nicht bloß eine Analogie, es ist derselbe
|
||||
Schattenpreis aus {ref:kap:lp}.
|
||||
Schattenpreis{idx:Schattenpreis} aus {ref:kap:lp}.
|
||||
|
||||
> **🎯 Merksatz**
|
||||
> Wenn zwei Probleme dieselbe Struktur haben, brauchen sie nicht zwei Modelle, sondern zwei
|
||||
|
|
@ -122,7 +122,7 @@ Schattenpreis aus {ref:kap:lp}.
|
|||
> — nicht daran, dass eine Tabelle es behauptet.
|
||||
|
||||
**Warum funktioniert das?** Weil ein LP nichts über die Bedeutung seiner Zahlen weiß. Es
|
||||
sieht eine Matrix, einen Kapazitätsvektor und einen Zielvektor. Ob in der Matrix Stunden,
|
||||
sieht eine Matrix, einen Kapazitätsvektor{idx:Kapazitätsvektor} und einen Zielvektor. Ob in der Matrix Stunden,
|
||||
Kilogramm oder Risikobeiträge stehen, kommt darin nicht vor.
|
||||
|
||||
---
|
||||
|
|
@ -646,7 +646,7 @@ Gebühr um 10 Einheiten zu erhöhen. Bis zu welcher Gebühr lohnt sich das — u
|
|||
Einschränkung dieser Aussage kennen Sie aus {ref:sec:lp-entartung}?
|
||||
|
||||
**Aufgabe ⭐⭐ — Die Brücke rückwärts.**
|
||||
Übertragen Sie die Ledoit-Wolf-Shrinkage aus {ref:kap:finanzdaten} auf Lieferzeiten:
|
||||
Übertragen Sie die Ledoit-Wolf-Shrinkage{idx:Ledoit-Wolf-Shrinkage} aus {ref:kap:finanzdaten} auf Lieferzeiten:
|
||||
Wo genau träte dort dasselbe Problem auf, und welche Daten bräuchten Sie?
|
||||
|
||||
**Aufgabe ⭐⭐ — CVaR mit Ganzzahligkeit.**
|
||||
|
|
@ -670,7 +670,7 @@ trägt — und schreiben Sie auf, welche der drei Zeilen im Weg steht.
|
|||
> geht vor wie im Portfoliomanagement:
|
||||
>
|
||||
> > *„Ich habe für jeden Lieferanten aus den letzten drei Jahren die mittlere Lieferzeit und
|
||||
> > die Kovarianzmatrix der Lieferzeiten geschätzt. Dann habe ich das Markowitz-Modell
|
||||
> > die Kovarianzmatrix{idx:Kovarianzmatrix} der Lieferzeiten geschätzt. Dann habe ich das Markowitz-Modell
|
||||
> > angewendet: minimiere die Varianz der Gesamtlieferzeit bei vorgegebener mittlerer
|
||||
> > Lieferzeit. Das Ergebnis ist ein sauber diversifiziertes Lieferantenportfolio."*
|
||||
>
|
||||
|
|
@ -723,7 +723,7 @@ trägt — und schreiben Sie auf, welche der drei Zeilen im Weg steht.
|
|||
## Zusammenfassung {#sec:bruecke-zusammenfassung}
|
||||
|
||||
* Die Behauptung „dieselben Methoden, andere Domäne" ist prüfbar — und hier geprüft: Ein
|
||||
Depot passt unverändert in die Klasse `Produktionsproblem`, und **eine** CVaR-Funktion
|
||||
Depot passt unverändert in die Klasse `Produktionsproblem`, und **eine** CVaR-Funktion{idx:Konvexität!Funktion}
|
||||
bearbeitet Kursverluste wie Lieferverzüge.
|
||||
* Der **Schattenpreis** einer Ressource heißt in der Finanzwelt *Preis des Risikos*. Es ist
|
||||
derselbe Dualwert derselben Nebenbedingung.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue