Glossar-Links: Fachbegriffe im Fließtext automatisch verlinken
Auto-Linking im Build: Glossar-Begriffe werden im Fließtext automatisch
erkannt und als Link auf den Glossar-Eintrag gesetzt — erste Nennung je
Begriff je Datei, dezent gestrichelte Unterstreichung im HTML, hyperref
im PDF. Kein manuelles Markieren bei Textänderungen nötig.
Neue Infrastruktur:
- glossar_eintraege_04.py: glossar_slug() + LINK_TEXTE-Map (automatisch
generiert aus EINTRAEGEN + Abkürzungs-Extraktion)
- erzeuge_glossar_04.py: jeder Eintrag bekommt {#gloss:<slug>}-Anchor
- build_version_04.py: resolve_glossar() — Auto-Linking + {gl:}-Marke
- web_04/site.css: .glossar-link (dezent, nicht wie Navigationslink)
5 neue Glossar-Einträge (waren als Begriff im Text, aber nicht im Glossar):
Solver, Scheduling, Graphen, Backtest, DCP (Disciplined Convex Programming)
Schutzmechanismen:
- Code-Blöcke, Inline-Code, {idx:}/{ref:}-Marken, Markdown-Links und
Überschriften werden nicht verlinkt
- Verschachtelung verhindert: 'CP-SAT-Solver' als Ganzes, nicht 'CP'+[
-'SAT'+[-'Solver'
- 'OR' als 2-Zeichen-Abkürzung nicht auto-verlinkt (False Positive in
'OR-Tools'); {gl:OR} als manuelle Marke
- Glossar selbst nicht auto-verlinkt (sonst Self-Links)
- reflow_markdown(): ::: als Block-Grenze (sonst kollabiert fenced div)
619 Glossar-Links im Gesamtdokument, 239 Anchor im Glossar, 34 im Vorwort.
This commit is contained in:
parent
81ddb02d5c
commit
e8abb66d75
52 changed files with 4316 additions and 1921 deletions
BIN
OR_HTML_04/Operations_Research_mit_Python_Version_04.pdf
generated
BIN
OR_HTML_04/Operations_Research_mit_Python_Version_04.pdf
generated
Binary file not shown.
50
OR_HTML_04/anhang-fehlerdiagnose.html
generated
50
OR_HTML_04/anhang-fehlerdiagnose.html
generated
|
|
@ -120,12 +120,12 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td>Solver meldet <code>INFEASIBLE</code></td>
|
||||
<td><a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> meldet <code>INFEASIBLE</code></td>
|
||||
<td><a href="#c1-infeasible">C1</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>INFEASIBLE</code>, aber keine einzelne Bedingung ist schuld</td>
|
||||
<td><a href="#c1-infeasible">C1</a>, Deletion Filter</td>
|
||||
<td><a href="#c1-infeasible">C1</a>, <a href="anhang-glossar.md#gloss:deletion-filter" class="glossar-link">Deletion Filter</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Solver meldet <code>UNBOUNDED</code></td>
|
||||
|
|
@ -152,7 +152,7 @@
|
|||
<td><a href="#c7-widersprüchliche-solver">C7</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>CVXPY wirft <code>DCPError</code></td>
|
||||
<td><a href="anhang-glossar.md#gloss:cvxpy" class="glossar-link">CVXPY</a> wirft <code>DCPError</code></td>
|
||||
<td><a href="#c8-dcperror">C8</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -160,7 +160,7 @@
|
|||
<td><a href="#c9-importfehler">C9</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Backtest sieht zu gut aus</td>
|
||||
<td><a href="anhang-glossar.md#gloss:backtest" class="glossar-link">Backtest</a> sieht zu gut aus</td>
|
||||
<td><a href="#c10-verdächtig-guter-backtest">C10</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -187,17 +187,17 @@
|
|||
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>modell.Add(linke_seite <span class="op"><=</span> rechte_seite <span class="op">+</span> schlupf)</span>
|
||||
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>strafen.append(<span class="dv">10_000</span> <span class="op">*</span> schlupf)</span></code></pre></div>
|
||||
<p>Nach dem Lösen zeigen die Schlupfvariablen mit Wert > 0 <strong>präzise, welche Bedingung</strong> wo und um wie viel verletzt werden musste. Das ist zugleich die produktionstaugliche Lösung (Muster B18).</p>
|
||||
<p><strong>Schritt 4 — Zeitfenster und Erreichbarkeit prüfen.</strong> Bei Scheduling und Routing: Ist jeder Termin überhaupt physisch erreichbar?</p>
|
||||
<p><strong>Schritt 4 — Zeitfenster und Erreichbarkeit prüfen.</strong> Bei <a href="anhang-glossar.md#gloss:scheduling" class="glossar-link">Scheduling</a> und Routing: Ist jeder Termin überhaupt physisch erreichbar?</p>
|
||||
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> kunde, (frueh, spaet) <span class="kw">in</span> <span class="bu">enumerate</span>(zeitfenster):</span>
|
||||
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">assert</span> distanz[depot][kunde] <span class="op"><=</span> spaet, <span class="ss">f"Kunde </span><span class="sc">{</span>kunde<span class="sc">}</span><span class="ss"> nicht rechtzeitig erreichbar"</span></span></code></pre></div>
|
||||
<p><strong>Schritt 5 — Rundungs- und Einheitenfehler.</strong> Sind Kapazitäten in Stunden, Verbräuche aber in Minuten? Rechnen CP-SAT-Modelle mit ganzen Zahlen, wo Sie Nachkommastellen brauchen? Ein klassischer Fall: <code>sum(w) == 1</code> mit Gleitkommazahlen — nutzen Sie eine Toleranz oder rechnen Sie in Ganzzahlen (Promille).</p>
|
||||
<p><strong>Schritt 5 — Rundungs- und Einheitenfehler.</strong> Sind Kapazitäten in Stunden, Verbräuche aber in Minuten? Rechnen <a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a>-Modelle mit ganzen Zahlen, wo Sie Nachkommastellen brauchen? Ein klassischer Fall: <code>sum(w) == 1</code> mit Gleitkommazahlen — nutzen Sie eine Toleranz oder rechnen Sie in Ganzzahlen (Promille).</p>
|
||||
<h3 id="wenn-die-fünf-schritte-nicht-reichen-den-konflikt-einkreisen">Wenn die fünf Schritte nicht reichen: den Konflikt einkreisen</h3>
|
||||
<p><strong>Warum Schritt 2 so oft ins Leere läuft.</strong> Bedingungen einzeln abzuschalten funktioniert nur, solange es <em>einen</em> Schuldigen gibt. Überlagern sich zwei unabhängige Widersprüche, bleibt das Modell nach jeder einzelnen Abschaltung unlösbar — die Suche endet mit null Treffern, obwohl beide Widersprüche unverändert im Modell stehen. Genau dann steht man vor einem Modell mit tausenden Restriktionen und einem Statuscode.</p>
|
||||
<p><strong>Der Deletion Filter</strong> dreht die Frage um. Er fragt nicht „ist <em>diese</em> Bedingung schuld?“, sondern „wird <em>diese</em> Bedingung für den Widerspruch überhaupt gebraucht?“ — und das ist eine Frage, die sich beantworten lässt:</p>
|
||||
<blockquote>
|
||||
<p>Nimm eine Bedingung versuchsweise heraus. Bleibt der Rest unlösbar, wurde sie nicht gebraucht: weg damit, endgültig. Wird der Rest lösbar, war sie beteiligt: sie bleibt.</p>
|
||||
</blockquote>
|
||||
<p>Nach genau einem Durchlauf über alle <span class="math inline">n</span> Bedingungen ist die übrig gebliebene Menge <strong>unreduzierbar</strong> — entfernt man aus ihr irgendeine Bedingung, ist der Rest lösbar. Das ist ein <em>Irreducible Infeasible Subset</em>, kurz IIS. Kommerzielle Solver bieten das als fertige Funktion an (<code>computeIIS</code> bei Gurobi, der Conflict Refiner bei CPLEX); im Open-Source-Werkzeugkasten dieses Buchs gibt es sie nicht — sie ist aber in zwanzig Zeilen selbst geschrieben, und sie kostet <span class="math inline">n</span> Aufrufe des Solvers statt <span class="math inline">2^n</span> durchprobierter Teilmengen.</p>
|
||||
<p>Nach genau einem Durchlauf über alle <span class="math inline">n</span> Bedingungen ist die übrig gebliebene Menge <strong>unreduzierbar</strong> — entfernt man aus ihr irgendeine Bedingung, ist der Rest lösbar. Das ist ein <em>Irreducible Infeasible Subset</em>, kurz <a href="anhang-glossar.md#gloss:iis-irreducible-infeasible-subset" class="glossar-link">IIS</a>. Kommerzielle Solver bieten das als fertige Funktion an (<code>computeIIS</code> bei <a href="anhang-glossar.md#gloss:gurobi" class="glossar-link">Gurobi</a>, der Conflict Refiner bei CPLEX); im Open-Source-Werkzeugkasten dieses Buchs gibt es sie nicht — sie ist aber in zwanzig Zeilen selbst geschrieben, und sie kostet <span class="math inline">n</span> Aufrufe des Solvers statt <span class="math inline">2^n</span> durchprobierter Teilmengen.</p>
|
||||
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||||
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Konfliktsuche.py</span></span>
|
||||
|
|
@ -530,7 +530,7 @@ Insgesamt 2874 Solveraufrufe fuer die gesamte Diagnose.
|
|||
====================================================================</code></pre>
|
||||
<p><strong>Vier Dinge sind daran wichtig.</strong></p>
|
||||
<ol type="1">
|
||||
<li><strong>Die Zulässigkeitsprüfung braucht keine Zielfunktion.</strong> <code>linprog</code> bekommt einen Nullvektor als Ziel. Unlösbarkeit hängt nie an der Zielfunktion — wer beim Diagnostizieren die echte Zielfunktion mitschleppt, bezahlt Rechenzeit für nichts.</li>
|
||||
<li><strong>Die Zulässigkeitsprüfung braucht keine <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a>.</strong> <code>linprog</code> bekommt einen Nullvektor als Ziel. Unlösbarkeit hängt nie an der Zielfunktion — wer beim Diagnostizieren die echte Zielfunktion mitschleppt, bezahlt Rechenzeit für nichts.</li>
|
||||
<li><strong>Gefiltert werden nur die aufgeführten Bedingungen, nicht die Variablenschranken.</strong> Die Nichtnegativität steht in <code>bounds</code> und bleibt in jedem Teilmodell stehen. Sitzt Ihr Widerspruch in den Schranken (<code>x >= 5</code> als Bound statt als Zeile), findet ihn der Filter nicht — schreiben Sie solche Grenzen dann als benannte Bedingung.</li>
|
||||
<li><strong>Sprechende Namen sind kein Luxus.</strong> Der Befund ist genau so brauchbar wie die Namen, die darin vorkommen. <code>constraint_47, constraint_112, constraint_9</code> ist kein Befund.</li>
|
||||
<li><strong>Der Filter liefert <em>einen</em> kleinsten Konflikt, nicht <em>den</em> kleinsten.</strong> Dieses Modell mit vierzehn Bedingungen enthält neun verschiedene minimale Konflikte; welchen man zu sehen bekommt, entscheidet allein die Prüfreihenfolge. Das ist kein Mangel des Verfahrens, sondern eine Eigenschaft des Problems.</li>
|
||||
|
|
@ -539,7 +539,7 @@ Insgesamt 2874 Solveraufrufe fuer die gesamte Diagnose.
|
|||
<blockquote>
|
||||
<p><strong>⚠️ Was der Filter kostet</strong> Ein Konflikt kostet <span class="math inline">n</span> Solverläufe. Bei 14 Bedingungen sind das 14 — bei 50 000 Restriktionen mit je zehn Sekunden Lösungszeit wären es knapp sechs Tage. Für große Modelle filtert man deshalb nicht einzeln, sondern <strong>gruppenweise</strong>: erst über Bedingungs<em>blöcke</em> (alle Kapazitäten, alle Verträge, alle Zeitfenster) laufen, dann den Filter nur noch innerhalb des einen Blocks anwenden, der übrig bleibt. Das ist derselbe Algorithmus auf einer gröberen Ebene und senkt die Zahl der Läufe um Größenordnungen.</p>
|
||||
</blockquote>
|
||||
<p><strong>Das Verhältnis zur Relaxation.</strong> Der Deletion Filter beantwortet die Frage <em>„was widerspricht sich?“</em>; die Schlupfvariablen aus Schritt 3 beantworten die Frage <em>„was tun wir jetzt?“</em>. Beide gehören in ein Produktionssystem, aber an verschiedene Stellen: der Filter in die Entwicklung und in die Fehlersuche, die Relaxation in den Betrieb (<code>Infeasibility_Diagnose.py</code>, <a href="praxisfallen.html#sec:praxisfallen-die-fuenf-typischen-praxisfallen">Abschnitt 22.3</a>). Ein System, das im Ernstfall den Konflikt <em>benennt</em> und trotzdem einen Notfallplan <em>liefert</em>, hat beides.</p>
|
||||
<p><strong>Das Verhältnis zur <a href="anhang-glossar.md#gloss:relaxation" class="glossar-link">Relaxation</a>.</strong> Der Deletion Filter beantwortet die Frage <em>„was widerspricht sich?“</em>; die Schlupfvariablen aus Schritt 3 beantworten die Frage <em>„was tun wir jetzt?“</em>. Beide gehören in ein Produktionssystem, aber an verschiedene Stellen: der Filter in die Entwicklung und in die Fehlersuche, die Relaxation in den Betrieb (<code>Infeasibility_Diagnose.py</code>, <a href="praxisfallen.html#sec:praxisfallen-die-fuenf-typischen-praxisfallen">Abschnitt 22.3</a>). Ein System, das im Ernstfall den Konflikt <em>benennt</em> und trotzdem einen Notfallplan <em>liefert</em>, hat beides.</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Die eigentliche Lehre</strong> <code>INFEASIBLE</code> in Produktion ist ein <strong>Entwurfsfehler</strong>, kein Betriebsfehler. Ein System, das im Ernstfall nur „geht nicht“ sagt, ist wertlos. Bauen Sie Schlupfvariablen von vornherein ein (<a href="praxisfallen.html#sec:praxisfallen-die-fuenf-typischen-praxisfallen">Abschnitt 22.3</a>).</p>
|
||||
</blockquote>
|
||||
|
|
@ -567,9 +567,9 @@ Insgesamt 2874 Solveraufrufe fuer die gesamte Diagnose.
|
|||
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>loesen()<span class="op">;</span> t2 <span class="op">=</span> time.perf_counter()</span>
|
||||
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"Aufbau </span><span class="sc">{</span>t1<span class="op">-</span>t0<span class="sc">:.2f}</span><span class="ss">s | Loesen </span><span class="sc">{</span>t2<span class="op">-</span>t1<span class="sc">:.2f}</span><span class="ss">s"</span>)</span></code></pre></div>
|
||||
<p>Bei CVXPY und bei Schleifen über Szenarien ist oft der <strong>Aufbau</strong> der Engpass, nicht der Solver (siehe <a href="cvar.html#sec:cvar-implementierung-cvar-portfolio-mit-reibung">Abschnitt 20.6</a>).</p>
|
||||
<p><strong>2. Big-M zu groß?</strong> Der häufigste Grund für explodierende MILP-Laufzeiten. Setzen Sie <span class="math inline">M</span> auf die kleinste gültige Schranke (<a href="milp.html#sec:milp-modellierungstricks-big-m-und-logische-bedingungen">Abschnitt 6.5</a>).</p>
|
||||
<p><strong>2. Big-M zu groß?</strong> Der häufigste Grund für explodierende <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a>-Laufzeiten. Setzen Sie <span class="math inline">M</span> auf die kleinste gültige Schranke (<a href="milp.html#sec:milp-modellierungstricks-big-m-und-logische-bedingungen">Abschnitt 6.5</a>).</p>
|
||||
<p><strong>3. Symmetrie im Modell?</strong> Identische Maschinen, austauschbare Mitarbeitende, gleichwertige Fahrzeuge — der Solver durchsucht alle Vertauschungen. Abhilfe: Ordnungsbedingungen (Muster B20).</p>
|
||||
<p><strong>4. Falsche Solverfamilie?</strong> Zuordnungsprobleme mit MILP, Routing mit CP-SAT von Hand nachgebaut, konvexe Probleme mit <code>scipy.optimize.minimize</code> — jeweils Größenordnungen langsamer als das passende Werkzeug (<a href="oekosystem.html#sec:oekosystem-wann-lohnt-sich-welche-ebene">Abschnitt 3.6</a>).</p>
|
||||
<p><strong>4. Falsche Solverfamilie?</strong> Zuordnungsprobleme mit MILP, Routing mit <a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a> von Hand nachgebaut, konvexe Probleme mit <code>scipy.optimize.minimize</code> — jeweils Größenordnungen langsamer als das passende Werkzeug (<a href="oekosystem.html#sec:oekosystem-wann-lohnt-sich-welche-ebene">Abschnitt 3.6</a>).</p>
|
||||
<p><strong>5. Wird vektorisiert?</strong></p>
|
||||
<div class="sourceCode" id="cb8"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="co"># langsam: # schnell:</span></span>
|
||||
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> s <span class="kw">in</span> <span class="bu">range</span>(S): constraints.append(u <span class="op">>=</span> <span class="op">-</span>(R <span class="op">@</span> w) <span class="op">-</span> gamma)</span>
|
||||
|
|
@ -616,9 +616,9 @@ Insgesamt 2874 Solveraufrufe fuer die gesamte Diagnose.
|
|||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td>Schlecht konditionierte Kovarianzmatrix</td>
|
||||
<td>Schlecht konditionierte <a href="anhang-glossar.md#gloss:kovarianzmatrix" class="glossar-link">Kovarianzmatrix</a></td>
|
||||
<td><code>np.linalg.cond(Sigma)</code></td>
|
||||
<td>Ledoit-Wolf-Shrinkage (<a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a>)</td>
|
||||
<td><a href="anhang-glossar.md#gloss:ledoit-wolf-shrinkage" class="glossar-link">Ledoit-Wolf-Shrinkage</a> (<a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a>)</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>Zu wenige Beobachtungen</td>
|
||||
|
|
@ -626,7 +626,7 @@ Insgesamt 2874 Solveraufrufe fuer die gesamte Diagnose.
|
|||
<td>Historie verlängern oder Universum verkleinern</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Alternativoptima</td>
|
||||
<td><a href="anhang-glossar.md#gloss:alternativoptima" class="glossar-link">Alternativoptima</a></td>
|
||||
<td>Zielfunktion bei mehreren Lösungen gleich?</td>
|
||||
<td>Regularisierung: kleinen <span class="math inline">L_2</span>-Term addieren</td>
|
||||
</tr>
|
||||
|
|
@ -641,12 +641,12 @@ Insgesamt 2874 Solveraufrufe fuer die gesamte Diagnose.
|
|||
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"Kondition </span><span class="sc">{</span>eig<span class="sc">.</span><span class="bu">max</span>()<span class="op">/</span>eig<span class="sc">.</span><span class="bu">min</span>()<span class="sc">:.0f}</span><span class="ss"> | kleinster EW </span><span class="sc">{</span>eig<span class="sc">.</span><span class="bu">min</span>()<span class="sc">:.2e}</span><span class="ss">"</span>)</span>
|
||||
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Faustregel: Kondition > 1000 ist bedenklich, > 10000 kritisch</span></span></code></pre></div>
|
||||
<h3 id="derselbe-fehler-außerhalb-der-finanzwelt">Derselbe Fehler außerhalb der Finanzwelt</h3>
|
||||
<p>Instabilität ist kein Portfolioproblem, sondern ein Skalierungsproblem — und es trifft jedes Modell, in dem Größen sehr verschiedener Ordnung nebeneinanderstehen. Euro-Beträge (<span class="math inline">10^7</span>) und Tonnen-Angaben (<span class="math inline">10^{-3}</span>) in derselben Matrix erzeugen eine Konditionszahl, die aus einer Datenunsicherheit von 0,1 % eine Lösungsänderung von 100 % machen kann. Die Konditionszahl ist genau die Obergrenze dieses Verstärkungsfaktors.</p>
|
||||
<p>Instabilität ist kein Portfolioproblem, sondern ein Skalierungsproblem — und es trifft jedes Modell, in dem Größen sehr verschiedener Ordnung nebeneinanderstehen. Euro-Beträge (<span class="math inline">10^7</span>) und Tonnen-Angaben (<span class="math inline">10^{-3}</span>) in derselben Matrix erzeugen eine <a href="anhang-glossar.md#gloss:konditionszahl" class="glossar-link">Konditionszahl</a>, die aus einer Datenunsicherheit von 0,1 % eine Lösungsänderung von 100 % machen kann. Die Konditionszahl ist genau die Obergrenze dieses Verstärkungsfaktors.</p>
|
||||
<div class="sourceCode" id="cb12"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"Kondition der Restriktionsmatrix: </span><span class="sc">{</span>np<span class="sc">.</span>linalg<span class="sc">.</span>cond(A)<span class="sc">:.1e}</span><span class="ss">"</span>)</span>
|
||||
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="co"># Grobe Peilung: Wertebereiche der Koeffizienten anschauen</span></span>
|
||||
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"kleinster / groesster Betrag: </span><span class="sc">{</span>np<span class="sc">.</span><span class="bu">abs</span>(A[A <span class="op">!=</span> <span class="dv">0</span>])<span class="sc">.</span><span class="bu">min</span>()<span class="sc">:.1e}</span><span class="ss"> "</span></span>
|
||||
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"/ </span><span class="sc">{</span>np<span class="sc">.</span><span class="bu">abs</span>(A)<span class="sc">.</span><span class="bu">max</span>()<span class="sc">:.1e}</span><span class="ss">"</span>)</span></code></pre></div>
|
||||
<p>Klaffen die Beträge um mehr als drei, vier Größenordnungen auseinander, rechnen Sie in anderen Einheiten (Tausend Euro statt Euro, Kilogramm statt Tonnen) oder skalieren Sie Zeilen und Spalten automatisch. <code>Skalierung_Kondition.py</code> zeigt beides samt Ruiz-Equilibrierung (<a href="fundament.html#sec:fundament-kondition">Abschnitt 2.7</a>).</p>
|
||||
<p>Klaffen die Beträge um mehr als drei, vier Größenordnungen auseinander, rechnen Sie in anderen Einheiten (Tausend Euro statt Euro, Kilogramm statt Tonnen) oder skalieren Sie Zeilen und Spalten automatisch. <code>Skalierung_Kondition.py</code> zeigt beides samt <a href="anhang-glossar.md#gloss:ruiz-equilibrierung" class="glossar-link">Ruiz-Equilibrierung</a> (<a href="fundament.html#sec:fundament-kondition">Abschnitt 2.7</a>).</p>
|
||||
<hr />
|
||||
<h2 id="c6-falsche-dualwerte">C6 — Falsche Dualwerte</h2>
|
||||
<p><strong>Symptom.</strong> Schattenpreise sind negativ, wo sie positiv sein sollten — oder null bei einer offensichtlich knappen Ressource.</p>
|
||||
|
|
@ -654,16 +654,16 @@ Insgesamt 2874 Solveraufrufe fuer die gesamte Diagnose.
|
|||
<p><strong>1. Vorzeichenkonvention.</strong> Haben Sie zur Maximierung negiert?</p>
|
||||
<div class="sourceCode" id="cb13"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>schattenpreise <span class="op">=</span> <span class="op">-</span>res.ineqlin.marginals <span class="co"># bei linprog nach Negation</span></span></code></pre></div>
|
||||
<p>Genau das ist die Vorzeichenfalle aus <a href="lp.html#sec:lp-die-vorzeichenfalle-bei-schattenpreisen">Abschnitt 5.7</a>.</p>
|
||||
<p><strong>2. Komplementärer Schlupf.</strong></p>
|
||||
<p><strong>2. <a href="anhang-glossar.md#gloss:komplementaerer-schlupf" class="glossar-link">Komplementärer Schlupf</a>.</strong></p>
|
||||
<div class="sourceCode" id="cb14"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> s, y <span class="kw">in</span> <span class="bu">zip</span>(res.slack, schattenpreise):</span>
|
||||
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">assert</span> <span class="bu">abs</span>(s <span class="op">*</span> y) <span class="op"><</span> <span class="fl">1e-6</span>, <span class="st">"Komplementaerer Schlupf verletzt!"</span></span></code></pre></div>
|
||||
<p>Eine Ressource mit Reserve <strong>muss</strong> Schattenpreis 0 haben.</p>
|
||||
<p>Eine Ressource mit Reserve <strong>muss</strong> <a href="anhang-glossar.md#gloss:schattenpreis" class="glossar-link">Schattenpreis</a> 0 haben.</p>
|
||||
<p><strong>3. Numerische Gegenprobe — der zuverlässigste Test.</strong></p>
|
||||
<div class="sourceCode" id="cb15"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>b_plus <span class="op">=</span> b.copy()<span class="op">;</span> b_plus[i] <span class="op">+=</span> <span class="fl">1.0</span></span>
|
||||
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>zuwachs <span class="op">=</span> loese(b_plus) <span class="op">-</span> loese(b)</span>
|
||||
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="cf">assert</span> <span class="bu">abs</span>(zuwachs <span class="op">-</span> schattenpreise[i]) <span class="op"><</span> <span class="fl">1e-6</span></span></code></pre></div>
|
||||
<p>Dieser Test ist <strong>unabhängig von jeder Vorzeichenkonvention</strong>. Nutzen Sie ihn.</p>
|
||||
<p><strong>4. Wenn alle drei Prüfungen bestehen und der Wert trotzdem seltsam ist: Entartung.</strong> Die drei Prüfungen oben setzen voraus, dass es <em>einen</em> richtigen Schattenpreis gibt. Bei einem entarteten Optimum — mehr aktive Nebenbedingungen als Variablen — gibt es den nicht. Der Wert ist dann nicht falsch, sondern <strong>mehrdeutig</strong>: zwei korrekte Solver liefern für dasselbe Optimum verschiedene Dualwerte, und die numerische Gegenprobe aus Schritt 3 schlägt fehl, weil der Zuwachs nach links und nach rechts unterschiedlich ausfällt.</p>
|
||||
<p><strong>4. Wenn alle drei Prüfungen bestehen und der Wert trotzdem seltsam ist: <a href="anhang-glossar.md#gloss:entartung" class="glossar-link">Entartung</a>.</strong> Die drei Prüfungen oben setzen voraus, dass es <em>einen</em> richtigen Schattenpreis gibt. Bei einem entarteten Optimum — mehr aktive Nebenbedingungen als Variablen — gibt es den nicht. Der Wert ist dann nicht falsch, sondern <strong>mehrdeutig</strong>: zwei korrekte Solver liefern für dasselbe Optimum verschiedene Dualwerte, und die numerische Gegenprobe aus Schritt 3 schlägt fehl, weil der Zuwachs nach links und nach rechts unterschiedlich ausfällt.</p>
|
||||
<div class="sourceCode" id="cb16"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>aktiv <span class="op">=</span> <span class="bu">int</span>(np.<span class="bu">sum</span>(res.slack <span class="op"><</span> <span class="fl">1e-9</span>)) <span class="co"># wie viele Bedingungen sind straff?</span></span>
|
||||
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> aktiv <span class="op">></span> <span class="bu">len</span>(res.x):</span>
|
||||
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Entartet: </span><span class="sc">{</span>aktiv<span class="sc">}</span><span class="ss"> aktive Bedingungen bei </span><span class="sc">{</span><span class="bu">len</span>(res.x)<span class="sc">}</span><span class="ss"> Variablen."</span>)</span>
|
||||
|
|
@ -676,7 +676,7 @@ Insgesamt 2874 Solveraufrufe fuer die gesamte Diagnose.
|
|||
<hr />
|
||||
<h2 id="c8-dcperror">C8 — DCPError</h2>
|
||||
<pre><code>cvxpy.error.DCPError: Problem does not follow DCP rules.</code></pre>
|
||||
<p><strong>Bedeutung.</strong> CVXPY kann die Konvexität Ihres Ausdrucks nicht beweisen — es lehnt ab, statt ein Ergebnis ohne Garantie zu liefern. <strong>Das ist ein Feature.</strong></p>
|
||||
<p><strong>Bedeutung.</strong> CVXPY kann die <a href="anhang-glossar.md#gloss:konvexitaet" class="glossar-link">Konvexität</a> Ihres Ausdrucks nicht beweisen — es lehnt ab, statt ein Ergebnis ohne Garantie zu liefern. <strong>Das ist ein Feature.</strong></p>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 44%" />
|
||||
|
|
@ -694,7 +694,7 @@ Insgesamt 2874 Solveraufrufe fuer die gesamte Diagnose.
|
|||
<tr class="odd">
|
||||
<td><code>x * y</code> (beide Variablen)</td>
|
||||
<td>bilinear</td>
|
||||
<td>umformulieren oder MILP/NLP</td>
|
||||
<td>umformulieren oder MILP/<a href="anhang-glossar.md#gloss:nichtlineare-programmierung-nlp" class="glossar-link">NLP</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>a / x</code></td>
|
||||
|
|
@ -703,7 +703,7 @@ Insgesamt 2874 Solveraufrufe fuer die gesamte Diagnose.
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>cp.sqrt(cp.quad_form(w, S))</code></td>
|
||||
<td><code>cp.sqrt</code> ist <strong>konkav</strong> und verlangt ein konkaves Argument — <code>quad_form</code> ist konvex. Der Ausdruck ist nie DCP, egal wie sauber <span class="math inline">S</span> ist</td>
|
||||
<td><code>cp.sqrt</code> ist <strong>konkav</strong> und verlangt ein konkaves Argument — <code>quad_form</code> ist konvex. Der Ausdruck ist nie <a href="anhang-glossar.md#gloss:dcp-disciplined-convex-programming" class="glossar-link">DCP</a>, egal wie sauber <span class="math inline">S</span> ist</td>
|
||||
<td>Cholesky <span class="math inline">S = LL^\top</span>, dann <code>cp.norm2(L.T @ w)</code>: die 2-Norm eines <strong>affinen</strong> Ausdrucks (siehe <code>CVaR_Portfolio.py</code>)</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -712,9 +712,9 @@ Insgesamt 2874 Solveraufrufe fuer die gesamte Diagnose.
|
|||
<td><code>cp.psd_wrap(S)</code>, <strong>wenn</strong> <span class="math inline">S</span> nachweislich PSD ist (z. B. eine Kovarianzmatrix). Behebt nur diese numerische Beanstandung, keine Regelverletzung im Aufbau</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Quotient (z. B. Sharpe Ratio)</td>
|
||||
<td>Quotient (z. B. <a href="anhang-glossar.md#gloss:sharpe-ratio" class="glossar-link">Sharpe Ratio</a>)</td>
|
||||
<td>nicht konvex</td>
|
||||
<td>Korn-Transformation (<a href="markowitz.html#sec:markowitz-das-mean-variance-modell">Abschnitt 19.4</a>)</td>
|
||||
<td><a href="anhang-glossar.md#gloss:korn-transformation" class="glossar-link">Korn-Transformation</a> (<a href="markowitz.html#sec:markowitz-das-mean-variance-modell">Abschnitt 19.4</a>)</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>cp.log(x)</code> maximieren</td>
|
||||
|
|
@ -730,7 +730,7 @@ Insgesamt 2874 Solveraufrufe fuer die gesamte Diagnose.
|
|||
<hr />
|
||||
<h2 id="c9-importfehler">C9 — Importfehler</h2>
|
||||
<pre><code>ImportError: .../highspy/_core...so: undefined symbol: _ZN5Highs13releaseMemoryEv</code></pre>
|
||||
<p><strong>Ursache.</strong> <code>ortools</code> und <code>highspy</code> bringen beide eine eigene HiGHS-Kopie mit; sie lassen sich auf vielen Systemen <strong>nicht im selben Prozess</strong> importieren (siehe <a href="oekosystem.html#sec:oekosystem-ein-system-vier-programmieransaetze">Abschnitt 3.5</a>). Der Konflikt entsteht auch <strong>indirekt</strong>: <code>cvxpy</code> importiert ein installiertes <code>highspy</code> bei der Solver-Erkennung selbst mit — ein Skript, das erst <code>cvxpy</code> und dann <code>ortools</code> importiert, crasht daher mit derselben Meldung.</p>
|
||||
<p><strong>Ursache.</strong> <code>ortools</code> und <code>highspy</code> bringen beide eine eigene <a href="anhang-glossar.md#gloss:highs" class="glossar-link">HiGHS</a>-Kopie mit; sie lassen sich auf vielen Systemen <strong>nicht im selben Prozess</strong> importieren (siehe <a href="oekosystem.html#sec:oekosystem-ein-system-vier-programmieransaetze">Abschnitt 3.5</a>). Der Konflikt entsteht auch <strong>indirekt</strong>: <code>cvxpy</code> importiert ein installiertes <code>highspy</code> bei der Solver-Erkennung selbst mit — ein Skript, das erst <code>cvxpy</code> und dann <code>ortools</code> importiert, crasht daher mit derselben Meldung.</p>
|
||||
<p><strong>Abhilfen (in dieser Reihenfolge):</strong> 1. Nur eines von beiden im selben Skript verwenden. 2. Getrennte Prozesse — ein <code>ProcessPoolExecutor</code> mit <code>mp_context="spawn"</code> und <code>max_tasks_per_child=1</code>, siehe <code>Ein_System_Vier_Ansaetze.py</code>. 3. Auf <code>highspy</code> verzichten: HiGHS ist ohnehin Backend von <code>scipy.optimize.linprog</code> und CVXPY. 4. Getrennte virtuelle Umgebungen.</p>
|
||||
<hr />
|
||||
<h2 id="c10-verdächtig-guter-backtest">C10 — Verdächtig guter Backtest</h2>
|
||||
|
|
|
|||
483
OR_HTML_04/anhang-glossar.html
generated
483
OR_HTML_04/anhang-glossar.html
generated
|
|
@ -102,264 +102,747 @@
|
|||
<h1 id="anhang-glossar">Anhang E: Glossar</h1>
|
||||
<p>Nachschlagewerk zu allen Fachbegriffen, Abkürzungen, Algorithmen und Bibliotheken dieses Buchs. Jeder Eintrag nennt am Ende den Abschnitt, in dem der Begriff eingeführt wird — ein Klick dorthin führt in der Online-Fassung direkt zur Erklärung im Zusammenhang. Wer einen Begriff an <em>allen</em> Fundstellen sucht, benutzt das Stichwortverzeichnis.</p>
|
||||
<h2 id="a">A</h2>
|
||||
<div id="gloss:absolutbetrag">
|
||||
<p><strong>Absolutbetrag</strong> — Modellierungsmuster für <span class="math inline">|x-z|</span>: Der Betrag selbst ist nicht linear, lässt sich aber durch eine Hilfsvariable <span class="math inline">d</span> mit den beiden Bedingungen <span class="math inline">x-z \le d</span> und <span class="math inline">z-x \le d</span> ersetzen. Das funktioniert nur, wenn <span class="math inline">d</span> minimiert wird — sonst bleibt die Schranke unausgeschöpft. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:adjusted-close">
|
||||
<p><strong>Adjusted Close</strong> — Um Dividenden und Splits bereinigter Schlusskurs. Nur mit ihm sind Renditen über längere Zeiträume vergleichbar; der unbereinigte Schlusskurs erzeugt an jedem Ausschüttungstag einen Scheinverlust. → <a href="finanzdaten.html#sec:finanzdaten-diskrete-und-logarithmische-renditen">Abschnitt 18.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:aktivierungsschalter">
|
||||
<p><strong>Aktivierungsschalter</strong> — Modellierungsmuster, das eine kontinuierliche Größe an eine Binärvariable koppelt: <span class="math inline">x \le M\,y</span> erlaubt <span class="math inline">x > 0</span> nur, wenn <span class="math inline">y = 1</span> ist. Grundbaustein für Fixkosten, Standortentscheidungen und Mindestmengen. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:almgren-chriss-modell">
|
||||
<p><strong>Almgren-Chriss-Modell</strong> — Standardmodell der optimalen Orderausführung. Es löst den Zielkonflikt zwischen Marktauswirkung bei schnellem Handeln und Volatilitätsrisiko bei langsamem Handeln und liefert einen Ausführungsplan über mehrere Perioden. → <a href="dynamische-programmierung.html#sec:dynamische-programmierung-das-almgren-chriss-problem-optimale-orderausfuehrung">Abschnitt 13.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:alternativoptima">
|
||||
<p><strong>Alternativoptima</strong> — Mehrere Lösungen mit identischem Zielfunktionswert. Sie treten auf, wenn die Zielfunktion parallel zu einer Kante des Polyeders verläuft oder die Matrix des quadratischen Terms nur semidefinit ist. Der Solver meldet dann eine beliebige davon — zwei Läufe können unterschiedlich aussehen und trotzdem beide optimal sein. → <a href="qp-nlp.html#sec:qp-nlp-das-quadratische-programm-qp">Abschnitt 11.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:approximate-dynamic-programming">
|
||||
<p><strong>Approximate Dynamic Programming</strong> — Sammelbegriff für Verfahren, die die Wertfunktion der dynamischen Programmierung nicht exakt tabellieren, sondern annähern — etwa durch Regression oder ein neuronales Netz. Antwort auf den Fluch der Dimensionalität, wenn der Zustandsraum zu groß zum Durchzählen wird. → <a href="praxisfallen.html#sec:praxisfallen-weiterfuehrende-literatur-und-roadmap">Abschnitt 22.9</a></p>
|
||||
</div>
|
||||
<h2 id="b">B</h2>
|
||||
<div id="gloss:backtest">
|
||||
<p><strong>Backtest</strong> — Rückblickender Test einer Strategie auf historischen Daten. Ein Backtest ist nur so glaubwürdig wie seine Daten, seine Kostenannahme und seine Trennung von Trainings- und Testzeitraum — <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a> zeigt die fünf Selbsttäuschungen, die ihn wertlos machen. → <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a></p>
|
||||
</div>
|
||||
<div id="gloss:bedingte-kopplung">
|
||||
<p><strong>Bedingte Kopplung</strong> — Modellierungsmuster für „wenn A <strong>und</strong> B, dann C“. Umgesetzt über <span class="math inline">y_C \ge y_A + y_B - 1</span>: Nur wenn beide Voraussetzungen gesetzt sind, wird die Folge erzwungen. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:bellman-gleichung">
|
||||
<p><strong>Bellman-Gleichung</strong> — Rekursionsgleichung der dynamischen Programmierung: Der Wert eines Zustands ist die Summe aus den unmittelbaren Kosten der besten Aktion und dem Wert des Folgezustands. Sie zerlegt eine mehrstufige Entscheidung in eine Kette einstufiger. → <a href="dynamische-programmierung.html#sec:dynamische-programmierung-das-bellmansche-optimalitaetsprinzip">Abschnitt 13.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:benders-zerlegung">
|
||||
<p><strong>Benders-Zerlegung</strong> — Dekompositionsverfahren für Probleme mit wenigen „schweren“ und vielen „leichten“ Variablen. Ein Masterproblem entscheidet über die schweren, ein Subproblem über den Rest und schickt Schnitte (Benders-Cuts) zurück, bis beide übereinstimmen. → <a href="praxisfallen.html#sec:praxisfallen-weiterfuehrende-literatur-und-roadmap">Abschnitt 22.9</a></p>
|
||||
</div>
|
||||
<div id="gloss:big-m-methode">
|
||||
<p><strong>Big-M-Methode</strong> — Modellierungstrick, der logische Bedingungen über eine hinreichend große Konstante <span class="math inline">M</span> an eine Binärvariable koppelt. <span class="math inline">M</span> sollte <strong>so klein wie möglich</strong> gewählt werden: Große Werte weichen die Relaxation auf, verschlechtern die Laufzeit und können zu Trickle Flow führen. → <a href="milp.html#sec:milp-modellierungstricks-big-m-und-logische-bedingungen">Abschnitt 6.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:binaervariable">
|
||||
<p><strong>Binärvariable</strong> — Entscheidungsvariable mit Wertebereich <span class="math inline">\{0,1\}</span>. Sie schaltet Fixkosten, Kapazitäten oder logische Alternativen an und aus und macht aus einem linearen Programm ein gemischt-ganzzahliges. → <a href="einfuehrung.html#sec:einfuehrung-die-vier-universellen-bausteine-jedes-or">Abschnitt 1.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:bipartites-matching">
|
||||
<p><strong>Bipartites Matching</strong> — Zuordnung zwischen zwei disjunkten Mengen — etwa Personen und Aufgaben — mit maximalem Nutzen oder minimalen Kosten. Klassisch gelöst durch den Ungarischen Algorithmus; die Modellmatrix ist total unimodular, weshalb schon das LP ganzzahlige Ecken hat. → <a href="graphen.html#sec:graphen-bipartites-matching-das-zuordnungsproblem">Abschnitt 8.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:black-box-effekt">
|
||||
<p><strong>Black-Box-Effekt</strong> — Ablehnung eines Optimierungssystems, weil seine Entscheidungen nicht nachvollziehbar sind. Gegenmittel sind ein Constraint-Trace für Einzelentscheidungen und eine Kostenzerlegung für Bewertungen. Akzeptanz ist keine Nebensache, sondern Betriebsvoraussetzung. → <a href="praxisfallen.html#sec:praxisfallen-die-fuenf-typischen-praxisfallen">Abschnitt 22.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:branch-and-bound">
|
||||
<p><strong>Branch-and-Bound</strong> — Exaktes Verfahren für ganzzahlige Probleme: Der Suchraum wird rekursiv zerlegt (Branching), und ein Zweig wird verworfen, sobald seine Relaxation schlechter ist als die beste bekannte Lösung (Bounding). Ohne das Abschneiden wäre es bloßes Durchprobieren. → <a href="milp.html#sec:milp-branch-and-bound">Abschnitt 6.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:branch-and-cut">
|
||||
<p><strong>Branch-and-Cut</strong> — Kombination aus Branch-and-Bound und Schnittebenenverfahren: In den Knoten des Suchbaums werden zusätzlich gültige Ungleichungen erzeugt, die gebrochene Lösungen abschneiden. Der Standardalgorithmus heutiger MILP-Solver. → <a href="oekosystem.html#sec:oekosystem-die-zwei-schichten-architektur">Abschnitt 3.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:brute-force">
|
||||
<p><strong>Brute Force</strong> — Vollständiges Durchprobieren aller Möglichkeiten. Für kleine Instanzen ein nützlicher Kontrollwert, in der Praxis meist chancenlos: Schon 20 binäre Entscheidungen ergeben über eine Million Kombinationen. → <a href="einfuehrung.html#sec:einfuehrung-was-ist-operations-research-wirklich">Abschnitt 1.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:budgeted-uncertainty">
|
||||
<p><strong>Budgeted Uncertainty</strong> — Robustheitsansatz nach Bertsimas und Sim: Höchstens <span class="math inline">\Gamma</span> von <span class="math inline">n</span> Parametern nehmen gleichzeitig ihren ungünstigsten Wert an. Der Parameter <span class="math inline">\Gamma</span> regelt stufenlos, wie vorsichtig die Lösung wird — bei <span class="math inline">\Gamma = 0</span> nominal, bei <span class="math inline">\Gamma = n</span> maximal pessimistisch. → <a href="unsicherheit.html#sec:unsicherheit-robuste-optimierung-gegen-den-worst-case">Abschnitt 12.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:budgetlimit">
|
||||
<p><strong>Budgetlimit</strong> — Nebenbedingung, die die Summe gewichteter Entscheidungen nach oben begrenzt. Der zugehörige Schattenpreis beantwortet unmittelbar, was eine zusätzliche Budgeteinheit einbrächte. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<h2 id="c">C</h2>
|
||||
<div id="gloss:calmar-ratio">
|
||||
<p><strong>Calmar Ratio</strong> — Jahresrendite geteilt durch den Betrag des maximalen Drawdowns. Ergänzt die Sharpe Ratio um die Verlustperspektive: Sie misst Ertrag je Einheit des schlimmsten erlebten Rückschlags statt je Einheit Schwankung. → <a href="handelsmaschine.html#sec:handelsmaschine-die-engine">Abschnitt 21.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:cdcl">
|
||||
<p><strong>CDCL</strong> — <em>Conflict-Driven Clause Learning</em> — das Suchprinzip moderner SAT-Solver. Aus jedem Widerspruch wird eine Sperrklausel abgeleitet, die verhindert, dass dieselbe Sackgasse erneut betreten wird; anschließend springt die Suche gezielt zurück statt Schritt für Schritt. → <a href="cpsat.html#sec:cpsat-ein-anderes-denkmodell">Abschnitt 7.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:chance-constraint">
|
||||
<p><strong>Chance Constraint</strong> — Nebenbedingung, die nicht immer, sondern nur mit vorgegebener Wahrscheinlichkeit gelten muss — etwa „die Versorgung reicht in 95 % der Fälle“. Bei normalverteilter Unsicherheit wird daraus eine konische Bedingung, sonst hilft eine szenariobasierte Big-M-Formulierung. → <a href="unsicherheit.html#sec:unsicherheit-chance-constraints">Abschnitt 12.7</a></p>
|
||||
</div>
|
||||
<div id="gloss:column-generation">
|
||||
<p><strong>Column Generation</strong> — Verfahren für Modelle mit sehr vielen Variablen: Gerechnet wird auf einer kleinen Teilmenge, und ein Preisproblem sucht wiederholt die eine Spalte, die sich noch lohnt. Erst wenn keine mehr existiert, ist das Optimum bewiesen. → <a href="metaheuristiken.html#sec:metaheuristiken-abgrenzung">Abschnitt 9.8</a></p>
|
||||
</div>
|
||||
<div id="gloss:conditional-value-at-risk-cvar">
|
||||
<p><strong>Conditional Value at Risk (CVaR)</strong> — Erwarteter Verlust in den schlechtesten Szenarien jenseits des Value at Risk. Anders als der VaR ist der CVaR kohärent und subadditiv und lässt sich nach Rockafellar und Uryasev exakt als lineares Programm formulieren. → <a href="cvar.html#sec:cvar-value-at-risk-und-conditional-value">Abschnitt 20.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:conflict-learning">
|
||||
<p><strong>Conflict Learning</strong> — Technik moderner SAT- und CP-Solver, aus jedem erkannten Widerspruch eine Sperrklausel abzuleiten. Der Solver lernt so aus Fehlschlägen, statt gleichartige Sackgassen immer wieder zu durchsuchen. → <a href="cpsat.html#sec:cpsat-ein-anderes-denkmodell">Abschnitt 7.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:constraint-attribution">
|
||||
<p><strong>Constraint Attribution</strong> — Diagnoseverfahren für den häufigsten Praxisfall: Das Modell rechnet, der Plan ist zulässig — und trotzdem enttäuschend. Jede Bedingungsgruppe wird einzeln gelockert und gemessen, wie sich der Zielwert ändert. Dasselbe Vorgehen wie der Deletion Filter, nur mit Kosten statt Zulässigkeit als Kriterium. → <a href="praxisfallen.html#sec:praxisfallen-attribution">Abschnitt 22.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:constraint-programming-cp">
|
||||
<p><strong>Constraint Programming (CP)</strong> — Paradigma, das nicht über Zielfunktionsgradienten, sondern über logische Verträglichkeit sucht: Constraints schränken Wertebereiche ein, bis eine zulässige Belegung gefunden ist. Stark bei Reihenfolgen, Schichtplänen und Ressourcenkonflikten. → <a href="cpsat.html#sec:cpsat-ein-anderes-denkmodell">Abschnitt 7.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:constraint-propagation">
|
||||
<p><strong>Constraint Propagation</strong> — Kernmechanismus von CP-Solvern: Aus einer Zuweisung werden unmögliche Werte anderer Variablen sofort entfernt. Der Suchbaum schrumpft dadurch, bevor er überhaupt durchsucht wird. Genau hier liegt der Vorteil globaler Constraints — ihre Propagatoren schließen weit mehr Werte aus als die gleichwertige Menge einzelner Ungleichungen. → <a href="cpsat.html#sec:cpsat-ein-anderes-denkmodell">Abschnitt 7.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:constraint-trace">
|
||||
<p><strong>Constraint-Trace</strong> — Nachvollziehbare Begründung einer einzelnen Solver-Entscheidung — „Warum bekommt Person A die Stunde und nicht Person B?“ — anhand der bindenden Bedingungen und Strafpunkte. Das Gegenmittel zum Black-Box-Effekt. → <a href="praxisfallen.html#sec:praxisfallen-die-fuenf-typischen-praxisfallen">Abschnitt 22.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:cp-sat">
|
||||
<p><strong>CP-SAT</strong> — Constraint-Programming-Solver von OR-Tools. Er übersetzt ein Modell in boolesche Erfüllbarkeit und löst es mit Propagation, Conflict Learning und paralleler Suche. Für Reihenfolge- und Zuordnungsprobleme meist schneller als ein MILP-Solver. → <a href="cpsat.html#sec:cpsat-ein-anderes-denkmodell">Abschnitt 7.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:cp-sat-solver">
|
||||
<p><strong>CP-SAT-Solver</strong> — Die Solver-Komponente von OR-Tools, angesprochen über <code>cp_model.CpSolver()</code>. Sie liefert neben der Lösung Statuscode, Laufzeit und die beste bekannte Schranke und lässt sich über <code>num_workers</code> auf mehrere Kerne verteilen. → <a href="cpsat.html#sec:cpsat-ein-anderes-denkmodell">Abschnitt 7.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:csr-format">
|
||||
<p><strong>CSR-Format</strong> — <em>Compressed Sparse Row</em> — Speicherformat für dünn besetzte Matrizen, das nur die von null verschiedenen Einträge samt ihrer Positionen ablegt. Für Optimierungsmodelle mit zehntausenden Nebenbedingungen der Unterschied zwischen passt und passt nicht in den Speicher. → <a href="oekosystem.html#sec:oekosystem-ein-system-vier-programmieransaetze">Abschnitt 3.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:cvrptw">
|
||||
<p><strong>CVRPTW</strong> — <em>Capacitated Vehicle Routing Problem with Time Windows</em> — Tourenplanung mit einer Flotte, Kapazitätsgrenzen je Fahrzeug und Zeitfenstern je Kunde. Die praxisnahe Variante des VRP und Standardfall der Routing-Bibliothek von OR-Tools. → <a href="graphen.html#sec:graphen-das-vehicle-routing-problem-mit-zeitfenstern">Abschnitt 8.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:cvxpy">
|
||||
<p><strong>CVXPY</strong> — Modellierungssprache für konvexe Optimierung. Sie schreibt das Problem in mathematiknaher Notation, prüft die Konvexität nach den Regeln der Disciplined Convex Programming und reicht es an einen passenden Solver weiter. → <a href="oekosystem.html#sec:oekosystem-die-werkzeuge-im-vergleich">Abschnitt 3.4</a></p>
|
||||
</div>
|
||||
<h2 id="d">D</h2>
|
||||
<div id="gloss:data-snooping">
|
||||
<p><strong>Data Snooping</strong> — Wiederholtes Ausprobieren von Strategien auf denselben Daten, bis eine gut aussieht. Der Fund ist dann eine Eigenschaft der Stichprobe, nicht des Marktes — gefährlicher als ein Programmierfehler, weil das Ergebnis plausibel wirkt. → <a href="handelsmaschine.html#sec:handelsmaschine-die-fuenf-selbsttaeuschungen-des-backtestens">Abschnitt 21.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:dcp-disciplined-convex-programming">
|
||||
<p><strong>DCP (Disciplined Convex Programming)</strong> — Regelwerk von CVXPY, das jede Variable als konkav, konvex oder affin ausweist und aus der Kombination der Bausteine die Konkavität/Konvexität der Zielfunktion und der Nebenbedingungen erschließt. <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a> erklärt es; ein <code>DCPError</code> meldet eine Verletzung. → <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a></p>
|
||||
</div>
|
||||
<div id="gloss:dcperror">
|
||||
<p><strong>DCPError</strong> — Fehlermeldung von CVXPY, wenn ein Ausdruck die Regeln der <em>Disciplined Convex Programming</em> verletzt. Sie besagt nicht, dass das Problem unlösbar ist, sondern dass CVXPY die Konvexität nicht nachweisen kann — meist hilft eine äquivalente Umformung. → <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></p>
|
||||
</div>
|
||||
<div id="gloss:deletion-filter">
|
||||
<p><strong>Deletion Filter</strong> — Verfahren zur Eingrenzung von Unlösbarkeit. Es fragt nicht „ist <em>diese</em> Bedingung schuld?“, sondern „wird <em>diese</em> Bedingung für den Widerspruch überhaupt gebraucht?“, und findet dadurch auch dann eine minimale unlösbare Teilmenge, wenn sich mehrere Widersprüche überlagern. → <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></p>
|
||||
</div>
|
||||
<div id="gloss:diskrete-rendite">
|
||||
<p><strong>Diskrete Rendite</strong> — Einfache Rendite <span class="math inline">(P_t - P_{t-1})/P_{t-1}</span>. Sie ist <strong>über Titel</strong> additiv und deshalb die richtige Wahl für Portfoliogewichte — anders als die logarithmische Rendite, die über die Zeit additiv ist. → <a href="finanzdaten.html#sec:finanzdaten-diskrete-und-logarithmische-renditen">Abschnitt 18.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:diversifikation">
|
||||
<p><strong>Diversifikation</strong> — Risikoreduktion durch Verteilung auf Titel, deren Renditen nicht vollständig gleichlaufen. Der Effekt steckt vollständig in den Kovarianzen: Bei Korrelation 1 verschwindet er, bei negativer Korrelation ist er am größten. → <a href="markowitz.html#sec:markowitz-warum-diversifikation-funktioniert">Abschnitt 19.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:dto-data-transfer-object">
|
||||
<p><strong>DTO (Data Transfer Object)</strong> — Schlichtes Objekt, das nur Daten transportiert und keine Logik enthält. Im Buch trägt die <code>Loesung</code>-Klasse in <code>or_kern.py</code> das Ergebnis eines Solverlaufs so aus der Rechenschicht heraus. → <a href="oekosystem.html#sec:oekosystem-ein-system-vier-programmieransaetze">Abschnitt 3.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:dual-simplex">
|
||||
<p><strong>Dual Simplex</strong> — Variante des Simplex-Verfahrens, die eine dual zulässige Basis beibehält und die primale Zulässigkeit herstellt. Das Verfahren der Wahl beim Warm-Start, etwa in jedem Knoten eines Branch-and-Bound-Baums. → <a href="oekosystem.html#sec:oekosystem-die-zwei-schichten-architektur">Abschnitt 3.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:duales-problem">
|
||||
<p><strong>Duales Problem</strong> — Das jedem Optimierungsproblem zugeordnete Gegenstück, dessen Variablen die Nebenbedingungen des Originals bepreisen. Seine Optimalwerte sind die Schattenpreise; im Optimum stimmen beide Zielfunktionswerte überein. → <a href="lp.html#sec:lp-dualitaet-und-schattenpreise">Abschnitt 5.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:dualitaetstheorie">
|
||||
<p><strong>Dualitätstheorie</strong> — Theorie des Zusammenhangs zwischen einem Optimierungsproblem und seinem Dualproblem. Der schwache Dualitätssatz liefert stets eine Schranke, der starke besagt, dass bei linearen Programmen beide Optima zusammenfallen. → <a href="lp.html#sec:lp-dualitaet-und-schattenpreise">Abschnitt 5.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:dynamische-programmierung-dp">
|
||||
<p><strong>Dynamische Programmierung (DP)</strong> — Lösungsprinzip für mehrstufige Entscheidungen: Das Problem wird in Zustände und Stufen zerlegt und rückwärts gelöst, wobei jeder Zustand nur einmal bewertet wird. Voraussetzung ist das Optimalitätsprinzip. → <a href="dynamische-programmierung.html#sec:dynamische-programmierung-das-bellmansche-optimalitaetsprinzip">Abschnitt 13.3</a></p>
|
||||
</div>
|
||||
<h2 id="e">E</h2>
|
||||
<div id="gloss:ecke-extrempunkt">
|
||||
<p><strong>Ecke (Extrempunkt)</strong> — Punkt des zulässigen Bereichs, der sich nicht als echte Mischung zweier anderer zulässiger Punkte schreiben lässt. Nach dem Fundamentalsatz der linearen Optimierung liegt in einer Ecke stets ein Optimum — deshalb sucht der Simplex nur dort. → <a href="fundament.html#sec:fundament-der-zulaessige-loesungsraum-und-das-polyeder">Abschnitt 2.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:effizienzgrenze-efficient-frontier">
|
||||
<p><strong>Effizienzgrenze (Efficient Frontier)</strong> — Kurve aller Portfolios, die zu gegebenem Risiko die höchste erwartete Rendite liefern. Portfolios darunter sind dominiert, Portfolios darüber unerreichbar. → <a href="markowitz.html#sec:markowitz-das-mean-variance-modell">Abschnitt 19.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:entartung">
|
||||
<p><strong>Entartung</strong> — Zustand, in dem mehr Nebenbedingungen aktiv sind, als Variablen frei bleiben. Der Simplex kann dann Basiswechsel ohne Zielwertverbesserung durchführen, und die Schattenpreise sind nicht mehr eindeutig — zwei Solver dürfen verschiedene, gleichermaßen korrekte Dualwerte melden. → <a href="lp.html#sec:lp-entartung">Abschnitt 5.9</a></p>
|
||||
</div>
|
||||
<div id="gloss:entscheidungsvariable">
|
||||
<p><strong>Entscheidungsvariable</strong> — Die vom Solver frei wählbare Größe eines Modells. Ihr Wertebereich — kontinuierlich, ganzzahlig oder binär — bestimmt die Problemklasse und damit den Lösungsaufwand. → <a href="einfuehrung.html#sec:einfuehrung-die-vier-universellen-bausteine-jedes-or">Abschnitt 1.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:entscheidungsvektor">
|
||||
<p><strong>Entscheidungsvektor</strong> — Zusammenfassung aller Entscheidungsvariablen zu einem Vektor <span class="math inline">\mathbf{x}</span>. Erst diese Schreibweise macht die kompakte Matrixform eines Modells möglich. → <a href="fundament.html#sec:fundament-warum-ueberhaupt-vektoren-und-matrizen">Abschnitt 2.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:entweder-oder-bedingung">
|
||||
<p><strong>Entweder-Oder-Bedingung</strong> — Modellierungsmuster für sich ausschließende Alternativen: Genau eine von mehreren Bedingungen soll gelten. Umgesetzt über Binärvariablen mit Summe 1 und Big-M-Kopplung an die jeweilige Bedingung. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:error-maximizer-effekt">
|
||||
<p><strong>Error-Maximizer-Effekt</strong> — Eigenschaft der Mean-Variance-Optimierung, Schätzfehler zu verstärken statt auszugleichen. Der Optimierer sucht gezielt die Richtungen mit der niedrigsten geschätzten Varianz — und das sind genau jene, deren Varianz am stärksten unterschätzt wurde. → <a href="finanzdaten.html#sec:finanzdaten-das-schaetzfehler-problem">Abschnitt 18.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:evpi-expected-value-of-perfect-information">
|
||||
<p><strong>EVPI (Expected Value of Perfect Information)</strong> — Differenz zwischen den erwarteten Kosten unter Unsicherheit und den Kosten bei perfektem Wissen. Obergrenze für den Wert jeder Prognoseverbesserung: Keine noch so gute Vorhersage kann mehr einbringen. → <a href="unsicherheit.html#sec:unsicherheit-zweistufige-stochastische-programmierung">Abschnitt 12.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:exklusiv-oder">
|
||||
<p><strong>Exklusiv-Oder</strong> — Modellierungsmuster für „genau eine von zwei Optionen“: <span class="math inline">y_A + y_B = 1</span>. Die Abgrenzung zum einfachen Oder (<span class="math inline">y_A + y_B \ge 1</span>) ist in der Praxis eine häufige Fehlerquelle. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:expected-shortfall">
|
||||
<p><strong>Expected Shortfall</strong> — Anderer Name für den Conditional Value at Risk; in der Bankenregulierung die gebräuchliche Bezeichnung. Beide meinen den erwarteten Verlust jenseits des VaR-Quantils. → <a href="cvar.html#sec:cvar-value-at-risk-und-conditional-value">Abschnitt 20.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:explainable-or">
|
||||
<p><strong>Explainable OR</strong> — Nachvollziehbarmachung von Solver-Ergebnissen über Schattenpreise, aktive Restriktionen, Constraint-Trace und Kostenzerlegung. Das Gegenstück zu Explainable AI für Optimierungsmodelle. → <a href="praxisfallen.html#sec:praxisfallen-die-fuenf-typischen-praxisfallen">Abschnitt 22.3</a></p>
|
||||
</div>
|
||||
<h2 id="f">F</h2>
|
||||
<div id="gloss:fallback-strategie">
|
||||
<p><strong>Fallback-Strategie</strong> — Festgelegtes Vorgehen für den Fall, dass der Solver kein Ergebnis liefert: letzter gültiger Plan, regelbasierte Notlösung, Alarm. Niemals: nichts. → <a href="praxisfallen.html#sec:praxisfallen-architektur-einer-produktionsreifen-or-plattform">Abschnitt 22.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:falsche-dualwerte">
|
||||
<p><strong>Falsche Dualwerte</strong> — Fehlerbild, bei dem Schattenpreise unplausibel wirken. Zwei Ursachen dominieren: Entartung macht sie mehrdeutig, und ganzzahlige Modelle haben streng genommen gar keine Dualwerte — was ein MILP-Solver zurückgibt, gehört zur Relaxation des letzten Knotens. → <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></p>
|
||||
</div>
|
||||
<div id="gloss:fat-tails">
|
||||
<p><strong>Fat Tails</strong> — Verteilungsränder, die dicker auslaufen als bei der Normalverteilung. Extremereignisse sind dann deutlich häufiger als das Normalmodell vorhersagt — der Grund, warum varianzbasierte Risikomaße das Verlustrisiko unterschätzen. → <a href="cvar.html#sec:cvar-die-zwei-schwaechen-des-markowitz-modells">Abschnitt 20.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:fluch-der-dimensionalitaet">
|
||||
<p><strong>Fluch der Dimensionalität</strong> — Exponentielles Wachstum des Zustandsraums mit jeder zusätzlichen Zustandsdimension. Es begrenzt die dynamische Programmierung und motiviert näherungsweise Verfahren. → <a href="dynamische-programmierung.html#sec:dynamische-programmierung-der-fluch-der-dimensionalitaet">Abschnitt 13.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:fluch-des-durchschnitts-flaw-of-averages">
|
||||
<p><strong>Fluch des Durchschnitts (Flaw of Averages)</strong> — Systematischer Fehler beim Planen mit Erwartungswerten statt mit Verteilungen. Das Ergebnis der Durchschnittsrechnung ist im Allgemeinen nicht der Durchschnitt der Ergebnisse; formal folgt das aus der Jensenschen Ungleichung. → <a href="unsicherheit.html#sec:unsicherheit-der-fluch-des-durchschnitts">Abschnitt 12.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:flusserhaltung">
|
||||
<p><strong>Flusserhaltung</strong> — Bedingung, dass an jedem Knoten Abfluss minus Zufluss dem Saldo des Knotens entspricht — das Kirchhoff-Gesetz der Netzwerkoptimierung. Summieren sich die Salden nicht zu null, ist das Problem grundsätzlich unlösbar. → <a href="graphen.html#sec:graphen-graphen-als-modellsprache">Abschnitt 8.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:fundamentalsatz-der-linearen-optimierung">
|
||||
<p><strong>Fundamentalsatz der linearen Optimierung</strong> — Das Optimum eines lösbaren linearen Programms wird stets in mindestens einer Ecke des zulässigen Polyeders angenommen. Die Rechtfertigung dafür, nur endlich viele Ecken statt unendlich vieler Punkte zu prüfen. → <a href="fundament.html#sec:fundament-der-zulaessige-loesungsraum-und-das-polyeder">Abschnitt 2.4</a></p>
|
||||
</div>
|
||||
<h2 id="g">G</h2>
|
||||
<div id="gloss:gemischt-ganzzahlige-optimierung-milp">
|
||||
<p><strong>Gemischt-ganzzahlige Optimierung (MILP)</strong> — <em>Mixed-Integer Linear Programming</em> — lineares Modell mit mindestens einer ganzzahligen oder binären Variablen. Die Ganzzahligkeit macht das Problem NP-schwer; gelöst wird es mit Branch-and-Cut. → <a href="milp.html#sec:milp-warum-runden-fundamental-scheitert">Abschnitt 6.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:genetischer-algorithmus">
|
||||
<p><strong>Genetischer Algorithmus</strong> — Metaheuristik, die eine Population von Lösungen durch Selektion, Rekombination und Mutation weiterentwickelt. Sie gibt keine Optimalitätsgarantie, kommt dafür mit Zielfunktionen zurecht, die weder linear noch differenzierbar sind. → <a href="metaheuristiken.html#sec:metaheuristiken-abgrenzung">Abschnitt 9.8</a></p>
|
||||
</div>
|
||||
<div id="gloss:gestaffelte-preise">
|
||||
<p><strong>Gestaffelte Preise</strong> — Modellierungsmuster für Mengenrabatte und Tarifstufen. Die Menge wird in Segmente zerlegt, jedes mit eigenem Preis; Binärvariablen erzwingen, dass ein Segment erst genutzt wird, wenn das vorhergehende ausgeschöpft ist. Ohne diese Reihenfolgebedingung sucht sich der Solver einfach das billigste Segment heraus. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:gil-global-interpreter-lock">
|
||||
<p><strong>GIL (Global Interpreter Lock)</strong> — Sperre des CPython-Interpreters, die verhindert, dass zwei Threads gleichzeitig Python-Code ausführen. Sie ist der Grund, warum echte Parallelität in Python über Prozesse statt Threads läuft — Solver umgehen sie, weil sie in C++ rechnen. → <a href="notation.html">Notation und Abkürzungen</a></p>
|
||||
</div>
|
||||
<div id="gloss:gini-koeffizient">
|
||||
<p><strong>Gini-Koeffizient</strong> — Maß für die Ungleichverteilung einer Größe zwischen 0 (alle gleich) und 1 (einer bekommt alles). Im Buch als Fairnesskennzahl für Wunscherfüllungsquoten verwendet. → <a href="projektwerkstatt.html">Projektwerkstatt</a></p>
|
||||
</div>
|
||||
<div id="gloss:gleitendes-fenster">
|
||||
<p><strong>Gleitendes Fenster</strong> — Auswertung, bei der ein Zeitfenster fester Länge über die Daten geschoben wird. Grundlage rollierender Schätzungen und des Walk-Forward-Backtests. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:global-minimum-variance-portfolio-gmv">
|
||||
<p><strong>Global Minimum Variance Portfolio (GMV)</strong> — Portfolio kleinstmöglicher Varianz. Es benötigt <strong>keine Renditeprognose</strong> und ist deshalb deutlich robuster gegen Schätzfehler als das renditemaximierende Mean-Variance-Portfolio. → <a href="markowitz.html#sec:markowitz-das-mean-variance-modell">Abschnitt 19.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:globale-constraints">
|
||||
<p><strong>Globale Constraints</strong> — Vorgefertigte Bausteine wie <code>AllDifferent</code>, <code>NoOverlap</code> oder <code>Cumulative</code>, die häufige Strukturen kompakt ausdrücken. Ihr eigentlicher Wert sind die spezialisierten Propagatoren, die weit mehr Werte ausschließen als die gleichwertige Menge einzelner Ungleichungen. → <a href="cpsat.html#sec:cpsat-globale-constraints-die-bausteine-von-cp">Abschnitt 7.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:globales-minimum">
|
||||
<p><strong>Globales Minimum</strong> — Der kleinste Zielfunktionswert im gesamten zulässigen Bereich. Bei konvexen Problemen ist jedes lokale Minimum zugleich global — der Grund, warum Konvexität die Grenze zwischen leicht und schwer markiert. → <a href="fundament.html#sec:fundament-konvexitaet-die-grenze-zwischen-leicht-und">Abschnitt 2.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:glop">
|
||||
<p><strong>GLOP</strong> — <em>Google Linear Optimization Package</em> — der LP-Solver in OR-Tools. Er löst rein kontinuierliche Probleme; sobald Ganzzahligkeit ins Spiel kommt, übernimmt CP-SAT oder ein MILP-Backend. → <a href="notation.html">Notation und Abkürzungen</a></p>
|
||||
</div>
|
||||
<div id="gloss:goldene-regel-des-backtestens">
|
||||
<p><strong>Goldene Regel des Backtestens</strong> — Zum Zeitpunkt <span class="math inline">t</span> darf nur Information verwendet werden, die zu <span class="math inline">t</span> vorlag. Der Selbsttest mit absichtlich manipulierter Zukunft prüft das automatisch: Wird der Backtest dadurch besser, liegt ein Lookahead-Bias vor. → <a href="handelsmaschine.html#sec:handelsmaschine-zusammenfassung">Abschnitt 21.12</a></p>
|
||||
</div>
|
||||
<div id="gloss:gradient">
|
||||
<p><strong>Gradient</strong> — Vektor der partiellen Ableitungen einer Funktion; er zeigt in Richtung des steilsten Anstiegs. Gradientenbasierte Verfahren wie SLSQP nutzen ihn, um sich schrittweise an ein Optimum heranzutasten. → <a href="qp-nlp.html#sec:qp-nlp-lernziele">Abschnitt 11.2</a></p>
|
||||
</div>
|
||||
<div id="gloss:graphen">
|
||||
<p><strong>Graphen</strong> — Mathematische Struktur aus Knoten und Kanten; das Modellierungsmittel für Netzwerke, Touren und Flüsse. <a href="graphen.html#kap-graphen">Kapitel 8</a> behandelt Min-Cost-Flow, Matching und das Vehicle Routing Problem als Graphanwendungen. → <a href="graphen.html#kap-graphen">Kapitel 8</a></p>
|
||||
</div>
|
||||
<div id="gloss:gurobi">
|
||||
<p><strong>Gurobi</strong> — Kommerzieller Hochleistungssolver für LP, MILP und QP. Im Buch nicht vorausgesetzt, aber als Referenzpunkt genannt: Über die Modellierungsschicht lässt er sich meist durch Ändern eines einzigen Arguments einsetzen. → <a href="milp.html#sec:milp-branch-and-bound">Abschnitt 6.4</a></p>
|
||||
</div>
|
||||
<h2 id="h">H</h2>
|
||||
<div id="gloss:herfindahl-index">
|
||||
<p><strong>Herfindahl-Index</strong> — Summe der quadrierten Anteile; Maß für Konzentration. Sein Kehrwert ist die <em>effektive Titelzahl</em> und beantwortet, auf wie viele gleich große Positionen ein Portfolio praktisch verteilt ist. → <a href="projektwerkstatt.html">Projektwerkstatt</a></p>
|
||||
</div>
|
||||
<div id="gloss:hierarchische-relaxation">
|
||||
<p><strong>Hierarchische Relaxation</strong> — Gegenmittel gegen Unlösbarkeit im Betrieb: Jede harte Bedingung, die im Notfall gebrochen werden darf, erhält eine teure Schlupfvariable. Der Solver liefert dann immer einen Plan und zeigt zugleich präzise, wo es klemmt. → <a href="praxisfallen.html#sec:praxisfallen-die-fuenf-typischen-praxisfallen">Abschnitt 22.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:highs">
|
||||
<p><strong>HiGHS</strong> — Offener Hochleistungssolver für LP, MILP und QP. Backend von <code>scipy.optimize.linprog</code> und CVXPY, direkt ansprechbar über <code>highspy</code>. → <a href="oekosystem.html#sec:oekosystem-die-werkzeuge-im-vergleich">Abschnitt 3.4</a></p>
|
||||
</div>
|
||||
<h2 id="i">I</h2>
|
||||
<div id="gloss:iis-irreducible-infeasible-subset">
|
||||
<p><strong>IIS (Irreducible Infeasible Subset)</strong> — Minimale Menge von Nebenbedingungen, die zusammen unlösbar sind, deren echte Teilmengen aber alle lösbar wären. Das präziseste Ergebnis, das eine Unlösbarkeitsdiagnose liefern kann. → <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></p>
|
||||
</div>
|
||||
<div id="gloss:implikation">
|
||||
<p><strong>Implikation</strong> — Modellierungsmuster für „wenn A, dann B“: <span class="math inline">y_B \ge y_A</span>. Die Umkehrung gilt dabei ausdrücklich nicht — <span class="math inline">B</span> darf auch ohne <span class="math inline">A</span> gesetzt sein. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:importfehler-zwischen-ortools-und-highspy">
|
||||
<p><strong>Importfehler zwischen ortools und highspy</strong> — Absturz beim Import beider Bibliotheken im selben Prozess: Sie bringen je eine eigene HiGHS-Kopie mit, deren C++-Symbole kollidieren. Abhilfe ist die Trennung in getrennte Prozesse — CVXPY zieht ein installiertes <code>highspy</code> dabei ungefragt mit hinein. → <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></p>
|
||||
</div>
|
||||
<div id="gloss:infeasibility">
|
||||
<p><strong>Infeasibility</strong> — Zustand eines Modells ohne jede zulässige Lösung. Im Betrieb über Schlupfvariablen mit hohem Strafgewicht aufzufangen, in der Diagnose über den Deletion Filter einzugrenzen. → <a href="praxisfallen.html#sec:praxisfallen-die-fuenf-typischen-praxisfallen">Abschnitt 22.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:instabile-loesung">
|
||||
<p><strong>Instabile Lösung</strong> — Fehlerbild, bei dem winzige Datenänderungen die Lösung völlig umwerfen. Meist eine Folge schlechter Konditionierung; die Konditionszahl zeigt es an, die Ruiz-Equilibrierung behebt es. → <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></p>
|
||||
</div>
|
||||
<div id="gloss:interior-point-verfahren">
|
||||
<p><strong>Interior-Point-Verfahren</strong> — Lösungsverfahren, das sich durch das Innere des zulässigen Bereichs zum Optimum bewegt, statt Ecken abzulaufen. Bei sehr großen Modellen oft schneller als der Simplex, liefert dafür keine Basislösung und damit weniger brauchbare Sensitivitätsinformationen. → <a href="oekosystem.html#sec:oekosystem-die-zwei-schichten-architektur">Abschnitt 3.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:intervallvariable">
|
||||
<p><strong>Intervallvariable</strong> — Variable mit Start, Dauer und Ende, die in CP-SAT eine Aktivität beschreibt. Sie ist die Voraussetzung für Überschneidungsverbote und Ressourcenprofile. → <a href="cpsat.html#sec:cpsat-globale-constraints-die-bausteine-von-cp">Abschnitt 7.4</a></p>
|
||||
</div>
|
||||
<h2 id="j">J</h2>
|
||||
<div id="gloss:jensensche-ungleichung">
|
||||
<p><strong>Jensensche Ungleichung</strong> — Für konvexe Funktionen gilt <span class="math inline">\mathbb{E}[f(X)] \ge f(\mathbb{E}[X])</span>. Die formale Grundlage des Fluchs des Durchschnitts: Mit Mittelwerten zu rechnen unterschätzt systematisch die erwarteten Kosten. → <a href="unsicherheit.html#sec:unsicherheit-der-fluch-des-durchschnitts">Abschnitt 12.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:job-shop-scheduling">
|
||||
<p><strong>Job-Shop-Scheduling</strong> — Ablaufplanung, bei der mehrere Aufträge in je eigener Reihenfolge über dieselben Maschinen laufen. Klassisches Anwendungsfeld von CP-SAT; Zielgröße ist meist der Makespan. → <a href="cpsat.html#sec:cpsat-intervallvariablen-job-shop-scheduling">Abschnitt 7.6</a></p>
|
||||
</div>
|
||||
<h2 id="k">K</h2>
|
||||
<div id="gloss:kanonische-standardform">
|
||||
<p><strong>Kanonische Standardform</strong> — Einheitliche Matrixschreibweise eines LP als <span class="math inline">\min \mathbf{c}^\top\mathbf{x}</span> unter den Bedingungen <span class="math inline">\mathbf{A}\mathbf{x} \le \mathbf{b}</span> und <span class="math inline">\mathbf{x} \ge 0</span>. Jedes lineare Modell lässt sich darauf bringen — Solver erwarten genau diese Form. → <a href="fundament.html#sec:fundament-warum-ueberhaupt-vektoren-und-matrizen">Abschnitt 2.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:kapazitaetsvektor">
|
||||
<p><strong>Kapazitätsvektor</strong> — Der Vektor <span class="math inline">\mathbf{b}</span> der rechten Seiten in <span class="math inline">\mathbf{A}\mathbf{x} \le \mathbf{b}</span>. Seine Einträge sind die verfügbaren Ressourcen, und die zugehörigen Schattenpreise sagen, was eine zusätzliche Einheit davon wert wäre. → <a href="fundament.html#sec:fundament-warum-ueberhaupt-vektoren-und-matrizen">Abschnitt 2.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:kardinalitaetsbeschraenkung">
|
||||
<p><strong>Kardinalitätsbeschränkung</strong> — Obergrenze für die Anzahl gleichzeitig aktiver Entscheidungen, formuliert über die Summe der zugehörigen Binärvariablen. Typisch für „höchstens zehn Titel im Depot“. → <a href="milp.html#sec:milp-modellierungstricks-big-m-und-logische-bedingungen">Abschnitt 6.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:karush-kuhn-tucker-bedingungen-kkt">
|
||||
<p><strong>Karush-Kuhn-Tucker-Bedingungen (KKT)</strong> — Notwendige Optimalitätsbedingungen restringierter Probleme: Stationarität, primale und duale Zulässigkeit sowie komplementärer Schlupf. Bei konvexen Problemen sind sie zugleich hinreichend und damit ein vollständiger Optimalitätsnachweis. → <a href="qp-nlp.html#sec:qp-nlp-die-karush-kuhn-tucker-bedingungen">Abschnitt 11.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:kohaerentes-risikomass">
|
||||
<p><strong>Kohärentes Risikomaß</strong> — Risikomaß mit den vier Eigenschaften Monotonie, Subadditivität, positive Homogenität und Translationsinvarianz. Der CVaR erfüllt sie, der VaR nicht — dessen Verletzung der Subadditivität kann Diversifikation rechnerisch bestrafen. → <a href="cvar.html#sec:cvar-value-at-risk-und-conditional-value">Abschnitt 20.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:kombinatorische-explosion">
|
||||
<p><strong>Kombinatorische Explosion</strong> — Überproportionales Wachstum der Zahl möglicher Lösungen mit der Problemgröße. Sie ist der Grund, warum systematisches Ausprobieren schon bei kleinen Instanzen aussichtslos wird. → <a href="einfuehrung.html#sec:einfuehrung-warum-ausprobieren-scheitert-mit-eigener-rechnung">Abschnitt 1.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:komplementaerer-schlupf">
|
||||
<p><strong>Komplementärer Schlupf</strong> — Bedingung <span class="math inline">s_i \cdot y_i = 0</span>: Eine Nebenbedingung ist entweder aktiv (kein Schlupf) oder ihr Schattenpreis verschwindet. Wirtschaftlich gelesen: Nur knappe Ressourcen haben einen Preis. → <a href="lp.html#sec:lp-dualitaet-und-schattenpreise">Abschnitt 5.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:konditionszahl">
|
||||
<p><strong>Konditionszahl</strong> — Verhältnis von größtem zu kleinstem Singulärwert einer Matrix. Sie misst, wie stark kleine Datenänderungen die Lösung verzerren können; hohe Werte kündigen numerische Probleme an, lange bevor der Solver etwas meldet. → <a href="finanzdaten.html#sec:finanzdaten-praxis-datenpipeline-mit-korrekter-spaltenreihenfolge">Abschnitt 18.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:konische-optimierung">
|
||||
<p><strong>Konische Optimierung</strong> — Erweiterung der linearen Optimierung auf Kegelbedingungen. Der Second-Order Cone (SOCP) erfasst Normen und damit Risikoschranken, die semidefinite Variante (SDP) Bedingungen an Matrizen. Beide bleiben konvex und damit global lösbar. → <a href="unsicherheit.html#sec:unsicherheit-chance-constraints">Abschnitt 12.7</a></p>
|
||||
</div>
|
||||
<div id="gloss:konvexitaet">
|
||||
<p><strong>Konvexität</strong> — Eigenschaft, bei der jede Verbindungsstrecke zweier Punkte innerhalb der Menge bzw. unterhalb des Funktionsgraphen liegt. Bei konvexen Problemen ist jedes lokale Optimum global — die eigentliche Grenze zwischen leicht und schwer lösbar. → <a href="fundament.html#sec:fundament-konvexitaet-die-grenze-zwischen-leicht-und">Abschnitt 2.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:korn-transformation">
|
||||
<p><strong>Korn-Transformation</strong> — Umformung der nicht-konvexen Sharpe-Ratio-Maximierung in ein konvexes quadratisches Programm durch Homogenisierung. Sie macht aus einem Bruch eine Skalierung und damit aus einem unlösbaren ein lösbares Problem. → <a href="markowitz.html#sec:markowitz-das-mean-variance-modell">Abschnitt 19.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:kostenzerlegung">
|
||||
<p><strong>Kostenzerlegung</strong> — Aufschlüsselung eines Zielfunktionswerts in seine Bestandteile — etwa Alpha-Ertrag, Risikoprämie und Transaktionskostenstrafe. Sie beantwortet die Frage „woraus besteht dieses Ergebnis?“ und ist ein Baustein der Erklärbarkeit. → <a href="praxisfallen.html#sec:praxisfallen-die-fuenf-typischen-praxisfallen">Abschnitt 22.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:kovarianzmatrix">
|
||||
<p><strong>Kovarianzmatrix</strong> — Matrix der paarweisen Kovarianzen aller Titel. Sie steuert im Markowitz-Modell den Diversifikationseffekt und ist bei vielen Titeln und wenigen Beobachtungen notorisch schlecht konditioniert. → <a href="finanzdaten.html#sec:finanzdaten-das-schaetzfehler-problem">Abschnitt 18.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:kumulative-ressource">
|
||||
<p><strong>Kumulative Ressource</strong> — Ressource mit begrenzter Kapazität, die mehrere Aktivitäten gleichzeitig nutzen können — etwa vier Monteure. In CP-SAT über <code>AddCumulative</code> ausgedrückt. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<h2 id="l">L</h2>
|
||||
<div id="gloss:lagrange-funktion">
|
||||
<p><strong>Lagrange-Funktion</strong> — Zielfunktion zuzüglich der mit Multiplikatoren gewichteten Nebenbedingungen. Ihre Stationaritätsbedingung ist die erste der KKT-Bedingungen und die Brücke zwischen restringierter und freier Optimierung. → <a href="qp-nlp.html#sec:qp-nlp-die-karush-kuhn-tucker-bedingungen">Abschnitt 11.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:lagrange-multiplikator">
|
||||
<p><strong>Lagrange-Multiplikator</strong> — Gewicht, mit dem eine Nebenbedingung in die Lagrange-Funktion eingeht. Sein Optimalwert ist der Schattenpreis der Bedingung. → <a href="qp-nlp.html#sec:qp-nlp-die-karush-kuhn-tucker-bedingungen">Abschnitt 11.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:large-neighborhood-search-lns">
|
||||
<p><strong>Large Neighborhood Search (LNS)</strong> — Metaheuristik, die wiederholt einen größeren Teil der aktuellen Lösung zerstört und exakt neu aufbaut. Sie verbindet die Reichweite heuristischer Sprünge mit der Genauigkeit eines Solvers auf dem Teilproblem. → <a href="metaheuristiken.html#sec:metaheuristiken-lns">Abschnitt 9.7</a></p>
|
||||
</div>
|
||||
<div id="gloss:laufzeitexplosion">
|
||||
<p><strong>Laufzeitexplosion</strong> — Fehlerbild, bei dem ein Modell nach einer kleinen Erweiterung nicht mehr fertig rechnet. Häufige Ursachen sind ein zu großes <span class="math inline">M</span>, fehlende Symmetriebrechung und eine schwache Relaxation. → <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></p>
|
||||
</div>
|
||||
<div id="gloss:ledoit-wolf-shrinkage">
|
||||
<p><strong>Ledoit-Wolf-Shrinkage</strong> — Schrumpfung der Stichprobenkovarianz in Richtung eines strukturierten Ziels; der optimale Mischungsfaktor wird analytisch bestimmt. <code>scikit-learn</code> verwendet die skalierte Einheitsmatrix als Ziel. → <a href="finanzdaten.html#sec:finanzdaten-ledoit-wolf-shrinkage">Abschnitt 18.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:lexikografische-optimierung">
|
||||
<p><strong>Lexikografische Optimierung</strong> — Mehrzielverfahren mit strenger Rangfolge: Das wichtigste Ziel wird optimiert, sein Wert festgeschrieben, dann das zweitwichtigste — und so fort. Kein Ziel darf zugunsten eines nachrangigen verschlechtert werden. → <a href="mehrziel.html#sec:mehrziel-epsilon">Abschnitt 14.7</a></p>
|
||||
</div>
|
||||
<div id="gloss:lineare-programmierung-lp">
|
||||
<p><strong>Lineare Programmierung (LP)</strong> — <em>Linear Programming</em> — Optimierung einer linearen Zielfunktion unter linearen Nebenbedingungen mit kontinuierlichen Variablen. Die am besten verstandene Problemklasse des Operations Research: in Polynomialzeit lösbar und mit vollständiger Dualitätstheorie. → <a href="lp.html#sec:lp-die-standardform-und-schlupfvariablen">Abschnitt 5.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:linopy">
|
||||
<p><strong>Linopy</strong> — Modellierungsbibliothek, die Optimierungsmodelle über beschriftete Achsen aufbaut (<code>xarray</code>-Stil). Ihre Stärke sind große, regelmäßig indizierte Modelle wie Energiesystemrechnungen. → <a href="oekosystem.html#sec:oekosystem-pyomo-linopy">Abschnitt 3.7</a></p>
|
||||
</div>
|
||||
<div id="gloss:linprog">
|
||||
<p><strong>linprog</strong> — Funktion <code>scipy.optimize.linprog</code> zum Lösen linearer Programme. Sie erwartet das Modell in kanonischer Standardform als Matrizen und benutzt seit SciPy 1.11 standardmäßig HiGHS als Backend. → <a href="lp.html#sec:lp-die-vorzeichenfalle-bei-schattenpreisen">Abschnitt 5.7</a></p>
|
||||
</div>
|
||||
<div id="gloss:logarithmische-rendite">
|
||||
<p><strong>Logarithmische Rendite</strong> — Stetige Rendite als Logarithmus des Preisverhältnisses. Sie ist <strong>über die Zeit</strong> additiv und deshalb die richtige Wahl für Zeitreihenaggregation — nicht aber für die Gewichtung im Portfolio. → <a href="finanzdaten.html#sec:finanzdaten-diskrete-und-logarithmische-renditen">Abschnitt 18.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:lokales-minimum">
|
||||
<p><strong>Lokales Minimum</strong> — Punkt, der in seiner Umgebung optimal ist, global aber übertroffen werden kann. Bei nichtkonvexen Problemen liefern gradientenbasierte Verfahren nur solche Punkte; ein Multistart macht das Problem sichtbar. → <a href="fundament.html#sec:fundament-konvexitaet-die-grenze-zwischen-leicht-und">Abschnitt 2.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:lookahead-bias">
|
||||
<p><strong>Lookahead-Bias</strong> — Fehler, bei dem Informationen in eine Entscheidung einfließen, die zum Entscheidungszeitpunkt noch nicht vorlagen. Die häufigste Ursache für Backtests, die zu gut aussehen, um wahr zu sein. → <a href="handelsmaschine.html#sec:handelsmaschine-die-fuenf-selbsttaeuschungen-des-backtestens">Abschnitt 21.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:lp-relaxation">
|
||||
<p><strong>LP-Relaxation</strong> — Das ganzzahlige Modell ohne die Ganzzahligkeitsforderung. Ihre Lösung ist schnell zu berechnen und liefert eine Schranke: Besser als der Relaxationswert kann die ganzzahlige Lösung nicht werden. Genau darauf beruht das Abschneiden im Branch-and-Bound. → <a href="milp.html#sec:milp-branch-and-bound">Abschnitt 6.4</a></p>
|
||||
</div>
|
||||
<h2 id="m">M</h2>
|
||||
<div id="gloss:makespan">
|
||||
<p><strong>Makespan</strong> — Gesamtdurchlaufzeit eines Ablaufplans: der Zeitpunkt, zu dem die letzte Aktivität endet. Standardzielgröße im Job-Shop-Scheduling. → <a href="cpsat.html#sec:cpsat-intervallvariablen-job-shop-scheduling">Abschnitt 7.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:mape">
|
||||
<p><strong>MAPE</strong> — <em>Mean Absolute Percentage Error</em> — mittlerer absoluter prozentualer Prognosefehler. Beliebt, weil einheitenfrei, aber unbrauchbar bei Werten nahe null. → <a href="prognose.html#sec:prognose-naht">Abschnitt 15.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:marchenko-pastur-gesetz">
|
||||
<p><strong>Marchenko-Pastur-Gesetz</strong> — Ergebnis der Zufallsmatrizentheorie über die Eigenwertverteilung von Stichproben-Kovarianzmatrizen. Es zeigt, dass die kleinsten Eigenwerte systematisch unterschätzt und die größten überschätzt werden — die theoretische Wurzel des Error-Maximizer-Effekts. → <a href="finanzdaten.html#sec:finanzdaten-das-schaetzfehler-problem">Abschnitt 18.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:markowitz-modell-mean-variance">
|
||||
<p><strong>Markowitz-Modell (Mean-Variance)</strong> — Rahmenwerk, das ein Portfolio über das Zusammenspiel von erwarteter Rendite und Kovarianz bewertet. Es begründete die moderne Portfoliotheorie und ist zugleich das Lehrbeispiel für die Empfindlichkeit gegenüber Schätzfehlern. → <a href="markowitz.html#sec:markowitz-das-mean-variance-modell">Abschnitt 19.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:marktauswirkung-market-impact">
|
||||
<p><strong>Marktauswirkung (Market Impact)</strong> — Preisverschlechterung, die eine eigene Order durch ihr Volumen auslöst. Sie wächst überproportional mit der Handelsgeschwindigkeit und ist der Grund, große Orders über die Zeit zu strecken. → <a href="dynamische-programmierung.html#sec:dynamische-programmierung-das-almgren-chriss-problem-optimale-orderausfuehrung">Abschnitt 13.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:matplotlib">
|
||||
<p><strong>Matplotlib</strong> — Standardbibliothek für statische Diagramme in Python. Im Buch erzeugt sie alle Abbildungen der Druckfassung; die interaktiven Fassungen der Website stammen von Plotly. → <a href="oekosystem.html#sec:oekosystem-die-werkzeuge-im-vergleich">Abschnitt 3.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:matrixform">
|
||||
<p><strong>Matrixform</strong> — Kompakte Schreibweise eines Modells über Vektoren und Matrizen statt einzelner Gleichungen. Sie ist nicht nur kürzer, sondern die Form, die Solver tatsächlich entgegennehmen. → <a href="fundament.html#sec:fundament-zusammenfassung">Abschnitt 2.12</a></p>
|
||||
</div>
|
||||
<div id="gloss:matrix-vektor-produkt">
|
||||
<p><strong>Matrix-Vektor-Produkt</strong> — Rechenoperation <span class="math inline">\mathbf{A}\mathbf{x}</span>, die jede Zeile der Matrix mit dem Vektor multipliziert. In der Optimierung berechnet sie den Ressourcenverbrauch aller Nebenbedingungen in einem Schritt. → <a href="fundament.html#sec:fundament-warum-ueberhaupt-vektoren-und-matrizen">Abschnitt 2.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:maximin-fairness">
|
||||
<p><strong>Maximin-Fairness</strong> — Zielsetzung „der am schlechtesten Gestellte soll möglichst gut dastehen“. Modelliert über eine Hilfsvariable <span class="math inline">t</span> mit <span class="math inline">t \le f_i(\mathbf{x})</span> für alle <span class="math inline">i</span> und Maximierung von <span class="math inline">t</span>. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:maximum-drawdown">
|
||||
<p><strong>Maximum Drawdown</strong> — Größter prozentualer Rückgang vom bisherigen Höchststand. Anders als die Volatilität misst er den tatsächlich erlittenen Verlustweg und ist deshalb die Kennzahl, an der Anleger aussteigen. → <a href="handelsmaschine.html#sec:handelsmaschine-die-engine">Abschnitt 21.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:mensch-in-der-schleife">
|
||||
<p><strong>Mensch in der Schleife</strong> — Betriebsprinzip, bei dem der Optimierer <strong>vorschlägt</strong> und ein Mensch <strong>entscheidet</strong> — zumindest in der Einführungsphase. Das baut Vertrauen auf und fängt Modellfehler ab, bevor sie wirksam werden. → <a href="praxisfallen.html#sec:praxisfallen-architektur-einer-produktionsreifen-or-plattform">Abschnitt 22.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:metaheuristik">
|
||||
<p><strong>Metaheuristik</strong> — Übergeordnetes Suchschema wie Simulated Annealing, Tabu-Suche oder genetische Algorithmen, das auf viele Problemtypen anwendbar ist. Es liefert gute Lösungen ohne Optimalitätsbeweis und ist dort angebracht, wo exakte Verfahren an der Größe scheitern. → <a href="metaheuristiken.html#sec:metaheuristiken-aufgabe">Abschnitt 9.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:min-cost-flow-problem">
|
||||
<p><strong>Min-Cost-Flow-Problem</strong> — Kostengünstigster Transport durch ein Netzwerk unter Kapazitäts- und Flusserhaltungsbedingungen. Die Modellmatrix ist total unimodular, weshalb schon die LP-Lösung ganzzahlig ausfällt. → <a href="graphen.html#sec:graphen-graphen-als-modellsprache">Abschnitt 8.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:mindestabnahmemenge">
|
||||
<p><strong>Mindestabnahmemenge</strong> — Bedingung „entweder gar nichts oder mindestens <span class="math inline">m</span>“. Sie ist nicht linear und braucht eine Binärvariable: <span class="math inline">m\,y \le x \le M\,y</span>. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:minlp">
|
||||
<p><strong>MINLP</strong> — <em>Mixed-Integer Nonlinear Programming</em> — Modelle mit ganzzahligen Variablen <strong>und</strong> nichtlinearen Funktionen. Die schwierigste der Standardklassen: Sie vereint die kombinatorische Explosion mit dem Problem lokaler Optima. → <a href="qp-nlp.html#sec:qp-nlp-nichtkonvex">Abschnitt 11.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:mip-gap">
|
||||
<p><strong>MIP-Gap</strong> — Relativer Abstand zwischen der besten gefundenen Lösung und der besten bekannten Schranke. Er beziffert, wie viel im schlechtesten Fall noch fehlt — ein Gap von 2 % heißt: höchstens 2 % besser ist überhaupt möglich. → <a href="praxisfallen.html#sec:praxisfallen-die-fuenf-typischen-praxisfallen">Abschnitt 22.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:miqp">
|
||||
<p><strong>MIQP</strong> — <em>Mixed-Integer Quadratic Programming</em> — quadratische Zielfunktion mit ganzzahligen Variablen. Der Fall, der entsteht, sobald ein Portfoliomodell eine Obergrenze für die Zahl der Titel bekommt. → <a href="notation.html">Notation und Abkürzungen</a></p>
|
||||
</div>
|
||||
<div id="gloss:monte-carlo-simulation">
|
||||
<p><strong>Monte-Carlo-Simulation</strong> — Erzeugung vieler Zufallsszenarien, um Kennzahlen empirisch zu schätzen. Sie <strong>bewertet</strong> eine gegebene Entscheidung, optimiert aber nicht — der Unterschied wird in der Praxis häufig übersehen. → <a href="unsicherheit.html#sec:unsicherheit-monte-carlo-simulation">Abschnitt 12.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:mse">
|
||||
<p><strong>MSE</strong> — <em>Mean Squared Error</em> — mittlerer quadratischer Fehler. Das Standardmaß der Prognosegüte; es bestraft große Abweichungen überproportional und ist nicht dasselbe wie geringe Entscheidungskosten. → <a href="notation.html">Notation und Abkürzungen</a></p>
|
||||
</div>
|
||||
<div id="gloss:mtz-formulierung">
|
||||
<p><strong>MTZ-Formulierung</strong> — Miller-Tucker-Zemlin-Bedingungen, die über Rangvariablen Kurzzyklen ausschließen. Kompakt in der Zahl der Nebenbedingungen, dafür mit schwacher Relaxation — der klassische Zielkonflikt bei Tourenmodellen. → <a href="graphen.html#sec:graphen-das-vehicle-routing-problem-mit-zeitfenstern">Abschnitt 8.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:multi-objective-optimization">
|
||||
<p><strong>Multi-Objective Optimization</strong> — Optimierung mit mehreren, konkurrierenden Zielen. Statt einer besten Lösung gibt es eine Pareto-Front; die Auswahl daraus ist eine Entscheidung, keine Rechnung. → <a href="praxisfallen.html#sec:praxisfallen-weiterfuehrende-literatur-und-roadmap">Abschnitt 22.9</a></p>
|
||||
</div>
|
||||
<h2 id="n">N</h2>
|
||||
<div id="gloss:nebenbedingung-constraint">
|
||||
<p><strong>Nebenbedingung (Constraint)</strong> — Gleichung oder Ungleichung, die zulässige von unzulässigen Lösungen trennt. Harte Bedingungen müssen erfüllt sein, weiche werden über Strafterme lediglich bepreist. → <a href="einfuehrung.html#sec:einfuehrung-die-vier-universellen-bausteine-jedes-or">Abschnitt 1.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:newsvendor-problem">
|
||||
<p><strong>Newsvendor-Problem</strong> — Klassisches Einperiodenmodell: Wie viel bestellt man bei unsicherer Nachfrage, wenn Überbestand und Fehlmenge unterschiedlich teuer sind? Die Lösung ist ein Quantil des Nachfragemodells, nicht ihr Erwartungswert. → <a href="unsicherheit.html#sec:unsicherheit-schnellstart">Abschnitt 12.1</a></p>
|
||||
</div>
|
||||
<div id="gloss:nichtlineare-programmierung-nlp">
|
||||
<p><strong>Nichtlineare Programmierung (NLP)</strong> — <em>Nonlinear Programming</em> — Problemklasse mit nichtlinearer Ziel- oder Nebenbedingungsfunktion. Ohne Konvexität liefern Verfahren wie SLSQP nur lokale Optima. → <a href="qp-nlp.html#sec:qp-nlp-nichtlineare-optimierung-mit-scipy-optimize-minimize">Abschnitt 11.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:nichtueberlappung">
|
||||
<p><strong>Nichtüberlappung</strong> — Bedingung, dass sich Aktivitäten auf derselben Ressource zeitlich nicht überschneiden. In CP-SAT über <code>AddNoOverlap</code> auf Intervallvariablen ausgedrückt. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:np-schwer">
|
||||
<p><strong>NP-schwer</strong> — Komplexitätsklasse von Problemen, für die kein Algorithmus mit polynomialer Laufzeit bekannt ist. Praktisch heißt das: Die Lösungszeit kann mit der Problemgröße explodieren — nicht aber, dass jede Instanz schwer wäre. → <a href="milp.html#sec:milp-branch-and-bound">Abschnitt 6.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:numpy">
|
||||
<p><strong>NumPy</strong> — Grundbibliothek für numerisches Rechnen in Python. Sie liefert das Array, mit dem Vektoren und Matrizen eines Modells überhaupt erst kompakt und schnell aufgebaut werden können. → <a href="oekosystem.html#sec:oekosystem-die-werkzeuge-im-vergleich">Abschnitt 3.4</a></p>
|
||||
</div>
|
||||
<h2 id="o">O</h2>
|
||||
<div id="gloss:operations-research-or">
|
||||
<p><strong>Operations Research (OR)</strong> — Disziplin, die reale Entscheidungsprobleme in mathematische Modelle überführt und mit exakten oder heuristischen Algorithmen löst. Sie beantwortet nicht „was wird geschehen?“, sondern „was sollen wir tun?“. → <a href="einfuehrung.html#sec:einfuehrung-was-ist-operations-research-wirklich">Abschnitt 1.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:optimalitaetsprinzip">
|
||||
<p><strong>Optimalitätsprinzip</strong> — Grundsatz von Bellman: Jede Teilpolitik einer optimalen Politik ist ihrerseits optimal für den erreichten Zustand. Ohne ihn wäre die Rückwärtsinduktion nicht zulässig. → <a href="dynamische-programmierung.html#sec:dynamische-programmierung-das-bellmansche-optimalitaetsprinzip">Abschnitt 13.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:or-tools">
|
||||
<p><strong>OR-Tools</strong> — Optimierungssammlung von Google mit CP-SAT, einer Routing-Bibliothek und Anbindungen an LP/MILP-Solver. Im Buch die erste Wahl für Reihenfolge-, Zuordnungs- und Tourenprobleme. → <a href="einfuehrung.html#sec:einfuehrung-lernziele">Abschnitt 1.2</a></p>
|
||||
</div>
|
||||
<div id="gloss:overfitting">
|
||||
<p><strong>Overfitting</strong> — Anpassung eines Modells an Zufälligkeiten der Trainingsdaten statt an die zugrunde liegende Struktur. Im Backtesting die Regel, nicht die Ausnahme — deshalb der Walk-Forward-Test. → <a href="handelsmaschine.html#sec:handelsmaschine-die-fuenf-selbsttaeuschungen-des-backtestens">Abschnitt 21.6</a></p>
|
||||
</div>
|
||||
<h2 id="p">P</h2>
|
||||
<div id="gloss:pandas">
|
||||
<p><strong>pandas</strong> — Bibliothek für tabellarische Daten mit Zeit- und Beschriftungsindex. Im Buch der übliche Weg von Roh- zu Modelldaten, besonders in den Finanzkapiteln. → <a href="oekosystem.html#sec:oekosystem-die-werkzeuge-im-vergleich">Abschnitt 3.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:parameter">
|
||||
<p><strong>Parameter</strong> — Feststehende Größe eines Modells — Kosten, Kapazitäten, Bedarfe. Parameter werden nicht optimiert, sondern gegeben; ihre Unsicherheit ist der Gegenstand der stochastischen und robusten Optimierung. → <a href="einfuehrung.html#sec:einfuehrung-die-vier-universellen-bausteine-jedes-or">Abschnitt 1.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:pareto-front">
|
||||
<p><strong>Pareto-Front</strong> — Menge aller Lösungen, bei denen kein Ziel verbessert werden kann, ohne ein anderes zu verschlechtern. Sie zeigt den Zielkonflikt als Kurve, statt ihn in einer Gewichtung zu verstecken. → <a href="mehrziel.html#sec:mehrziel-dominanz">Abschnitt 14.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:pivotisierung">
|
||||
<p><strong>Pivotisierung</strong> — Basiswechsel im Simplex-Verfahren: Eine Variable verlässt die Basis, eine andere tritt ein. Jeder Pivotschritt entspricht dem Weiterwandern zur benachbarten Ecke des Polyeders. → <a href="lp.html#sec:lp-der-simplex-algorithmus-schritt-fuer-schritt">Abschnitt 5.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:plotly">
|
||||
<p><strong>Plotly</strong> — Bibliothek für interaktive Diagramme im Browser. Die Website des Buchs bindet damit Gantt-Diagramme, Effizienzlinien und Pareto-Fronten zum Zoomen und Erkunden ein. → <a href="oekosystem.html#sec:oekosystem-die-werkzeuge-im-vergleich">Abschnitt 3.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:polars">
|
||||
<p><strong>Polars</strong> — Schnelle DataFrame-Bibliothek mit spaltenorientiertem Speicher und verzögerter Auswertung. Im Buch als Alternative zu pandas dort erwähnt, wo der Modellaufbau selbst zum Engpass wird. → <a href="oekosystem.html#sec:oekosystem-vektorisierung">Abschnitt 3.8</a></p>
|
||||
</div>
|
||||
<div id="gloss:polyeder">
|
||||
<p><strong>Polyeder</strong> — Schnittmenge endlich vieler Halbräume — die geometrische Gestalt des zulässigen Bereichs eines linearen Programms. Seine Ecken sind die Kandidaten für das Optimum. → <a href="fundament.html#sec:fundament-der-zulaessige-loesungsraum-und-das-polyeder">Abschnitt 2.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:positiv-semi-definit">
|
||||
<p><strong>Positiv (semi-)definit</strong> — Eigenschaft einer symmetrischen Matrix, deren Eigenwerte alle <span class="math inline">> 0</span> (definit) bzw. <span class="math inline">\ge 0</span> (semidefinit) sind. Definit bedeutet streng konvex und eine eindeutige Lösung, semidefinit konvex mit möglicherweise mehreren. → <a href="qp-nlp.html#sec:qp-nlp-das-quadratische-programm-qp">Abschnitt 11.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:praeskriptive-analytik">
|
||||
<p><strong>Präskriptive Analytik</strong> — Analysestufe, die vorschreibt, welche Handlung unter den gegebenen Bedingungen die beste ist. Sie folgt auf die deskriptive (was war?) und die prädiktive Stufe (was wird?). → <a href="einfuehrung.html#sec:einfuehrung-was-ist-operations-research-wirklich">Abschnitt 1.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:predict-then-optimize">
|
||||
<p><strong>Predict-then-Optimize</strong> — Zweistufiges Vorgehen: erst prognostizieren, dann mit der Prognose optimieren. Der Bruch liegt dazwischen — das Prognosemodell minimiert Vorhersagefehler, nicht Entscheidungskosten. → <a href="prognose.html#sec:prognose-naht">Abschnitt 15.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:primales-problem">
|
||||
<p><strong>Primales Problem</strong> — Das ursprünglich formulierte Optimierungsproblem, im Gegensatz zu seinem Dualproblem. Welches von beiden „primal“ heißt, ist Konvention: Das Duale des Dualen ist wieder das Primale. → <a href="lp.html#sec:lp-dualitaet-und-schattenpreise">Abschnitt 5.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:pydantic">
|
||||
<p><strong>pydantic</strong> — Bibliothek zur Validierung von Datenstrukturen anhand von Typannotationen. Im Buch prüft sie die Eingaben des Optimierungsdienstes, bevor ein Modell überhaupt gebaut wird. → <a href="oekosystem.html#sec:oekosystem-die-werkzeuge-im-vergleich">Abschnitt 3.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:pymoo">
|
||||
<p><strong>pymoo</strong> — Bibliothek für mehrkriterielle Optimierung mit evolutionären Verfahren. Sie liefert Pareto-Fronten dort, wo sich die Ziele nicht sinnvoll skalarisieren lassen. → <a href="oekosystem.html#sec:oekosystem-die-werkzeuge-im-vergleich">Abschnitt 3.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:pyomo">
|
||||
<p><strong>Pyomo</strong> — Umfangreiche Modellierungssprache für Optimierung in Python, mit Unterstützung für abstrakte Modelle, viele Solver und nichtlineare Formulierungen. Mächtiger, aber ausführlicher als CVXPY. → <a href="oekosystem.html#sec:oekosystem-pyomo-linopy">Abschnitt 3.7</a></p>
|
||||
</div>
|
||||
<h2 id="q">Q</h2>
|
||||
<div id="gloss:q-learning">
|
||||
<p><strong>Q-Learning</strong> — Verfahren des bestärkenden Lernens, das den Wert von Zustand-Aktion-Paaren aus Erfahrung schätzt, ohne ein Modell der Umgebung zu kennen. Verwandt mit der dynamischen Programmierung, aber lernend statt rechnend. → <a href="dynamische-programmierung.html#sec:dynamische-programmierung-der-fluch-der-dimensionalitaet">Abschnitt 13.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:quadratische-programmierung-qp">
|
||||
<p><strong>Quadratische Programmierung (QP)</strong> — <em>Quadratic Programming</em> — Optimierung einer quadratischen Zielfunktion unter linearen Nebenbedingungen. Bei positiv semidefiniter Matrix konvex und damit zuverlässig global lösbar; die Portfoliooptimierung ist der Standardfall. → <a href="qp-nlp.html#sec:qp-nlp-das-quadratische-programm-qp">Abschnitt 11.3</a></p>
|
||||
</div>
|
||||
<h2 id="r">R</h2>
|
||||
<div id="gloss:rebalancing">
|
||||
<p><strong>Rebalancing</strong> — Periodische Rückführung des Portfolios auf die Zielgewichte. Zu häufig kostet Gebühren, zu selten lässt die Gewichte driften — und die Termine müssen Handelstage sein. → <a href="handelsmaschine.html#sec:handelsmaschine-rebalancing-termine-richtig-bestimmen">Abschnitt 21.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:regime-shift">
|
||||
<p><strong>Regime-Shift</strong> — Strukturbruch in den Daten, nach dem historisch geschätzte Momente ihre Gültigkeit verlieren. Kein Modellfehler, sondern eine Eigenschaft der Welt — abzufangen über kürzere Schätzfenster und robuste Formulierungen. → <a href="praxisfallen.html#sec:praxisfallen-die-fuenf-typischen-praxisfallen">Abschnitt 22.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:reinforcement-learning">
|
||||
<p><strong>Reinforcement Learning</strong> — Lernen einer Entscheidungsstrategie aus Rückmeldungen der Umgebung. Es löst dieselbe Klasse mehrstufiger Probleme wie die dynamische Programmierung, benötigt aber kein explizites Übergangsmodell. → <a href="dynamische-programmierung.html#sec:dynamische-programmierung-der-fluch-der-dimensionalitaet">Abschnitt 13.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:relaxation">
|
||||
<p><strong>Relaxation</strong> — Absichtliches Weglassen einschränkender Forderungen — typischerweise der Ganzzahligkeit —, um eine schnell berechenbare Schranke zu gewinnen. Der Wert der Relaxation begrenzt, wie gut die echte Lösung überhaupt werden kann. → <a href="milp.html#sec:milp-branch-and-bound">Abschnitt 6.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:robuste-optimierung">
|
||||
<p><strong>Robuste Optimierung</strong> — Auslegung auf den ungünstigsten Fall innerhalb einer Unsicherheitsmenge. Sie verlangt keine Wahrscheinlichkeiten, sondern nur eine Angabe darüber, wie weit die Parameter schwanken können. → <a href="unsicherheit.html#sec:unsicherheit-robuste-optimierung-gegen-den-worst-case">Abschnitt 12.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:rockafellar-uryasev-theorem">
|
||||
<p><strong>Rockafellar-Uryasev-Theorem</strong> — Ergebnis, das die CVaR-Minimierung in eine konvexe Hilfsfunktion überführt. Es macht die Optimierung des Tail-Risikos mit gewöhnlichen linearen Solvern möglich. → <a href="cvar.html#sec:cvar-value-at-risk-und-conditional-value">Abschnitt 20.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:routing-bibliothek">
|
||||
<p><strong>Routing-Bibliothek</strong> — Spezialisierter Teil von OR-Tools für Touren- und Reihenfolgeprobleme. Sie arbeitet heuristisch mit Zeitbudget — „optimal“ wird hier in der Regel nicht bewiesen. → <a href="graphen.html#sec:graphen-zusammenfassung">Abschnitt 8.10</a></p>
|
||||
</div>
|
||||
<div id="gloss:rucksackproblem">
|
||||
<p><strong>Rucksackproblem</strong> — Auswahl von Gegenständen mit Wert und Gewicht unter einer Kapazitätsgrenze. Das Schulbeispiel der ganzzahligen Optimierung und Modell für jede Budgetauswahl. → <a href="milp.html#sec:milp-beispiel-das-rucksackproblem">Abschnitt 6.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:rueckwaertsinduktion">
|
||||
<p><strong>Rückwärtsinduktion</strong> — Lösungsrichtung der dynamischen Programmierung: von der letzten Stufe rückwärts. Nur dort steht der Wert eines Zustands ohne Kenntnis der Zukunft fest, und von dort aus lässt sich jede frühere Stufe auf bereits bekannte Werte zurückführen. → <a href="dynamische-programmierung.html#sec:dynamische-programmierung-lernziele">Abschnitt 13.2</a></p>
|
||||
</div>
|
||||
<div id="gloss:ruiz-equilibrierung">
|
||||
<p><strong>Ruiz-Equilibrierung</strong> — Skalierungsverfahren, das Zeilen und Spalten einer Matrix iterativ so multipliziert, dass alle Beträge in derselben Größenordnung liegen. Nach wenigen Durchläufen liegen die Maxima bei 1 — die einfachste wirksame Gegenmaßnahme gegen schlechte Konditionierung. → <a href="fundament.html#sec:fundament-kondition">Abschnitt 2.7</a></p>
|
||||
</div>
|
||||
<div id="gloss:ruestzeit">
|
||||
<p><strong>Rüstzeit</strong> — Umschaltzeit zwischen zwei aufeinanderfolgenden Aufträgen auf derselben Maschine. Sie ist reihenfolgeabhängig und macht aus einer einfachen Zuordnung ein Reihenfolgeproblem. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<h2 id="s">S</h2>
|
||||
<div id="gloss:sat-boolean-satisfiability">
|
||||
<p><strong>SAT (Boolean Satisfiability)</strong> — Problem, für eine aussagenlogische Formel eine erfüllende Belegung zu finden. Das erste als NP-vollständig bewiesene Problem — und die Sprache, in die CP-SAT jedes Modell übersetzt. → <a href="cpsat.html#sec:cpsat-ein-anderes-denkmodell">Abschnitt 7.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:satz-von-birkhoff-und-von-neumann">
|
||||
<p><strong>Satz von Birkhoff und von Neumann</strong> — Jede doppelt stochastische Matrix ist eine Mischung von Permutationsmatrizen. Er erklärt, warum das Zuordnungsproblem schon als lineares Programm ganzzahlige Lösungen liefert. → <a href="graphen.html#sec:graphen-bipartites-matching-das-zuordnungsproblem">Abschnitt 8.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:schattenpreis">
|
||||
<p><strong>Schattenpreis</strong> — Optimalwert einer Dualvariablen: Um wie viel ändert sich der Zielwert, wenn die zugehörige Ressource um eine Einheit erweitert wird? Er gilt nur lokal — innerhalb des Bereichs, den die Sensitivitätsanalyse ausweist. → <a href="lp.html#sec:lp-dualitaet-und-schattenpreise">Abschnitt 5.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:schaetzfehler">
|
||||
<p><strong>Schätzfehler</strong> — Abweichung geschätzter Größen wie Renditen oder Kovarianzen von ihren wahren Werten. In der Portfoliooptimierung nicht ein Randproblem, sondern das Hauptproblem. → <a href="finanzdaten.html#sec:finanzdaten-das-schaetzfehler-problem">Abschnitt 18.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:scheduling">
|
||||
<p><strong>Scheduling</strong> — Zuweisung von Tätigkeiten an Maschinen oder Personen unter Ressourcen- und Reihenfolgebedingungen. <a href="cpsat.html#kap-cpsat">Kapitel 7</a> behandelt es mit CP-SAT (Intervallvariablen), <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a> mit Simulated Annealing und LNS. → <a href="cpsat.html#kap-cpsat">Kapitel 7</a></p>
|
||||
</div>
|
||||
<div id="gloss:schlupfvariable">
|
||||
<p><strong>Schlupfvariable</strong> — Nichtnegative Hilfsvariable, die eine Ungleichung in eine Gleichung überführt. Ihr Wert zeigt die ungenutzte Reserve; ist er null, ist die Bedingung bindend. → <a href="lp.html#sec:lp-die-standardform-und-schlupfvariablen">Abschnitt 5.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:schnittebenen-cutting-planes">
|
||||
<p><strong>Schnittebenen (Cutting Planes)</strong> — Zusätzliche gültige Ungleichungen, die gebrochene LP-Lösungen abschneiden, ohne einen einzigen ganzzahligen Punkt zu verlieren. Sie verschärfen die Relaxation und verkleinern damit den Suchbaum. → <a href="milp.html#sec:milp-branch-and-bound">Abschnitt 6.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:scikit-learn">
|
||||
<p><strong>scikit-learn</strong> — Bibliothek für maschinelles Lernen. Im Buch für Prognosemodelle und für die Ledoit-Wolf-Shrinkage der Kovarianzmatrix eingesetzt. → <a href="oekosystem.html#sec:oekosystem-die-werkzeuge-im-vergleich">Abschnitt 3.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:scip">
|
||||
<p><strong>SCIP</strong> — Akademischer Solver für gemischt-ganzzahlige lineare und nichtlineare Programme, über OR-Tools und Pyomo ansprechbar. Für Forschung und Lehre frei nutzbar; kommerzieller Einsatz verlangt eine eigene Lizenz. → <a href="milp.html#sec:milp-branch-and-bound">Abschnitt 6.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:scipy">
|
||||
<p><strong>SciPy</strong> — Wissenschaftliche Standardbibliothek von Python. Ihr Teilmodul <code>scipy.optimize</code> enthält mit <code>linprog</code>, <code>milp</code> und <code>minimize</code> die Einstiegswerkzeuge für lineare, ganzzahlige und nichtlineare Optimierung. → <a href="oekosystem.html#sec:oekosystem-die-werkzeuge-im-vergleich">Abschnitt 3.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:semikontinuierliche-variable">
|
||||
<p><strong>Semikontinuierliche Variable</strong> — Variable, die entweder null ist oder in einem Intervall <span class="math inline">[m, M]</span> liegt. Sie erfasst Mindestlosgrößen und wird über eine Binärvariable modelliert. → <a href="milp.html#sec:milp-modellierungstricks-big-m-und-logische-bedingungen">Abschnitt 6.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:sensitivitaetsanalyse">
|
||||
<p><strong>Sensitivitätsanalyse</strong> — Untersuchung, in welchem Bereich sich Koeffizienten und Kapazitäten ändern dürfen, ohne die Struktur der Optimallösung zu verändern. Sie macht aus einer Zahl eine Aussage über ihre Belastbarkeit. → <a href="lp.html#sec:lp-praxisfall-sensitivitaetsanalyse-mit-korrekten-schattenpreisen">Abschnitt 5.8</a></p>
|
||||
</div>
|
||||
<div id="gloss:shannon-entropie">
|
||||
<p><strong>Shannon-Entropie</strong> — Maß für die Gleichverteiltheit einer Verteilung. Als Zielfunktion eingesetzt erzwingt sie Streuung, ohne eine bestimmte Aufteilung vorzugeben. → <a href="qp-nlp.html#sec:qp-nlp-nichtlineare-optimierung-mit-scipy-optimize-minimize">Abschnitt 11.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:sharpe-ratio">
|
||||
<p><strong>Sharpe Ratio</strong> — Überrendite über den risikofreien Zins je Einheit Volatilität. Ihre Maximierung ist zunächst nicht konvex, wird es aber durch die Korn-Transformation. → <a href="markowitz.html#sec:markowitz-das-mean-variance-modell">Abschnitt 19.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:simplex-algorithmus">
|
||||
<p><strong>Simplex-Algorithmus</strong> — Verfahren von Dantzig, das von Ecke zu Ecke des Polyeders wandert und den Zielfunktionswert dabei monoton verbessert. Im schlechtesten Fall exponentiell, in der Praxis außerordentlich zuverlässig. → <a href="lp.html#sec:lp-der-simplex-algorithmus-schritt-fuer-schritt">Abschnitt 5.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:simulated-annealing">
|
||||
<p><strong>Simulated Annealing</strong> — Metaheuristik nach dem Vorbild des Metallabkühlens: Verschlechterungen werden anfangs häufig, später kaum noch akzeptiert. So entkommt die Suche lokalen Optima, ohne die Richtung ganz zu verlieren. → <a href="metaheuristiken.html#sec:metaheuristiken-annealing">Abschnitt 9.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:skalarisierung">
|
||||
<p><strong>Skalarisierung</strong> — Zusammenfassung mehrerer Ziele zu einer gewichteten Summe. Bequem, aber mit zwei Haken: Die Gewichte sind Werturteile, und nicht jeder Punkt der Pareto-Front lässt sich so erreichen. → <a href="mehrziel.html#sec:mehrziel-skalarisierung">Abschnitt 14.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:skalarprodukt">
|
||||
<p><strong>Skalarprodukt</strong> — Summe der paarweisen Produkte zweier Vektoren, <span class="math inline">\mathbf{c}^\top\mathbf{x}</span>. In der Optimierung die kompakte Schreibweise jeder linearen Zielfunktion. → <a href="fundament.html#sec:fundament-warum-ueberhaupt-vektoren-und-matrizen">Abschnitt 2.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:slsqp">
|
||||
<p><strong>SLSQP</strong> — <em>Sequential Least Squares Programming</em> — gradientenbasiertes Verfahren in <code>scipy.optimize.minimize</code> für nichtlineare Probleme mit Nebenbedingungen. Es findet lokale Optima; ohne Konvexität entscheidet der Startpunkt über das Ergebnis. → <a href="qp-nlp.html#sec:qp-nlp-nichtlineare-optimierung-mit-scipy-optimize-minimize">Abschnitt 11.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:snapshot-prinzip">
|
||||
<p><strong>Snapshot-Prinzip</strong> — Betriebsregel, nach der jeder Optimierungslauf auf einem unveränderlichen Datenschnappschuss mit eigener Kennung arbeitet. Nur so ist ein Ergebnis später reproduzierbar — und im Streitfall belegbar. → <a href="praxisfallen.html#sec:praxisfallen-architektur-einer-produktionsreifen-or-plattform">Abschnitt 22.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:solver">
|
||||
<p><strong>Solver</strong> — Softwarekomponente, die ein mathematisches Modell löst — also das Optimierungsproblem in eine Lösung übersetzt. <a href="oekosystem.html#kap-oekosystem">Kapitel 3</a> vergleicht die in diesem Buch verwendeten Solver (HiGHS, OR-Tools/CP-SAT, CVXPY) und ihre Stärken. → <a href="oekosystem.html#kap-oekosystem">Kapitel 3</a></p>
|
||||
</div>
|
||||
<div id="gloss:solver-status">
|
||||
<p><strong>Solver-Status</strong> — Rückgabewert, mit dem ein Solver das Ergebnis einordnet: <code>OPTIMAL</code> (bewiesen optimal), <code>FEASIBLE</code> (zulässig, aber unbewiesen), <code>INFEASIBLE</code> (keine zulässige Lösung), <code>UNBOUNDED</code> (Zielwert unbeschränkt) und <code>UNKNOWN</code> (Abbruch ohne Aussage). Ihn ungeprüft zu übergehen ist die häufigste Fehlerquelle im produktiven Einsatz. → <a href="notation.html">Notation und Abkürzungen</a></p>
|
||||
</div>
|
||||
<div id="gloss:starker-dualitaetssatz">
|
||||
<p><strong>Starker Dualitätssatz</strong> — Aussage, dass primales und duales Problem im Optimum denselben Zielfunktionswert besitzen — bei linearen Programmen immer, sobald beide lösbar sind. Er macht den Dualwert zu einem belastbaren Preis statt zu einer bloßen Schranke. → <a href="lp.html#sec:lp-dualitaet-und-schattenpreise">Abschnitt 5.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:stichproben-kovarianzmatrix">
|
||||
<p><strong>Stichproben-Kovarianzmatrix</strong> — Aus historischen Daten geschätzte Kovarianzmatrix. Bei weniger Beobachtungen als Titeln ist sie singulär und damit nicht invertierbar; schon bei ähnlicher Größenordnung wird sie extrem instabil. → <a href="finanzdaten.html#sec:finanzdaten-das-schaetzfehler-problem">Abschnitt 18.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:stochastische-programmierung">
|
||||
<p><strong>Stochastische Programmierung</strong> — Optimierung unter Unsicherheit mit bekannten Wahrscheinlichkeiten. In der zweistufigen Form wird zwischen Entscheidungen vor und nach der Beobachtung unterschieden — genau der Unterschied, den der Fluch des Durchschnitts einebnet. → <a href="unsicherheit.html#sec:unsicherheit-zweistufige-stochastische-programmierung">Abschnitt 12.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:strafkosten">
|
||||
<p><strong>Strafkosten</strong> — Kosten, mit denen die Verletzung einer weichen Bedingung in der Zielfunktion belegt wird. Ihre Höhe ist eine Modellierungsentscheidung: Sie legt fest, wie viel Regelverstoß was wert ist. → <a href="einfuehrung.html#sec:einfuehrung-die-vier-universellen-bausteine-jedes-or">Abschnitt 1.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:subadditivitaet">
|
||||
<p><strong>Subadditivität</strong> — Eigenschaft <span class="math inline">\rho(A+B) \le \rho(A)+\rho(B)</span>: Diversifikation darf das Risiko nicht erhöhen. Der VaR verletzt sie, weshalb er kein kohärentes Risikomaß ist. → <a href="cvar.html#sec:cvar-value-at-risk-und-conditional-value">Abschnitt 20.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:subtour">
|
||||
<p><strong>Subtour</strong> — Kurzzyklus, der nur einen Teil der Knoten enthält und das Depot umgeht. Ohne eigene Bedingungen — etwa MTZ — liefert ein Tourenmodell solche Gebilde als scheinbar optimale Lösung. → <a href="graphen.html#sec:graphen-das-vehicle-routing-problem-mit-zeitfenstern">Abschnitt 8.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:survivorship-bias">
|
||||
<p><strong>Survivorship-Bias</strong> — Verzerrung durch die Auswahl nur derjenigen Titel, die es bis heute gibt. Die ausgeschiedenen fehlen — und mit ihnen die schlechtesten Verläufe. → <a href="handelsmaschine.html#sec:handelsmaschine-die-fuenf-selbsttaeuschungen-des-backtestens">Abschnitt 21.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:symmetriebrechung">
|
||||
<p><strong>Symmetriebrechung</strong> — Zusätzliche Ordnungsbedingungen, die verhindern, dass der Solver gleichwertige Vertauschungen mehrfach durchsucht. Bei identischen Maschinen oder Fahrzeugen oft der größte einzelne Laufzeitgewinn. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<h2 id="t">T</h2>
|
||||
<div id="gloss:tabu-suche">
|
||||
<p><strong>Tabu-Suche</strong> — Metaheuristik, die zuletzt besuchte Lösungen für einige Schritte sperrt. Die Sperrliste zwingt die Suche aus lokalen Optima heraus, statt zwischen zwei Nachbarn zu pendeln. → <a href="metaheuristiken.html#sec:metaheuristiken-abgrenzung">Abschnitt 9.8</a></p>
|
||||
</div>
|
||||
<div id="gloss:tangentialportfolio">
|
||||
<p><strong>Tangentialportfolio</strong> — Portfolio auf der Effizienzgrenze mit der höchsten Sharpe Ratio — der Berührpunkt der Kapitalmarktlinie. Es reagiert besonders empfindlich auf Renditeschätzfehler. → <a href="markowitz.html#sec:markowitz-das-mean-variance-modell">Abschnitt 19.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:technologiematrix">
|
||||
<p><strong>Technologiematrix</strong> — Die Matrix <span class="math inline">\mathbf{A}</span> der Verbrauchskoeffizienten. Ihr Eintrag <span class="math inline">a_{ij}</span> sagt, wie viel von Ressource <span class="math inline">i</span> eine Einheit von Aktivität <span class="math inline">j</span> verbraucht. Zusammen mit dem Kapazitätsvektor <span class="math inline">\mathbf{b}</span> bildet sie die Nebenbedingungen <span class="math inline">\mathbf{A}\mathbf{x} \le \mathbf{b}</span>. → <a href="fundament.html#sec:fundament-warum-ueberhaupt-vektoren-und-matrizen">Abschnitt 2.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:totale-unimodularitaet">
|
||||
<p><strong>Totale Unimodularität</strong> — Eigenschaft einer Matrix, bei der jede quadratische Teilmatrix die Determinante <span class="math inline">0</span>, <span class="math inline">+1</span> oder <span class="math inline">-1</span> hat. Folge: Alle Ecken des Polyeders sind ganzzahlig — Ganzzahligkeit muss gar nicht gefordert werden. → <a href="graphen.html#sec:graphen-bipartites-matching-das-zuordnungsproblem">Abschnitt 8.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:transaktionskosten">
|
||||
<p><strong>Transaktionskosten</strong> — Beim Umschichten anfallende Kosten aus Gebühren, Spread und Marktauswirkung. Über eine <span class="math inline">L_1</span>-Strafe modellierbar, die zugleich den Turnover begrenzt. → <a href="cvar.html#sec:cvar-transaktionskosten-ueber-die-l-1-norm">Abschnitt 20.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:trickle-flow">
|
||||
<p><strong>Trickle Flow</strong> — Fehlerbild bei zu großem <span class="math inline">M</span>: Ein verschwindend kleiner Schaltwert — etwa <span class="math inline">4 \cdot 10^{-8}</span> — gilt dem Solver als null, lässt aber multipliziert mit einem riesigen <span class="math inline">M</span> einen großen Fluss durch. Das Lager liefert, ohne offiziell geöffnet zu sein, und die Fixkosten fehlen in der Rechnung. → <a href="anhang-loesungen.html#sec:loesungen-milp">Abschnitt A.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:tsp-traveling-salesperson-problem">
|
||||
<p><strong>TSP (Traveling Salesperson Problem)</strong> — Suche nach der kürzesten Rundreise durch <span class="math inline">n</span> Orte. Das bekannteste NP-schwere Problem und der Ausgangspunkt aller Tourenmodelle. → <a href="graphen.html#sec:graphen-das-vehicle-routing-problem-mit-zeitfenstern">Abschnitt 8.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:turnover-umschlag">
|
||||
<p><strong>Turnover (Umschlag)</strong> — Summe der absoluten Gewichtsänderungen einer Umschichtung. Die Größe, an der Transaktionskosten hängen — und die Kennzahl, mit der man Rebalancing-Regeln vergleicht. → <a href="cvar.html#sec:cvar-transaktionskosten-ueber-die-l-1-norm">Abschnitt 20.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:twap">
|
||||
<p><strong>TWAP</strong> — <em>Time-Weighted Average Price</em> — Ausführungsstrategie, die eine Order gleichmäßig über die Zeit verteilt. Einfache Vergleichsgröße für jede optimierte Ausführung. → <a href="dynamische-programmierung.html#sec:dynamische-programmierung-das-almgren-chriss-problem-optimale-orderausfuehrung">Abschnitt 13.4</a></p>
|
||||
</div>
|
||||
<h2 id="u">U</h2>
|
||||
<div id="gloss:umruestkosten">
|
||||
<p><strong>Umrüstkosten</strong> — Kosten, die beim Wechsel zwischen zwei Produkten anfallen. Sie hängen vom Vorgänger ab und erzwingen deshalb Binärvariablen über Paare statt über einzelne Aufträge. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:unbounded">
|
||||
<p><strong>Unbounded</strong> — Zustand, in dem der Zielwert unbeschränkt verbessert werden kann. Fast immer ein Modellfehler — eine fehlende Kapazitätsgrenze oder ein vergessenes Vorzeichen —, nicht ein besonders gutes Ergebnis. → <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></p>
|
||||
</div>
|
||||
<div id="gloss:ungarischer-algorithmus">
|
||||
<p><strong>Ungarischer Algorithmus</strong> — Kombinatorisches Verfahren für das Zuordnungsproblem mit polynomialer Laufzeit. Es löst exakt, was als allgemeines MILP deutlich teurer wäre. → <a href="graphen.html#sec:graphen-zusammenfassung">Abschnitt 8.10</a></p>
|
||||
</div>
|
||||
<div id="gloss:unsicherheitsmenge">
|
||||
<p><strong>Unsicherheitsmenge</strong> — Vorab definierter Bereich möglicher Parameterwerte, gegen dessen ungünstigstes Element eine robuste Lösung abgesichert wird. Ihre Größe steuert unmittelbar den Preis der Robustheit. → <a href="unsicherheit.html#sec:unsicherheit-robuste-optimierung-gegen-den-worst-case">Abschnitt 12.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:unsinniges-ergebnis">
|
||||
<p><strong>Unsinniges Ergebnis</strong> — Fehlerbild, bei dem der Solver zwar <code>OPTIMAL</code> meldet, die Lösung aber offensichtlich unbrauchbar ist. Dann ist nicht die Rechnung falsch, sondern das Modell: Es beschreibt eine andere Wirklichkeit als die gemeinte. → <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></p>
|
||||
</div>
|
||||
<h2 id="v">V</h2>
|
||||
<div id="gloss:value-at-risk-var">
|
||||
<p><strong>Value at Risk (VaR)</strong> — Verlustschwelle, die mit vorgegebener Wahrscheinlichkeit nicht überschritten wird. Sie sagt nichts über die Verlusthöhe dahinter und ist nicht subadditiv — beides Gründe für den Übergang zum CVaR. → <a href="cvar.html#sec:cvar-value-at-risk-und-conditional-value">Abschnitt 20.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:vehicle-routing-problem-vrp">
|
||||
<p><strong>Vehicle Routing Problem (VRP)</strong> — Verallgemeinerung des TSP auf mehrere Fahrzeuge mit Depot und Kapazitätsgrenzen. In der Variante mit Zeitfenstern (VRPTW) ist es der praktische Standardfall der Tourenplanung. Sich kreuzende Touren sind hier kein Fehler: Die Zeitfenster können die Reihenfolge erzwingen. → <a href="graphen.html#sec:graphen-das-vehicle-routing-problem-mit-zeitfenstern">Abschnitt 8.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:verdaechtig-guter-backtest">
|
||||
<p><strong>Verdächtig guter Backtest</strong> — Fehlerbild der Finanzkapitel: eine Strategie, die im Rückblick zu gut abschneidet. Die Prüfreihenfolge lautet Lookahead, Survivorship, Kosten, Data Snooping — in dieser Reihenfolge, weil sie nach Häufigkeit sortiert ist. → <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></p>
|
||||
</div>
|
||||
<div id="gloss:verhaeltnis-bedingung">
|
||||
<p><strong>Verhältnis-Bedingung</strong> — Anforderung der Art „höchstens 30 % aus einer Quelle“. Sie wird linear, sobald man sie als <span class="math inline">x_i \le 0{,}3 \sum_j x_j</span> schreibt statt als Bruch. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:vertauschte-spalten">
|
||||
<p><strong>Vertauschte Spalten</strong> — Fehlerbild, bei dem Daten und Modell unterschiedliche Reihenfolgen annehmen. Es rechnet widerspruchsfrei und liefert dennoch Unsinn — deshalb gehört die Spaltenreihenfolge abgesichert, nicht angenommen. → <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></p>
|
||||
</div>
|
||||
<div id="gloss:volatilitaet">
|
||||
<p><strong>Volatilität</strong> — Standardabweichung der Renditen, üblicherweise auf ein Jahr skaliert. Sie misst Schwankung in beide Richtungen und behandelt Gewinne damit wie Verluste. → <a href="finanzdaten.html#sec:finanzdaten-diskrete-und-logarithmische-renditen">Abschnitt 18.3</a></p>
|
||||
</div>
|
||||
<div id="gloss:vorrangbeziehung">
|
||||
<p><strong>Vorrangbeziehung</strong> — Bedingung „Aktivität A muss vor Aktivität B abgeschlossen sein“, formuliert als <span class="math inline">\text{Ende}_A \le \text{Start}_B</span>. Der Grundbaustein jeder Ablaufplanung. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<h2 id="w">W</h2>
|
||||
<div id="gloss:walk-forward-backtest">
|
||||
<p><strong>Walk-Forward-Backtest</strong> — Rollierende Auswertung, bei der Parameter stets nur auf Vergangenheitsdaten geschätzt und auf dem unmittelbar folgenden Zeitraum getestet werden. Die einzige Backtest-Bauform, die Lookahead strukturell ausschließt. → <a href="handelsmaschine.html#sec:handelsmaschine-die-engine">Abschnitt 21.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:warm-start">
|
||||
<p><strong>Warm-Start</strong> — Übergabe einer bekannten Lösung als Startpunkt. Bei wiederholten, ähnlichen Läufen — etwa täglicher Neuplanung — oft der größte Zeitgewinn überhaupt. → <a href="milp.html#sec:milp-gap">Abschnitt 6.8</a></p>
|
||||
</div>
|
||||
<div id="gloss:weiche-grenze-mit-strafkosten">
|
||||
<p><strong>Weiche Grenze mit Strafkosten</strong> — Modellierungsmuster, das eine Schranke überschreitbar macht und die Überschreitung über eine Schlupfvariable in der Zielfunktion bepreist. So bleibt das Modell lösbar und zeigt trotzdem, wo es klemmt. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:widerspruechliche-solver">
|
||||
<p><strong>Widersprüchliche Solver</strong> — Fehlerbild, bei dem zwei Solver verschiedene Lösungen melden. Bei gleichem Zielwert sind es Alternativoptima und beide haben recht; bei verschiedenem Zielwert liegt ein Modell- oder Toleranzproblem vor. → <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></p>
|
||||
</div>
|
||||
<div id="gloss:wurzel-zeit-regel">
|
||||
<p><strong>Wurzel-Zeit-Regel</strong> — Skalierung der Volatilität mit <span class="math inline">\sqrt{T}</span>. Sie gilt streng nur für Standardabweichungen unabhängiger Größen ohne Drift — für VaR und CVaR ist sie lediglich eine grobe Näherung. → <a href="cvar.html#sec:cvar-implementierung-cvar-portfolio-mit-reibung">Abschnitt 20.6</a></p>
|
||||
</div>
|
||||
<h2 id="y">Y</h2>
|
||||
<div id="gloss:yfinance">
|
||||
<p><strong>yfinance</strong> — Bibliothek zum Abruf historischer Kursdaten. Die einzige Abhängigkeit des Buchs, die eine Internetverbindung braucht — vier Programme nutzen sie. → <a href="oekosystem.html#sec:oekosystem-die-werkzeuge-im-vergleich">Abschnitt 3.4</a></p>
|
||||
</div>
|
||||
<h2 id="z">Z</h2>
|
||||
<div id="gloss:zielfunktion">
|
||||
<p><strong>Zielfunktion</strong> — Der zu minimierende oder maximierende Ausdruck, der die Entscheidungsvariablen zu einer einzigen Bewertungszahl verdichtet. Ihre Formulierung entscheidet, was das Modell überhaupt für gut hält. → <a href="einfuehrung.html#sec:einfuehrung-die-vier-universellen-bausteine-jedes-or">Abschnitt 1.6</a></p>
|
||||
</div>
|
||||
<div id="gloss:zufallsmatrizentheorie">
|
||||
<p><strong>Zufallsmatrizentheorie</strong> — <em>Random Matrix Theory</em> — Theorie der Eigenwertverteilung zufälliger Matrizen. Sie liefert den Maßstab dafür, welche Struktur in einer geschätzten Kovarianzmatrix echt ist und welche bloßes Rauschen. → <a href="finanzdaten.html#sec:finanzdaten-das-schaetzfehler-problem">Abschnitt 18.4</a></p>
|
||||
</div>
|
||||
<div id="gloss:zulaessiger-bereich-feasible-region">
|
||||
<p><strong>Zulässiger Bereich (Feasible Region)</strong> — Menge aller Punkte, die sämtliche Nebenbedingungen gleichzeitig erfüllen. Ist sie leer, ist das Modell unlösbar; ist sie unbeschränkt, kann der Zielwert entgleiten. → <a href="anhang-literatur.html#anhang-literatur">Anhang F</a></p>
|
||||
</div>
|
||||
<div id="gloss:zuordnungsproblem">
|
||||
<p><strong>Zuordnungsproblem</strong> — Eins-zu-eins-Zuordnung zweier gleich großer Mengen mit minimalen Kosten. Dank totaler Unimodularität schon als LP ganzzahlig lösbar. → <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a></p>
|
||||
</div>
|
||||
<div id="gloss:zustandslosigkeit">
|
||||
<p><strong>Zustandslosigkeit</strong> — Betriebsprinzip, nach dem der rechnende Dienst keinen Zustand hält: Eingabe und Ausgabe sind Daten. Das macht Skalierung und Wiederholung trivial. → <a href="praxisfallen.html#sec:praxisfallen-architektur-einer-produktionsreifen-or-plattform">Abschnitt 22.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:zustandsraum">
|
||||
<p><strong>Zustandsraum</strong> — Menge aller Zustände, die ein mehrstufiges Entscheidungsproblem annehmen kann. Seine Größe entscheidet, ob dynamische Programmierung praktikabel ist. → <a href="dynamische-programmierung.html#sec:dynamische-programmierung-der-fluch-der-dimensionalitaet">Abschnitt 13.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:zwei-phasen-simplex-methode">
|
||||
<p><strong>Zwei-Phasen-Simplex-Methode</strong> — Vorgehen, um überhaupt eine erste zulässige Ecke zu finden. Phase 1 minimiert mit Hilfsvariablen die Verletzung der Nebenbedingungen; bleibt dabei ein Rest, ist das Modell unlösbar. Erst Phase 2 optimiert die eigentliche Zielfunktion. → <a href="anhang-loesungen.html#sec:loesungen-lp">Abschnitt A.5</a></p>
|
||||
</div>
|
||||
<div id="gloss:zweischichtige-architektur">
|
||||
<p><strong>Zweischichtige Architektur</strong> — Trennung in eine Modellierungsschicht, in der man das Problem mathematiknah formuliert, und eine Solver-Schicht aus hochoptimierten C++-Bibliotheken. Man schreibt Optimierungsalgorithmen im modernen OR nicht selbst. → <a href="oekosystem.html#sec:oekosystem-die-zwei-schichten-architektur">Abschnitt 3.3</a></p>
|
||||
</div>
|
||||
|
||||
</article>
|
||||
<button type="button" class="fortschritt-knopf" data-kapitel="anhang-glossar.html"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg> <span>Als gelesen markieren</span></button>
|
||||
|
|
|
|||
74
OR_HTML_04/anhang-literatur.html
generated
74
OR_HTML_04/anhang-literatur.html
generated
|
|
@ -110,83 +110,83 @@
|
|||
<h2 id="grundlagen-und-standardwerke-des-operations-research">Grundlagen und Standardwerke des Operations Research</h2>
|
||||
<p><em>Zu <a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> und <a href="fundament.html#kap-fundament">Kapitel 2</a>.</em></p>
|
||||
<ul>
|
||||
<li>★★★ <strong>Bertsimas, D. & Tsitsiklis, J. N. (1997):</strong> <em>Introduction to Linear Optimization.</em> Athena Scientific, Belmont. [Lineare Optimierung] <em>Standardwerk zur geometrischen und algebraischen Theorie des Simplex-Verfahrens, Dualität, Sensitivitätsanalyse und Netzwerkflüssen. Alt, aber unverändert die klarste Herleitung der Dualitätstheorie.</em></li>
|
||||
<li>★★★ <strong>Nocedal, J. & Wright, S. J. (2006):</strong> <em>Numerical Optimization</em> (2. Aufl.). Springer, New York. DOI: 10.1007/978-0-387-40065-5 [Numerik der Optimierung] <em>Warum Verfahren numerisch scheitern: Konditionierung, Schrittweitensteuerung, Konvergenzraten. Die Grundlage des Abschnitts über Skalierung und Ruiz-Equilibrierung.</em></li>
|
||||
<li>★★★ <strong>Bertsimas, D. & Tsitsiklis, J. N. (1997):</strong> <em>Introduction to Linear Optimization.</em> Athena Scientific, Belmont. [Lineare Optimierung] <em>Standardwerk zur geometrischen und algebraischen Theorie des Simplex-Verfahrens, Dualität, <a href="anhang-glossar.md#gloss:sensitivitaetsanalyse" class="glossar-link">Sensitivitätsanalyse</a> und Netzwerkflüssen. Alt, aber unverändert die klarste Herleitung der <a href="anhang-glossar.md#gloss:dualitaetstheorie" class="glossar-link">Dualitätstheorie</a>.</em></li>
|
||||
<li>★★★ <strong>Nocedal, J. & Wright, S. J. (2006):</strong> <em>Numerical Optimization</em> (2. Aufl.). Springer, New York. DOI: 10.1007/978-0-387-40065-5 [Numerik der Optimierung] <em>Warum Verfahren numerisch scheitern: Konditionierung, Schrittweitensteuerung, Konvergenzraten. Die Grundlage des Abschnitts über Skalierung und <a href="anhang-glossar.md#gloss:ruiz-equilibrierung" class="glossar-link">Ruiz-Equilibrierung</a>.</em></li>
|
||||
<li>★★ <strong>Hillier, F. S. & Lieberman, G. J. (2021):</strong> <em>Introduction to Operations Research</em> (11. Aufl.). McGraw-Hill, New York. [OR-Überblick] <em>Breite Einführung inklusive Warteschlangen, Entscheidungsmodellen und Simulation — die Themen, die dieses Buch bewusst auslässt.</em></li>
|
||||
<li>★★ <strong>Kallrath, J. (2021):</strong> <em>Business Optimization Using Mathematical Programming</em> (2. Aufl.). Springer, Cham. DOI: 10.1007/978-3-030-73237-0 [Modellierungspraxis] <em>Der Brückenschlag von der betrieblichen Fragestellung zum Modell, mit ausführlichem Katalog industrieller Anwendungsfälle. Nächster Nachbar zu <a href="modellierung.html#kap-modellierung">Kapitel 4</a>.</em></li>
|
||||
<li>★ <strong>Dantzig, G. B. (1963):</strong> <em>Linear Programming and Extensions.</em> Princeton University Press. DOI: 10.1515/9781400884179 [Historisch] <em>Das Originalwerk des Erfinders des Simplex-Algorithmus. Historisch bedeutend, für die tägliche Arbeit heute entbehrlich.</em></li>
|
||||
<li>★ <strong>Dantzig, G. B. (1963):</strong> <em>Linear Programming and Extensions.</em> Princeton University Press. DOI: 10.1515/9781400884179 [Historisch] <em>Das Originalwerk des Erfinders des <a href="anhang-glossar.md#gloss:simplex-algorithmus" class="glossar-link">Simplex-Algorithmus</a>. Historisch bedeutend, für die tägliche Arbeit heute entbehrlich.</em></li>
|
||||
</ul>
|
||||
<h2 id="modellierung-in-python-bibliotheken-und-modellierungsschichten">Modellierung in Python: Bibliotheken und Modellierungsschichten</h2>
|
||||
<p><em>Zu <a href="oekosystem.html#kap-oekosystem">Kapitel 3</a>.</em></p>
|
||||
<ul>
|
||||
<li>★★★ <strong>Diamond, S. & Boyd, S. (2016):</strong> <em>CVXPY: A Python-embedded modeling language for convex optimization.</em> In: <em>Journal of Machine Learning Research</em> 17(83), S. 1–5. [Bibliothek: CVXPY] <em>Die Referenz zur im Buch am häufigsten benutzten Modellierungsschicht. <a href="https://www.cvxpy.org">www.cvxpy.org</a></em></li>
|
||||
<li>★★★ <strong>Diamond, S. & Boyd, S. (2016):</strong> <em><a href="anhang-glossar.md#gloss:cvxpy" class="glossar-link">CVXPY</a>: A Python-embedded modeling language for convex optimization.</em> In: <em>Journal of Machine Learning Research</em> 17(83), S. 1–5. [Bibliothek: CVXPY] <em>Die Referenz zur im Buch am häufigsten benutzten Modellierungsschicht. <a href="https://www.cvxpy.org">www.cvxpy.org</a></em></li>
|
||||
<li>★★ <strong>Agrawal, A., Verschueren, R., Diamond, S. & Boyd, S. (2018):</strong> <em>A rewriting system for convex optimization problems.</em> In: <em>Journal of Control and Decision</em> 5(1), S. 42–60. DOI: 10.1080/23307706.2017.1397554 [Bibliothek: CVXPY] <em>Erklärt, was CVXPY beim Übersetzen tatsächlich tut — und warum ein <code>DCPError</code> kein Solverfehler ist.</em></li>
|
||||
<li>★★★ <strong>Bynum, M. L., Hackebeil, G. A., Hart, W. E., Laird, C. D., Nicholson, B. L., Siirola, J. D., Watson, J.-P. & Woodruff, D. L. (2021):</strong> <em>Pyomo — Optimization Modeling in Python</em> (3. Aufl.). Springer, Cham. DOI: 10.1007/978-3-030-68928-5 [Bibliothek: Pyomo] <em>Das Referenzbuch der Autoren zur mächtigsten der drei im Buch verglichenen Modellierungsschichten.</em></li>
|
||||
<li>★★ <strong>Hofmann, F. (2023):</strong> <em>Linopy: Linear optimization with n-dimensional labeled variables.</em> In: <em>Journal of Open Source Software</em> 8(84), 4823. DOI: 10.21105/joss.04823 [Bibliothek: linopy] <em>Beschreibt den beschrifteten-Achsen-Ansatz und enthält den Speicher- und Geschwindigkeitsvergleich gegen Pyomo, PuLP, CVXPY und gurobipy. Frei zugänglich.</em></li>
|
||||
<li>★★ <strong>Virtanen, P., Gommers, R., Oliphant, T. E. et al. (2020):</strong> <em>SciPy 1.0: fundamental algorithms for scientific computing in Python.</em> In: <em>Nature Methods</em> 17, S. 261–272. DOI: 10.1038/s41592-019-0686-2 [Bibliothek: SciPy] <em>Die zitierfähige Quelle zu <code>scipy.optimize</code> — dem Einstiegspunkt in <a href="lp.html#kap-lp">Kapitel 5</a>.</em></li>
|
||||
<li>★★ <strong>Harris, C. R., Millman, K. J., van der Walt, S. J. et al. (2020):</strong> <em>Array programming with NumPy.</em> In: <em>Nature</em> 585, S. 357–362. DOI: 10.1038/s41586-020-2649-2 [Bibliothek: NumPy] <em>Grundlage jeder vektorisierten Modellerzeugung; siehe den Abschnitt über den Aufbau großer Modelle.</em></li>
|
||||
<li>★★★ <strong>Bynum, M. L., Hackebeil, G. A., Hart, W. E., Laird, C. D., Nicholson, B. L., Siirola, J. D., Watson, J.-P. & Woodruff, D. L. (2021):</strong> <em><a href="anhang-glossar.md#gloss:pyomo" class="glossar-link">Pyomo</a> — Optimization Modeling in Python</em> (3. Aufl.). Springer, Cham. DOI: 10.1007/978-3-030-68928-5 [Bibliothek: Pyomo] <em>Das Referenzbuch der Autoren zur mächtigsten der drei im Buch verglichenen Modellierungsschichten.</em></li>
|
||||
<li>★★ <strong>Hofmann, F. (2023):</strong> <em><a href="anhang-glossar.md#gloss:linopy" class="glossar-link">Linopy</a>: Linear optimization with n-dimensional labeled variables.</em> In: <em>Journal of Open Source Software</em> 8(84), 4823. DOI: 10.21105/joss.04823 [Bibliothek: linopy] <em>Beschreibt den beschrifteten-Achsen-Ansatz und enthält den Speicher- und Geschwindigkeitsvergleich gegen Pyomo, PuLP, CVXPY und gurobipy. Frei zugänglich.</em></li>
|
||||
<li>★★ <strong>Virtanen, P., Gommers, R., Oliphant, T. E. et al. (2020):</strong> <em><a href="anhang-glossar.md#gloss:scipy" class="glossar-link">SciPy</a> 1.0: fundamental algorithms for scientific computing in Python.</em> In: <em>Nature Methods</em> 17, S. 261–272. DOI: 10.1038/s41592-019-0686-2 [Bibliothek: SciPy] <em>Die zitierfähige Quelle zu <code>scipy.optimize</code> — dem Einstiegspunkt in <a href="lp.html#kap-lp">Kapitel 5</a>.</em></li>
|
||||
<li>★★ <strong>Harris, C. R., Millman, K. J., van der Walt, S. J. et al. (2020):</strong> <em>Array programming with <a href="anhang-glossar.md#gloss:numpy" class="glossar-link">NumPy</a>.</em> In: <em>Nature</em> 585, S. 357–362. DOI: 10.1038/s41586-020-2649-2 [Bibliothek: NumPy] <em>Grundlage jeder vektorisierten Modellerzeugung; siehe den Abschnitt über den Aufbau großer Modelle.</em></li>
|
||||
</ul>
|
||||
<h2 id="lineare-und-ganzzahlige-optimierung">Lineare und ganzzahlige Optimierung</h2>
|
||||
<p><em>Zu <a href="lp.html#kap-lp">Kapitel 5</a> und <a href="milp.html#kap-milp">Kapitel 6</a>.</em></p>
|
||||
<ul>
|
||||
<li>★★★ <strong>Wolsey, L. A. (2020):</strong> <em>Integer Programming</em> (2. Aufl.). Wiley, Hoboken. DOI: 10.1002/9781119606475 [Ganzzahlige Optimierung] <em>Branch-and-Bound, Branch-and-Cut, Polyedertheorie, Formulierungsstärke. Die Begründung dafür, warum ein kleines <span class="math inline">M</span> besser ist als ein großes.</em></li>
|
||||
<li>★★★ <strong>Wolsey, L. A. (2020):</strong> <em>Integer Programming</em> (2. Aufl.). Wiley, Hoboken. DOI: 10.1002/9781119606475 [Ganzzahlige Optimierung] <em><a href="anhang-glossar.md#gloss:branch-and-bound" class="glossar-link">Branch-and-Bound</a>, <a href="anhang-glossar.md#gloss:branch-and-cut" class="glossar-link">Branch-and-Cut</a>, Polyedertheorie, Formulierungsstärke. Die Begründung dafür, warum ein kleines <span class="math inline">M</span> besser ist als ein großes.</em></li>
|
||||
<li>★★★ <strong>Conforti, M., Cornuéjols, G. & Zambelli, G. (2014):</strong> <em>Integer Programming.</em> Springer, Cham. DOI: 10.1007/978-3-319-11008-0 [Ganzzahlige Optimierung] <em>Modernere Darstellung als Wolsey, mit ausführlicher Behandlung von Schnittebenen und totaler Unimodularität.</em></li>
|
||||
<li>★★ <strong>Klotz, E. & Newman, A. M. (2013):</strong> <em>Practical guidelines for solving difficult mixed integer linear programs.</em> In: <em>Surveys in Operations Research and Management Science</em> 18(1–2), S. 18–32. DOI: 10.1016/j.sorms.2012.12.001 [Ganzzahlige Optimierung] <em>Was zu tun ist, wenn ein Modell nicht fertig rechnet — Skalierung, Formulierung, Symmetrie. Die Literaturgrundlage von <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a>.</em></li>
|
||||
<li>★★ <strong>Achterberg, T. (2009):</strong> <em>SCIP: solving constraint integer programs.</em> In: <em>Mathematical Programming Computation</em> 1(1), S. 1–41. DOI: 10.1007/s12532-008-0001-1 [Solver: SCIP] <em>Beschreibt die Verbindung von MILP und Constraint Programming in einem Solver.</em></li>
|
||||
<li>★★ <strong>Achterberg, T. (2009):</strong> <em><a href="anhang-glossar.md#gloss:scip" class="glossar-link">SCIP</a>: solving constraint integer programs.</em> In: <em>Mathematical Programming Computation</em> 1(1), S. 1–41. DOI: 10.1007/s12532-008-0001-1 [<a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a>: SCIP] <em>Beschreibt die Verbindung von <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> und Constraint Programming in einem Solver.</em></li>
|
||||
</ul>
|
||||
<h2 id="moderne-solver-implementierung-vergleich-und-benchmarks">Moderne Solver: Implementierung, Vergleich und Benchmarks</h2>
|
||||
<p><em>Zu <a href="oekosystem.html#kap-oekosystem">Kapitel 3</a> und <a href="anhang-spickzettel.html#anhang-spickzettel">Anhang D</a>. Neuer Abschnitt: Das Buch vergleicht durchgehend Solver, die Literatur dazu stand bisher verstreut.</em></p>
|
||||
<ul>
|
||||
<li>★★★ <strong>Huangfu, Q. & Hall, J. A. J. (2018):</strong> <em>Parallelizing the dual revised simplex method.</em> In: <em>Mathematical Programming Computation</em> 10(1), S. 119–142. DOI: 10.1007/s12532-017-0130-5 [Solver: HiGHS] <em>Die vom HiGHS-Projekt selbst benannte Zitierquelle. HiGHS ist das Backend von <code>scipy.optimize.linprog</code> und CVXPY. <a href="https://highs.dev">highs.dev</a></em></li>
|
||||
<li>★★★ <strong>Huangfu, Q. & Hall, J. A. J. (2018):</strong> <em>Parallelizing the dual revised simplex method.</em> In: <em>Mathematical Programming Computation</em> 10(1), S. 119–142. DOI: 10.1007/s12532-017-0130-5 [Solver: <a href="anhang-glossar.md#gloss:highs" class="glossar-link">HiGHS</a>] <em>Die vom HiGHS-Projekt selbst benannte Zitierquelle. HiGHS ist das Backend von <code>scipy.optimize.linprog</code> und CVXPY. <a href="https://highs.dev">highs.dev</a></em></li>
|
||||
<li>★★★ <strong>Gleixner, A., Hendel, G., Gamrath, G. et al. (2021):</strong> <em>MIPLIB 2017: data-driven compilation of the 6th mixed-integer programming library.</em> In: <em>Mathematical Programming Computation</em> 13(3), S. 443–490. DOI: 10.1007/s12532-020-00194-3 [Benchmarks] <em>Die Testmenge, auf der praktisch jeder Solververgleich beruht: 1065 Instanzen, davon 240 als Benchmark-Teilmenge. Frei zugänglich; Daten unter <a href="https://miplib.zib.de">miplib.zib.de</a>.</em></li>
|
||||
<li>★★★ <strong>Mittelmann, H. D.:</strong> <em>Benchmarks for Optimization Software.</em> Arizona State University. <a href="https://plato.asu.edu/bench.html">plato.asu.edu/bench.html</a> [Benchmarks] <em>Die laufend aktualisierte Referenzmessung für LP-, MILP- und QP-Solver. <strong>Wichtige Einschränkung:</strong> Seit 2024 sind die kommerziellen Solver auf eigenen Wunsch nicht mehr enthalten; ein direkter Vergleich Gurobi gegen HiGHS ist dort nicht mehr möglich.</em></li>
|
||||
<li>★★★ <strong>Mittelmann, H. D.:</strong> <em>Benchmarks for Optimization Software.</em> Arizona State University. <a href="https://plato.asu.edu/bench.html">plato.asu.edu/bench.html</a> [Benchmarks] <em>Die laufend aktualisierte Referenzmessung für <a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a>-, MILP- und <a href="anhang-glossar.md#gloss:quadratische-programmierung-qp" class="glossar-link">QP</a>-Solver. <strong>Wichtige Einschränkung:</strong> Seit 2024 sind die kommerziellen Solver auf eigenen Wunsch nicht mehr enthalten; ein direkter Vergleich <a href="anhang-glossar.md#gloss:gurobi" class="glossar-link">Gurobi</a> gegen HiGHS ist dort nicht mehr möglich.</em></li>
|
||||
<li>★★ <strong>Bolusani, S., Besançon, M., Bestuzheva, K. et al. (2024):</strong> <em>The SCIP Optimization Suite 9.0.</em> Technischer Bericht, Zuse-Institut Berlin. arXiv:2402.17702 [Solver: SCIP] <em>Beschreibt Aufbau und Komponenten der Suite. Die Reihe wird fortgeschrieben — die jeweils aktuelle Fassung steht unter <a href="https://www.scipopt.org">scipopt.org</a>; beim Zitieren die tatsächlich benutzte Version angeben.</em></li>
|
||||
<li>★★ <strong>Perron, L. & Furnon, V.:</strong> <em>OR-Tools.</em> Google. <a href="https://developers.google.com/optimization">developers.google.com/optimization</a> · Quellcode: <a href="https://github.com/google/or-tools">github.com/google/or-tools</a> [Solver: OR-Tools] <em>Die Sammlung, aus der das Buch CP-SAT und die Routing-Bibliothek benutzt.</em></li>
|
||||
<li>★★ <strong>Perron, L. & Furnon, V.:</strong> <em><a href="anhang-glossar.md#gloss:or-tools" class="glossar-link">OR-Tools</a>.</em> Google. <a href="https://developers.google.com/optimization">developers.google.com/optimization</a> · Quellcode: <a href="https://github.com/google/or-tools">github.com/google/or-tools</a> [Solver: OR-Tools] <em>Die Sammlung, aus der das Buch <a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a> und die <a href="anhang-glossar.md#gloss:routing-bibliothek" class="glossar-link">Routing-Bibliothek</a> benutzt.</em></li>
|
||||
</ul>
|
||||
<h2 id="constraint-programming-und-scheduling">Constraint Programming und Scheduling</h2>
|
||||
<p><em>Zu <a href="cpsat.html#kap-cpsat">Kapitel 7</a>.</em></p>
|
||||
<ul>
|
||||
<li>★★★ <strong>Rossi, F., van Beek, P. & Walsh, T. (Hrsg., 2006):</strong> <em>Handbook of Constraint Programming.</em> Foundations of Artificial Intelligence, Bd. 2. Elsevier, Amsterdam. [Constraint Programming] <em>Nach wie vor das Referenzwerk zu Propagation, globalen Constraints und Suchstrategien.</em></li>
|
||||
<li>★★★ <strong>Perron, L. & Furnon, V.:</strong> <em>OR-Tools CP-SAT Solver Documentation.</em> Google. <a href="https://developers.google.com/optimization/cp">developers.google.com/optimization/cp</a> [Solver: CP-SAT] <em>Die einzige vollständige Beschreibung des im Buch benutzten Solvers. Der Abschnitt zu <code>AddNoOverlap</code> und <code>AddCumulative</code> deckt sich mit <a href="cpsat.html#kap-cpsat">Kapitel 7</a>.</em></li>
|
||||
<li>★★ <strong>Laborie, P., Rogerie, J., Shaw, P. & Vilím, P. (2018):</strong> <em>IBM ILOG CP Optimizer for scheduling.</em> In: <em>Constraints</em> 23(2), S. 210–250. DOI: 10.1007/s10601-018-9281-x [Scheduling] <em>Intervallvariablen und Ressourcenprofile aus Sicht des konkurrierenden Solvers — lehrreich für das Verständnis der Modellierungsprimitive.</em></li>
|
||||
<li>★★★ <strong>Perron, L. & Furnon, V.:</strong> <em>OR-Tools <a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a> Solver Documentation.</em> Google. <a href="https://developers.google.com/optimization/cp">developers.google.com/optimization/cp</a> [Solver: CP-SAT] <em>Die einzige vollständige Beschreibung des im Buch benutzten Solvers. Der Abschnitt zu <code>AddNoOverlap</code> und <code>AddCumulative</code> deckt sich mit <a href="cpsat.html#kap-cpsat">Kapitel 7</a>.</em></li>
|
||||
<li>★★ <strong>Laborie, P., Rogerie, J., Shaw, P. & Vilím, P. (2018):</strong> <em>IBM ILOG CP Optimizer for scheduling.</em> In: <em>Constraints</em> 23(2), S. 210–250. DOI: 10.1007/s10601-018-9281-x [<a href="anhang-glossar.md#gloss:scheduling" class="glossar-link">Scheduling</a>] <em>Intervallvariablen und Ressourcenprofile aus Sicht des konkurrierenden Solvers — lehrreich für das Verständnis der Modellierungsprimitive.</em></li>
|
||||
<li>★★ <strong>Biere, A., Heule, M., van Maaren, H. & Walsh, T. (Hrsg., 2021):</strong> <em>Handbook of Satisfiability</em> (2. Aufl.). Frontiers in Artificial Intelligence and Applications, Bd. 336. IOS Press, Amsterdam. DOI: 10.3233/FAIA336 [SAT] <em>Die Grundlage dessen, was CP-SAT unter der Haube tut: Conflict-Driven Clause Learning, Klausellernen, Neustarts.</em></li>
|
||||
</ul>
|
||||
<h2 id="graphen-flüsse-und-tourenplanung">Graphen, Flüsse und Tourenplanung</h2>
|
||||
<p><em>Zu <a href="graphen.html#kap-graphen">Kapitel 8</a>. Neuer Abschnitt.</em></p>
|
||||
<ul>
|
||||
<li>★★★ <strong>Ahuja, R. K., Magnanti, T. L. & Orlin, J. B. (1993):</strong> <em>Network Flows: Theory, Algorithms, and Applications.</em> Prentice Hall, Englewood Cliffs. [Netzwerkflüsse] <em>Das Standardwerk zu Min-Cost-Flow, Matching und totaler Unimodularität — der Grund, warum diese Modelle schon als LP ganzzahlig lösen.</em></li>
|
||||
<li>★★★ <strong>Toth, P. & Vigo, D. (Hrsg., 2014):</strong> <em>Vehicle Routing: Problems, Methods, and Applications</em> (2. Aufl.). SIAM, Philadelphia. DOI: 10.1137/1.9781611973594 [VRP] <em>Das Referenzwerk zur Tourenplanung, einschließlich Kapazitäten, Zeitfenstern und Subtour-Eliminierung.</em></li>
|
||||
<li>★★★ <strong>Toth, P. & Vigo, D. (Hrsg., 2014):</strong> <em>Vehicle Routing: Problems, Methods, and Applications</em> (2. Aufl.). SIAM, Philadelphia. DOI: 10.1137/1.9781611973594 [<a href="anhang-glossar.md#gloss:vehicle-routing-problem-vrp" class="glossar-link">VRP</a>] <em>Das Referenzwerk zur Tourenplanung, einschließlich Kapazitäten, Zeitfenstern und <a href="anhang-glossar.md#gloss:subtour" class="glossar-link">Subtour</a>-Eliminierung.</em></li>
|
||||
<li>★★ <strong>Vidal, T., Laporte, G. & Matl, P. (2020):</strong> <em>A concise guide to existing and emerging vehicle routing problem variants.</em> In: <em>European Journal of Operational Research</em> 286(2), S. 401–416. DOI: 10.1016/j.ejor.2019.10.010 [VRP] <em>Übersicht über die Variantenvielfalt — hilfreich, um die eigene Aufgabe einzuordnen, bevor man modelliert. Frei zugänglich als arXiv:1906.06750.</em></li>
|
||||
<li>★ <strong>Kuhn, H. W. (1955):</strong> <em>The Hungarian method for the assignment problem.</em> In: <em>Naval Research Logistics Quarterly</em> 2(1–2), S. 83–97. DOI: 10.1002/nav.3800020109 [Zuordnungsproblem] <em>Das Originalverfahren hinter <code>scipy.optimize.linear_sum_assignment</code>.</em></li>
|
||||
<li>★ <strong>Kuhn, H. W. (1955):</strong> <em>The Hungarian method for the assignment problem.</em> In: <em>Naval Research Logistics Quarterly</em> 2(1–2), S. 83–97. DOI: 10.1002/nav.3800020109 [<a href="anhang-glossar.md#gloss:zuordnungsproblem" class="glossar-link">Zuordnungsproblem</a>] <em>Das Originalverfahren hinter <code>scipy.optimize.linear_sum_assignment</code>.</em></li>
|
||||
</ul>
|
||||
<h2 id="metaheuristiken">Metaheuristiken</h2>
|
||||
<p><em>Zu <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a>. Neuer Abschnitt.</em></p>
|
||||
<ul>
|
||||
<li>★★★ <strong>Gendreau, M. & Potvin, J.-Y. (Hrsg., 2019):</strong> <em>Handbook of Metaheuristics</em> (3. Aufl.). Springer, Cham. DOI: 10.1007/978-3-319-91086-4 <a href="#metaheuristiken">Metaheuristiken</a> <em>Sammelband zu Tabu-Suche, Simulated Annealing, LNS, genetischen Verfahren — jeweils von den Urhebern geschrieben.</em></li>
|
||||
<li>★★★ <strong>Gendreau, M. & Potvin, J.-Y. (Hrsg., 2019):</strong> <em>Handbook of Metaheuristics</em> (3. Aufl.). Springer, Cham. DOI: 10.1007/978-3-319-91086-4 <a href="#metaheuristiken">Metaheuristiken</a> <em>Sammelband zu <a href="anhang-glossar.md#gloss:tabu-suche" class="glossar-link">Tabu-Suche</a>, <a href="anhang-glossar.md#gloss:simulated-annealing" class="glossar-link">Simulated Annealing</a>, <a href="anhang-glossar.md#gloss:large-neighborhood-search-lns" class="glossar-link">LNS</a>, genetischen Verfahren — jeweils von den Urhebern geschrieben.</em></li>
|
||||
<li>★★★ <strong>Pisinger, D. & Ropke, S. (2010):</strong> <em>Large Neighborhood Search.</em> In: Gendreau, M. & Potvin, J.-Y. (Hrsg.): <em>Handbook of Metaheuristics</em>, S. 399–419. Springer. DOI: 10.1007/978-1-4419-1665-5_13 <a href="#metaheuristiken">Metaheuristiken</a> <em>Die Darstellung des Verfahrens, das im Buch die exakte Suche auf Teilproblemen mit heuristischem Zerstören verbindet.</em></li>
|
||||
<li>★★ <strong>Kirkpatrick, S., Gelatt, C. D. & Vecchi, M. P. (1983):</strong> <em>Optimization by Simulated Annealing.</em> In: <em>Science</em> 220(4598), S. 671–680. DOI: 10.1126/science.220.4598.671 <a href="#metaheuristiken">Metaheuristiken</a> <em>Die Originalarbeit; die Abkühlungsanalogie stammt von hier.</em></li>
|
||||
<li>★★ <strong>Sörensen, K. (2015):</strong> <em>Metaheuristics — the metaphor exposed.</em> In: <em>International Transactions in Operational Research</em> 22(1), S. 3–18. DOI: 10.1111/itor.12001 <a href="#metaheuristiken">Metaheuristiken</a> <em>Kritik an der Flut naturanaloger „neuer” Verfahren. Vor der Auswahl einer Metaheuristik zu lesen — sie erspart viel Zeit.</em></li>
|
||||
<li>★★ <strong>Sörensen, K. (2015):</strong> <em>Metaheuristics — the metaphor exposed.</em> In: <em>International Transactions in Operational Research</em> 22(1), S. 3–18. DOI: 10.1111/itor.12001 <a href="#metaheuristiken">Metaheuristiken</a> <em>Kritik an der Flut naturanaloger „neuer” Verfahren. Vor der Auswahl einer <a href="anhang-glossar.md#gloss:metaheuristik" class="glossar-link">Metaheuristik</a> zu lesen — sie erspart viel Zeit.</em></li>
|
||||
</ul>
|
||||
<h2 id="spaltengenerierung-und-dekomposition">Spaltengenerierung und Dekomposition</h2>
|
||||
<p><em>Zu <a href="dekomposition.html#kap-dekomposition">Kapitel 10</a>. Neuer Abschnitt.</em></p>
|
||||
<ul>
|
||||
<li>★★★ <strong>Desaulniers, G., Desrosiers, J. & Solomon, M. M. (Hrsg., 2005):</strong> <em>Column Generation.</em> Springer, New York. DOI: 10.1007/b135457 [Spaltengenerierung] <em>Das Referenzwerk zum Verfahren, einschließlich Stabilisierung und Branch-and-Price.</em></li>
|
||||
<li>★★★ <strong>Desaulniers, G., Desrosiers, J. & Solomon, M. M. (Hrsg., 2005):</strong> <em><a href="anhang-glossar.md#gloss:column-generation" class="glossar-link">Column Generation</a>.</em> Springer, New York. DOI: 10.1007/b135457 [Spaltengenerierung] <em>Das Referenzwerk zum Verfahren, einschließlich Stabilisierung und Branch-and-Price.</em></li>
|
||||
<li>★★★ <strong>Lübbecke, M. E. & Desrosiers, J. (2005):</strong> <em>Selected Topics in Column Generation.</em> In: <em>Operations Research</em> 53(6), S. 1007–1023. DOI: 10.1287/opre.1050.0234 [Spaltengenerierung] <em>Kompakter als das Buch und für den Einstieg besser geeignet; erklärt das Preisproblem sauber.</em></li>
|
||||
<li>★★ <strong>Rahmaniani, R., Crainic, T. G., Gendreau, M. & Rei, W. (2017):</strong> <em>The Benders decomposition algorithm: A literature review.</em> In: <em>European Journal of Operational Research</em> 259(3), S. 801–817. DOI: 10.1016/j.ejor.2016.12.005 [Dekomposition] <em>Übersicht über Varianten und Beschleunigungen — die Gegenrichtung zur Spaltengenerierung.</em></li>
|
||||
</ul>
|
||||
<h2 id="konvexe-und-nichtlineare-optimierung">Konvexe und nichtlineare Optimierung</h2>
|
||||
<p><em>Zu <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a>.</em></p>
|
||||
<ul>
|
||||
<li>★★★ <strong>Boyd, S. & Vandenberghe, L. (2004):</strong> <em>Convex Optimization.</em> Cambridge University Press. DOI: 10.1017/CBO9780511804441 [Konvexe Optimierung] <em>Referenzwerk für konvexe Mengen, KKT-Bedingungen, QP und SDP; die theoretische Basis von CVXPY. Frei verfügbar unter <a href="https://web.stanford.edu/~boyd/cvxbook/">stanford.edu/~boyd/cvxbook</a>.</em></li>
|
||||
<li>★★ <strong>Kraft, D. (1988):</strong> <em>A Software Package for Sequential Quadratic Programming.</em> DFVLR-FB 88-28, Deutsche Forschungs- und Versuchsanstalt für Luft- und Raumfahrt, Köln. [Nichtlineare Optimierung] <em>Die Originalarbeit zu SLSQP — dem Verfahren hinter <code>scipy.optimize.minimize</code>.</em></li>
|
||||
<li>★★ <strong>Lobo, M. S., Vandenberghe, L., Boyd, S. & Lebret, H. (1998):</strong> <em>Applications of second-order cone programming.</em> In: <em>Linear Algebra and its Applications</em> 284(1–3), S. 193–228. DOI: 10.1016/S0024-3795(98)10032-0 [Konische Optimierung] <em>Warum sich Risikoschranken und Normbedingungen als SOCP schreiben lassen — die Grundlage der Chance-Constraints-Formulierung in <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a>.</em></li>
|
||||
<li>★★★ <strong>Boyd, S. & Vandenberghe, L. (2004):</strong> <em>Convex Optimization.</em> Cambridge University Press. DOI: 10.1017/CBO9780511804441 [Konvexe Optimierung] <em>Referenzwerk für konvexe Mengen, <a href="anhang-glossar.md#gloss:karush-kuhn-tucker-bedingungen-kkt" class="glossar-link">KKT</a>-Bedingungen, QP und SDP; die theoretische Basis von CVXPY. Frei verfügbar unter <a href="https://web.stanford.edu/~boyd/cvxbook/">stanford.edu/~boyd/cvxbook</a>.</em></li>
|
||||
<li>★★ <strong>Kraft, D. (1988):</strong> <em>A Software Package for Sequential Quadratic Programming.</em> DFVLR-FB 88-28, Deutsche Forschungs- und Versuchsanstalt für Luft- und Raumfahrt, Köln. [Nichtlineare Optimierung] <em>Die Originalarbeit zu <a href="anhang-glossar.md#gloss:slsqp" class="glossar-link">SLSQP</a> — dem Verfahren hinter <code>scipy.optimize.minimize</code>.</em></li>
|
||||
<li>★★ <strong>Lobo, M. S., Vandenberghe, L., Boyd, S. & Lebret, H. (1998):</strong> <em>Applications of second-order cone programming.</em> In: <em>Linear Algebra and its Applications</em> 284(1–3), S. 193–228. DOI: 10.1016/S0024-3795(98)10032-0 [<a href="anhang-glossar.md#gloss:konische-optimierung" class="glossar-link">Konische Optimierung</a>] <em>Warum sich Risikoschranken und Normbedingungen als SOCP schreiben lassen — die Grundlage der Chance-Constraints-Formulierung in <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a>.</em></li>
|
||||
</ul>
|
||||
<h2 id="optimierung-unter-unsicherheit-stochastisch-robust-chance-constraints">Optimierung unter Unsicherheit: stochastisch, robust, Chance Constraints</h2>
|
||||
<p><em>Zu <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a> und <a href="supplychain.html#kap-supplychain">Kapitel 17</a>. Aus dem früheren Block „Konvexe, nichtlineare und robuste Optimierung” herausgelöst und erweitert.</em></p>
|
||||
<ul>
|
||||
<li>★★★ <strong>Birge, J. R. & Louveaux, F. (2011):</strong> <em>Introduction to Stochastic Programming</em> (2. Aufl.). Springer, New York. DOI: 10.1007/978-1-4614-0237-4 [Stochastische Optimierung] <em>Das Standardwerk zur zweistufigen Optimierung, Szenariobäumen und dem Wert perfekter Information (EVPI).</em></li>
|
||||
<li>★★★ <strong>Ben-Tal, A., El Ghaoui, L. & Nemirovski, A. (2009):</strong> <em>Robust Optimization.</em> Princeton University Press. DOI: 10.1515/9781400831050 [Robuste Optimierung] <em>Die geschlossene Darstellung der robusten Gegenstücke und ihrer konischen Umformung.</em></li>
|
||||
<li>★★★ <strong>Bertsimas, D. & Sim, M. (2004):</strong> <em>The Price of Robustness.</em> In: <em>Operations Research</em> 52(1), S. 35–53. DOI: 10.1287/opre.1030.0065 [Robuste Optimierung] <em>Quelle des Budgeted-Uncertainty-Ansatzes: Der Parameter <span class="math inline">\Gamma</span> regelt stufenlos, wie vorsichtig die Lösung wird.</em></li>
|
||||
<li>★★★ <strong>Birge, J. R. & Louveaux, F. (2011):</strong> <em>Introduction to Stochastic Programming</em> (2. Aufl.). Springer, New York. DOI: 10.1007/978-1-4614-0237-4 [Stochastische Optimierung] <em>Das Standardwerk zur zweistufigen Optimierung, Szenariobäumen und dem Wert perfekter Information (<a href="anhang-glossar.md#gloss:evpi-expected-value-of-perfect-information" class="glossar-link">EVPI</a>).</em></li>
|
||||
<li>★★★ <strong>Ben-Tal, A., El Ghaoui, L. & Nemirovski, A. (2009):</strong> <em>Robust Optimization.</em> Princeton University Press. DOI: 10.1515/9781400831050 [<a href="anhang-glossar.md#gloss:robuste-optimierung" class="glossar-link">Robuste Optimierung</a>] <em>Die geschlossene Darstellung der robusten Gegenstücke und ihrer konischen Umformung.</em></li>
|
||||
<li>★★★ <strong>Bertsimas, D. & Sim, M. (2004):</strong> <em>The Price of Robustness.</em> In: <em>Operations Research</em> 52(1), S. 35–53. DOI: 10.1287/opre.1030.0065 [Robuste Optimierung] <em>Quelle des Budgeted-Uncertainty-Ansatzes: Der <a href="anhang-glossar.md#gloss:parameter" class="glossar-link">Parameter</a> <span class="math inline">\Gamma</span> regelt stufenlos, wie vorsichtig die Lösung wird.</em></li>
|
||||
<li>★★ <strong>Nemirovski, A. & Shapiro, A. (2007):</strong> <em>Convex Approximations of Chance Constrained Programs.</em> In: <em>SIAM Journal on Optimization</em> 17(4), S. 969–996. DOI: 10.1137/050622328 [Chance Constraints] <em>Zeigt, wann sich eine Wahrscheinlichkeitsbedingung konvex annähern lässt — und wann nicht.</em></li>
|
||||
<li>★★ <strong>Charnes, A. & Cooper, W. W. (1959):</strong> <em>Chance-Constrained Programming.</em> In: <em>Management Science</em> 6(1), S. 73–79. DOI: 10.1287/mnsc.6.1.73 [Chance Constraints] <em>Die Originalarbeit, die den Begriff geprägt hat.</em></li>
|
||||
<li>★★ <strong>Savage, S. L. (2009):</strong> <em>The Flaw of Averages.</em> Wiley, Hoboken. [Unsicherheit] <em>Die populäre Darstellung des Fluchs des Durchschnitts. Ohne Formeln, dafür mit den Beispielen, die in Besprechungen wirken.</em></li>
|
||||
|
|
@ -194,17 +194,17 @@
|
|||
<h2 id="dynamische-programmierung-und-sequenzielle-entscheidungen">Dynamische Programmierung und sequenzielle Entscheidungen</h2>
|
||||
<p><em>Zu <a href="dynamische-programmierung.html#kap-dynamische-programmierung">Kapitel 13</a>. Neuer Abschnitt.</em></p>
|
||||
<ul>
|
||||
<li>★★★ <strong>Powell, W. B. (2022):</strong> <em>Reinforcement Learning and Stochastic Optimization: A Unified Framework for Sequential Decisions.</em> Wiley, Hoboken. DOI: 10.1002/9781119815068 [Dynamische Programmierung] <em>Ordnet dynamische Programmierung, approximative Verfahren und bestärkendes Lernen in einen gemeinsamen Rahmen — genau die Einordnung, die <a href="dynamische-programmierung.html#kap-dynamische-programmierung">Kapitel 13</a> am Schluss vornimmt.</em></li>
|
||||
<li>★★★ <strong>Bertsekas, D. P. (2017):</strong> <em>Dynamic Programming and Optimal Control, Vol. I</em> (4. Aufl.). Athena Scientific, Belmont. [Dynamische Programmierung] <em>Die mathematisch strenge Darstellung des Optimalitätsprinzips und der Rückwärtsinduktion.</em></li>
|
||||
<li>★★★ <strong>Powell, W. B. (2022):</strong> <em><a href="anhang-glossar.md#gloss:reinforcement-learning" class="glossar-link">Reinforcement Learning</a> and Stochastic Optimization: A Unified Framework for Sequential Decisions.</em> Wiley, Hoboken. DOI: 10.1002/9781119815068 [Dynamische Programmierung] <em>Ordnet dynamische Programmierung, approximative Verfahren und bestärkendes Lernen in einen gemeinsamen Rahmen — genau die Einordnung, die <a href="dynamische-programmierung.html#kap-dynamische-programmierung">Kapitel 13</a> am Schluss vornimmt.</em></li>
|
||||
<li>★★★ <strong>Bertsekas, D. P. (2017):</strong> <em>Dynamic Programming and Optimal Control, Vol. I</em> (4. Aufl.). Athena Scientific, Belmont. [Dynamische Programmierung] <em>Die mathematisch strenge Darstellung des Optimalitätsprinzips und der <a href="anhang-glossar.md#gloss:rueckwaertsinduktion" class="glossar-link">Rückwärtsinduktion</a>.</em></li>
|
||||
<li>★★ <strong>Sutton, R. S. & Barto, A. G. (2018):</strong> <em>Reinforcement Learning: An Introduction</em> (2. Aufl.). MIT Press, Cambridge. [Reinforcement Learning] <em>Der Standardtext zum lernenden Gegenstück. Frei verfügbar auf der Seite der Autoren.</em></li>
|
||||
<li>★ <strong>Bellman, R. (1957):</strong> <em>Dynamic Programming.</em> Princeton University Press. [Historisch] <em>Das Originalwerk. Für die praktische Arbeit heute durch Powell und Bertsekas ersetzt.</em></li>
|
||||
</ul>
|
||||
<h2 id="mehrkriterielle-optimierung">Mehrkriterielle Optimierung</h2>
|
||||
<p><em>Zu <a href="mehrziel.html#kap-mehrziel">Kapitel 14</a>. Neuer Abschnitt.</em></p>
|
||||
<ul>
|
||||
<li>★★★ <strong>Ehrgott, M. (2005):</strong> <em>Multicriteria Optimization</em> (2. Aufl.). Springer, Berlin. DOI: 10.1007/3-540-27659-9 <a href="#mehrkriterielle-optimierung">Mehrkriterielle Optimierung</a> <em>Pareto-Optimalität, Skalarisierung und ihre Grenzen — insbesondere die Frage, welche Punkte der Front eine gewichtete Summe überhaupt erreichen kann.</em></li>
|
||||
<li>★★★ <strong>Ehrgott, M. (2005):</strong> <em>Multicriteria Optimization</em> (2. Aufl.). Springer, Berlin. DOI: 10.1007/3-540-27659-9 <a href="#mehrkriterielle-optimierung">Mehrkriterielle Optimierung</a> <em>Pareto-Optimalität, <a href="anhang-glossar.md#gloss:skalarisierung" class="glossar-link">Skalarisierung</a> und ihre Grenzen — insbesondere die Frage, welche Punkte der Front eine gewichtete Summe überhaupt erreichen kann.</em></li>
|
||||
<li>★★ <strong>Miettinen, K. (1999):</strong> <em>Nonlinear Multiobjective Optimization.</em> Kluwer, Boston. DOI: 10.1007/978-1-4615-5563-6 <a href="#mehrkriterielle-optimierung">Mehrkriterielle Optimierung</a> <em>Systematik der Verfahren, geordnet danach, wann die Präferenz des Entscheiders einfließt.</em></li>
|
||||
<li>★★ <strong>Blank, J. & Deb, K. (2020):</strong> <em>pymoo: Multi-Objective Optimization in Python.</em> In: <em>IEEE Access</em> 8, S. 89497–89509. DOI: 10.1109/ACCESS.2020.2990567 [Bibliothek: pymoo] <em>Die im Buch für evolutionäre Pareto-Fronten benutzte Bibliothek. <a href="https://pymoo.org">pymoo.org</a></em></li>
|
||||
<li>★★ <strong>Blank, J. & Deb, K. (2020):</strong> <em><a href="anhang-glossar.md#gloss:pymoo" class="glossar-link">pymoo</a>: <a href="anhang-glossar.md#gloss:multi-objective-optimization" class="glossar-link">Multi-Objective Optimization</a> in Python.</em> In: <em>IEEE Access</em> 8, S. 89497–89509. DOI: 10.1109/ACCESS.2020.2990567 [Bibliothek: pymoo] <em>Die im Buch für evolutionäre Pareto-Fronten benutzte Bibliothek. <a href="https://pymoo.org">pymoo.org</a></em></li>
|
||||
</ul>
|
||||
<h2 id="lernbasierte-optimierung-maschinelles-lernen-und-or">Lernbasierte Optimierung: maschinelles Lernen und OR</h2>
|
||||
<p><em>Zu <a href="prognose.html#kap-prognose">Kapitel 15</a>. Neuer Abschnitt — im Buch als eigenes Kapitel behandelt, in der Literaturliste bisher gar nicht vertreten.</em></p>
|
||||
|
|
@ -226,21 +226,21 @@
|
|||
<p><em>Zu <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a>, <a href="markowitz.html#kap-markowitz">Kapitel 19</a>, <a href="cvar.html#kap-cvar">Kapitel 20</a> und <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a>.</em></p>
|
||||
<ul>
|
||||
<li>★★★ <strong>Markowitz, H. (1952):</strong> <em>Portfolio Selection.</em> In: <em>The Journal of Finance</em> 7(1), S. 77–91. DOI: 10.2307/2975974 [Portfoliotheorie] <em>Die Arbeit, die das Zusammenspiel von Rendite und Kovarianz zum Optimierungsproblem gemacht hat.</em></li>
|
||||
<li>★★★ <strong>Rockafellar, R. T. & Uryasev, S. (2000):</strong> <em>Optimization of Conditional Value-at-Risk.</em> In: <em>Journal of Risk</em> 2(3), S. 21–41. DOI: 10.21314/JOR.2000.038 [Risikomaße] <em>Der Satz, der die CVaR-Minimierung in ein lineares Programm überführt.</em></li>
|
||||
<li>★★★ <strong>Rockafellar, R. T. & Uryasev, S. (2000):</strong> <em>Optimization of Conditional Value-at-Risk.</em> In: <em>Journal of Risk</em> 2(3), S. 21–41. DOI: 10.21314/JOR.2000.038 [Risikomaße] <em>Der Satz, der die <a href="anhang-glossar.md#gloss:conditional-value-at-risk-cvar" class="glossar-link">CVaR</a>-Minimierung in ein lineares Programm überführt.</em></li>
|
||||
<li>★★★ <strong>Ledoit, O. & Wolf, M. (2004):</strong> <em>A well-conditioned estimator for large-dimensional covariance matrices.</em> In: <em>Journal of Multivariate Analysis</em> 88(2), S. 365–411. DOI: 10.1016/S0047-259X(03)00096-4 [Kovarianzschätzung] <em>Quelle des von <code>scikit-learn</code> verwendeten Shrinkage-Ziels (skalierte Einheitsmatrix).</em></li>
|
||||
<li>★★★ <strong>Cornuéjols, G., Peña, J. & Tütüncü, R. (2018):</strong> <em>Optimization Methods in Finance</em> (2. Aufl.). Cambridge University Press. DOI: 10.1017/9781107297340 [Finanzoptimierung] <em>Die Brücke zwischen Optimierungstheorie und Finanzanwendung; deckt QP, SOCP und robuste Portfolios ab.</em></li>
|
||||
<li>★★★ <strong>Almgren, R. & Chriss, N. (2001):</strong> <em>Optimal Execution of Portfolio Transactions.</em> In: <em>Journal of Risk</em> 3(2), S. 5–39. DOI: 10.21314/jor.2001.041 [Orderausführung] <em>Das Modell hinter dem Beispiel zur optimalen Orderausführung in <a href="dynamische-programmierung.html#kap-dynamische-programmierung">Kapitel 13</a>.</em></li>
|
||||
<li>★★ <strong>Ledoit, O. & Wolf, M. (2003):</strong> <em>Improved estimation of the covariance matrix of stock returns with an application to portfolio selection.</em> In: <em>Journal of Empirical Finance</em> 10(5), S. 603–621. DOI: 10.1016/S0927-5398(03)00007-0 [Kovarianzschätzung] <em>Die frühere Arbeit mit dem Konstant-Korrelations-Ziel.</em></li>
|
||||
<li>★★ <strong>DeMiguel, V., Garlappi, L. & Uppal, R. (2009):</strong> <em>Optimal Versus Naive Diversification: How Inefficient is the 1/N Portfolio Strategy?</em> In: <em>Review of Financial Studies</em> 22(5), S. 1915–1953. DOI: 10.1093/rfs/hhm075 [Portfoliotheorie] <em>Die Studie, die 1/N als ernstzunehmenden Vergleichsmaßstab etabliert hat — der Grund, warum im Buch jeder Optimierer gegen sie antreten muss.</em></li>
|
||||
<li>★★ <strong>López de Prado, M. (2018):</strong> <em>Advances in Financial Machine Learning.</em> Wiley, Hoboken. [Backtesting] <em>Backtest-Overfitting, Deflated Sharpe Ratio, Denoising der Kovarianzmatrix. Die Literaturgrundlage der fünf Selbsttäuschungen des Backtestens.</em></li>
|
||||
<li>★★ <strong>López de Prado, M. (2018):</strong> <em>Advances in Financial Machine Learning.</em> Wiley, Hoboken. [Backtesting] <em><a href="anhang-glossar.md#gloss:backtest" class="glossar-link">Backtest</a>-<a href="anhang-glossar.md#gloss:overfitting" class="glossar-link">Overfitting</a>, Deflated <a href="anhang-glossar.md#gloss:sharpe-ratio" class="glossar-link">Sharpe Ratio</a>, Denoising der <a href="anhang-glossar.md#gloss:kovarianzmatrix" class="glossar-link">Kovarianzmatrix</a>. Die Literaturgrundlage der fünf Selbsttäuschungen des Backtestens.</em></li>
|
||||
<li>★★ <strong>Bailey, D. H. & López de Prado, M. (2014):</strong> <em>The Deflated Sharpe Ratio: Correcting for Selection Bias, Backtest Overfitting, and Non-Normality.</em> In: <em>The Journal of Portfolio Management</em> 40(5), S. 94–107. DOI: 10.3905/jpm.2014.40.5.094 [Backtesting] <em>Beziffert, wie stark eine Sharpe Ratio zu korrigieren ist, wenn man viele Strategien ausprobiert hat.</em></li>
|
||||
</ul>
|
||||
<h2 id="praxis-betrieb-test-und-auslieferung-von-optimierungsmodellen">Praxis: Betrieb, Test und Auslieferung von Optimierungsmodellen</h2>
|
||||
<p><em>Zu <a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a> und <a href="testing.html#kap-testing">Kapitel 23</a>. Neuer Abschnitt.</em></p>
|
||||
<ul>
|
||||
<li>★★★ <strong>Chinneck, J. W. (2008):</strong> <em>Feasibility and Infeasibility in Optimization: Algorithms and Computational Methods.</em> Springer, New York. DOI: 10.1007/978-0-387-74932-7 [Fehlerdiagnose] <em>Das Standardwerk zur Unlösbarkeitsdiagnose, einschließlich des Deletion Filters und der irreduziblen unlösbaren Teilmengen (IIS). Direkte Grundlage von <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a>.</em></li>
|
||||
<li>★★★ <strong>Chinneck, J. W. (2008):</strong> <em>Feasibility and <a href="anhang-glossar.md#gloss:infeasibility" class="glossar-link">Infeasibility</a> in Optimization: Algorithms and Computational Methods.</em> Springer, New York. DOI: 10.1007/978-0-387-74932-7 [Fehlerdiagnose] <em>Das Standardwerk zur Unlösbarkeitsdiagnose, einschließlich des Deletion Filters und der irreduziblen unlösbaren Teilmengen (<a href="anhang-glossar.md#gloss:iis-irreducible-infeasible-subset" class="glossar-link">IIS</a>). Direkte Grundlage von <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a>.</em></li>
|
||||
<li>★★ <strong>Sculley, D., Holt, G., Golovin, D. et al. (2015):</strong> <em>Hidden Technical Debt in Machine Learning Systems.</em> In: <em>Advances in Neural Information Processing Systems</em> 28, S. 2503–2511. [Betrieb] <em>Über Systeme, deren Modell nur ein kleiner Teil ist — überträgt sich unmittelbar auf den Betrieb von Optimierungsdiensten. Frei zugänglich.</em></li>
|
||||
<li>★★ <strong>Kleppmann, M. (2017):</strong> <em>Designing Data-Intensive Applications.</em> O’Reilly, Sebastopol. [Betrieb] <em>Snapshot-Prinzip, Zustandslosigkeit, Versionierung und Reproduzierbarkeit — die Architekturfragen hinter der OR-Plattform in <a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a>.</em></li>
|
||||
<li>★★ <strong>Kleppmann, M. (2017):</strong> <em>Designing Data-Intensive Applications.</em> O’Reilly, Sebastopol. [Betrieb] <em><a href="anhang-glossar.md#gloss:snapshot-prinzip" class="glossar-link">Snapshot-Prinzip</a>, <a href="anhang-glossar.md#gloss:zustandslosigkeit" class="glossar-link">Zustandslosigkeit</a>, Versionierung und Reproduzierbarkeit — die Architekturfragen hinter der OR-Plattform in <a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a>.</em></li>
|
||||
<li>★★ <strong>Ramírez, S.:</strong> <em>FastAPI Documentation.</em> <a href="https://fastapi.tiangolo.com">fastapi.tiangolo.com</a> [Betrieb] <em>Die Grundlage des Optimierungsdienstes in <a href="testing.html#kap-testing">Kapitel 23</a>, einschließlich der Eingabevalidierung über <code>pydantic</code>.</em></li>
|
||||
</ul>
|
||||
<h2 id="software-dokumentation-und-datenquellen">Software, Dokumentation und Datenquellen</h2>
|
||||
|
|
@ -252,7 +252,7 @@
|
|||
<li><strong>Pyomo:</strong> <a href="https://www.pyomo.org">pyomo.org</a></li>
|
||||
<li><strong>linopy:</strong> <a href="https://linopy.readthedocs.io">linopy.readthedocs.io</a></li>
|
||||
<li><strong>pymoo:</strong> <a href="https://pymoo.org">pymoo.org</a></li>
|
||||
<li><strong>scikit-learn, Covariance Estimation:</strong> <a href="https://scikit-learn.org/stable/modules/covariance.html">scikit-learn.org/stable/modules/covariance.html</a></li>
|
||||
<li><strong><a href="anhang-glossar.md#gloss:scikit-learn" class="glossar-link">scikit-learn</a>, Covariance Estimation:</strong> <a href="https://scikit-learn.org/stable/modules/covariance.html">scikit-learn.org/stable/modules/covariance.html</a></li>
|
||||
<li><strong>MIPLIB 2017 — Instanzensammlung:</strong> <a href="https://miplib.zib.de">miplib.zib.de</a></li>
|
||||
<li><strong>Mittelmann-Benchmarks:</strong> <a href="https://plato.asu.edu/bench.html">plato.asu.edu/bench.html</a></li>
|
||||
</ul>
|
||||
|
|
@ -261,7 +261,7 @@
|
|||
<li><strong>INFORMS</strong> — Institute for Operations Research and the Management Sciences. <a href="https://www.informs.org">www.informs.org</a></li>
|
||||
<li><strong>GOR</strong> — Gesellschaft für Operations Research e. V., deutschsprachiger Fachverband. <a href="https://www.gor-ev.de">www.gor-ev.de</a></li>
|
||||
<li><strong>EURO</strong> — Association of European Operational Research Societies. <a href="https://www.euro-online.org">www.euro-online.org</a></li>
|
||||
<li><strong>Basel Committee on Banking Supervision:</strong> <em>Minimum capital requirements for market risk</em> (Basel III, FRTB). Bank for International Settlements. <em>Grundlage der aufsichtsrechtlichen Umstellung von Value at Risk auf Expected Shortfall.</em></li>
|
||||
<li><strong>Basel Committee on Banking Supervision:</strong> <em>Minimum capital requirements for market risk</em> (Basel III, FRTB). Bank for International Settlements. <em>Grundlage der aufsichtsrechtlichen Umstellung von Value at Risk auf <a href="anhang-glossar.md#gloss:expected-shortfall" class="glossar-link">Expected Shortfall</a>.</em></li>
|
||||
<li><strong>Europäische Union:</strong> <em>MiFID II</em> (Richtlinie 2014/65/EU) sowie die ESMA-Leitlinien zum algorithmischen Handel. <em>Regulatorischer Rahmen für die Handelsmaschine aus <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a>.</em></li>
|
||||
</ul>
|
||||
<h2 id="änderungsprotokoll">Änderungsprotokoll</h2>
|
||||
|
|
@ -269,7 +269,7 @@
|
|||
<p><strong>Entfernt: kein einziger Eintrag.</strong> Alle 27 Einträge der Vorgängerfassung wurden geprüft; sie sind korrekt zitiert, in ihrem Feld weiterhin maßgeblich und nicht redundant zueinander. Es gab damit keine Streichkandidaten. Zwei Einträge sind jedoch auf <strong>★ optional</strong> herabgestuft, weil sie historisch bedeutend, für die tägliche Arbeit aber entbehrlich sind: Dantzig (1963) und Bellman (1957) — beide inzwischen durch modernere Darstellungen ersetzt, die im selben Block stehen. Hillier & Lieberman (2021) bleibt bei ★★, ist aber ausdrücklich als Überblickswerk ohne Python-Bezug gekennzeichnet.</p>
|
||||
<p><strong>Neu aufgenommen: 60 Einträge</strong> — von 27 auf 87. Davon sind 72 mit einer Relevanzangabe versehen (34 × ★★★, 35 × ★★, 3 × ★); die übrigen 15 sind Softwareverweise, Datenquellen und Institutionen ohne Autorenschaft. 63 Einträge tragen eine Jahresangabe, 22 davon stammen aus 2018 oder später.</p>
|
||||
<p><strong>Zur Vorgabe „bevorzugt Werke ab 2018”:</strong> Sie ließ sich nur teilweise einlösen, und zwar aus der Sache heraus. In weiten Teilen des Operations Research sind die maßgeblichen Werke älter — Ahuja/Magnanti/Orlin (1993) zu Netzwerkflüssen, Boyd/Vandenberghe (2004) zur konvexen Optimierung, Ehrgott (2005) zur Mehrkriterialität, Birge/Louveaux (2011) zur stochastischen Programmierung. Sie durch jüngere, aber weniger maßgebliche Titel zu ersetzen hätte die Liste verschlechtert. Neuer als 2018 ist konsequent dort, wo sich das Feld tatsächlich bewegt hat: Solver-Benchmarks, Python-Bibliotheken und lernbasierte Optimierung.</p>
|
||||
<p><strong>Neue Themenabschnitte: zwölf.</strong> Sie entsprechen Kapiteln, die in der Vorgängerfassung keinen eigenen Literaturblock hatten: <em>Modellierung in Python</em>, <em>Lineare und ganzzahlige Optimierung</em>, <em>Moderne Solver und Benchmarks</em>, <em>Graphen, Flüsse und Tourenplanung</em>, <em>Metaheuristiken</em>, <em>Spaltengenerierung und Dekomposition</em>, <em>Optimierung unter Unsicherheit</em>, <em>Dynamische Programmierung</em>, <em>Mehrkriterielle Optimierung</em>, <em>Lernbasierte Optimierung</em>, <em>Supply Chain, Energie und Produktionsplanung</em> sowie <em>Praxis: Betrieb, Test und Auslieferung</em>. Der frühere Block „Konvexe, nichtlineare und robuste Optimierung” wurde dabei geteilt, weil das Buch Unsicherheit in einem eigenen Kapitel behandelt.</p>
|
||||
<p><strong>Neue Themenabschnitte: zwölf.</strong> Sie entsprechen Kapiteln, die in der Vorgängerfassung keinen eigenen Literaturblock hatten: <em>Modellierung in Python</em>, <em>Lineare und ganzzahlige Optimierung</em>, <em>Moderne Solver und Benchmarks</em>, <em><a href="anhang-glossar.md#gloss:graphen" class="glossar-link">Graphen</a>, Flüsse und Tourenplanung</em>, <em>Metaheuristiken</em>, <em>Spaltengenerierung und Dekomposition</em>, <em>Optimierung unter Unsicherheit</em>, <em>Dynamische Programmierung</em>, <em>Mehrkriterielle Optimierung</em>, <em>Lernbasierte Optimierung</em>, <em>Supply Chain, Energie und Produktionsplanung</em> sowie <em>Praxis: Betrieb, Test und Auslieferung</em>. Der frühere Block „Konvexe, nichtlineare und robuste Optimierung” wurde dabei geteilt, weil das Buch Unsicherheit in einem eigenen Kapitel behandelt.</p>
|
||||
<p><strong>Nicht angelegt wurden zwei erwogene Abschnitte:</strong> <em>Diskrete Ereignissimulation</em> und <em>Cloud-basierte Solver-Nutzung</em>. Beide Themen kommen im Buch nicht vor — eine Literaturliste soll das Buch erschließen und nicht darüber hinausweisen. Der API-gestützte Betrieb eines Solvers ist stattdessen im Praxisblock erfasst.</p>
|
||||
<h3 id="prüfung-gegen-crossref">Prüfung gegen Crossref</h3>
|
||||
<p>Alle Einträge wurden einzeln gegen die Crossref-API geprüft — bei einem Literaturverzeichnis ist eine erfundene oder falsch zitierte Quelle der schwerste Fehler, weil der Leser sie sucht und nicht findet.</p>
|
||||
|
|
|
|||
124
OR_HTML_04/anhang-loesungen.html
generated
124
OR_HTML_04/anhang-loesungen.html
generated
|
|
@ -106,9 +106,9 @@
|
|||
<hr />
|
||||
<h2 id="sec:loesungen-einfuehrung">A.1 Lösungen zu Kapitel „Einführung in Operations Research — Vom Ursprung zur mathematischen Entscheidungsfindung“</h2>
|
||||
<p><strong>1.1 — Analytik-Stufen.</strong> (a) deskriptiv (Vergangenheit beschreiben). (b) prädiktiv (Prognose). (c) <strong>präskriptiv</strong> (Handlungsanweisung unter Restriktionen). (d) prädiktiv (Klassifikation). (e) <strong>präskriptiv</strong> — hier kommt das begrenzte Budget ins Spiel, es muss zugeteilt werden. Beachten Sie das Paar (d)/(e): Die Prognose sagt, <em>wer</em> kündigen wird; die Optimierung sagt, <em>wen</em> man mit dem vorhandenen Geld halten kann.</p>
|
||||
<p><strong>1.2 — Hart oder weich?</strong> (a) <strong>hart</strong> — gesetzlich zwingend. (b) <strong>weich</strong> — Wunsch, mit Strafkosten. (c) <strong>hart</strong> — Patientensicherheit, rechtlich vorgeschrieben. (d) <strong>weich</strong> — Fairnessziel, über Strafterme. (e) <strong>hart</strong>, falls tariflich/gesetzlich fixiert, sonst weich mit sehr hoher Strafe. Faustregel: Hart ist nur, was rechtlich oder physikalisch unmöglich zu verletzen ist.</p>
|
||||
<p><strong>1.2 — Hart oder weich?</strong> (a) <strong>hart</strong> — gesetzlich zwingend. (b) <strong>weich</strong> — Wunsch, mit <a href="anhang-glossar.md#gloss:strafkosten" class="glossar-link">Strafkosten</a>. (c) <strong>hart</strong> — Patientensicherheit, rechtlich vorgeschrieben. (d) <strong>weich</strong> — Fairnessziel, über Strafterme. (e) <strong>hart</strong>, falls tariflich/gesetzlich fixiert, sonst weich mit sehr hoher Strafe. Faustregel: Hart ist nur, was rechtlich oder physikalisch unmöglich zu verletzen ist.</p>
|
||||
<p><strong>1.3 — Kombinatorik.</strong> (a) <span class="math inline">12! = 479\,001\,600</span>. (b) <span class="math inline">479\,001\,600 / 5\cdot10^6 \approx 95{,}8</span> Sekunden <span class="math inline">\approx 1{,}6</span> Minuten. (c) <span class="math inline">13! = 6\,227\,020\,800</span>; das sind <span class="math inline">1245</span> s <span class="math inline">\approx 20{,}8</span> Minuten — <strong>Faktor 13</strong>. Jeder weitere Auftrag multipliziert die Zeit mit der neuen Anzahl. (d) Eine Stunde <span class="math inline">= 3600</span> s <span class="math inline">\to 1{,}8\cdot10^{10}</span> Prüfungen. <span class="math inline">13! = 6{,}2\cdot10^9</span> ✓, <span class="math inline">14! = 8{,}7\cdot10^{10}</span> ✗. Also <strong>13 Aufträge</strong>.</p>
|
||||
<p><strong>1.4 — Modell lesen.</strong> (a) Variablen <span class="math inline">x_1, x_2 \ge 0</span>; Parameter <span class="math inline">(3,5)</span> und die Kapazitäten <span class="math inline">(4,12,18)</span>; Zielfunktion <span class="math inline">\max 3x_1+5x_2</span>; vier Nebenbedingungen inkl. Nichtnegativität. (b) <span class="math inline">(2,6)</span>: <span class="math inline">2\le4</span> ✓, <span class="math inline">12\le12</span> ✓, <span class="math inline">6+12=18\le18</span> ✓ → zulässig, <span class="math inline">Z=36</span>. <span class="math inline">(4,3)</span>: <span class="math inline">4\le4</span> ✓, <span class="math inline">6\le12</span> ✓, <span class="math inline">12+6=18\le18</span> ✓ → zulässig, <span class="math inline">Z=27</span>. (c) Beste ganzzahlige Lösung ist <span class="math inline">(2,6)</span> mit <span class="math inline">Z=36</span> — sie ist hier bereits ganzzahlig, weil die Ecke des Polyeders zufällig auf Gitterpunkten liegt.</p>
|
||||
<p><strong>1.4 — Modell lesen.</strong> (a) Variablen <span class="math inline">x_1, x_2 \ge 0</span>; <a href="anhang-glossar.md#gloss:parameter" class="glossar-link">Parameter</a> <span class="math inline">(3,5)</span> und die Kapazitäten <span class="math inline">(4,12,18)</span>; <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a> <span class="math inline">\max 3x_1+5x_2</span>; vier Nebenbedingungen inkl. Nichtnegativität. (b) <span class="math inline">(2,6)</span>: <span class="math inline">2\le4</span> ✓, <span class="math inline">12\le12</span> ✓, <span class="math inline">6+12=18\le18</span> ✓ → zulässig, <span class="math inline">Z=36</span>. <span class="math inline">(4,3)</span>: <span class="math inline">4\le4</span> ✓, <span class="math inline">6\le12</span> ✓, <span class="math inline">12+6=18\le18</span> ✓ → zulässig, <span class="math inline">Z=27</span>. (c) Beste ganzzahlige Lösung ist <span class="math inline">(2,6)</span> mit <span class="math inline">Z=36</span> — sie ist hier bereits ganzzahlig, weil die Ecke des Polyeders zufällig auf Gitterpunkten liegt.</p>
|
||||
<p><strong>1.5 — Bäckerei.</strong></p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> ortools.sat.python <span class="im">import</span> cp_model</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>m <span class="op">=</span> cp_model.CpModel()</span>
|
||||
|
|
@ -121,8 +121,8 @@
|
|||
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>s <span class="op">=</span> cp_model.CpSolver()<span class="op">;</span> s.Solve(m)</span></code></pre></div>
|
||||
<p><strong>Ergebnis:</strong> <span class="math inline">x_1 = 96</span> Brote, <span class="math inline">x_2 = 70</span> Zehnerpackungen, Deckungsbeitrag <strong>450,00 €</strong>.</p>
|
||||
<p>Probe: Mehl <span class="math inline">0{,}5\cdot96 + 0{,}6\cdot70 = 48 + 42 = 90</span> kg ✓ (voll ausgelastet); Ofen <span class="math inline">4\cdot96 + 3\cdot70 = 384+210 = 594 \le 600</span> ✓; Vertrag <span class="math inline">96 \ge 40</span> ✓; <span class="math inline">Z = 2{,}5\cdot96 + 3\cdot70 = 240 + 210 = 450</span> ✓.</p>
|
||||
<p><strong>Zwei lehrreiche Beobachtungen:</strong> 1. Die <strong>Vertragsbedingung <span class="math inline">x_1 \ge 40</span> ist nicht bindend</strong> — der Solver backt freiwillig 96 Brote. Wer aus der Aufgabenstellung schließt, die Mindestmenge werde „gerade so“ erfüllt, liegt falsch. 2. Das <strong>kontinuierliche</strong> Optimum <span class="math inline">(40;\ 116{,}67)</span> liefert <strong>denselben</strong> Zielwert 450. Das Problem hat also mehrere optimale Lösungen — die Zielfunktion verläuft parallel zur Mehlrestriktion (<span class="math inline">2{,}5/0{,}5 = 5 = 3{,}0/0{,}6</span>). Prüfen Sie das nach: Genau deshalb ist hier auch die ganzzahlige Lösung ohne Verlust erreichbar.</p>
|
||||
<p><strong>1.6 — Sensitivität durch Ausprobieren.</strong> Schleife über <code>RAM_GESAMT in range(54, 73, 2)</code>, jeweils Modell neu lösen. (a) Ab 62 GB steigt der Gewinn nicht mehr — dann bindet die <strong>vCPU</strong>-Grenze, RAM ist nicht mehr der Engpass. (b) Der Zuwachs je GB ist der <strong>Schattenpreis</strong> (<a href="lp.html#kap-lp">Kapitel 5</a>). Solange RAM bindet, liegt er bei 31,25 €/GB; danach fällt er auf 0.</p>
|
||||
<p><strong>Zwei lehrreiche Beobachtungen:</strong> 1. Die <strong>Vertragsbedingung <span class="math inline">x_1 \ge 40</span> ist nicht bindend</strong> — der <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> backt freiwillig 96 Brote. Wer aus der Aufgabenstellung schließt, die Mindestmenge werde „gerade so“ erfüllt, liegt falsch. 2. Das <strong>kontinuierliche</strong> Optimum <span class="math inline">(40;\ 116{,}67)</span> liefert <strong>denselben</strong> Zielwert 450. Das Problem hat also mehrere optimale Lösungen — die Zielfunktion verläuft parallel zur Mehlrestriktion (<span class="math inline">2{,}5/0{,}5 = 5 = 3{,}0/0{,}6</span>). Prüfen Sie das nach: Genau deshalb ist hier auch die ganzzahlige Lösung ohne Verlust erreichbar.</p>
|
||||
<p><strong>1.6 — Sensitivität durch Ausprobieren.</strong> Schleife über <code>RAM_GESAMT in range(54, 73, 2)</code>, jeweils Modell neu lösen. (a) Ab 62 GB steigt der Gewinn nicht mehr — dann bindet die <strong>vCPU</strong>-Grenze, RAM ist nicht mehr der Engpass. (b) Der Zuwachs je GB ist der <strong><a href="anhang-glossar.md#gloss:schattenpreis" class="glossar-link">Schattenpreis</a></strong> (<a href="lp.html#kap-lp">Kapitel 5</a>). Solange RAM bindet, liegt er bei 31,25 €/GB; danach fällt er auf 0.</p>
|
||||
<p><strong>1.7 — Eigenes Problem.</strong> Individuell. Prüfkriterien: Sind die Variablen wirklich <em>entscheidbar</em> (nicht bereits festgelegt)? Hat die Zielfunktion eine <strong>Einheit</strong>? Ist jede harte Bedingung wirklich unverhandelbar?</p>
|
||||
<h3 id="finde-den-denkfehler-die-schreinerei-verdoppelt-ihren-gewinn">Finde den Denkfehler — Die Schreinerei verdoppelt ihren Gewinn</h3>
|
||||
<ol type="a">
|
||||
|
|
@ -159,7 +159,7 @@
|
|||
<p><strong>2.1 — Matrixform lesen.</strong> <span class="math inline">\max 4x_1 + x_2 + 6x_3</span> u. d. N. <span class="math inline">x_1 + 2x_2 \le 10</span>, <span class="math inline">x_2 + 3x_3 \le 12</span>, <span class="math inline">x \ge 0</span>. <strong>3 Variablen, 2 Nebenbedingungen</strong> (plus Nichtnegativität).</p>
|
||||
<p><strong>2.2 — Standardform.</strong> <span class="math inline">\min -7x_1 + 2x_2</span> u. d. N. <span class="math inline">-4x_1 - x_2 \le -20</span> (aus „<span class="math inline">\ge</span>“ durch Multiplikation mit <span class="math inline">-1</span>), <span class="math inline">x_1 - x_2 \le 3</span> <strong>und</strong> <span class="math inline">-x_1 + x_2 \le -3</span> (Gleichung als zwei Ungleichungen), <span class="math inline">x_1, x_2 \ge 0</span>.</p>
|
||||
<p><strong>2.3 — Ecken von Hand.</strong> (b) Ecken: <span class="math inline">(0,0)</span>, <span class="math inline">(6,0)</span>, <span class="math inline">(4,4)</span>, <span class="math inline">(0,8)</span>. (c) <span class="math inline">Z</span>: 0, 12, 20, <strong>24</strong> → Optimum <span class="math inline">(0,8)</span> mit <span class="math inline">Z = 24</span>. (d) Bei <span class="math inline">\max 2x_1+2x_2</span>: <span class="math inline">Z(4,4) = 16</span>, <span class="math inline">Z(0,8) = 16</span> — die Zielfunktion ist <strong>parallel zur Kante</strong> <span class="math inline">x_1+x_2=8</span>. Es gibt dann <strong>unendlich viele</strong> optimale Lösungen (die ganze Kante), aber weiterhin mindestens eine in einer Ecke — der Fundamentalsatz bleibt gültig.</p>
|
||||
<p><strong>2.4 — Konvexität.</strong> (a) konvex (linear, sogar affin — Grenzfall, auch konkav). (b) konvex (<span class="math inline">f'' = 12x^2 \ge 0</span>). (c) <strong>nicht</strong> konvex, sondern <strong>konkav</strong> (<span class="math inline">f'' = -\tfrac14 x^{-3/2} < 0</span>). (d) <strong>nicht</strong> konvex, konkav (<span class="math inline">f'' = -1/x^2 < 0</span>). (e) konvex (Summe konvexer Funktionen; Hesse-Matrix <span class="math inline">2\mathbf{I} \succ 0</span>). (f) konvexe Menge (Kreisscheibe). (g) <strong>konvexe Menge</strong> — der Bereich oberhalb der Hyperbel im positiven Quadranten ist konvex (Achtung, überraschend: die <em>Funktion</em> <span class="math inline">1/x</span> ist konvex, und die Menge <span class="math inline">\{x_2 \ge 1/x_1\}</span> ist der Epigraph einer konvexen Funktion, also konvex).</p>
|
||||
<p><strong>2.4 — <a href="anhang-glossar.md#gloss:konvexitaet" class="glossar-link">Konvexität</a>.</strong> (a) konvex (linear, sogar affin — Grenzfall, auch konkav). (b) konvex (<span class="math inline">f'' = 12x^2 \ge 0</span>). (c) <strong>nicht</strong> konvex, sondern <strong>konkav</strong> (<span class="math inline">f'' = -\tfrac14 x^{-3/2} < 0</span>). (d) <strong>nicht</strong> konvex, konkav (<span class="math inline">f'' = -1/x^2 < 0</span>). (e) konvex (Summe konvexer Funktionen; Hesse-Matrix <span class="math inline">2\mathbf{I} \succ 0</span>). (f) konvexe Menge (Kreisscheibe). (g) <strong>konvexe Menge</strong> — der Bereich oberhalb der Hyperbel im positiven Quadranten ist konvex (Achtung, überraschend: die <em>Funktion</em> <span class="math inline">1/x</span> ist konvex, und die Menge <span class="math inline">\{x_2 \ge 1/x_1\}</span> ist der Epigraph einer konvexen Funktion, also konvex).</p>
|
||||
<p><strong>2.5 — Positive Semidefinitheit.</strong> <span class="math inline">\mathbf{P}_1</span>: Eigenwerte <span class="math inline">\approx (3{,}8;\ 9{,}2)</span> → PSD ✓, Korrelation <span class="math inline">1/\sqrt{4\cdot9} = 0{,}167</span> ✓. <span class="math inline">\mathbf{P}_2</span>: Eigenwerte <span class="math inline">\approx (-0{,}6;\ 13{,}6)</span> → <strong>nicht PSD</strong>; implizierte Korrelation <span class="math inline">7/\sqrt{36} = 1{,}167 > 1</span> — unmöglich. <span class="math inline">\mathbf{P}_3</span>: Eigenwerte <span class="math inline">(0{,}5;\ 0{,}5;\ 2{,}0)</span> → PSD ✓.</p>
|
||||
<p><strong>2.6 — Bäckerei visualisieren.</strong> Ecken: <span class="math inline">(40,0)</span>, <span class="math inline">(150,0)</span>, <span class="math inline">(40,116{,}67)</span> und der Schnittpunkt von Mehl- und Ofengrenze. Beste Ecke ist <span class="math inline">(40;\ 116{,}67)</span> mit <span class="math inline">Z = 450</span> (im kontinuierlichen Fall).</p>
|
||||
<p><strong>2.7 — Eigenwert-Clipping.</strong></p>
|
||||
|
|
@ -169,7 +169,7 @@
|
|||
<p>Für <span class="math inline">\mathbf{P}_2</span> ergibt sich eine PSD-Matrix mit Korrelation exakt <span class="math inline">1{,}0</span> — das Verfahren zieht die unmögliche Korrelation auf den nächstgelegenen zulässigen Wert. Für Kovarianzmatrizen setzt man in der Praxis auf einen kleinen positiven Wert statt auf 0 (<code>np.maximum(lam, 1e-10)</code>), damit die Matrix invertierbar bleibt.</p>
|
||||
<h3 id="finde-den-denkfehler-die-unauffällige-transposition">Finde den Denkfehler — Die unauffällige Transposition</h3>
|
||||
<ol type="a">
|
||||
<li><p><strong>Warum nichts auffällt.</strong> <span class="math inline">\mathbf{A}</span> ist quadratisch, also passen die Dimensionen auch transponiert. NumPy prüft Formen, nicht Bedeutungen; der Solver bekommt ein vollkommen zulässiges LP vorgelegt und löst es korrekt — nur eben ein <strong>anderes</strong>. Eine Transposition ist genau dann gefährlich, wenn sie folgenlos <em>aussieht</em>: Wäre die Matrix <span class="math inline">2 \times 3</span> gewesen, hätte NumPy sofort einen Dimensionsfehler geworfen.</p></li>
|
||||
<li><p><strong>Warum nichts auffällt.</strong> <span class="math inline">\mathbf{A}</span> ist quadratisch, also passen die Dimensionen auch transponiert. <a href="anhang-glossar.md#gloss:numpy" class="glossar-link">NumPy</a> prüft Formen, nicht Bedeutungen; der Solver bekommt ein vollkommen zulässiges <a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a> vorgelegt und löst es korrekt — nur eben ein <strong>anderes</strong>. Eine Transposition ist genau dann gefährlich, wenn sie folgenlos <em>aussieht</em>: Wäre die Matrix <span class="math inline">2 \times 3</span> gewesen, hätte NumPy sofort einen Dimensionsfehler geworfen.</p></li>
|
||||
<li><p><strong>Der Plan an den echten Restriktionen.</strong> Mit <span class="math inline">\mathbf{A} = \begin{pmatrix} 1 & 2 \\ 3 & 1\end{pmatrix}</span> und <span class="math inline">\mathbf{x} = (5{,}6;\ 0{,}8)</span>:</p></li>
|
||||
</ol>
|
||||
<p><span class="math display">\mathbf{A}\mathbf{x} = \begin{pmatrix} 1\cdot5{,}6 + 2\cdot0{,}8 \\ 3\cdot5{,}6 + 1\cdot0{,}8\end{pmatrix} = \begin{pmatrix} 7{,}2 \\ 17{,}6 \end{pmatrix} \quad\text{gegen}\quad \mathbf{b} = \begin{pmatrix} 8 \\ 12\end{pmatrix}</span></p>
|
||||
|
|
@ -184,7 +184,7 @@
|
|||
<p>Vorbeugend hilft außerdem, Matrizen nie positionsweise abzutippen, sondern über benannte Spalten aus einer Tabelle zu erzeugen — genau das tut <code>Excel_Bruecke.py</code> aus <a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a>.</p>
|
||||
<h3 id="quiz-loesung-fundament">Micro-Quiz</h3>
|
||||
<p><strong>1 — (b).</strong> Der Fundamentalsatz sagt nur, dass ein Optimum <em>in einer Ecke angenommen wird</em>. (a) ist falsch, weil es mehrere optimale Ecken geben kann (wenn die Zielfunktion parallel zu einer Kante verläuft) und dann sogar unendlich viele optimale Punkte auf der Verbindungsstrecke. (c) ist falsch, weil die Zahl der Eckenkandidaten kombinatorisch wächst: Bei 6 Variablen und 4 Ungleichungen plus 6 Nichtnegativitäten sind <span class="math inline">\binom{10}{6} = 210</span> Systeme zu prüfen — bei 50 Variablen wären es <span class="math inline">10^{29}</span>. Der Satz sagt, <em>wo</em> man suchen muss, nicht dass die Suche billig ist.</p>
|
||||
<p><strong>2 — (b).</strong> Faustregel <span class="math inline">\kappa = 10^{k}</span> ⟹ etwa <span class="math inline">k</span> signifikante Stellen verloren; bei <span class="math inline">10^{11}</span> bleiben von 16 rund 5. Das Modell ist deshalb nicht unlösbar (a) — es rechnet nur mit einer Genauigkeit, die den Ergebnissen nicht mehr anzusehen ist. (c) verwechselt die Konditionszahl mit einem Aufwandsmaß; sie sagt nichts über die Iterationszahl.</p>
|
||||
<p><strong>2 — (b).</strong> Faustregel <span class="math inline">\kappa = 10^{k}</span> ⟹ etwa <span class="math inline">k</span> signifikante Stellen verloren; bei <span class="math inline">10^{11}</span> bleiben von 16 rund 5. Das Modell ist deshalb nicht unlösbar (a) — es rechnet nur mit einer Genauigkeit, die den Ergebnissen nicht mehr anzusehen ist. (c) verwechselt die <a href="anhang-glossar.md#gloss:konditionszahl" class="glossar-link">Konditionszahl</a> mit einem Aufwandsmaß; sie sagt nichts über die Iterationszahl.</p>
|
||||
<p><strong>3 — (c).</strong> <code>int()</code> schneidet ab: <code>int(0.99999998) == 0</code> macht aus einer Ja- eine Nein-Entscheidung (a). Den Wert unverändert weiterzureichen (b) verschiebt das Problem nur in die nachgelagerte Verarbeitung, wo dann irgendwann doch jemand <code>int()</code> schreibt. Richtig ist die Prüfung gegen die Toleranz mit Fehlermeldung im Zweifelsfall — die Funktion <code>sichere_ganzzahl()</code> aus <code>Skalierung_Kondition.py</code>.</p>
|
||||
<h3 id="selbsttest-loesung-fundament">Selbsttest</h3>
|
||||
<ol type="1">
|
||||
|
|
@ -196,18 +196,18 @@
|
|||
</ol>
|
||||
<hr />
|
||||
<h2 id="sec:loesungen-oekosystem">A.3 Lösungen zu Kapitel „Das Python-Ökosystem für OR — Solver, Bindings und Modellierungsschichten“</h2>
|
||||
<p><strong>3.1 — Solverwahl.</strong> (a) CP-SAT (diskrete Zuordnung mit Zeitfenstern). (b) <code>scipy.optimize.linprog</code> (klassisches Mischungs-LP, klein). (c) CVXPY (konvexes QP). (d) MIQP — CVXPY mit Binärvariablen und MIQP-fähigem Solver, oder Heuristik. (e) MILP über <code>highspy</code> oder CP-SAT (Standortproblem mit Fixkosten). (f) <code>scipy.optimize.minimize</code> mit Multistart (nicht konvex).</p>
|
||||
<p><strong>3.1 — Solverwahl.</strong> (a) <a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a> (diskrete Zuordnung mit Zeitfenstern). (b) <code>scipy.optimize.linprog</code> (klassisches Mischungs-LP, klein). (c) <a href="anhang-glossar.md#gloss:cvxpy" class="glossar-link">CVXPY</a> (konvexes <a href="anhang-glossar.md#gloss:quadratische-programmierung-qp" class="glossar-link">QP</a>). (d) <a href="anhang-glossar.md#gloss:miqp" class="glossar-link">MIQP</a> — CVXPY mit Binärvariablen und MIQP-fähigem Solver, oder Heuristik. (e) <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> über <code>highspy</code> oder <a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a> (Standortproblem mit Fixkosten). (f) <code>scipy.optimize.minimize</code> mit Multistart (nicht konvex).</p>
|
||||
<p><strong>3.2 — Bäckerei viermal.</strong> Alle vier müssen <span class="math inline">Z = 448</span> (ganzzahlig) bzw. <span class="math inline">450</span> (kontinuierlich) liefern. Denken Sie an die Prozesstrennung, falls <code>ortools</code> und <code>highspy</code> kollidieren.</p>
|
||||
<p><strong>3.3 — CSR-Format.</strong> <code>values = [3, 1, 2, 5, 4, 6]</code>, <code>indices = [0, 3, 2, 0, 1, 3]</code>, <code>starts = [0, 2, 3]</code>. CSR speichert 6 Werte + 6 Indizes + 3 Startpositionen = 15 Zahlen; die volle Matrix hätte <span class="math inline">3\times4 = 12</span>. <strong>Bei dieser winzigen, dicht besetzten Matrix lohnt CSR nicht</strong> — der Vorteil entsteht erst bei großer, dünn besetzter Struktur (z. B. 1000×1000 mit 0,5 % Besetzung: 15 000 statt 1 000 000 Zahlen).</p>
|
||||
<p><strong>3.3 — <a href="anhang-glossar.md#gloss:csr-format" class="glossar-link">CSR-Format</a>.</strong> <code>values = [3, 1, 2, 5, 4, 6]</code>, <code>indices = [0, 3, 2, 0, 1, 3]</code>, <code>starts = [0, 2, 3]</code>. CSR speichert 6 Werte + 6 Indizes + 3 Startpositionen = 15 Zahlen; die volle Matrix hätte <span class="math inline">3\times4 = 12</span>. <strong>Bei dieser winzigen, dicht besetzten Matrix lohnt CSR nicht</strong> — der Vorteil entsteht erst bei großer, dünn besetzter Struktur (z. B. 1000×1000 mit 0,5 % Besetzung: 15 000 statt 1 000 000 Zahlen).</p>
|
||||
<p><strong>3.4 — Konvexitätsprüfung.</strong> <span class="math inline">\min x^3</span> wirft <code>DCPError: Problem does not follow DCP rules</code>, weil <span class="math inline">x^3</span> auf <span class="math inline">[-2,2]</span> weder konvex noch konkav ist. <span class="math inline">\min x^2</span> läuft und liefert <span class="math inline">x=0</span>. Der Unterschied: CVXPY akzeptiert nur Ausdrücke, deren Konvexität es <strong>beweisen</strong> kann — dafür garantiert es das globale Optimum.</p>
|
||||
<p><strong>3.5 — Laufzeitvergleich.</strong> Erwartetes Muster: <code>linprog</code> und <code>highspy</code> liegen bei kleinen Modellen gleichauf (Overhead dominiert); ab etwa <span class="math inline">n \gtrsim 500</span> zieht <code>highspy</code> davon, weil der Modellaufbau effizienter ist. CVXPY hat den größten festen Aufwand (Ausdrucksbaum-Kompilierung), der bei wiederholten Läufen mit <code>cp.Parameter</code> teilweise entfällt.</p>
|
||||
<p><strong>3.6 — Eigene Entscheidungshilfe.</strong> Ergänzungen: Bei kommerzieller Lizenz Gurobi/CPLEX über Pyomo oder CVXPY empfehlen; bei Lesbarkeitsanforderung Pyomo (algebraische Notation, Trennung von Daten und Modell).</p>
|
||||
<p><strong>3.6 — Eigene Entscheidungshilfe.</strong> Ergänzungen: Bei kommerzieller Lizenz <a href="anhang-glossar.md#gloss:gurobi" class="glossar-link">Gurobi</a>/CPLEX über <a href="anhang-glossar.md#gloss:pyomo" class="glossar-link">Pyomo</a> oder CVXPY empfehlen; bei Lesbarkeitsanforderung Pyomo (algebraische Notation, Trennung von Daten und Modell).</p>
|
||||
<h3 id="finde-den-denkfehler-der-solver-der-angeblich-dreimal-schneller-ist">Finde den Denkfehler — Der Solver, der angeblich dreimal schneller ist</h3>
|
||||
<ol type="a">
|
||||
<li><strong>Was da alles mitgemessen wird.</strong> Die Stoppuhr läuft ab der ersten Zeile, also mindestens über drei Dinge, die mit Lösegeschwindigkeit nichts zu tun haben:</li>
|
||||
</ol>
|
||||
<ol type="1">
|
||||
<li><strong>Der <code>import</code>.</strong> CVXPY zieht beim ersten Import seine gesamte Solver-Erkennung hoch — allein das kostet regelmäßig über eine Sekunde. <code>linprog</code> steht in einem Prozess, der SciPy ohnehin schon geladen hat, praktisch sofort bereit.</li>
|
||||
<li><strong>Der <code>import</code>.</strong> CVXPY zieht beim ersten Import seine gesamte Solver-Erkennung hoch — allein das kostet regelmäßig über eine Sekunde. <code>linprog</code> steht in einem Prozess, der <a href="anhang-glossar.md#gloss:scipy" class="glossar-link">SciPy</a> ohnehin schon geladen hat, praktisch sofort bereit.</li>
|
||||
<li><strong>Der Modellaufbau.</strong> CVXPY baut einen Ausdrucksbaum und kompiliert ihn in die Standardform des Solvers. Das ist echter Aufwand — aber Aufbau, nicht Rechnen.</li>
|
||||
<li><strong>Die Reihenfolge.</strong> CVXPY läuft zuerst und bezahlt dabei alles, was danach im Betriebssystem-Cache liegt: Bibliotheken, Speicherseiten, JIT-Wärme. Tauschen Sie die beiden Blöcke, und die Zahlen verschieben sich allein deshalb.</li>
|
||||
</ol>
|
||||
|
|
@ -237,14 +237,14 @@
|
|||
<h3 id="quiz-loesung-oekosystem">Micro-Quiz</h3>
|
||||
<p><strong>1 — (b) CP-SAT.</strong> Es geht um diskrete Zuweisung mit logischen Regeln („nicht gleichzeitig“) — CP-SATs Kerngebiet, und Regeln dieser Art formuliert man dort direkt statt über Big-M-Umwege. (a) scheidet aus, weil CVXPY keine sinnvolle Ganzzahligkeit in dieser Größenordnung bietet; (c) findet bei einem diskreten Problem bestenfalls ein lokales Optimum und hat keinerlei Handhabe für „entweder–oder“-Regeln.</p>
|
||||
<p><strong>2 — (c) Modellaufbau vektorisieren.</strong> 32 von 40 Sekunden fallen an, <em>bevor</em> der Solver startet. Ein kommerzieller Solver (a) beschleunigt bestenfalls die verbleibenden 8 Sekunden — selbst bei Faktor 4 gewinnen Sie 6 der 40 Sekunden. Das Zeitlimit (b) betrifft den Abbruch, nicht die Geschwindigkeit. Die Regel dahinter: <strong>erst messen, wo die Zeit hingeht, dann optimieren.</strong></p>
|
||||
<p><strong>3 — (b).</strong> Alle vier sind Modellierungsschichten über HiGHS. Deshalb liefern sie denselben Zielwert (bis auf Toleranz) und unterscheiden sich in der reinen Rechenzeit kaum — wohl aber im Aufbauaufwand und in der Lesbarkeit. (a) ist falsch: Niemand von ihnen implementiert den Simplex in Python, das wäre um Größenordnungen zu langsam. (c) ist falsch: Nicht-konvexe Probleme global zu lösen kann keines dieser Werkzeuge — dafür braucht es spezialisierte globale Solver (<a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a>).</p>
|
||||
<p><strong>3 — (b).</strong> Alle vier sind Modellierungsschichten über <a href="anhang-glossar.md#gloss:highs" class="glossar-link">HiGHS</a>. Deshalb liefern sie denselben Zielwert (bis auf Toleranz) und unterscheiden sich in der reinen Rechenzeit kaum — wohl aber im Aufbauaufwand und in der Lesbarkeit. (a) ist falsch: Niemand von ihnen implementiert den Simplex in Python, das wäre um Größenordnungen zu langsam. (c) ist falsch: Nicht-konvexe Probleme global zu lösen kann keines dieser Werkzeuge — dafür braucht es spezialisierte globale Solver (<a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a>).</p>
|
||||
<h3 id="selbsttest-loesung-oekosystem">Selbsttest</h3>
|
||||
<ol type="1">
|
||||
<li>Modellierungsschicht (Python) und Solver-Schicht (C++). Die Trennung erlaubt Solvertausch ohne Modelländerung.</li>
|
||||
<li>CVXPY prüft die Konvexität und lehnt ab, was es nicht garantieren kann; <code>minimize</code> prüft nichts und liefert ein lokales Optimum.</li>
|
||||
<li>Werte, Spaltenindizes und Zeilenstartpositionen der Nicht-Null-Einträge. Entscheidend, weil reale Modelle extrem dünn besetzt sind.</li>
|
||||
<li>Wegen des Kompilierungsaufwands des Ausdrucksbaums. Kein Argument dagegen, weil dieser Aufwand einmalig ist, die Lesbarkeit hoch und die Konvexitätsprüfung wertvoll.</li>
|
||||
<li>Bei rein kontinuierlichen Problemen (CP-SAT kennt nur ganze Zahlen) und bei reinen Routing-Problemen (dort ist die Routing-Bibliothek überlegen).</li>
|
||||
<li>Bei rein kontinuierlichen Problemen (CP-SAT kennt nur ganze Zahlen) und bei reinen Routing-Problemen (dort ist die <a href="anhang-glossar.md#gloss:routing-bibliothek" class="glossar-link">Routing-Bibliothek</a> überlegen).</li>
|
||||
</ol>
|
||||
<hr />
|
||||
<h2 id="sec:loesungen-modellierung">A.4 Lösungen zu Kapitel „Vom Management-Wunsch zum Modell“</h2>
|
||||
|
|
@ -327,7 +327,7 @@
|
|||
<p><strong>5.1 — Schlupf deuten.</strong> (a) Ressourcen 1 und 3 (Schlupf 0). (b) Ja: Überall ist <span class="math inline">s_i \cdot y_i = 0</span>. (c) In Ressource 3 — der höchste Schattenpreis (9,8) bedeutet den größten Grenznutzen.</p>
|
||||
<p><strong>5.2 — Vorzeichen.</strong> Er hat die Zielfunktion für <code>linprog</code> negiert und die Dualwerte nicht zurückgedreht. Der korrekte Schattenpreis ist <strong>+45 €</strong>.</p>
|
||||
<p><strong>5.3 — Simplex von Hand.</strong> Starttableau mit <span class="math inline">s_1, s_2</span> in der Basis. Erste Iteration: Pivotspalte <span class="math inline">x_1</span> (<span class="math inline">-5</span>), Quotienten <span class="math inline">24/6 = 4</span> und <span class="math inline">6/1 = 6</span> → Pivotzeile 1. Nach dem Tausch: <span class="math inline">x_1 = 4</span>, <span class="math inline">Z = 20</span>. Zweite Iteration: Pivotspalte <span class="math inline">x_2</span>, Pivotzeile 2 → <span class="math inline">x_1 = 3</span>, <span class="math inline">x_2 = 1{,}5</span>, <span class="math inline">Z = 21</span>. <strong>Optimum:</strong> <span class="math inline">\mathbf{x}^* = (3;\ 1{,}5)</span>, <span class="math inline">Z^* = 21</span>, Schattenpreise <span class="math inline">y^* = (0{,}75;\ 0{,}50)</span>.</p>
|
||||
<p><strong>5.4 — Duales Problem.</strong> <span class="math inline">\min 24y_1 + 6y_2</span> u. d. N. <span class="math inline">6y_1 + y_2 \ge 5</span>, <span class="math inline">4y_1 + 2y_2 \ge 4</span>, <span class="math inline">y \ge 0</span>. Lösung <span class="math inline">y^* = (0{,}75;\ 0{,}50)</span>. Probe der Restriktionen: <span class="math inline">6\cdot0{,}75 + 0{,}5 = 5</span> ✓ (mit Gleichheit, weil <span class="math inline">x_1 > 0</span>), <span class="math inline">4\cdot0{,}75 + 2\cdot0{,}5 = 4</span> ✓ (ebenfalls Gleichheit, weil <span class="math inline">x_2 > 0</span>). Zielwert <span class="math inline">24\cdot0{,}75 + 6\cdot0{,}5 = 18 + 3 = 21 = Z^*</span> ✓ — starker Dualitätssatz bestätigt.</p>
|
||||
<p><strong>5.4 — <a href="anhang-glossar.md#gloss:duales-problem" class="glossar-link">Duales Problem</a>.</strong> <span class="math inline">\min 24y_1 + 6y_2</span> u. d. N. <span class="math inline">6y_1 + y_2 \ge 5</span>, <span class="math inline">4y_1 + 2y_2 \ge 4</span>, <span class="math inline">y \ge 0</span>. Lösung <span class="math inline">y^* = (0{,}75;\ 0{,}50)</span>. Probe der Restriktionen: <span class="math inline">6\cdot0{,}75 + 0{,}5 = 5</span> ✓ (mit Gleichheit, weil <span class="math inline">x_1 > 0</span>), <span class="math inline">4\cdot0{,}75 + 2\cdot0{,}5 = 4</span> ✓ (ebenfalls Gleichheit, weil <span class="math inline">x_2 > 0</span>). Zielwert <span class="math inline">24\cdot0{,}75 + 6\cdot0{,}5 = 18 + 3 = 21 = Z^*</span> ✓ — starker Dualitätssatz bestätigt.</p>
|
||||
<p><strong>5.5 — Unbeschränktheit.</strong> Der Solver wirft „Problem ist unbeschränkt“. Geometrisch: Der zulässige Bereich <span class="math inline">\{x_1 - x_2 \le 5,\ x \ge 0\}</span> ist nach oben offen — man kann <span class="math inline">x_1</span> und <span class="math inline">x_2</span> gemeinsam beliebig wachsen lassen (z. B. <span class="math inline">x_1 = x_2 = t</span> für <span class="math inline">t \to \infty</span>), ohne eine Bedingung zu verletzen, und <span class="math inline">Z = 2t</span> wächst mit. In der Praxis fehlt fast immer eine Kapazitätsgrenze.</p>
|
||||
<p><strong>5.6 — Gültigkeitsbereich.</strong> (a) Bei ca. 66,7 Stunden Prüfkapazität wird die <strong>Lackierzeit</strong> zum Engpass; der Schattenpreis der Prüfung fällt dann. (b) Zukaufen lohnt bis zu dem Punkt, an dem der Schattenpreis unter 18 €/h fällt. (c) Der Gewinnverlauf ist <strong>stückweise linear und konkav</strong>: Jedes Teilstück hat die Steigung des jeweils gültigen Schattenpreises, und die Steigungen werden immer flacher — jede zusätzliche Einheit bringt weniger, weil andere Engpässe nachrücken.</p>
|
||||
<p><strong>5.7 — Phase 1.</strong> Ansatz: Für jede Zeile mit <span class="math inline">b_i < 0</span> (nach Umformung zu <span class="math inline">\ge</span>) eine künstliche Variable <span class="math inline">a_i \ge 0</span> einführen, Hilfszielfunktion <span class="math inline">\min \sum a_i</span> lösen. Ist das Minimum 0, existiert eine zulässige Basislösung, und man startet Phase 2 mit dem erreichten Tableau. Ist es <span class="math inline">> 0</span>, ist das Problem unzulässig. Für das Beispiel: Optimum <span class="math inline">(12;\ 0)</span>, <span class="math inline">Z = 36</span>.</p>
|
||||
|
|
@ -409,7 +409,7 @@
|
|||
<p>Das ist die allgemeine Regel für jede Sensitivitätsaussage über mehr als eine Grenzeinheit: <strong>Der Schattenpreis zeigt die Richtung, die Neuberechnung liefert den Betrag.</strong> Bei einer Investitionsentscheidung kostet ein zusätzlicher Solverlauf Millisekunden — und hier hätte er 380 000 € gespart.</p>
|
||||
<h3 id="quiz-loesung-lp">Micro-Quiz</h3>
|
||||
<p><strong>1 — (b).</strong> Genau der Satz vom komplementären Schlupf: <span class="math inline">s_i \cdot y_i = 0</span>. Ist Schlupf vorhanden, muss der Dualwert null sein. (a) hat die Aussage in ihr Gegenteil verkehrt; (c) verwechselt Schlupf mit Auslastung — <span class="math inline">s_i = 12</span> heißt gerade, dass 12 Einheiten <em>übrig</em> sind.</p>
|
||||
<p><strong>2 — (b) Entartung.</strong> 7 aktive Bedingungen bei 5 Variablen bedeuten: Die Ecke ist überbestimmt, es gibt mehrere optimale Dualvektoren, und welchen der Solver zeigt, hängt vom gewählten Verfahren ab. (a) verharmlost genau den Fall, der Fehlentscheidungen produziert; (c) verwechselt Entartung mit Unlösbarkeit — der Plan selbst ist völlig in Ordnung und eindeutig.</p>
|
||||
<p><strong>2 — (b) <a href="anhang-glossar.md#gloss:entartung" class="glossar-link">Entartung</a>.</strong> 7 aktive Bedingungen bei 5 Variablen bedeuten: Die Ecke ist überbestimmt, es gibt mehrere optimale Dualvektoren, und welchen der Solver zeigt, hängt vom gewählten Verfahren ab. (a) verharmlost genau den Fall, der Fehlentscheidungen produziert; (c) verwechselt Entartung mit Unlösbarkeit — der Plan selbst ist völlig in Ordnung und eindeutig.</p>
|
||||
<p><strong>3 — (b).</strong> Der Schlupf ist Solver-Rauschen in der Größenordnung der Maschinengenauigkeit — rechnerisch null, aber nicht <code>== 0.0</code>. Richtig ist <code>abs(schlupf) < 1e-7</code>. (a) unterstellt dem Solver einen Fehler, den er nicht gemacht hat; (c) ist frei erfunden — Schlupfwerte sind bei korrekt aufgestelltem Modell nie negativ, abgesehen von genau diesem Rauschen.</p>
|
||||
<h3 id="selbsttest-loesung-lp">Selbsttest</h3>
|
||||
<ol type="1">
|
||||
|
|
@ -422,9 +422,9 @@
|
|||
<hr />
|
||||
<h2 id="sec:loesungen-milp">A.6 Lösungen zu Kapitel „Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound“</h2>
|
||||
<p><strong>6.1 — Runden widerlegen.</strong> Beispiel: <span class="math inline">\max x_1 + x_2</span> u. d. N. <span class="math inline">10x_1 + 10x_2 \le 15</span>, ganzzahlig. LP-Optimum <span class="math inline">Z = 1{,}5</span>; Abrunden ergibt <span class="math inline">(0,0)</span> mit <span class="math inline">Z = 0</span> — <strong>100 % Verlust</strong>. Das ganzzahlige Optimum ist <span class="math inline">(1,0)</span> mit <span class="math inline">Z = 1</span>. Prinzip: kleine Zahlen plus knappe Kapazität.</p>
|
||||
<p><strong>6.2 — Big-M wählen.</strong> <span class="math inline">M = 250</span> (die bekannte Kapazität). Bei <span class="math inline">M = 10^6</span> bleibt das Modell korrekt, aber die LP-Relaxation wird extrem schwach: <span class="math inline">y_j</span> darf schon bei <span class="math inline">x_j/10^6</span> liegen, die Schranke ist praktisch wertlos, und Branch-and-Bound muss weit mehr Knoten durchsuchen.</p>
|
||||
<p><strong>6.2 — Big-M wählen.</strong> <span class="math inline">M = 250</span> (die bekannte Kapazität). Bei <span class="math inline">M = 10^6</span> bleibt das Modell korrekt, aber die <a href="anhang-glossar.md#gloss:lp-relaxation" class="glossar-link">LP-Relaxation</a> wird extrem schwach: <span class="math inline">y_j</span> darf schon bei <span class="math inline">x_j/10^6</span> liegen, die Schranke ist praktisch wertlos, und <a href="anhang-glossar.md#gloss:branch-and-bound" class="glossar-link">Branch-and-Bound</a> muss weit mehr Knoten durchsuchen.</p>
|
||||
<p><strong>6.3 — Regeln übersetzen.</strong> (a) <span class="math inline">y_A + y_B \le 1</span>. (b) <span class="math inline">\sum_{j=1}^4 y_j \ge 2</span>. (c) <span class="math inline">y_1 + y_2 - 1 \le y_{\text{Lager}}</span>. (d) <span class="math inline">500\,y \le x \le 2000\,y</span> mit <span class="math inline">y \in \{0,1\}</span>. (e) <span class="math inline">\sum_{j=1}^3 y_j = 1</span>.</p>
|
||||
<p><strong>6.4 — Branch-and-Bound.</strong> LP-Relaxation der Wurzel: nach Nutzen/Gewicht sortieren (<span class="math inline">8/5=1{,}6</span>; <span class="math inline">11/7=1{,}57</span>; <span class="math inline">6/4=1{,}5</span>; <span class="math inline">4/3=1{,}33</span>). Gierig füllen: <span class="math inline">x_1=1</span> (Rest 9), <span class="math inline">x_2=1</span> (Rest 2), <span class="math inline">x_3 = 0{,}5</span> → <span class="math inline">Z_{LP} = 8+11+3 = 22</span>. Verzweigen über <span class="math inline">x_3</span>. Ast <span class="math inline">x_3=0</span>: <span class="math inline">x_1=1,x_2=1,x_4=2/3</span> → <span class="math inline">Z = 21{,}67</span>; weiter verzweigen → beste ganzzahlige Lösung <span class="math inline">(1,1,0,0)</span> mit <span class="math inline">Z=19</span>. Ast <span class="math inline">x_3=1</span>: <span class="math inline">x_1=1</span>, <span class="math inline">x_3=1</span>, Rest 5 → <span class="math inline">x_2=5/7</span> → <span class="math inline">Z = 21{,}86</span>; verzweigen führt auf <span class="math inline">(1,0,1,1)</span> mit <span class="math inline">Z = 18</span> und <span class="math inline">(0,1,1,0)</span> mit <span class="math inline">Z=17</span>. <strong>Optimum: <span class="math inline">(1,1,0,0)</span>, <span class="math inline">Z = 19</span>.</strong></p>
|
||||
<p><strong>6.4 — Branch-and-Bound.</strong> LP-<a href="anhang-glossar.md#gloss:relaxation" class="glossar-link">Relaxation</a> der Wurzel: nach Nutzen/Gewicht sortieren (<span class="math inline">8/5=1{,}6</span>; <span class="math inline">11/7=1{,}57</span>; <span class="math inline">6/4=1{,}5</span>; <span class="math inline">4/3=1{,}33</span>). Gierig füllen: <span class="math inline">x_1=1</span> (Rest 9), <span class="math inline">x_2=1</span> (Rest 2), <span class="math inline">x_3 = 0{,}5</span> → <span class="math inline">Z_{LP} = 8+11+3 = 22</span>. Verzweigen über <span class="math inline">x_3</span>. Ast <span class="math inline">x_3=0</span>: <span class="math inline">x_1=1,x_2=1,x_4=2/3</span> → <span class="math inline">Z = 21{,}67</span>; weiter verzweigen → beste ganzzahlige Lösung <span class="math inline">(1,1,0,0)</span> mit <span class="math inline">Z=19</span>. Ast <span class="math inline">x_3=1</span>: <span class="math inline">x_1=1</span>, <span class="math inline">x_3=1</span>, Rest 5 → <span class="math inline">x_2=5/7</span> → <span class="math inline">Z = 21{,}86</span>; verzweigen führt auf <span class="math inline">(1,0,1,1)</span> mit <span class="math inline">Z = 18</span> und <span class="math inline">(0,1,1,0)</span> mit <span class="math inline">Z=17</span>. <strong>Optimum: <span class="math inline">(1,1,0,0)</span>, <span class="math inline">Z = 19</span>.</strong></p>
|
||||
<p><strong>6.5 — Kardinalität variieren.</strong> (a) Ab <span class="math inline">K = 3</span> steigt der Ertrag nicht mehr wesentlich, weil bereits drei Positionen à 40 000 € das Budget von 100 000 € abdecken können. (b) Rechenzeit steigt zunächst (mehr Kombinationen), fällt bei großem <span class="math inline">K</span> wieder (Restriktion bindet nicht mehr). (c) Der faire Preis ist die Differenz der Netto-Erträge zwischen <span class="math inline">K=3</span> und <span class="math inline">K=4</span> — bei den gegebenen Daten nahe null, weil die Obergrenze von 40 000 € bereits bindet.</p>
|
||||
<p><strong>6.6 — Big-M-Effekt.</strong> Erwartetes Muster: Knotenzahl und Laufzeit steigen deutlich mit <span class="math inline">M</span>. Bei <span class="math inline">M = 10^9</span> ist die Relaxation so schwach, dass der Solver kaum noch prunen kann.</p>
|
||||
<p><strong>6.7 — Standortplanung.</strong> Modell wie in Projekt P4. Prüfen Sie: Gesamtkapazität der eröffneten Lager <span class="math inline">\ge</span> Gesamtbedarf (140); bei Kapazität 80 je Lager sind mindestens <span class="math inline">\lceil 140/80 \rceil = 2</span> Lager nötig.</p>
|
||||
|
|
@ -458,8 +458,8 @@
|
|||
<p><strong>Vorbeugend</strong> gilt weiter die Regel aus dem Kapitel: <span class="math inline">M</span> so klein wie möglich, hergeleitet aus einer echten Kapazität. Hier wäre das schlicht die Lagerkapazität — mehr kann ein Lager ohnehin nicht ausliefern.</p>
|
||||
<h3 id="quiz-loesung-milp">Micro-Quiz</h3>
|
||||
<p><strong>1 — (b).</strong> Der Gap <span class="math inline">(48\,200 - 47\,100)/48\,200 = 2{,}3\,\%</span> ist eine <strong>Garantie</strong>, keine Schätzung: Besser als 47 100 € kann es nachweislich nicht werden, also ist der vorliegende Plan höchstens 2,3 % zu teuer. (a) wirft eine völlig brauchbare Lösung weg — genau der Fehler, den <code>if status == OPTIMAL: ... else: return None</code> produziert. (c) verwechselt die Schranke mit einem erreichbaren Wert: 47 100 € ist eine <em>untere</em> Schranke, es ist völlig offen, ob ein Plan mit diesen Kosten überhaupt existiert.</p>
|
||||
<p><strong>2 — (b).</strong> Die Laufzeit (a) ist ein realer, aber beherrschbarer Nachteil — man merkt ihn und kann reagieren. Der Trickle Flow dagegen ist <strong>still</strong>: Das Modell meldet <code>Optimal</code>, liefert eine Zahl, und niemand sieht, dass die Fixkosten verschwunden sind. Ein Fehler, den man bemerkt, ist immer harmloser als einer, den man nicht bemerkt. (c) ist frei erfunden — negative Kosten entstehen dabei nicht.</p>
|
||||
<p><strong>3 — (c).</strong> Ein Hinweis ist für CP-SAT unverbindlich: Er wird als Startlösung ausprobiert und verworfen, wenn er nicht zulässig ist. Das Ergebnis bleibt in jedem Fall korrekt (b ist also falsch), und <code>INFEASIBLE</code> bezieht sich immer auf das Modell, nie auf einen Hinweis (a ist falsch). Praktische Konsequenz: Prüfen Sie Ihre Startlösung selbst auf Zulässigkeit — sonst messen Sie einen Warm-Start-Effekt, den es gar nicht gibt.</p>
|
||||
<p><strong>2 — (b).</strong> Die Laufzeit (a) ist ein realer, aber beherrschbarer Nachteil — man merkt ihn und kann reagieren. Der <a href="anhang-glossar.md#gloss:trickle-flow" class="glossar-link">Trickle Flow</a> dagegen ist <strong>still</strong>: Das Modell meldet <code>Optimal</code>, liefert eine Zahl, und niemand sieht, dass die Fixkosten verschwunden sind. Ein Fehler, den man bemerkt, ist immer harmloser als einer, den man nicht bemerkt. (c) ist frei erfunden — negative Kosten entstehen dabei nicht.</p>
|
||||
<p><strong>3 — (c).</strong> Ein Hinweis ist für CP-SAT unverbindlich: Er wird als Startlösung ausprobiert und verworfen, wenn er nicht zulässig ist. Das Ergebnis bleibt in jedem Fall korrekt (b ist also falsch), und <code>INFEASIBLE</code> bezieht sich immer auf das Modell, nie auf einen Hinweis (a ist falsch). Praktische Konsequenz: Prüfen Sie Ihre Startlösung selbst auf Zulässigkeit — sonst messen Sie einen <a href="anhang-glossar.md#gloss:warm-start" class="glossar-link">Warm-Start</a>-Effekt, den es gar nicht gibt.</p>
|
||||
<h3 id="selbsttest-loesung-milp">Selbsttest</h3>
|
||||
<ol type="1">
|
||||
<li>Weil die Relaxation <strong>mehr</strong> Lösungen zulässt (alle ganzzahligen plus gebrochene) — das Maximum über einer größeren Menge ist mindestens so groß.</li>
|
||||
|
|
@ -473,7 +473,7 @@
|
|||
<p><strong>7.1 — Propagation.</strong> Aus <span class="math inline">x_1 + x_2 = 8</span> und <span class="math inline">x_1 < x_2</span> folgt <span class="math inline">x_1 < 4</span>, also <span class="math inline">x_1 \in \{2,3\}</span> (denn <span class="math inline">x_2 = 8-x_1 \le 6</span> verlangt <span class="math inline">x_1 \ge 2</span>) und entsprechend <span class="math inline">x_2 \in \{5,6\}</span>. Aus 36 Kombinationen werden 2 zulässige.</p>
|
||||
<p><strong>7.2 — Hart oder weich.</strong> (a) hart. (b) weich, mittlere Strafe (~50). (c) hart. (d) weich, mittlere Strafe (~80, weil geteilte Dienste stark belasten). (e) hart, falls gesetzlich; sonst weich mit sehr hoher Strafe (~1000).</p>
|
||||
<p><strong>7.3 — Regeln ergänzen.</strong> (a) <code>for s in (2,3): modell.Add(x["Frau_Albrecht", s] == 0)</code> (b) Hilfsvariablen <code>arbeitet_bauer</code>, <code>arbeitet_koch</code> per <code>AddMaxEquality</code> an die Zuweisungssummen koppeln, dann <code>modell.Add(arbeitet_bauer + arbeitet_koch <= 1)</code>. (c) Belohnung = negative Strafe: <code>strafterme.append(-30 * folge_var)</code>, wobei <code>folge_var</code> per <code>AddBoolAnd</code>/<code>OnlyEnforceIf</code> an <span class="math inline">x_{p,0} \wedge x_{p,1}</span> gekoppelt wird.</p>
|
||||
<p><strong>7.4 — Infeasibility.</strong> Mit <code>MAX_VERTRETUNGEN = 0</code> meldet der Solver <code>INFEASIBLE</code>. Nach Einbau der Schlupfvariablen lässt der Solver <strong>alle vier</strong> Stunden ausfallen (4 × 10 000 = 40 000 Strafpunkte) — es geht nicht anders. Interessanter wird es bei <code>MAX_VERTRETUNGEN = 1</code>: Dann fällt genau die Stunde aus, für die am wenigsten qualifiziertes Personal zur Verfügung steht.</p>
|
||||
<p><strong>7.4 — <a href="anhang-glossar.md#gloss:infeasibility" class="glossar-link">Infeasibility</a>.</strong> Mit <code>MAX_VERTRETUNGEN = 0</code> meldet der Solver <code>INFEASIBLE</code>. Nach Einbau der Schlupfvariablen lässt der Solver <strong>alle vier</strong> Stunden ausfallen (4 × 10 000 = 40 000 Strafpunkte) — es geht nicht anders. Interessanter wird es bei <code>MAX_VERTRETUNGEN = 1</code>: Dann fällt genau die Stunde aus, für die am wenigsten qualifiziertes Personal zur Verfügung steht.</p>
|
||||
<p><strong>7.5 — Sudoku.</strong></p>
|
||||
<div class="sourceCode" id="cb10"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>x <span class="op">=</span> [[m.NewIntVar(<span class="dv">1</span>, <span class="dv">9</span>, <span class="ss">f"x</span><span class="sc">{</span>i<span class="sc">}{</span>j<span class="sc">}</span><span class="ss">"</span>) <span class="cf">for</span> j <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">9</span>)] <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">9</span>)]</span>
|
||||
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">9</span>): m.AddAllDifferent(x[i]) <span class="co"># Zeilen</span></span>
|
||||
|
|
@ -507,7 +507,7 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Nur die Kombination trägt. (c) Bei <strong>15 Aufträgen</strong> (60 s Zeitlimit): Ein Arbeiter läuft ins Limit und meldet <code>FEASIBLE</code> mit Makespan 200; acht Arbeiter melden <code>OPTIMAL</code> mit <strong>demselben</strong> Makespan 200 nach 26,4 s. Bei 13 Aufträgen sind es 11,2 s gegen 2,8 s, bei 14 schon 21,4 s gegen 3,7 s. Bemerkenswert ist, dass beide denselben Wert finden — der Unterschied liegt nicht in der Lösung, sondern im <strong>Beweis</strong>, dass es keine bessere gibt. Genau diese Arbeit teilen sich die parallelen Stränge auf.</p>
|
||||
<p>Nur die Kombination trägt. (c) Bei <strong>15 Aufträgen</strong> (60 s Zeitlimit): Ein Arbeiter läuft ins Limit und meldet <code>FEASIBLE</code> mit <a href="anhang-glossar.md#gloss:makespan" class="glossar-link">Makespan</a> 200; acht Arbeiter melden <code>OPTIMAL</code> mit <strong>demselben</strong> Makespan 200 nach 26,4 s. Bei 13 Aufträgen sind es 11,2 s gegen 2,8 s, bei 14 schon 21,4 s gegen 3,7 s. Bemerkenswert ist, dass beide denselben Wert finden — der Unterschied liegt nicht in der Lösung, sondern im <strong>Beweis</strong>, dass es keine bessere gibt. Genau diese Arbeit teilen sich die parallelen Stränge auf.</p>
|
||||
<p><strong>7.7 — Job-Shop erweitern.</strong> (a) Rüstzeiten: <code>AddNoOverlap</code> durch paarweise Disjunktionen mit Übergangszeit ersetzen, oder <code>AddCircuit</code> je Maschine mit Übergangsmatrix. (b) Verspätung: <code>tardiness = MaxEquality(0, ende - faellig)</code>, in die Zielfunktion. (c) <code>AddCumulative(intervalle, [1]*n, 2)</code> statt <code>AddNoOverlap</code> für die Doppelmaschine.</p>
|
||||
<p><strong>7.8 — Wochendienstplan.</strong> Siehe Projekt P2. Kernpunkte: Nachtschicht-Folgeregel über <code>AddImplication</code>; „höchstens 5 Tage in Folge“ über gleitende Fenster (<code>sum(x[p,t..t+5]) <= 5</code>).</p>
|
||||
<h3 id="finde-den-denkfehler-die-betriebsvereinbarung-die-niemanden-interessiert">Finde den Denkfehler — Die Betriebsvereinbarung, die niemanden interessiert</h3>
|
||||
|
|
@ -579,7 +579,7 @@
|
|||
<h3 id="quiz-loesung-cpsat">Micro-Quiz</h3>
|
||||
<p><strong>1 — (b) wirkungslos.</strong> <code>INFEASIBLE</code> ist kein Abbruch, sondern ein <strong>Beweis</strong>: CP-SAT hat gezeigt, dass keine zulässige Lösung existiert. Mehr Zeit (a) oder mehr Arbeiter (c) ändern daran nichts — sie bestätigen dasselbe Ergebnis nur schneller. Der Unterschied zu <code>UNKNOWN</code> ist genau dieser: Dort <em>wurde</em> nichts gefunden, hier <em>gibt es</em> nichts. Die Ursache liegt in den harten Regeln; Anhang C zeigt, wie man die widersprüchliche Teilmenge isoliert.</p>
|
||||
<p><strong>2 — (b).</strong> <code>AddNoOverlap</code> ist kompakter <em>und</em> propagiert stärker, weil der spezialisierte Propagator alle Intervalle gemeinsam betrachtet statt paarweise. (a) ist falsch: Beide Formulierungen beschreiben dieselbe Menge zulässiger Lösungen, also auch dasselbe Optimum — der Unterschied liegt in der Laufzeit, nicht in der Qualität. (c) ist falsch: CP-SAT rechnet ausschließlich mit ganzen Zahlen, kontinuierliche Zeiten kann es gerade <strong>nicht</strong>.</p>
|
||||
<p><strong>3 — (b).</strong> Mehrfache Optima sind bei Scheduling der Normalfall, kein Fehler. (a) verwechselt Eindeutigkeit mit Korrektheit; (c) unterstellt ein Genauigkeitsproblem, das es nicht gibt — alle gefundenen Pläne haben exakt denselben Makespan. Praktische Konsequenz: <code>assert plan == erwarteter_plan</code> besteht mal und scheitert mal, ohne dass sich am Code etwas geändert hat. Prüfen Sie stattdessen <code>assert makespan == 11</code> und die Einhaltung aller Regeln. Wer eine reproduzierbare Ausgabe braucht — etwa für ein Buch —, fixiert <code>num_workers</code> und <code>random_seed</code>.</p>
|
||||
<p><strong>3 — (b).</strong> Mehrfache Optima sind bei <a href="anhang-glossar.md#gloss:scheduling" class="glossar-link">Scheduling</a> der Normalfall, kein Fehler. (a) verwechselt Eindeutigkeit mit Korrektheit; (c) unterstellt ein Genauigkeitsproblem, das es nicht gibt — alle gefundenen Pläne haben exakt denselben Makespan. Praktische Konsequenz: <code>assert plan == erwarteter_plan</code> besteht mal und scheitert mal, ohne dass sich am Code etwas geändert hat. Prüfen Sie stattdessen <code>assert makespan == 11</code> und die Einhaltung aller Regeln. Wer eine reproduzierbare Ausgabe braucht — etwa für ein Buch —, fixiert <code>num_workers</code> und <code>random_seed</code>.</p>
|
||||
<h3 id="selbsttest-loesung-cpsat">Selbsttest</h3>
|
||||
<ol type="1">
|
||||
<li>Sie entfernt Werte aus den Wertebereichen, die aufgrund der Bedingungen unmöglich sind — <strong>bevor</strong> gesucht wird. Dadurch schrumpft der Suchbaum drastisch.</li>
|
||||
|
|
@ -592,7 +592,7 @@
|
|||
</ol>
|
||||
<hr />
|
||||
<h2 id="sec:loesungen-graphen">A.8 Lösungen zu Kapitel „Graphen, Flüsse und Touren — Min-Cost-Flow, Matching und VRP“</h2>
|
||||
<p><strong>8.1 — Flusserhaltung.</strong> <span class="math inline">b_i = (15+3) - (12+8) = -2</span> → <strong>Senke</strong> (Nettobedarf 2).</p>
|
||||
<p><strong>8.1 — <a href="anhang-glossar.md#gloss:flusserhaltung" class="glossar-link">Flusserhaltung</a>.</strong> <span class="math inline">b_i = (15+3) - (12+8) = -2</span> → <strong>Senke</strong> (Nettobedarf 2).</p>
|
||||
<p><strong>8.2 — Unlösbarkeit.</strong> Die Summe aller Flusserhaltungsgleichungen ergibt <span class="math inline">\sum_i b_i = 0</span> (jede Kante taucht einmal mit <span class="math inline">+1</span> und einmal mit <span class="math inline">-1</span> auf). Ist die Summe ungleich null, widersprechen sich die Gleichungen. Bei Angebotsüberschuss führt man einen künstlichen <strong>Dummy-Senkenknoten</strong> mit dem Restbedarf und Kosten 0 ein.</p>
|
||||
<p><strong>8.3 — Transportproblem.</strong> (a) Angebot <span class="math inline">30+25+45 = 100</span>, Bedarf <span class="math inline">25+30+20+25 = 100</span> ✓ (b) Optimale Kosten: <strong>790</strong>. Transportplan:</p>
|
||||
<table>
|
||||
|
|
@ -644,8 +644,8 @@
|
|||
<p>Beachten Sie, dass Werk 3 seine günstigste Verbindung (L4 zu 5) voll ausschöpft und W2 ausschließlich L1 beliefert (9), obwohl L4 mit 7 billiger wäre — dort ist der Bedarf bereits von W3 gedeckt. (c) Die Lösung ist ganzzahlig, obwohl nicht gefordert — die Transportmatrix ist <strong>total unimodular</strong>, alle Ecken sind ganzzahlig.</p>
|
||||
<p><strong>8.4 — Zuordnung mit Verboten.</strong> Kosten auf einen sehr hohen Wert setzen (<code>kosten[2][2] = 1e6</code>) oder mit <code>np.inf</code> arbeiten (bei <code>linear_sum_assignment</code> erlaubt). Die Lösung weicht auf die zweitbeste Zuordnung für Carla aus; die Gesamtkosten steigen um die Differenz.</p>
|
||||
<p><strong>8.5 — Engpass finden.</strong> Die Dualwerte der Kapazitätsschranken (<code>res.upper.marginals</code> bei <code>linprog</code>) zeigen es direkt; alternativ jede Kapazität einzeln um 1 erhöhen und neu rechnen. Im Beispiel ist die Kante <code>Werk_A → Umschlag</code> der Engpass (voll ausgelastet, günstigster Weg).</p>
|
||||
<p><strong>8.6 — VRP variieren.</strong> (a) Mit 3 Fahrzeugen werden die Touren länger, die Gesamtfahrzeit steigt leicht, die Auslastung deutlich. (b) Unlösbar, sobald <span class="math inline">\text{Kapazität} \times \text{Fahrzeuge} < \text{Gesamtbedarf}</span> (hier: bei 3 Fahrzeugen à 10 sind 30 < 37 → unlösbar) <strong>oder</strong> wenn Zeitfenster nicht mehr eingehalten werden können. (c) 1 s liefert meist eine brauchbare, 30 s eine spürbar bessere Lösung — die Metaheuristik verbessert kontinuierlich. (d) Doppelte Servicezeit kann Zeitfenster verletzen → möglicherweise unlösbar.</p>
|
||||
<p><strong>8.7 — TSP mit MTZ.</strong> Erwartetes Ergebnis: Bei 8 Städten löst das MILP in Sekunden. Ab etwa 12–15 Städten wird die schwache MTZ-Relaxation zum Problem, und die Laufzeit steigt stark — während OR-Tools weiterhin in Sekundenbruchteilen sehr gute Touren liefert.</p>
|
||||
<p><strong>8.6 — <a href="anhang-glossar.md#gloss:vehicle-routing-problem-vrp" class="glossar-link">VRP</a> variieren.</strong> (a) Mit 3 Fahrzeugen werden die Touren länger, die Gesamtfahrzeit steigt leicht, die Auslastung deutlich. (b) Unlösbar, sobald <span class="math inline">\text{Kapazität} \times \text{Fahrzeuge} < \text{Gesamtbedarf}</span> (hier: bei 3 Fahrzeugen à 10 sind 30 < 37 → unlösbar) <strong>oder</strong> wenn Zeitfenster nicht mehr eingehalten werden können. (c) 1 s liefert meist eine brauchbare, 30 s eine spürbar bessere Lösung — die <a href="anhang-glossar.md#gloss:metaheuristik" class="glossar-link">Metaheuristik</a> verbessert kontinuierlich. (d) Doppelte Servicezeit kann Zeitfenster verletzen → möglicherweise unlösbar.</p>
|
||||
<p><strong>8.7 — <a href="anhang-glossar.md#gloss:tsp-traveling-salesperson-problem" class="glossar-link">TSP</a> mit MTZ.</strong> Erwartetes Ergebnis: Bei 8 Städten löst das MILP in Sekunden. Ab etwa 12–15 Städten wird die schwache MTZ-Relaxation zum Problem, und die Laufzeit steigt stark — während <a href="anhang-glossar.md#gloss:or-tools" class="glossar-link">OR-Tools</a> weiterhin in Sekundenbruchteilen sehr gute Touren liefert.</p>
|
||||
<h3 id="finde-den-denkfehler-die-vergessene-dimension">Finde den Denkfehler — Die vergessene Dimension</h3>
|
||||
<ol type="a">
|
||||
<li><strong>Was die Fahrzeuge tun.</strong> Fahrzeuge 1, 2 und 3 fahren <strong>gar nicht</strong> — sie stehen mit null Stopps im Depot. Fahrzeug 4 bedient alle 16 Kunden und lädt dabei <strong>37 Paletten</strong> bei einer Kapazität von 10. Es ist um 270 % überladen. Physikalisch ist dieser Plan nicht ausführbar; im Modell ist er die beste Lösung.</li>
|
||||
|
|
@ -694,12 +694,12 @@
|
|||
<p><strong>Es fehlt die Schranke.</strong></p>
|
||||
<p>Alles, was der Kollege sagt, stimmt. Der Fehler liegt darin, was er <em>nicht</em> sagt: Die Ersparnis wird gegen die <strong>bisherige Praxis</strong> gemessen, nicht gegen das <strong>Mögliche</strong>. Damit beantwortet die Zahl eine andere Frage als die, die das Management stellt.</p>
|
||||
<p><code>Metaheuristik_vs_Exakt.py</code> liefert die fehlende Zahl in der Spalte <em>Schranke</em>: <strong>1 768 Minuten</strong>. Der Abstand der vorgestellten Lösung zum Bestmöglichen beträgt also bis zu 25 %, nicht 0 %. In derselben Nacht, in der 640 Stunden gefeiert werden, liegen möglicherweise weitere 2 000 Stunden ungenutzt herum.</p>
|
||||
<p>Die Konsequenz ist keine Absage an das Projekt — 6,2 % sind echt und werden verdient. Die Konsequenz ist eine ehrliche Fortschreibung: „Wir heben 6,2 % und wissen, dass bis zu einem Viertel noch offen ist. Der nächste Schritt ist LNS.“ Wer die Schranke verschweigt, erklärt das Projekt für abgeschlossen und lässt den größeren Teil liegen.</p>
|
||||
<p>Die Konsequenz ist keine Absage an das Projekt — 6,2 % sind echt und werden verdient. Die Konsequenz ist eine ehrliche Fortschreibung: „Wir heben 6,2 % und wissen, dass bis zu einem Viertel noch offen ist. Der nächste Schritt ist <a href="anhang-glossar.md#gloss:large-neighborhood-search-lns" class="glossar-link">LNS</a>.“ Wer die Schranke verschweigt, erklärt das Projekt für abgeschlossen und lässt den größeren Teil liegen.</p>
|
||||
<blockquote>
|
||||
<p>Dasselbe Muster in anderer Verkleidung: Kapitel Handelsmaschine, <code>Data_Snooping.py</code> — dort fehlt nicht die Schranke, sondern die Zahl der Versuche. Beide Male macht eine weggelassene Kennzahl aus einem korrekten Ergebnis eine irreführende Aussage.</p>
|
||||
</blockquote>
|
||||
<h3 id="quiz-loesung-metaheuristiken">Micro-Quiz</h3>
|
||||
<p><strong>1. b)</strong> Eine lokale Suche lebt von der Zahl geprüfter Züge. Die volle Summe kostet <span class="math inline">O(n)</span> statt <span class="math inline">O(1)</span> — bei 500 Aufträgen zwei Größenordnungen weniger Züge im selben Zeitbudget. Numerisch ist an der vollen Summe nichts falsch (a), und die Konvergenzaussagen zu Simulated Annealing hängen nicht an der Bewertungsfunktion (c).</p>
|
||||
<p><strong>1. b)</strong> Eine lokale Suche lebt von der Zahl geprüfter Züge. Die volle Summe kostet <span class="math inline">O(n)</span> statt <span class="math inline">O(1)</span> — bei 500 Aufträgen zwei Größenordnungen weniger Züge im selben Zeitbudget. Numerisch ist an der vollen Summe nichts falsch (a), und die Konvergenzaussagen zu <a href="anhang-glossar.md#gloss:simulated-annealing" class="glossar-link">Simulated Annealing</a> hängen nicht an der Bewertungsfunktion (c).</p>
|
||||
<p><strong>2. b)</strong> Die angenommenen Verschlechterungen summieren sich. 0,29 % von mehreren hunderttausend Zügen sind einige hundert angenommene Verschlechterungen zu je rund 70 Minuten — genug, um die Suche auf das 2,1-fache der Startlösung zu tragen. Die Annahmewahrscheinlichkeit <strong>sinkt</strong> im Lauf (a ist falsch), und numerisch instabil ist nichts (c).</p>
|
||||
<p><strong>3. b)</strong> Die untere Schranke. Sie ist unabhängig davon, wie gut die gefundene Lösung ist, und die einzige verfügbare Aussage darüber, wie viel Luft noch nach oben ist. (c) klingt plausibel, ist hier aber falsch: Die CP-SAT-Lösung war <em>schlechter</em> als die Faustregel und damit als Startlösung unbrauchbar.</p>
|
||||
<h3 id="selbsttest-loesung-metaheuristiken">Selbsttest</h3>
|
||||
|
|
@ -754,14 +754,14 @@
|
|||
</tbody>
|
||||
</table>
|
||||
<p>Der Fehler steckt in der Vorstellung, „aufrunden” koste höchstens eine Rolle. Aufgerundet wird nicht <strong>eine</strong> Zahl, sondern <strong>dreizehn</strong> — je Muster eine. Jede einzelne Aufrundung kostet bis zu eine Rolle, und in der Summe sind es sechs.</p>
|
||||
<p>Die Schranke sagt: <em>Weniger als 73 Rollen sind unmöglich.</em> Sie sagt <strong>nicht</strong>: <em>Jede zulässige Lösung liegt höchstens eine Rolle darüber.</em> Das ist die Verwechslung von unterer Schranke und Gütegarantie — dieselbe Verwechslung wie beim MIP-Gap in <a href="milp.html#sec:milp-gap">Abschnitt 6.8</a>, nur in die andere Richtung.</p>
|
||||
<p>Die Schranke sagt: <em>Weniger als 73 Rollen sind unmöglich.</em> Sie sagt <strong>nicht</strong>: <em>Jede zulässige Lösung liegt höchstens eine Rolle darüber.</em> Das ist die Verwechslung von unterer Schranke und Gütegarantie — dieselbe Verwechslung wie beim <a href="anhang-glossar.md#gloss:mip-gap" class="glossar-link">MIP-Gap</a> in <a href="milp.html#sec:milp-gap">Abschnitt 6.8</a>, nur in die andere Richtung.</p>
|
||||
<p><strong>Was der Kollege stattdessen hätte tun müssen:</strong> das Master ein zweites Mal lösen, diesmal mit <code>integrality=1</code> über genau die Spalten, die er ohnehin schon erzeugt hat. Das ist eine Zeile, dauert Millisekunden und liefert 73 statt 79. Er hatte alles dafür bereits vorliegen.</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Die allgemeine Lehre</strong> Eine gebrochene LP-Lösung ist kein Plan, sondern eine Schranke. Der Weg zur ganzzahligen Lösung führt über den Solver, nicht über <code>ceil()</code>.</p>
|
||||
</blockquote>
|
||||
<h3 id="quiz-loesung-dekomposition">Micro-Quiz</h3>
|
||||
<p><strong>1. b)</strong> Das Mustermodell kennt keine einzelnen Rollen und damit keine austauschbaren Objekte — die Symmetrie verschwindet. (a) trifft zufällig auch zu, ist aber nicht der Grund; (c) ist falsch, die LP-Lösung ist hier gerade <strong>nicht</strong> ganzzahlig (72,92).</p>
|
||||
<p><strong>2. b)</strong> Ein Rucksackproblem: Nutzen sind die Schattenpreise, Gewichte die Breiten, Kapazität die Rollenbreite. (c) beschreibt eine Heuristik — dann wäre das Verfahren nicht mehr exakt, weil man nie sicher wüsste, ob es wirklich kein lohnendes Muster mehr gibt.</p>
|
||||
<p><strong>2. b)</strong> Ein <a href="anhang-glossar.md#gloss:rucksackproblem" class="glossar-link">Rucksackproblem</a>: Nutzen sind die Schattenpreise, Gewichte die Breiten, Kapazität die Rollenbreite. (c) beschreibt eine Heuristik — dann wäre das Verfahren nicht mehr exakt, weil man nie sicher wüsste, ob es wirklich kein lohnendes Muster mehr gibt.</p>
|
||||
<p><strong>3. b)</strong> Die untere Schranke von 33,60 beweist, dass mindestens 34 Rollen nötig sind. Damit weiß man, dass die 35 der Faustregel höchstens eine daneben liegen — und kann aufhören zu suchen. Genau diese Aussage kann eine Heuristik allein nie liefern (<a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a>).</p>
|
||||
<h3 id="selbsttest-loesung-dekomposition">Selbsttest</h3>
|
||||
<ol type="1">
|
||||
|
|
@ -774,8 +774,8 @@
|
|||
<hr />
|
||||
<h2 id="sec:loesungen-qp-nlp">A.11 Lösungen zu Kapitel „Quadratische und nichtlineare Optimierung — KKT, Lagrange, Konvexität“</h2>
|
||||
<p><strong>11.1 — Konvexität einordnen.</strong> PSD (alle <span class="math inline">\ge 0</span>) → <strong>konvex</strong>, aber <strong>nicht streng</strong> konvex; die Lösung ist <strong>nicht notwendig eindeutig</strong>. Der Eigenwert 0 bedeutet eine <strong>flache Richtung</strong>: Entlang des zugehörigen Eigenvektors ändert sich der quadratische Term nicht — es gibt eine Rinne statt eines Punktes.</p>
|
||||
<p><strong>11.2 — Komplementärer Schlupf.</strong> Ja, verträglich: <span class="math inline">\lambda_i w_i = 0</span> gilt für alle <span class="math inline">i</span> (<span class="math inline">w_2 = 0</span> mit <span class="math inline">\lambda_2 > 0</span>; die anderen mit <span class="math inline">\lambda = 0</span>). <span class="math inline">\lambda_2 = 0{,}03</span> bedeutet: Würde man Titel 2 zwingen, ein kleines positives Gewicht zu tragen, verschlechterte sich der Zielwert um 0,03 je Einheit — die Nichtnegativitätsschranke ist dort <strong>bindend</strong>.</p>
|
||||
<p><strong>11.3 — KKT von Hand.</strong> <span class="math inline">\mathcal{L} = x_1^2 + x_2^2 + \lambda(4 - x_1 - x_2)</span>. Stationarität: <span class="math inline">2x_1 = \lambda</span>, <span class="math inline">2x_2 = \lambda</span> → <span class="math inline">x_1 = x_2</span>. Bindend (<span class="math inline">\lambda > 0</span>): <span class="math inline">x_1 + x_2 = 4</span> → <span class="math inline">x_1 = x_2 = 2</span>, <span class="math inline">\lambda = 4</span>. Prüfung: <span class="math inline">\lambda = 4 > 0</span> ✓, <span class="math inline">f = 8</span>. <strong>Interpretation:</strong> Würde die Forderung auf <span class="math inline">\ge 4{,}1</span> steigen, stiege <span class="math inline">f</span> um etwa <span class="math inline">4 \cdot 0{,}1 = 0{,}4</span>. Probe: <span class="math inline">2\cdot(2{,}05)^2 = 8{,}405</span> ✓.</p>
|
||||
<p><strong>11.2 — <a href="anhang-glossar.md#gloss:komplementaerer-schlupf" class="glossar-link">Komplementärer Schlupf</a>.</strong> Ja, verträglich: <span class="math inline">\lambda_i w_i = 0</span> gilt für alle <span class="math inline">i</span> (<span class="math inline">w_2 = 0</span> mit <span class="math inline">\lambda_2 > 0</span>; die anderen mit <span class="math inline">\lambda = 0</span>). <span class="math inline">\lambda_2 = 0{,}03</span> bedeutet: Würde man Titel 2 zwingen, ein kleines positives Gewicht zu tragen, verschlechterte sich der Zielwert um 0,03 je Einheit — die Nichtnegativitätsschranke ist dort <strong>bindend</strong>.</p>
|
||||
<p><strong>11.3 — <a href="anhang-glossar.md#gloss:karush-kuhn-tucker-bedingungen-kkt" class="glossar-link">KKT</a> von Hand.</strong> <span class="math inline">\mathcal{L} = x_1^2 + x_2^2 + \lambda(4 - x_1 - x_2)</span>. Stationarität: <span class="math inline">2x_1 = \lambda</span>, <span class="math inline">2x_2 = \lambda</span> → <span class="math inline">x_1 = x_2</span>. Bindend (<span class="math inline">\lambda > 0</span>): <span class="math inline">x_1 + x_2 = 4</span> → <span class="math inline">x_1 = x_2 = 2</span>, <span class="math inline">\lambda = 4</span>. Prüfung: <span class="math inline">\lambda = 4 > 0</span> ✓, <span class="math inline">f = 8</span>. <strong>Interpretation:</strong> Würde die Forderung auf <span class="math inline">\ge 4{,}1</span> steigen, stiege <span class="math inline">f</span> um etwa <span class="math inline">4 \cdot 0{,}1 = 0{,}4</span>. Probe: <span class="math inline">2\cdot(2{,}05)^2 = 8{,}405</span> ✓.</p>
|
||||
<p><strong>11.4 — Unmögliche Korrelationsmatrix.</strong> Eigenwerte <span class="math inline">\approx (-0{,}62;\ 1{,}0;\ 2{,}62)</span> → <strong>nicht PSD</strong>, also unmöglich. Anschaulich: Wenn A stark <strong>positiv</strong> mit B korreliert und B stark positiv mit C, kann A nicht gleichzeitig stark <strong>negativ</strong> mit C korrelieren — Korrelation ist eingeschränkt transitiv. Formal: <span class="math inline">\rho_{AC} \ge \rho_{AB}\rho_{BC} - \sqrt{(1-\rho_{AB}^2)(1-\rho_{BC}^2)} = 0{,}81 - 0{,}19 = 0{,}62</span>; verlangt waren <span class="math inline">-0{,}9</span>.</p>
|
||||
<p><strong>11.5 — Gewichtung untersuchen.</strong> Erwartetes Muster: Größeres <span class="math inline">\alpha</span> → mehr Rendite, mehr Konzentration im Titel mit höchstem <span class="math inline">\mu</span>. Größeres <span class="math inline">\beta</span> → gleichmäßigere Gewichte, Entropie steigt Richtung <span class="math inline">\ln 4 = 1{,}386</span>. Ab etwa <span class="math inline">\beta \approx 0{,}1</span> dominiert die Entropie und man nähert sich der Gleichgewichtung. <strong>Empfehlung an einen Ausschuss:</strong> Nicht mit <span class="math inline">\beta</span> argumentieren, sondern mit der resultierenden <strong>Maximalposition</strong> — „mit dieser Einstellung liegt keine Position über 40 %“ ist verständlich, „<span class="math inline">\beta = 0{,}015</span>“ nicht.</p>
|
||||
<p><strong>11.6 — Nicht-Konvexität demonstrieren.</strong> Mit der bewusst fehlerhaft konstruierten Matrix finden 20 Startpunkte typischerweise mehrere verschiedene Optima; die „Portfoliovarianz“ <span class="math inline">w^\top\Sigma w</span> kann bei geeigneten Gewichten negativ werden (der zugehörige Eigenvektor liegt allerdings teilweise außerhalb des zulässigen Bereichs <span class="math inline">w \ge 0{,}001</span>, <span class="math inline">\sum w = 1</span> — deshalb fällt der Fehler bei naiver Prüfung nicht auf).</p>
|
||||
|
|
@ -807,14 +807,14 @@
|
|||
<ol type="1">
|
||||
<li><strong>Prüfen</strong>, ob die Matrix positiv semidefinit ist (Zeile aus (b)) — beim Einlesen, nicht beim Optimieren.</li>
|
||||
<li><strong>Die Ursache suchen.</strong> Korrelationen aus verschiedenen Quellen, Zeiträumen oder Frequenzen sind fast nie widerspruchsfrei. Schätzen Sie die Matrix aus <strong>einem</strong> konsistenten Datensatz.</li>
|
||||
<li>Ist das nicht möglich, die Matrix <strong>reparieren</strong>: negative Eigenwerte auf null setzen und rekonstruieren (<em>Eigenwert-Clipping</em>, siehe die Aufgabe <em>Konvexität einer Kovarianzmatrix reparieren</em> in <a href="fundament.html#kap-fundament">Kapitel 2</a>) oder gleich einen Shrinkage-Schätzer verwenden, der positive Semidefinitheit garantiert (<a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a>).</li>
|
||||
<li>Ist das nicht möglich, die Matrix <strong>reparieren</strong>: negative Eigenwerte auf null setzen und rekonstruieren (<em>Eigenwert-Clipping</em>, siehe die Aufgabe <em>Konvexität einer <a href="anhang-glossar.md#gloss:kovarianzmatrix" class="glossar-link">Kovarianzmatrix</a> reparieren</em> in <a href="fundament.html#kap-fundament">Kapitel 2</a>) oder gleich einen Shrinkage-Schätzer verwenden, der positive Semidefinitheit garantiert (<a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a>).</li>
|
||||
</ol>
|
||||
<blockquote>
|
||||
<p><strong>Der Merksatz dazu:</strong> Eine Kovarianzmatrix ist kein Behälter für einzeln geschätzte Zahlen, sondern ein geometrisches Objekt. Nicht jede Kombination von Korrelationen existiert.</p>
|
||||
</blockquote>
|
||||
<h3 id="quiz-loesung-qp-nlp">Micro-Quiz</h3>
|
||||
<p><strong>1 — (b).</strong> Der <code>DCPError</code> ist eine inhaltliche Aussage: Für diese Formulierung kann es keine Optimalitätsgarantie geben. Auf <code>scipy</code> auszuweichen (a) beseitigt die Meldung, nicht die Ursache — man bekommt dann ein lokales Ergebnis ohne Garantie und ohne Warnung, wie <a href="qp-nlp.html#sec:qp-nlp-denkfehler">Abschnitt 11.8</a> zeigt. Toleranzen (c) haben mit Konvexität nichts zu tun. Richtig ist, zwischen zwei bewussten Wegen zu wählen: konvex umformulieren, oder lokal rechnen <strong>und</strong> das im Bericht kenntlich machen.</p>
|
||||
<p><strong>2 — (b) ein lokales Minimum.</strong> <code>success: True</code> beschreibt die Konvergenz des Verfahrens, nicht die Qualität des Ergebnisses. Bei Mengenrabatten ist die Zielfunktion nicht konvex, also kann es mehrere lokale Minima geben — im Kapitelbeispiel fünf, mit 8 % Spanne. (a) wäre nur bei einem konvexen Problem richtig. (c) ist zu pessimistisch: Ein lokales Minimum ist es sehr wohl, die Zulässigkeit wird von SLSQP eingehalten.</p>
|
||||
<p><strong>2 — (b) ein lokales Minimum.</strong> <code>success: True</code> beschreibt die Konvergenz des Verfahrens, nicht die Qualität des Ergebnisses. Bei Mengenrabatten ist die Zielfunktion nicht konvex, also kann es mehrere lokale Minima geben — im Kapitelbeispiel fünf, mit 8 % Spanne. (a) wäre nur bei einem konvexen Problem richtig. (c) ist zu pessimistisch: Ein lokales Minimum ist es sehr wohl, die Zulässigkeit wird von <a href="anhang-glossar.md#gloss:slsqp" class="glossar-link">SLSQP</a> eingehalten.</p>
|
||||
<p><strong>3 — (c) Schattenpreis.</strong> <span class="math inline">\lambda^*</span> ist die Ableitung des optimalen Zielwerts nach der rechten Seite der Nebenbedingung — dieselbe Bedeutung wie der Dualwert im LP (<a href="lp.html#kap-lp">Kapitel 5</a>), nur für allgemeine, auch krumme Nebenbedingungen. (a) und (b) verwechseln den Multiplikator mit einer Verletzungszahl beziehungsweise mit dem Schlupf; der Schlupf ist bei einer bindenden Bedingung gerade <strong>null</strong> (komplementärer Schlupf).</p>
|
||||
<h3 id="selbsttest-loesung-qp-nlp">Selbsttest</h3>
|
||||
<ol type="1">
|
||||
|
|
@ -827,12 +827,12 @@
|
|||
<hr />
|
||||
<h2 id="sec:loesungen-unsicherheit">A.12 Lösungen zu Kapitel „Optimierung unter Unsicherheit — Monte-Carlo, Stochastik, Robustheit“</h2>
|
||||
<p><strong>12.1 — Fluch des Durchschnitts.</strong> Weil sich Verzögerungen <strong>fortpflanzen</strong> und die Verteilung rechtsschief ist: Ein Gewerk, das früher fertig wird, beschleunigt selten den Gesamtablauf (der nächste Schritt ist noch nicht bereit), ein verspätetes verzögert alles. Weitere Beispiele: Wartezeiten in Warteschlangen (nichtlinear in der Auslastung), Projektkosten mit Nachträgen.</p>
|
||||
<p><strong>12.2 — Ansatz wählen.</strong> (a) robust (Ausfall ist existenziell, Wahrscheinlichkeiten unzuverlässig). (b) stochastisch (Verteilung bekannt). (c) robust bzw. Extremwertstatistik (seltene Ereignisse, katastrophale Folgen). (d) stochastisch (Szenarien mit Wahrscheinlichkeiten liegen vor). (e) Chance Constraint — die Zusage ist bereits als Quote formuliert („an 99 % aller Wintertage“). Robust wäre hier zu teuer (es gibt immer einen kälteren Tag), der Erwartungswert zu schwach (er sagt nichts über die Zusage).</p>
|
||||
<p><strong>12.2 — Ansatz wählen.</strong> (a) robust (Ausfall ist existenziell, Wahrscheinlichkeiten unzuverlässig). (b) stochastisch (Verteilung bekannt). (c) robust bzw. Extremwertstatistik (seltene Ereignisse, katastrophale Folgen). (d) stochastisch (Szenarien mit Wahrscheinlichkeiten liegen vor). (e) <a href="anhang-glossar.md#gloss:chance-constraint" class="glossar-link">Chance Constraint</a> — die Zusage ist bereits als Quote formuliert („an 99 % aller Wintertage“). Robust wäre hier zu teuer (es gibt immer einen kälteren Tag), der Erwartungswert zu schwach (er sagt nichts über die Zusage).</p>
|
||||
<p><strong>12.3 — Zweistufig rechnen.</strong> (a) Mit Spot = 60: Ableitung bei <span class="math inline">x \in (100,250)</span>: <span class="math inline">40 - 60\cdot0{,}5 + 5\cdot0{,}5 = 40-30+2{,}5 = +12{,}5 > 0</span> → Kapazität <strong>senken</strong>. Bei <span class="math inline">x < 100</span>: <span class="math inline">40 - 60 = -20 < 0</span> → erhöhen. Optimum daher <span class="math inline">x^* = 100</span>. (b) Billige Nachbesserung macht Vorhalten unattraktiv. (c) Bei <span class="math inline">x = 225</span> optimal müsste die Ableitung dort das Vorzeichen wechseln — das ist bei diskreten Szenarien nur zufällig der Fall; der Mittelwert ist nur bei symmetrischen Kosten und stetiger Verteilung optimal.</p>
|
||||
<p><strong>12.4 — EVPI interpretieren.</strong> Selbst eine <strong>perfekte</strong> Prognose wäre nur 8 400 € pro Jahr wert. Eine Lösung für 15 000 € kann sich also <strong>niemals</strong> rechnen — unabhängig von ihrer Güte. Argument: „Der theoretische Maximalnutzen liegt unter dem Preis.“</p>
|
||||
<p><strong>12.4 — <a href="anhang-glossar.md#gloss:evpi-expected-value-of-perfect-information" class="glossar-link">EVPI</a> interpretieren.</strong> Selbst eine <strong>perfekte</strong> Prognose wäre nur 8 400 € pro Jahr wert. Eine Lösung für 15 000 € kann sich also <strong>niemals</strong> rechnen — unabhängig von ihrer Güte. Argument: „Der theoretische Maximalnutzen liegt unter dem Preis.“</p>
|
||||
<p><strong>12.5 — Monte-Carlo erweitern.</strong> (a) Servicelevel 95 %: Kapazität = 95 %-Quantil des Bedarfs (ca. 485). Die Zusatzkosten gegenüber dem Kostenoptimum (180) betragen ein Vielfaches — Servicelevel ist teuer, und genau diese Zahl braucht die Geschäftsleitung für die Entscheidung. (b) <code>cvar = kosten[kosten >= np.quantile(kosten, 0.95)].mean()</code>. (c) Erwartetes Bild: Bei kleiner Kapazität ist die Kostenverteilung stark rechtsschief (seltene, teure Notzukäufe); bei großer Kapazität schmal und nach rechts verschoben.</p>
|
||||
<p><strong>12.6 — Den Preis der Zusage selbst bestimmen.</strong> (a) Die Kosten je Prozentpunkt steigen weiter steil an; der Mix verschiebt sich dabei fast nur noch zugunsten des Gaskraftwerks, weil Biomasse längst an ihrer Ausbaugrenze liegt. Wind und Sonne bleiben bei einem kleinen Rest — sie senken über ihre Gegenläufigkeit die Norm, tragen zur gesicherten Leistung aber kaum bei. (b) Der Unterschied ist <strong>nicht</strong> numerisch, sondern inhaltlich. Bei 200 MW Biomasse liefert selbst der <strong>Vollausbau</strong> in der Kältewelle nur rund 440 MW — 7,5 % der Szenarien sind schlicht nicht bedienbar, egal wie viel Geld man ausgibt. Das Szenariomodell sieht diese Fälle in den Daten und meldet korrekt <code>infeasible</code>, sobald die Zusage über 92 % steigt. Das analytische Modell kennt sie nicht: Für eine Normalverteilung ist jede Zusage unter 100 % erfüllbar, wenn man nur genug Streuung wegkauft. Es meldet <code>optimal</code> — und der Plan hält gemessen 87,4 %. Glauben sollte man dem Szenariomodell: Ein <code>infeasible</code> ist hier die <strong>richtige</strong> Antwort. Es sagt, dass die Zusage nicht am Budget scheitert, sondern am Kraftwerkspark, und dass nicht mehr Geld hilft, sondern nur eine andere Anlage oder eine kleinere Zusage. (c) Sinngemäß: „99,99 % kosten nicht 5 % mehr als 99 %, sondern ein Vielfaches — der letzte Prozentpunkt ist bereits 4,5-mal so teuer wie der erste. Sagen Sie mir, was ein Ausfalltag das Unternehmen kostet, dann rechne ich aus, welche Quote sich lohnt. Und die Zusage gilt nur für die Wetterlagen, die wir modelliert haben — die Kältewelle gehört hinein.“</p>
|
||||
<p><strong>12.7 — Budgeted Uncertainty.</strong></p>
|
||||
<p><strong>12.7 — <a href="anhang-glossar.md#gloss:budgeted-uncertainty" class="glossar-link">Budgeted Uncertainty</a>.</strong></p>
|
||||
<div class="sourceCode" id="cb14"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>abzug <span class="op">=</span> cp.sum_largest(cp.multiply(UNSICHERHEIT, w), Gamma)</span>
|
||||
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>ziel <span class="op">=</span> cp.Maximize(MU_SCHAETZUNG <span class="op">@</span> w <span class="op">-</span> abzug <span class="op">-</span> <span class="fl">0.5</span><span class="op">*</span>LAMBDA<span class="op">*</span>cp.quad_form(w, SIGMA))</span></code></pre></div>
|
||||
<p><span class="math inline">\Gamma = 0</span> entspricht dem nominalen Fall, <span class="math inline">\Gamma = n</span> dem vollen Worst Case. Dazwischen steuert <span class="math inline">\Gamma</span> die Vorsicht stufenlos — der praktisch nützlichste Bereich liegt meist bei <span class="math inline">\Gamma \approx \sqrt{n}</span>.</p>
|
||||
|
|
@ -844,7 +844,7 @@
|
|||
\mathbb{E}\big[\max(D_1,\dots,D_5)\big] \;\ne\; \max\big(\mathbb{E}[D_1],\dots,\mathbb{E}[D_5]\big)
|
||||
</span></p>
|
||||
<p>Anschaulich: Das Projekt ist fertig, wenn das <strong>letzte</strong> Gewerk fertig ist. Ein Gewerk, das statt 11 nur 7 Tage braucht, bringt niemandem etwas — die anderen sind ja noch dran. Ein Gewerk, das 17 Tage braucht, hält alle auf. Die guten Ausreißer verpuffen, die schlechten schlagen voll durch.</p>
|
||||
<p>Damit gilt für das Maximum immer <span class="math inline">\mathbb{E}[\max] \ge \max(\mathbb{E})</span>. Die Differenz ist kein Schätzfehler, sondern eine <strong>systematische Verzerrung</strong> — sie geht immer in dieselbe Richtung, und sie wächst mit der Streuung der Einzelschätzungen.</p>
|
||||
<p>Damit gilt für das Maximum immer <span class="math inline">\mathbb{E}[\max] \ge \max(\mathbb{E})</span>. Die Differenz ist kein <a href="anhang-glossar.md#gloss:schaetzfehler" class="glossar-link">Schätzfehler</a>, sondern eine <strong>systematische Verzerrung</strong> — sie geht immer in dieselbe Richtung, und sie wächst mit der Streuung der Einzelschätzungen.</p>
|
||||
<ol start="2" type="a">
|
||||
<li><strong>Warum 95,5 %.</strong> Damit das Projekt die geplanten 11,33 Tage hält, müssen <strong>alle fünf</strong> Gewerke gleichzeitig ihren Mittelwert unterbieten. Für die Dreiecksverteilung <span class="math inline">(6;\ 10;\ 18)</span> ist die Wahrscheinlichkeit dafür je Gewerk</li>
|
||||
</ol>
|
||||
|
|
@ -870,7 +870,7 @@ F(11{,}33) = 1 - \frac{(18-11{,}33)^2}{(18-6)(18-10)} = 1 - \frac{44{,}4}{96} =
|
|||
<p>Und die Formulierung gegenüber dem Auftraggeber lautet nicht „der Umbau dauert 17 Tage“, sondern: <em>„In 9 von 10 Fällen sind wir nach 17 Tagen fertig; im Mittel nach 14,4.“</em> Diese zwei Zahlen sind eine belastbare Zusage — eine einzelne ist es nie.</p>
|
||||
<h3 id="quiz-loesung-unsicherheit">Micro-Quiz</h3>
|
||||
<p><strong>1 — (b).</strong> Das kritische Verhältnis <span class="math inline">1400/(1400+120) = 0{,}921</span> gibt an, wie weit man sich auf die günstigere Fehlerseite stellen soll: Bestellt wird das 92,1-%-Quantil des Bedarfs, hier 38 Stück. (a) ignoriert die Kostenasymmetrie und kostet im Kapitelbeispiel 160 % mehr. (c) verwechselt die Fragestellung: Die Kapitalbindung <em>ist</em> bereits in den 120 € je überzähligem Stück enthalten — sie rechtfertigt keine zusätzliche Kürzung.</p>
|
||||
<p><strong>2 — (b).</strong> Der Unterschied liegt darin, <strong>was man wissen muss</strong>: Stochastische Optimierung setzt eine Wahrscheinlichkeitsverteilung voraus und minimiert den Erwartungswert; robuste Optimierung kommt mit einer bloßen Bandbreite aus und sichert den ungünstigsten Fall darin ab. Keines ist „genauer“ (a) — sie beantworten verschiedene Fragen. (c) trifft es nicht: Robuste Optimierung betrachtet nicht mehr Szenarien, sondern eine ganze Menge auf einmal, und interessiert sich darin nur für den schlechtesten Punkt.</p>
|
||||
<p><strong>2 — (b).</strong> Der Unterschied liegt darin, <strong>was man wissen muss</strong>: Stochastische Optimierung setzt eine Wahrscheinlichkeitsverteilung voraus und minimiert den Erwartungswert; robuste Optimierung kommt mit einer bloßen Bandbreite aus und sichert den ungünstigsten Fall darin ab. Keines ist „genauer“ (a) — sie beantworten verschiedene Fragen. (c) trifft es nicht: <a href="anhang-glossar.md#gloss:robuste-optimierung" class="glossar-link">Robuste Optimierung</a> betrachtet nicht mehr Szenarien, sondern eine ganze Menge auf einmal, und interessiert sich darin nur für den schlechtesten Punkt.</p>
|
||||
<p><strong>3 — (c).</strong> Bei durchgehender Linearität und ohne nachgelagerte Entscheidung gilt <span class="math inline">\mathbb{E}[f(X)] = f(\mathbb{E}[X])</span> — dann ist Rechnen mit Mittelwerten korrekt. Sobald aber ein Maximum, ein Minimum, ein Betrag oder eine Nachbesserungsentscheidung auftaucht, gilt das nicht mehr: Genau das sind die beiden Fälle aus Schnellstart (asymmetrische Kosten über <code>maximum</code>) und <a href="unsicherheit.html#sec:unsicherheit-denkfehler">Abschnitt 12.9</a> (Maximum über parallele Vorgänge). (a) ist die Fehlannahme, um die es im ganzen Kapitel geht; (b) ist zu absolut — es gibt den linearen Fall, in dem es tatsächlich zulässig ist.</p>
|
||||
<h3 id="selbsttest-loesung-unsicherheit">Selbsttest</h3>
|
||||
<ol type="1">
|
||||
|
|
@ -885,9 +885,9 @@ F(11{,}33) = 1 - \frac{(18-11{,}33)^2}{(18-6)(18-10)} = 1 - \frac{44{,}4}{96} =
|
|||
<hr />
|
||||
<h2 id="sec:loesungen-dynamische-programmierung">A.13 Lösungen zu Kapitel „Dynamische Programmierung — Die Bellman-Gleichung und Order-Execution“</h2>
|
||||
<p><strong>13.1 — Bausteine.</strong> Stufe = Tag 1–5; Zustand = verbleibende Distanz (ggf. plus Erschöpfungsgrad); Aktion = heutige Tagesetappe; Wertfunktion = minimale Restanstrengung. <strong>Nicht</strong> in den Zustand gehören: bereits gelaufene Kilometer (redundant, wenn die Restdistanz bekannt ist) und das Wetter von gestern (ohne Einfluss auf die Zukunft).</p>
|
||||
<p><strong>13.2 — Optimalitätsprinzip.</strong> Weil der Wert eines Zustands nur von den <em>künftigen</em> Entscheidungen abhängt, kann man ihn ab dem Ende rekursiv berechnen. Hängen die Kosten zusätzlich von <strong>früheren</strong> Aktionen ab, ist die Markov-Eigenschaft verletzt — die Lösung: die relevante Vergangenheit <strong>in den Zustand aufnehmen</strong> (dann wächst allerdings der Zustandsraum).</p>
|
||||
<p><strong>13.3 — Rückwärtsinduktion.</strong> Mit <span class="math inline">C(n) = n^2 + 2n</span> und 5 Einheiten in 3 Perioden ergibt sich als optimaler Pfad <span class="math inline">2 \to 2 \to 1</span> (oder eine Permutation davon) mit Gesamtkosten <span class="math inline">8 + 8 + 3 = 19</span>. Alles auf einmal kostet <span class="math inline">25 + 10 = 35</span>.</p>
|
||||
<p><strong>13.4 — Rucksack als DP.</strong></p>
|
||||
<p><strong>13.2 — <a href="anhang-glossar.md#gloss:optimalitaetsprinzip" class="glossar-link">Optimalitätsprinzip</a>.</strong> Weil der Wert eines Zustands nur von den <em>künftigen</em> Entscheidungen abhängt, kann man ihn ab dem Ende rekursiv berechnen. Hängen die Kosten zusätzlich von <strong>früheren</strong> Aktionen ab, ist die Markov-Eigenschaft verletzt — die Lösung: die relevante Vergangenheit <strong>in den Zustand aufnehmen</strong> (dann wächst allerdings der <a href="anhang-glossar.md#gloss:zustandsraum" class="glossar-link">Zustandsraum</a>).</p>
|
||||
<p><strong>13.3 — <a href="anhang-glossar.md#gloss:rueckwaertsinduktion" class="glossar-link">Rückwärtsinduktion</a>.</strong> Mit <span class="math inline">C(n) = n^2 + 2n</span> und 5 Einheiten in 3 Perioden ergibt sich als optimaler Pfad <span class="math inline">2 \to 2 \to 1</span> (oder eine Permutation davon) mit Gesamtkosten <span class="math inline">8 + 8 + 3 = 19</span>. Alles auf einmal kostet <span class="math inline">25 + 10 = 35</span>.</p>
|
||||
<p><strong>13.4 — Rucksack als <a href="anhang-glossar.md#gloss:dynamische-programmierung-dp" class="glossar-link">DP</a>.</strong></p>
|
||||
<div class="sourceCode" id="cb16"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>V <span class="op">=</span> np.zeros((n <span class="op">+</span> <span class="dv">1</span>, kapazitaet <span class="op">+</span> <span class="dv">1</span>))</span>
|
||||
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">1</span>, n <span class="op">+</span> <span class="dv">1</span>):</span>
|
||||
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> c <span class="kw">in</span> <span class="bu">range</span>(kapazitaet <span class="op">+</span> <span class="dv">1</span>):</span>
|
||||
|
|
@ -944,7 +944,7 @@ F(11{,}33) = 1 - \frac{(18-11{,}33)^2}{(18-6)(18-10)} = 1 - \frac{44{,}4}{96} =
|
|||
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a> ...</span>
|
||||
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a> kosten <span class="op">=</span> (RUESTKOSTEN <span class="cf">if</span> (p <span class="op">></span> <span class="dv">0</span> <span class="kw">and</span> <span class="kw">not</span> lief_vorher) <span class="cf">else</span> <span class="dv">0</span>) <span class="op">+</span> ...</span>
|
||||
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a> rest, plan <span class="op">=</span> V(t <span class="op">+</span> <span class="dv">1</span>, neu, p <span class="op">></span> <span class="dv">0</span>)</span></code></pre></div>
|
||||
<p>Damit findet die Rückwärtsinduktion <span class="math inline">(3, 1, 4, 2)</span> für 70 € — das nachgerechnete Optimum. Der Zustandsraum <strong>verdoppelt</strong> sich (je Lagerstand zwei Varianten, „lief“ und „lief nicht“). Das ist der übliche Preis: Vollständigkeit des Zustands kostet Größe, und genau hier beginnt der Fluch der Dimensionalität.</p>
|
||||
<p>Damit findet die Rückwärtsinduktion <span class="math inline">(3, 1, 4, 2)</span> für 70 € — das nachgerechnete Optimum. Der Zustandsraum <strong>verdoppelt</strong> sich (je Lagerstand zwei Varianten, „lief“ und „lief nicht“). Das ist der übliche Preis: Vollständigkeit des Zustands kostet Größe, und genau hier beginnt der <a href="anhang-glossar.md#gloss:fluch-der-dimensionalitaet" class="glossar-link">Fluch der Dimensionalität</a>.</p>
|
||||
<ol start="4" type="a">
|
||||
<li><strong>Warum der richtige Betrag das Tückische ist.</strong> Man würde erwarten, dass ein falsches Modell auch einen falschen Kostenbetrag ausgibt — dann fiele es beim Nachrechnen auf. Hier nicht: Für den von ihm gewählten Plan <span class="math inline">(5,0,5,0)</span> stimmt die Rechnung zufällig, weil in diesem Plan tatsächlich jede Produktionsperiode auf eine Pause folgt. Modellannahme und Wirklichkeit fallen für <strong>genau diese eine Lösung</strong> zusammen.</li>
|
||||
</ol>
|
||||
|
|
@ -962,7 +962,7 @@ F(11{,}33) = 1 - \frac{(18-11{,}33)^2}{(18-6)(18-10)} = 1 - \frac{44{,}4}{96} =
|
|||
<li>Jeder Teilabschnitt einer optimalen Strategie ist selbst optimal für den Zustand, in dem er beginnt.</li>
|
||||
<li>Weil <span class="math inline">V_{t+1}</span> bekannt sein muss, um <span class="math inline">V_t</span> zu berechnen — und am Ende ist der Wert bekannt.</li>
|
||||
<li>Alles, was die Zukunft beeinflusst, und nichts weiter. Unvollständig ist er, wenn die Kosten oder Übergänge zusätzlich von der Vorgeschichte abhängen.</li>
|
||||
<li>Der Aufwand wächst multiplikativ mit jeder Zustandsdimension. Gegenmittel: gröbere Diskretisierung/Zustandsreduktion, Funktionsapproximation (ADP), Reinforcement Learning.</li>
|
||||
<li>Der Aufwand wächst multiplikativ mit jeder Zustandsdimension. Gegenmittel: gröbere Diskretisierung/Zustandsreduktion, Funktionsapproximation (ADP), <a href="anhang-glossar.md#gloss:reinforcement-learning" class="glossar-link">Reinforcement Learning</a>.</li>
|
||||
<li>Weil sie eine <strong>unabhängige</strong> Prüfung ermöglicht — Größenordnungsfehler und Vorzeichenfehler fallen sofort auf.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
|
|
@ -974,7 +974,7 @@ F(11{,}33) = 1 - \frac{(18-11{,}33)^2}{(18-6)(18-10)} = 1 - \frac{44{,}4}{96} =
|
|||
<p>Begründung in einem Satz: <em>„Für 646 Euro sparen wir 843 Kilogramm CO₂ — zu 77 Cent je Kilogramm, während wir intern mit 90 Cent rechnen.“</em></p>
|
||||
<p><strong>14.3 — Mehr Trassen.</strong> Mit 8 statt 5 Trassen wird der Engpass schwächer. Zu erwarten ist eine <strong>kürzere</strong> Front: Der Zielkonflikt entsteht ja allein aus der Knappheit; je mehr Trassen, desto näher rücken Kostenminimum und CO₂-Minimum zusammen. Im Grenzfall genügend vieler Trassen fallen beide zusammen — die Bahn ist billiger <em>und</em> sauberer, also gibt es gar keinen Konflikt mehr und die Front schrumpft auf einen Punkt.</p>
|
||||
<p>Der Lehrpunkt: <strong>Ein Zielkonflikt ist keine Eigenschaft der Ziele, sondern der Knappheit.</strong> Wer ihn auflösen will, sollte zuerst prüfen, ob sich die Ressource vermehren lässt, statt über Gewichte zu verhandeln.</p>
|
||||
<p><strong>14.4 — Die Front der Relaxation.</strong> Ohne <code>integrality</code> ist der zulässige Bereich konvex, und die Pareto-Front liegt vollständig auf ihrer eigenen unteren konvexen Hülle. Es gibt also <strong>keinen</strong> Punkt oberhalb — jeder Punkt der Front ist durch ein passendes Gewicht erreichbar.</p>
|
||||
<p><strong>14.4 — Die Front der Relaxation.</strong> Ohne <code>integrality</code> ist der zulässige Bereich konvex, und die <a href="anhang-glossar.md#gloss:pareto-front" class="glossar-link">Pareto-Front</a> liegt vollständig auf ihrer eigenen unteren konvexen Hülle. Es gibt also <strong>keinen</strong> Punkt oberhalb — jeder Punkt der Front ist durch ein passendes Gewicht erreichbar.</p>
|
||||
<p>Genau das ist der Grund, warum das Problem in Lehrbüchern zur linearen Programmierung nicht vorkommt und in der betrieblichen Praxis ständig: Sobald „welcher Träger“, „welches Lager“ oder „welche Schicht“ entschieden wird, zerfällt der Bereich in einzelne Punkte, und zwischen ihnen entstehen die Einbuchtungen, in denen die nicht gestützten Lösungen liegen.</p>
|
||||
<p><strong>14.5 — Drei Ziele.</strong> Die Front wird zu einer Fläche im dreidimensionalen Zielraum. Das ε-Verfahren braucht dann ein <strong>Gitter</strong> über zwei Schranken statt einer Folge über eine — der Aufwand wächst von <span class="math inline">O(k)</span> auf <span class="math inline">O(k^2)</span>, bei <span class="math inline">m</span> Zielen auf <span class="math inline">O(k^{m-1})</span>.</p>
|
||||
<p>Zwei praktische Folgerungen: Erstens ist bei drei und mehr Zielen die vollständige Front meist nicht mehr bezahlbar; man arbeitet dann mit einer Stichprobe oder mit Metaheuristiken, die eine Front approximieren (NSGA-II, in <code>pymoo</code> enthalten). Zweitens ist eine Front mit hunderten Punkten für die Entscheidung ohnehin unbrauchbar — ab drei Zielen ist die bessere Frage meist, ob sich zwei davon zusammenfassen lassen.</p>
|
||||
|
|
@ -1004,11 +1004,11 @@ F(11{,}33) = 1 - \frac{(18-11{,}33)^2}{(18-6)(18-10)} = 1 - \frac{44{,}4}{96} =
|
|||
<p>Das ist die richtige Richtung und leicht zu merken: Je billiger der Überhang, desto großzügiger darf man ansetzen. Im Grenzfall kostenloser Entsorgung (<span class="math inline">c_+ \to 0</span>) geht das kritische Verhältnis gegen 1 — man bestellt so viel, dass praktisch nie etwas fehlt.</p>
|
||||
<p><strong>15.2 — Wann ist der Mittelwert richtig?</strong> Nur wenn <span class="math inline">c_- = c_+</span> <strong>und</strong> die Nachfrageverteilung symmetrisch ist. Dann liegt das kritische Verhältnis bei 0,5, das 50-%-Quantil ist der Median, und bei Symmetrie fällt der Median mit dem Mittelwert zusammen.</p>
|
||||
<p>Beide Bedingungen sind unrealistisch. Fehlmenge und Überhang kosten fast nie dasselbe — bei Frischware ist der Überhang teurer, bei Ersatzteilen die Fehlmenge um Größenordnungen. Und Nachfrageverteilungen sind meist rechtsschief. Der Mittelwert ist damit die Ausnahme, nicht die Regel — er wird nur benutzt, weil Regressionsmodelle ihn standardmäßig liefern.</p>
|
||||
<p><strong>15.3 — Die Kennzahl der Prognoseabteilung.</strong> Die Rangfolge bleibt: Die Punktprognose gewinnt auch beim MAPE, weil beide Maße den <em>Erwartungswert</em> belohnen — der MAPE etwas anders gewichtet, aber ebenfalls symmetrisch in dem Sinne, dass er nicht weiß, dass Unterschätzung teurer ist als Überschätzung.</p>
|
||||
<p><strong>15.3 — Die Kennzahl der Prognoseabteilung.</strong> Die Rangfolge bleibt: Die Punktprognose gewinnt auch beim <a href="anhang-glossar.md#gloss:mape" class="glossar-link">MAPE</a>, weil beide Maße den <em>Erwartungswert</em> belohnen — der MAPE etwas anders gewichtet, aber ebenfalls symmetrisch in dem Sinne, dass er nicht weiß, dass Unterschätzung teurer ist als Überschätzung.</p>
|
||||
<p>Das ist kein Zufall, sondern der Kern des Kapitels: <strong>Jedes rein statistische Fehlermaß ignoriert die Kostenasymmetrie.</strong> Man kann das Problem nicht lösen, indem man das Fehlermaß wechselt; man muss die Kosten selbst messen. (Die einzige Ausnahme ist der <em>Pinball Loss</em> — genau das Maß, das die Quantilregression minimiert, und das ist eben kein allgemeines Prognosemaß, sondern eines für ein bestimmtes Quantil.)</p>
|
||||
<p><strong>15.4 — Zwei Quantile.</strong> Das Band ist an <strong>Aktionstagen</strong> deutlich breiter — dort ist die Streuung im Modell fast viermal so groß. Genau das ist die Information, die eine Punktprognose plus fester Zuschlag wegwirft.</p>
|
||||
<p>Ein praktischer Nebeneffekt: Ein solches Band ist die verständlichste Form, Unsicherheit an die Disposition zu berichten. „Zwischen 130 und 210” sagt einem Menschen mehr als „170 ± Sicherheitszuschlag”.</p>
|
||||
<p><strong>15.5 — Der Wert der Merkmale.</strong> Zu erwarten ist, dass die <strong>Kosten stärker steigen als der MSE</strong>. Der Grund: Das Merkmal „Aktion” trägt zwei verschiedene Informationen — es verschiebt den Erwartungswert (um 45 Stück) <em>und</em> die Streuung (von 8 auf 30). Der MSE bemerkt nur den ersten Teil; die Entscheidungskosten spüren beide.</p>
|
||||
<p><strong>15.5 — Der Wert der Merkmale.</strong> Zu erwarten ist, dass die <strong>Kosten stärker steigen als der <a href="anhang-glossar.md#gloss:mse" class="glossar-link">MSE</a></strong>. Der Grund: Das Merkmal „Aktion” trägt zwei verschiedene Informationen — es verschiebt den Erwartungswert (um 45 Stück) <em>und</em> die Streuung (von 8 auf 30). Der MSE bemerkt nur den ersten Teil; die Entscheidungskosten spüren beide.</p>
|
||||
<p>Der Lehrsatz dahinter: <strong>Der Wert eines Merkmals hängt davon ab, wofür man es benutzt.</strong> Eine Merkmalsauswahl, die nach MSE-Beitrag sortiert, wirft möglicherweise genau die Merkmale weg, die für die Entscheidung am wichtigsten sind — nämlich die, die etwas über die Unsicherheit sagen.</p>
|
||||
<h3 id="denkfehler-loesung-prognose">Finde den Denkfehler — „Wir haben die Prognose um 18 % verbessert“</h3>
|
||||
<p><strong>Der Sicherheitszuschlag stammt aus den Residuen des alten Modells.</strong></p>
|
||||
|
|
@ -1044,7 +1044,7 @@ F(11{,}33) = 1 - \frac{(18-11{,}33)^2}{(18-6)(18-10)} = 1 - \frac{44{,}4}{96} =
|
|||
<p><strong>16.3 — Die Brücke rückwärts.</strong> Shrinkage hilft, wenn man eine <strong>Kovarianzmatrix</strong> aus wenigen Beobachtungen schätzt. Bei Lieferzeiten tritt genau dasselbe Problem auf, sobald man die <em>Korrelationen zwischen</em> Lieferanten braucht — und die braucht man, sobald Lieferanten gemeinsame Ursachen haben: derselbe Hafen, dasselbe Vorprodukt, dieselbe Region.</p>
|
||||
<p>Bei 40 Lieferanten hat die Kovarianzmatrix 820 zu schätzende Einträge. Wer dafür 36 Monatswerte hat, schätzt 820 Zahlen aus 36 Beobachtungen — dasselbe Missverhältnis wie bei Aktienrenditen, mit denselben Folgen (<code>Kovarianz_Falle.py</code>).</p>
|
||||
<p>Benötigt würden: Lieferzeit-Zeitreihen je Lieferant über denselben Zeitraum, gleich getaktet. Genau daran scheitert es in der Praxis meist — die Daten liegen in Bestellvorgängen, nicht in einer Matrix.</p>
|
||||
<p><strong>16.4 — CVaR mit Ganzzahligkeit.</strong> Man ergänzt Binärvariablen <span class="math inline">y_j</span> je Lieferant und die Kopplung <span class="math inline">w_j \le y_j</span> sowie <span class="math inline">\sum_j y_j \le 3</span>. Da CVXPY gemischt-ganzzahlige Probleme unterstützt, genügt <code>cp.Variable(n, boolean=True)</code>.</p>
|
||||
<p><strong>16.4 — <a href="anhang-glossar.md#gloss:conditional-value-at-risk-cvar" class="glossar-link">CVaR</a> mit Ganzzahligkeit.</strong> Man ergänzt Binärvariablen <span class="math inline">y_j</span> je Lieferant und die Kopplung <span class="math inline">w_j \le y_j</span> sowie <span class="math inline">\sum_j y_j \le 3</span>. Da CVXPY gemischt-ganzzahlige Probleme unterstützt, genügt <code>cp.Variable(n, boolean=True)</code>.</p>
|
||||
<p>Zu erwarten ist ein <strong>höherer</strong> CVaR: Der zulässige Bereich wird kleiner, und die Feinabstimmung über sechs Lieferanten fällt weg. Der Aufschlag ist der Preis der Vertragswirklichkeit — und genau die Zahl, die man dem Einkauf vorlegt, wenn dort jemand sagt, drei Lieferanten seien genug.</p>
|
||||
<p><strong>16.5 — Die eigene Brücke.</strong> Freie Antwort. Eine gute Bearbeitung nennt das Modell, die Entsprechung und <strong>die Zeile der Grenztabelle, die im Weg steht</strong> — meist ist es die dritte (Teilbarkeit) oder die erste (gemessen gegen geschätzt). Wenn keine im Weg steht, ist die Übertragung wahrscheinlich zu oberflächlich geprüft.</p>
|
||||
<h3 id="denkfehler-loesung-bruecke">Finde den Denkfehler — „Das ist doch dasselbe Problem“</h3>
|
||||
|
|
@ -1061,7 +1061,7 @@ F(11{,}33) = 1 - \frac{(18-11{,}33)^2}{(18-6)(18-10)} = 1 - \frac{44{,}4}{96} =
|
|||
<h3 id="selbsttest-loesung-bruecke">Selbsttest</h3>
|
||||
<ol type="1">
|
||||
<li>Montagestunden ↔︎ Kapital; Plattenmaterial ↔︎ Risikobudget; Deckungsbeitrag je Stück ↔︎ erwarteter Ertrag je 1 000 €. (Weitere: Mindestlosgröße ↔︎ Mindestordergröße, Rüstkosten ↔︎ Ordergebühr, Sortimentsbreite ↔︎ Kardinalitätsgrenze.)</li>
|
||||
<li>Ein LP sieht eine Matrix, einen Kapazitätsvektor und einen Zielvektor — Bedeutung kommt darin nicht vor. Das ist hier ein Vorteil, weil derselbe geprüfte, getestete Code beide Domänen bedient; man erbt die Verlässlichkeit mit.</li>
|
||||
<li>Ein LP sieht eine Matrix, einen <a href="anhang-glossar.md#gloss:kapazitaetsvektor" class="glossar-link">Kapazitätsvektor</a> und einen Zielvektor — Bedeutung kommt darin nicht vor. Das ist hier ein Vorteil, weil derselbe geprüfte, getestete Code beide Domänen bedient; man erbt die Verlässlichkeit mit.</li>
|
||||
<li>„Stellen Sie sich vor, Ihre Engpassmaschine wäre nicht die Fräse, sondern eine Vorschrift: Sie dürfen nur eine bestimmte Menge Risiko in den Büchern haben. Der Schattenpreis sagt dann, was eine Lockerung dieser Vorschrift wert wäre — genau wie bei einer zusätzlichen Maschinenstunde.”</li>
|
||||
<li><strong>Fette Ränder</strong> (seltene, aber sehr große Abweichungen). Die Standardabweichung mittelt sie weg und bestraft außerdem Abweichungen nach oben genauso wie nach unten; CVaR sieht ausschließlich auf den schlechten Rand.</li>
|
||||
<li><ol type="a">
|
||||
|
|
@ -1151,7 +1151,7 @@ u_{k,\tau} \le 1 - b_{k,t} \qquad \text{für } \tau = t, \dots, t + M_k - 1
|
|||
<ol type="1">
|
||||
<li>Log-Renditen sind Differenzen von Logarithmen — die addieren sich über die Zeit. Diskrete Renditen sind lineare Anteile am Kapital — die addieren sich über gewichtete Positionen.</li>
|
||||
<li>Die Optimierung sucht die Richtungen kleinster geschätzter Varianz — genau jene, deren Eigenwerte am stärksten nach unten verzerrt sind. Sie optimiert dadurch in das Schätzrauschen hinein.</li>
|
||||
<li>Der Rang von <span class="math inline">\mathbf{X}^\top\mathbf{X}</span> ist höchstens <span class="math inline">T < N</span> — die Matrix ist nicht invertierbar, das GMV-Problem hat unendlich viele Lösungen.</li>
|
||||
<li>Der Rang von <span class="math inline">\mathbf{X}^\top\mathbf{X}</span> ist höchstens <span class="math inline">T < N</span> — die Matrix ist nicht invertierbar, das <a href="anhang-glossar.md#gloss:global-minimum-variance-portfolio-gmv" class="glossar-link">GMV</a>-Problem hat unendlich viele Lösungen.</li>
|
||||
<li>Stichprobenmatrix (unverzerrt, verrauscht) mit strukturiertem Ziel (verzerrt, stabil). <span class="math inline">\delta</span> wird analytisch so bestimmt, dass der erwartete quadratische Fehler minimal wird.</li>
|
||||
<li>Skalierte Einheitsmatrix (sklearn) und Konstant-Korrelations-Ziel (LW 2003).</li>
|
||||
</ol>
|
||||
|
|
@ -1195,9 +1195,9 @@ u_{k,\tau} \le 1 - b_{k,t} \qquad \text{für } \tau = t, \dots, t + M_k - 1
|
|||
</tbody>
|
||||
</table>
|
||||
<p>Rechenweg für <span class="math inline">(0{,}5;\ 0{,}5)</span>: <span class="math inline">\sigma_p^2 = 0{,}25\cdot0{,}0625 + 0{,}25\cdot0{,}0144 + 2\cdot0{,}25\cdot(-0{,}2)\cdot0{,}25\cdot0{,}12 = 0{,}015625 + 0{,}0036 - 0{,}003 = 0{,}016225</span>, also <span class="math inline">\sigma_p = 12{,}74\,\%</span>.</p>
|
||||
<p>Beste Sharpe Ratio unter den vier Kandidaten: <span class="math inline">(0{,}3;\ 0{,}7)</span>. Das exakte Optimum liegt bei <span class="math inline">w_1 = 0{,}318</span>. <strong>Bemerkenswert:</strong> Die Mischung <span class="math inline">(0{,}3;\ 0{,}7)</span> hat mit 10,08 % eine <strong>geringere</strong> Volatilität als <em>beide</em> Einzeltitel (25 % und 12 %) — genau der Diversifikationseffekt, den die negative Korrelation ermöglicht.</p>
|
||||
<p>Beste <a href="anhang-glossar.md#gloss:sharpe-ratio" class="glossar-link">Sharpe Ratio</a> unter den vier Kandidaten: <span class="math inline">(0{,}3;\ 0{,}7)</span>. Das exakte Optimum liegt bei <span class="math inline">w_1 = 0{,}318</span>. <strong>Bemerkenswert:</strong> Die Mischung <span class="math inline">(0{,}3;\ 0{,}7)</span> hat mit 10,08 % eine <strong>geringere</strong> <a href="anhang-glossar.md#gloss:volatilitaet" class="glossar-link">Volatilität</a> als <em>beide</em> Einzeltitel (25 % und 12 %) — genau der Diversifikationseffekt, den die negative Korrelation ermöglicht.</p>
|
||||
<p><strong>19.2 — Lambda deuten.</strong> Von <span class="math inline">\lambda=0</span> (GMV, linker unterer Punkt der Kurve) wandert die Lösung entlang der Effizienzgrenze nach rechts oben, bis sie bei <span class="math inline">\lambda\to\infty</span> im Titel mit der höchsten Rendite endet (bzw. an der Positionsobergrenze).</p>
|
||||
<p><strong>19.3 — Korn-Transformation.</strong> <span class="math inline">\text{SR}(c\mathbf{w}) = \frac{c\mathbf{w}^\top\boldsymbol{\mu}-r_f}{\sqrt{c^2\mathbf{w}^\top\boldsymbol{\Sigma}\mathbf{w}}}</span> — bei einem Portfolio mit <span class="math inline">\sum w_i = 1</span> und Überrenditen geschrieben als <span class="math inline">\mathbf{w}^\top(\boldsymbol{\mu}-r_f\mathbf{1})</span> kürzt sich <span class="math inline">c</span> heraus. Mit der Bedingung <span class="math inline">\sum w_i = 1</span> ist die Skala jedoch <strong>fixiert</strong>, man kann also nicht frei skalieren. Die Transformation ersetzt diese Bedingung durch <span class="math inline">\sum y_i = \kappa</span> mit freiem <span class="math inline">\kappa</span> und normiert stattdessen die Überrendite auf 1 — dadurch wird die Skala wieder frei und das Problem konvex.</p>
|
||||
<p><strong>19.3 — <a href="anhang-glossar.md#gloss:korn-transformation" class="glossar-link">Korn-Transformation</a>.</strong> <span class="math inline">\text{SR}(c\mathbf{w}) = \frac{c\mathbf{w}^\top\boldsymbol{\mu}-r_f}{\sqrt{c^2\mathbf{w}^\top\boldsymbol{\Sigma}\mathbf{w}}}</span> — bei einem Portfolio mit <span class="math inline">\sum w_i = 1</span> und Überrenditen geschrieben als <span class="math inline">\mathbf{w}^\top(\boldsymbol{\mu}-r_f\mathbf{1})</span> kürzt sich <span class="math inline">c</span> heraus. Mit der Bedingung <span class="math inline">\sum w_i = 1</span> ist die Skala jedoch <strong>fixiert</strong>, man kann also nicht frei skalieren. Die Transformation ersetzt diese Bedingung durch <span class="math inline">\sum y_i = \kappa</span> mit freiem <span class="math inline">\kappa</span> und normiert stattdessen die Überrendite auf 1 — dadurch wird die Skala wieder frei und das Problem konvex.</p>
|
||||
<p><strong>19.4 — Restriktionen kosten.</strong> Erwartetes Muster: Sharpe Ratio sinkt monoton mit strengerer Grenze. Unlösbar wird es bei <span class="math inline">w_{\max} < 1/n</span> — dann kann die Summe der Gewichte 1 nicht mehr erreicht werden.</p>
|
||||
<p><strong>19.5 — Den Sektorfehler nachstellen.</strong> (a) AAPL, AMZN, CVX, GS statt AAPL, MSFT, NVDA, AMZN. (b) Die Gewichte unterscheiden sich deutlich, weil die eigentlich zu begrenzenden Tech-Titel frei laufen. (c) <strong>Nein</strong> — die Kennzahlen sehen völlig plausibel aus. Genau das macht den Fehler so gefährlich.</p>
|
||||
<p><strong>19.6 — Kardinalität.</strong> Erwartung: Die Sharpe Ratio sinkt leicht, die Rechenzeit steigt deutlich (MIQP statt QP). Bei <span class="math inline">K \ge 5</span> und <span class="math inline">w_{\max} = 0{,}20</span> ist die Restriktion praktisch nicht mehr bindend.</p>
|
||||
|
|
@ -1237,7 +1237,7 @@ T \ge \left(\frac{2\sigma}{\mu}\right)^2 = \left(\frac{2 \cdot 0{,}012}{0{,}0004
|
|||
</ol>
|
||||
<p><strong>Und die Kontrollfrage für den Alltag:</strong> Rechnen Sie Ihr Modell mit den Daten des halben Zeitraums und dann mit denen der anderen Hälfte. Wenn die Gewichte dabei stark springen, optimieren Sie Rauschen — unabhängig davon, wie gut die Kennzahlen im Schätzzeitraum aussehen.</p>
|
||||
<h3 id="quiz-loesung-markowitz">Micro-Quiz</h3>
|
||||
<p><strong>1 — (b).</strong> Das renditestärkste Portfolio auf der Effizienzlinie hat notwendig das schlechteste Rendite-Risiko-Verhältnis (im Kapitelbeispiel 0,44 gegenüber 0,75 beim Optimum) und besteht vollständig aus der renditestärksten Einzelanlage — Diversifikation findet dort gar nicht mehr statt. (a) und (c) sind sachlich falsch: Der Punkt ist numerisch völlig unproblematisch und wird von CVXPY ohne Weiteres gefunden.</p>
|
||||
<p><strong>1 — (b).</strong> Das renditestärkste Portfolio auf der Effizienzlinie hat notwendig das schlechteste Rendite-Risiko-Verhältnis (im Kapitelbeispiel 0,44 gegenüber 0,75 beim Optimum) und besteht vollständig aus der renditestärksten Einzelanlage — <a href="anhang-glossar.md#gloss:diversifikation" class="glossar-link">Diversifikation</a> findet dort gar nicht mehr statt. (a) und (c) sind sachlich falsch: Der Punkt ist numerisch völlig unproblematisch und wird von CVXPY ohne Weiteres gefunden.</p>
|
||||
<p><strong>2 — (b) es braucht keine Renditeschätzung.</strong> Renditen sind die mit Abstand unzuverlässigste Eingangsgröße (Standardfehler größer als der geschätzte Wert selbst); wer sie nicht benötigt, umgeht das Problem vollständig. (a) trifft nicht zu — die Nebenbedingungen sind dieselben. (c) ist falsch: Das Minimum-Varianz-Portfolio erzielt <em>erwartungsgemäß</em> weniger Rendite; sein Vorteil liegt in der Verlässlichkeit, nicht in der Höhe.</p>
|
||||
<p><strong>3 — (b) Schätzfehler.</strong> Eine Konzentration von 44 % auf einen von zwölf Titeln ist das typische Bild eines Optimierers, der einem Rauschsignal folgt — im Kapitelbeispiel entsteht sie sogar dann, wenn alle Anlagen nachweislich identisch sind. (a) mag zutreffen, ist aber die unwahrscheinlichere Erklärung und muss belegt werden, nicht angenommen. (c) beschriebe ein anderes Fehlerbild: Eine falsch skalierte Kovarianzmatrix führt zu unplausiblen Risikowerten, nicht zu Konzentration.</p>
|
||||
<h3 id="selbsttest-loesung-markowitz">Selbsttest</h3>
|
||||
|
|
@ -1250,8 +1250,8 @@ T \ge \left(\frac{2\sigma}{\mu}\right)^2 = \left(\frac{2 \cdot 0{,}012}{0{,}0004
|
|||
</ol>
|
||||
<hr />
|
||||
<h2 id="sec:loesungen-cvar">A.20 Lösungen zu Kapitel „Tail-Risiko, CVaR und Transaktionskosten“</h2>
|
||||
<p><strong>20.1 — VaR und CVaR von Hand.</strong> Sortierte Verluste: <span class="math inline">-2{,}0; -1{,}2; -0{,}8; -0{,}4; 0{,}3; 0{,}6; 1{,}1; 2{,}1; 5{,}4; 8{,}9</span>. Das 80 %-Quantil ist der 8. Wert: <span class="math inline">\text{VaR}_{80\%} = 2{,}1</span>. $_{80%} = $ Mittel der schlechtesten 20 % <span class="math inline">= (5{,}4+8{,}9)/2 = \mathbf{7{,}15}</span>.</p>
|
||||
<p><strong>20.2 — Subadditivität.</strong> Ein Risikomaß sollte Diversifikation nie bestrafen: Das Risiko eines zusammengelegten Portfolios darf nicht größer sein als die Summe der Einzelrisiken. Wird das verletzt, hätte eine Bank einen Anreiz, Portfolios künstlich aufzuspalten, um Eigenkapitalanforderungen zu senken — ökonomisch unsinnig.</p>
|
||||
<p><strong>20.1 — <a href="anhang-glossar.md#gloss:value-at-risk-var" class="glossar-link">VaR</a> und CVaR von Hand.</strong> Sortierte Verluste: <span class="math inline">-2{,}0; -1{,}2; -0{,}8; -0{,}4; 0{,}3; 0{,}6; 1{,}1; 2{,}1; 5{,}4; 8{,}9</span>. Das 80 %-Quantil ist der 8. Wert: <span class="math inline">\text{VaR}_{80\%} = 2{,}1</span>. $_{80%} = $ Mittel der schlechtesten 20 % <span class="math inline">= (5{,}4+8{,}9)/2 = \mathbf{7{,}15}</span>.</p>
|
||||
<p><strong>20.2 — <a href="anhang-glossar.md#gloss:subadditivitaet" class="glossar-link">Subadditivität</a>.</strong> Ein Risikomaß sollte Diversifikation nie bestrafen: Das Risiko eines zusammengelegten Portfolios darf nicht größer sein als die Summe der Einzelrisiken. Wird das verletzt, hätte eine Bank einen Anreiz, Portfolios künstlich aufzuspalten, um Eigenkapitalanforderungen zu senken — ökonomisch unsinnig.</p>
|
||||
<p><strong>20.3 — Rockafellar-Uryasev nachvollziehen.</strong> (a) Schlechtestes Drittel von <span class="math inline">(1,4,9)</span> ist <span class="math inline">\{9\}</span> → CVaR <span class="math inline">= 9</span>. (b) Mit <span class="math inline">\frac{1}{S(1-\alpha)} = \frac{1}{3\cdot(1/3)} = 1</span>: <span class="math inline">\gamma=0</span>: <span class="math inline">0 + (1+4+9) = 14</span>. <span class="math inline">\gamma=1</span>: <span class="math inline">1 + (0+3+8) = 12</span>. <span class="math inline">\gamma=4</span>: <span class="math inline">4 + (0+0+5) = \mathbf{9}</span>. <span class="math inline">\gamma=5</span>: <span class="math inline">5+4 = 9</span>. <span class="math inline">\gamma=9</span>: <span class="math inline">9+0 = 9</span>. (c) Minimum ab <span class="math inline">\gamma = 4</span> bei <strong>9</strong> — identisch mit (a) ✓. (Das Minimum wird auf einem ganzen Intervall angenommen, weil die Funktion stückweise linear ist — genau der Grund, warum der CVaR nicht <em>streng</em> konvex ist.)</p>
|
||||
<p><strong>20.4 — Einheiten prüfen.</strong> In einem Modell, das annualisierte Rendite gegen täglichen CVaR verrechnet, wirkt <span class="math inline">1{,}5</span> effektiv als <span class="math inline">1{,}5/252 \approx 0{,}006</span> auf Tagesbasis — der Risikoterm ist also um Faktor 252 zu leicht gewichtet. Um dieselbe Wirkung wie <code>RISIKOAVERSION = 1.5</code> im konsistenten Tagesmodell zu erzielen, hätte man dort <code>lambda_risk = 1.5 * 252 = 378</code> setzen müssen.</p>
|
||||
<p><strong>20.5 — Risikoaversion kalibrieren.</strong> (a) Konkav, ähnlich der Markowitz-Frontier, aber im Rendite-CVaR-Raum. (b) Bei Normalverteilung entspricht CVaR-Optimierung ungefähr der Varianz-Optimierung; die Ergebnisse divergieren umso stärker, je schiefer die Verteilung ist. (c) Empfehlung ohne Fachjargon: „Bei dieser Einstellung liegt der durchschnittliche Verlust an den schlechtesten fünf Prozent der Tage bei X Prozent — bei einer erwarteten Rendite von Y Prozent.“ Das ist entscheidbar; „<span class="math inline">\lambda = 4</span>“ ist es nicht.</p>
|
||||
|
|
@ -1284,7 +1284,7 @@ T \ge \left(\frac{2\sigma}{\mu}\right)^2 = \left(\frac{2 \cdot 0{,}012}{0{,}0004
|
|||
<li><strong>Warum der CVaR das nicht kann.</strong> Der CVaR mittelt über den <strong>gesamten</strong> Schwanz, statt an seiner Grenze stehenzubleiben. Damit sieht er den Ausfall in jedem der drei Fälle, und das Ergebnis verhält sich wie erwartet: 79,59 € und 79,66 € einzeln, 101,33 € zusammen statt 159,24 € — die Diversifikation <strong>senkt</strong> das Risiko um rund ein Drittel.</li>
|
||||
</ol>
|
||||
<p>Formal folgt die Subadditivität daraus, dass der CVaR sich als <strong>Maximum über Erwartungswerte</strong> schreiben lässt (Darstellungssatz für kohärente Risikomaße), und Maxima von Erwartungswerten sind stets subadditiv. Anschaulicher: Ein Mittelwert über eine Menge verhält sich gutartig, wenn man Mengen zusammenlegt; ein Quantil nicht — es kann springen, sobald sich die Reihenfolge der Szenarien ändert.</p>
|
||||
<p><strong>Die praktische Konsequenz</strong> ist die Umstellung der Bankenaufsicht mit Basel III vom VaR auf den <em>Expected Shortfall</em> — dieselbe Größe, die hier CVaR heißt. Und für Ihre eigenen Modelle, auch außerhalb der Finanzwelt: Wo immer Sie eine Risikokennzahl über Einheiten aggregieren wollen, prüfen Sie zuerst, ob das Maß das überhaupt zulässt.</p>
|
||||
<p><strong>Die praktische Konsequenz</strong> ist die Umstellung der Bankenaufsicht mit Basel III vom VaR auf den <em><a href="anhang-glossar.md#gloss:expected-shortfall" class="glossar-link">Expected Shortfall</a></em> — dieselbe Größe, die hier CVaR heißt. Und für Ihre eigenen Modelle, auch außerhalb der Finanzwelt: Wo immer Sie eine Risikokennzahl über Einheiten aggregieren wollen, prüfen Sie zuerst, ob das Maß das überhaupt zulässt.</p>
|
||||
<h3 id="quiz-loesung-cvar">Micro-Quiz</h3>
|
||||
<p><strong>1 — (b) nichts.</strong> Der VaR ist ein Quantil: Er markiert die Schwelle und sagt nichts über den Bereich dahinter. Genau das zeigt der Schnellstart dieses Kapitels — zwei Anlagen mit identischem VaR von 3,00 %, aber CVaR 3,00 % gegen 9,17 %. (a) verwechselt die Schwelle mit dem, was hinter ihr liegt. (c) ist ebenfalls falsch: Anlage B hat zwar die höhere Schwankung, aber die Schwankung allein sagt nichts über die Form des Schwanzes — genau deshalb reicht auch die Varianz als Risikomaß nicht aus.</p>
|
||||
<p><strong>2 — (b).</strong> Rockafellar und Uryasev zeigen, dass sich der CVaR als Minimum über eine Hilfsvariable <span class="math inline">\gamma</span> schreiben lässt; mit Schlupfvariablen für die Terme <span class="math inline">\max(\cdot, 0)</span> wird daraus ein gewöhnliches LP. Die VaR-Minimierung ist dagegen nicht-konvex (das Quantil springt) und hat viele lokale Optima — dasselbe Problem wie in <a href="qp-nlp.html#sec:qp-nlp-nichtkonvex">Abschnitt 11.6</a>. (a) ist zwar zutreffend, aber nicht der entscheidende Grund; (c) ist eine wahre Aussage ohne Bezug zur Optimierbarkeit.</p>
|
||||
|
|
@ -1299,15 +1299,15 @@ T \ge \left(\frac{2\sigma}{\mu}\right)^2 = \left(\frac{2 \cdot 0{,}012}{0{,}0004
|
|||
</ol>
|
||||
<hr />
|
||||
<h2 id="sec:loesungen-handelsmaschine">A.21 Lösungen zu Kapitel „Die vollständige quantitative Handelsmaschine“</h2>
|
||||
<p><strong>21.1 — Lookahead erkennen.</strong> (a) sauber (<code>:heute</code>). (b) <strong>Lookahead</strong> — gesamter Zeitraum. (c) <strong>Lookahead</strong> — Volatilität über den ganzen Zeitraum enthält Zukunft. (d) sauber — Gewichte aus Daten bis heute, angewendet auf heute (idealerweise auf morgen). (e) <strong>Survivorship-Bias</strong> — das Universum wird danach gefiltert, wer über den gesamten Zeitraum Daten hat.</p>
|
||||
<p><strong>21.1 — Lookahead erkennen.</strong> (a) sauber (<code>:heute</code>). (b) <strong>Lookahead</strong> — gesamter Zeitraum. (c) <strong>Lookahead</strong> — Volatilität über den ganzen Zeitraum enthält Zukunft. (d) sauber — Gewichte aus Daten bis heute, angewendet auf heute (idealerweise auf morgen). (e) <strong><a href="anhang-glossar.md#gloss:survivorship-bias" class="glossar-link">Survivorship-Bias</a></strong> — das Universum wird danach gefiltert, wer über den gesamten Zeitraum Daten hat.</p>
|
||||
<p><strong>21.2 — Kennzahlen deuten.</strong> A: Sharpe <span class="math inline">= (12-2)/22 = 0{,}45</span>, Calmar <span class="math inline">= 12/35 = 0{,}34</span>. B: Sharpe <span class="math inline">= (8-2)/9 = 0{,}67</span>, Calmar <span class="math inline">= 8/12 = 0{,}67</span>. <strong>Empfehlung: B</strong> — für einen Pensionsfonds ist der Drawdown entscheidend, weil laufende Auszahlungen in einer Verlustphase Substanz vernichten. B ist in beiden risikoadjustierten Maßen besser.</p>
|
||||
<p><strong>21.3 — Rebalancing-Kalender.</strong> Etwa 25–30 % der Termine fallen aus. Die Kennzahlen ändern sich messbar — in welche Richtung, ist zufällig. Genau das ist der Punkt: Der Fehler verzerrt, ohne aufzufallen.</p>
|
||||
<p><strong>21.3 — <a href="anhang-glossar.md#gloss:rebalancing" class="glossar-link">Rebalancing</a>-Kalender.</strong> Etwa 25–30 % der Termine fallen aus. Die Kennzahlen ändern sich messbar — in welche Richtung, ist zufällig. Genau das ist der Punkt: Der Fehler verzerrt, ohne aufzufallen.</p>
|
||||
<p><strong>21.4 — Rebalancing-Frequenz.</strong> Typisches Muster: Turnover und Kosten steigen etwa linear mit der Frequenz, der Bruttoertrag verbessert sich nur unterproportional. Bei 0,15 % Gebühren ist monatlich meist vertretbar, bei 0,5 % eher quartalsweise. Ein <strong>Toleranzband</strong> (nur handeln bei Abweichung > x %) schlägt fast immer die feste Frequenz.</p>
|
||||
<p><strong>21.5 — Krisenverhalten.</strong> Erwartung: Die Überrendite ist selten stabil; oft stammt sie aus wenigen Perioden. Folgerung: Eine gute Gesamtkennzahl kann von einer einzigen glücklichen Phase getragen sein — <strong>immer</strong> nach Teilzeiträumen aufschlüsseln.</p>
|
||||
<p><strong>21.6 — Data Snooping messen.</strong> Erwartetes Ergebnis: Die beste In-Sample-Sharpe-Ratio liegt deutlich über dem Mittelwert aller Varianten; auf dem zurückgehaltenen Zeitraum fällt sie Richtung Mittelwert zurück. Die <strong>Differenz zwischen (a) und (c) ist der Selektionseffekt</strong> — genau das, was die Deflated Sharpe Ratio korrigieren soll.</p>
|
||||
<p><strong>21.6 — <a href="anhang-glossar.md#gloss:data-snooping" class="glossar-link">Data Snooping</a> messen.</strong> Erwartetes Ergebnis: Die beste In-Sample-Sharpe-Ratio liegt deutlich über dem Mittelwert aller Varianten; auf dem zurückgehaltenen Zeitraum fällt sie Richtung Mittelwert zurück. Die <strong>Differenz zwischen (a) und (c) ist der Selektionseffekt</strong> — genau das, was die Deflated Sharpe Ratio korrigieren soll.</p>
|
||||
<h3 id="finde-den-denkfehler-die-strategie-mit-dem-hochsignifikanten-ergebnis">Finde den Denkfehler — Die Strategie mit dem hochsignifikanten Ergebnis</h3>
|
||||
<ol type="a">
|
||||
<li><strong>Warum ein korrekter Backtest wertlos sein kann.</strong> Der Backtest misst genau das, was er messen soll: die Wertentwicklung <em>dieser einen</em> Strategie. Die Frage, die beantwortet werden soll, lautet aber anders — nämlich: <em>„Ist dieses Ergebnis besser, als es Zufall erklären kann?“</em></li>
|
||||
<li><strong>Warum ein korrekter <a href="anhang-glossar.md#gloss:backtest" class="glossar-link">Backtest</a> wertlos sein kann.</strong> Der Backtest misst genau das, was er messen soll: die Wertentwicklung <em>dieser einen</em> Strategie. Die Frage, die beantwortet werden soll, lautet aber anders — nämlich: <em>„Ist dieses Ergebnis besser, als es Zufall erklären kann?“</em></li>
|
||||
</ol>
|
||||
<p>Und für diese Frage ist entscheidend, dass die Strategie als <strong>Beste aus hundert</strong> ausgewählt wurde. Ein p-Wert von 0,0094 bedeutet: „Wenn diese Strategie keinen Vorteil hätte, sähe sie in 0,94 % der Fälle so gut aus.“ Bei hundert Versuchen erwartet man aber rund fünf Ergebnisse unter dem 5-%-Niveau — allein durch Zufall. Genau das zeigt die Tabelle: Auf reinem Rauschen liefert die Beste von hundert im Mittel Sharpe 1,13 und p = 0,0094. <strong>Dieselben Zahlen.</strong></p>
|
||||
<p>Der Fehler steckt nicht im Backtest, sondern in der <strong>Auswahl</strong>. Deshalb ist er auch durch noch so sorgfältiges Programmieren nicht zu verhindern.</p>
|
||||
|
|
@ -1428,7 +1428,7 @@ T \ge \left(\frac{2\sigma}{\mu}\right)^2 = \left(\frac{2 \cdot 0{,}012}{0{,}0004
|
|||
<h3 id="quiz-loesung-praxisfallen">Micro-Quiz</h3>
|
||||
<p><strong>1 — (b) das Zeitlimit greift.</strong> Eine Laufzeit, die exakt dem Limit entspricht und über Monate konstant bleibt, ist kein Stabilitätsbeleg, sondern zeigt, dass der Solver jedes Mal abgebrochen wird. (a) ist die Fehldeutung, um die es im Denkfehler geht. (c) läge nahe, wenn die Laufzeit <em>schwankte</em> oder das Limit überschritte — hier ist die Ursache aber im Modell und in der Datenmenge zu suchen, nicht in der Hardware.</p>
|
||||
<p><strong>2 — (b) aus dem ausgegebenen Tourenplan.</strong> Eine Prüfung muss von der <strong>Lösung</strong> ausgehen und die Anforderungen unabhängig nachrechnen. (a) fragt die Ladungsdimension — also ausgerechnet den Baustein, dessen Fehlen der Fehler war (siehe <a href="graphen.html#sec:graphen-denkfehler">Abschnitt 8.7</a>); existiert sie nicht, stürzt die Prüfung ab, existiert sie, kann sie per Konstruktion nie verletzt sein. (c) prüft gar nichts: Ob eine Kapazität in der Zielfunktion bepreist ist, sagt nichts darüber, ob sie eingehalten wurde.</p>
|
||||
<p><strong>3 — (c) hierarchisch lockern.</strong> <code>INFEASIBLE</code> sagt nur, <em>dass</em> ein Widerspruch existiert, nicht <em>welche</em> Regeln ihn erzeugen. Ersetzt man harte Verbote durch sehr teure Strafkosten, liefert der Solver wieder eine Lösung — und die verletzten Regeln stehen benannt in der Kostenzerlegung. Genau das tut <code>Infeasibility_Diagnose.py</code>. (a) hilft nicht: <code>INFEASIBLE</code> ist ein Beweis, kein Abbruch. (b) verschiebt das Problem und verliert die Gelegenheit, die Ursache zu finden, solange sie noch frisch ist.</p>
|
||||
<p><strong>3 — (c) hierarchisch lockern.</strong> <code>INFEASIBLE</code> sagt nur, <em>dass</em> ein Widerspruch existiert, nicht <em>welche</em> Regeln ihn erzeugen. Ersetzt man harte Verbote durch sehr teure Strafkosten, liefert der Solver wieder eine Lösung — und die verletzten Regeln stehen benannt in der <a href="anhang-glossar.md#gloss:kostenzerlegung" class="glossar-link">Kostenzerlegung</a>. Genau das tut <code>Infeasibility_Diagnose.py</code>. (a) hilft nicht: <code>INFEASIBLE</code> ist ein Beweis, kein Abbruch. (b) verschiebt das Problem und verliert die Gelegenheit, die Ursache zu finden, solange sie noch frisch ist.</p>
|
||||
<h3 id="selbsttest-loesung-praxisfallen">Selbsttest</h3>
|
||||
<ol type="1">
|
||||
<li>Durch hierarchische Relaxation: Schlupfvariablen mit hohen, gestaffelten Strafkosten für die verletzbaren Bedingungen.</li>
|
||||
|
|
@ -1460,7 +1460,7 @@ T \ge \left(\frac{2\sigma}{\mu}\right)^2 = \left(\frac{2 \cdot 0{,}012}{0{,}0004
|
|||
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a> <span class="st">"if (mengen < -toleranz).any():"</span>, <span class="st">"if (mengen < toleranz).any():"</span>),</span></code></pre></div>
|
||||
<p>Die erste wird getötet (<code>test_pruefung_findet_kapazitaetsverletzung</code>). Die zweite ist interessanter: Sie macht die Prüfung <em>strenger</em> statt schwächer — eine Lösung mit einer Menge von exakt 0 würde als negativ beanstandet. Ob sie überlebt, hängt daran, ob die Suite eine Instanz enthält, in der ein Produkt mit Menge 0 vorkommt. In der Schreinerei ist das nicht der Fall — die Mutation überlebt also und zeigt eine echte Lücke: Es fehlt eine Testinstanz, in der ein Produkt nicht produziert wird.</p>
|
||||
<p><strong>23.4 — Der Benchmark mit MILP.</strong> Zu erwarten ist, dass sich die Reihenfolge ändert. Beim reinen LP entscheidet vor allem der Modellaufbau in Python; beim MILP verschiebt sich das Gewicht zum Lösen, und dort spielen die Branch-and-Bound-Heuristiken der Bibliotheken gegeneinander. Die Spalte „Anteil” sollte bei allen deutlich <strong>fallen</strong> — nicht weil der Aufbau schneller würde, sondern weil das Lösen langsamer wird. Genau deshalb steht im Kapitel, dass die Tabelle nichts über MILPs sagt.</p>
|
||||
<p><strong>23.5 — Der Dienst mit Zeitlimit.</strong> Der Modellbauer in <code>or_kern.py</code> nimmt bisher kein Zeitlimit entgegen — das ist der erste Schritt (bei GLOP <code>solver.SetTimeLimit(millisekunden)</code>). Danach im Arbeiter durchreichen und den Status auswerten: Liefert der Solver <code>ZEITLIMIT</code>, ist <code>stand</code> weiterhin <code>gescheitert</code>, aber mit einer anderen Begründung als bei <code>UNZULAESSIG</code> — der Unterschied zwischen „rechne länger” und „ändere das Modell” (<a href="milp.html#kap-milp">Kapitel 6</a>).</p>
|
||||
<p><strong>23.5 — Der Dienst mit Zeitlimit.</strong> Der Modellbauer in <code>or_kern.py</code> nimmt bisher kein Zeitlimit entgegen — das ist der erste Schritt (bei <a href="anhang-glossar.md#gloss:glop" class="glossar-link">GLOP</a> <code>solver.SetTimeLimit(millisekunden)</code>). Danach im Arbeiter durchreichen und den Status auswerten: Liefert der Solver <code>ZEITLIMIT</code>, ist <code>stand</code> weiterhin <code>gescheitert</code>, aber mit einer anderen Begründung als bei <code>UNZULAESSIG</code> — der Unterschied zwischen „rechne länger” und „ändere das Modell” (<a href="milp.html#kap-milp">Kapitel 6</a>).</p>
|
||||
<p>Für den Test braucht es eine Instanz, die das Limit reißt. Ein LP eignet sich schlecht dafür; nehmen Sie ein MILP mit einigen hundert Binärvariablen und ein Limit von 0,1 Sekunden.</p>
|
||||
<h3 id="denkfehler-loesung-testing">Finde den Denkfehler — „Die Suite ist grün, das Modell stimmt”</h3>
|
||||
<p><strong>Alle Prüfungen benutzen dieselbe falsche Zahl.</strong></p>
|
||||
|
|
@ -1486,7 +1486,7 @@ T \ge \left(\frac{2\sigma}{\mu}\right)^2 = \left(\frac{2 \cdot 0{,}012}{0{,}0004
|
|||
<li>„Grün” heißt nur, dass kein Test fehlgeschlagen ist — das gilt auch für eine Suite aus lauter <code>assert True</code>. „Prüft etwas” heißt, dass die Tests bei einem eingebauten Fehler rot würden; genau das misst der Mutationstest.</li>
|
||||
<li>Weil sonst nicht erkennbar ist, welche Hälfte die Zeit kostet. Im Kapitel gehen bei OR-Tools 78 % in den Aufbau — wer nur die Gesamtzeit sieht, wechselt den Solver und ändert damit fast nichts.</li>
|
||||
<li>Weil die Rechnung Sekunden bis Minuten dauert. Eine synchrone Antwort läuft in den Timeout des Reverse Proxy und blockiert währenddessen einen Arbeiter. <code>202</code> heißt „angenommen, noch nicht fertig” — genau die richtige Aussage.</li>
|
||||
<li>Ein Threadpool genügt, wenn der Solver den GIL freigibt — das tun die C++-Bibliotheken (OR-Tools, HiGHS) während <code>Solve()</code>, im Kapitel mit Faktor 3,5 bei vier Threads gemessen. Eine in reinem Python geschriebene Heuristik hält den GIL; für sie braucht es Prozesse.</li>
|
||||
<li>Ein Threadpool genügt, wenn der Solver den <a href="anhang-glossar.md#gloss:gil-global-interpreter-lock" class="glossar-link">GIL</a> freigibt — das tun die C++-Bibliotheken (OR-Tools, HiGHS) während <code>Solve()</code>, im Kapitel mit Faktor 3,5 bei vier Threads gemessen. Eine in reinem Python geschriebene Heuristik hält den GIL; für sie braucht es Prozesse.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
|
||||
|
|
|
|||
56
OR_HTML_04/anhang-modellierungsmuster.html
generated
56
OR_HTML_04/anhang-modellierungsmuster.html
generated
|
|
@ -129,7 +129,7 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td>B1</td>
|
||||
<td>Aktivierungsschalter</td>
|
||||
<td><a href="anhang-glossar.md#gloss:aktivierungsschalter" class="glossar-link">Aktivierungsschalter</a></td>
|
||||
<td>„Wenn genutzt, dann Fixkosten“</td>
|
||||
<td><a href="milp.html#kap-milp">Kapitel 6</a></td>
|
||||
</tr>
|
||||
|
|
@ -141,7 +141,7 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td>B3</td>
|
||||
<td>Implikation</td>
|
||||
<td><a href="anhang-glossar.md#gloss:implikation" class="glossar-link">Implikation</a></td>
|
||||
<td>„Wenn A, dann auch B“</td>
|
||||
<td><a href="milp.html#kap-milp">Kapitel 6</a></td>
|
||||
</tr>
|
||||
|
|
@ -153,7 +153,7 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td>B5</td>
|
||||
<td>Exklusiv-Oder</td>
|
||||
<td><a href="anhang-glossar.md#gloss:exklusiv-oder" class="glossar-link">Exklusiv-Oder</a></td>
|
||||
<td>„Genau eines von N“</td>
|
||||
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
|
||||
</tr>
|
||||
|
|
@ -165,7 +165,7 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td>B7</td>
|
||||
<td>Bedingte Kopplung</td>
|
||||
<td><a href="anhang-glossar.md#gloss:bedingte-kopplung" class="glossar-link">Bedingte Kopplung</a></td>
|
||||
<td>„Wenn A und B, dann C“</td>
|
||||
<td><a href="milp.html#kap-milp">Kapitel 6</a></td>
|
||||
</tr>
|
||||
|
|
@ -183,25 +183,25 @@
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td>B9</td>
|
||||
<td>Gestaffelte Preise</td>
|
||||
<td><a href="anhang-glossar.md#gloss:gestaffelte-preise" class="glossar-link">Gestaffelte Preise</a></td>
|
||||
<td>„Erste 100 Stück billiger“</td>
|
||||
<td>—</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>B10</td>
|
||||
<td>Absolutbetrag</td>
|
||||
<td><a href="anhang-glossar.md#gloss:absolutbetrag" class="glossar-link">Absolutbetrag</a></td>
|
||||
<td>„Abweichung nach oben wie unten“</td>
|
||||
<td><a href="cvar.html#kap-cvar">Kapitel 20</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>B11</td>
|
||||
<td>Min/Max in der Zielfunktion</td>
|
||||
<td>Min/Max in der <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a></td>
|
||||
<td>„Den Schlechtesten verbessern“</td>
|
||||
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>B12</td>
|
||||
<td>Verhältnis-Bedingung</td>
|
||||
<td><a href="anhang-glossar.md#gloss:verhaeltnis-bedingung" class="glossar-link">Verhältnis-Bedingung</a></td>
|
||||
<td>„Anteil mindestens 30 %“</td>
|
||||
<td><a href="markowitz.html#kap-markowitz">Kapitel 19</a></td>
|
||||
</tr>
|
||||
|
|
@ -213,7 +213,7 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td>B27</td>
|
||||
<td>Budgetlimit</td>
|
||||
<td><a href="anhang-glossar.md#gloss:budgetlimit" class="glossar-link">Budgetlimit</a></td>
|
||||
<td>„Mehr als 2 Mio. gibt es nicht“</td>
|
||||
<td><a href="milp.html#kap-milp">Kapitel 6</a></td>
|
||||
</tr>
|
||||
|
|
@ -225,37 +225,37 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td>B13</td>
|
||||
<td>Vorrangbeziehung</td>
|
||||
<td><a href="anhang-glossar.md#gloss:vorrangbeziehung" class="glossar-link">Vorrangbeziehung</a></td>
|
||||
<td>„B erst nach A“</td>
|
||||
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>B14</td>
|
||||
<td>Nichtüberlappung</td>
|
||||
<td><a href="anhang-glossar.md#gloss:nichtueberlappung" class="glossar-link">Nichtüberlappung</a></td>
|
||||
<td>„Eine Maschine, ein Job“</td>
|
||||
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>B15</td>
|
||||
<td>Kumulative Ressource</td>
|
||||
<td><a href="anhang-glossar.md#gloss:kumulative-ressource" class="glossar-link">Kumulative Ressource</a></td>
|
||||
<td>„Höchstens 3 gleichzeitig“</td>
|
||||
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>B16</td>
|
||||
<td>Gleitendes Fenster</td>
|
||||
<td><a href="anhang-glossar.md#gloss:gleitendes-fenster" class="glossar-link">Gleitendes Fenster</a></td>
|
||||
<td>„Höchstens 5 Tage in Folge“</td>
|
||||
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>B17</td>
|
||||
<td>Umrüstkosten</td>
|
||||
<td><a href="anhang-glossar.md#gloss:umruestkosten" class="glossar-link">Umrüstkosten</a></td>
|
||||
<td>„Wechsel kostet extra“</td>
|
||||
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>B26</td>
|
||||
<td>Rüstzeit als Kapazität</td>
|
||||
<td><a href="anhang-glossar.md#gloss:ruestzeit" class="glossar-link">Rüstzeit</a> als Kapazität</td>
|
||||
<td>„Umbauen kostet Maschinenstunden“</td>
|
||||
<td><a href="supplychain.html#kap-supplychain">Kapitel 17</a></td>
|
||||
</tr>
|
||||
|
|
@ -279,14 +279,14 @@
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td>B20</td>
|
||||
<td>Symmetriebrechung</td>
|
||||
<td><a href="anhang-glossar.md#gloss:symmetriebrechung" class="glossar-link">Symmetriebrechung</a></td>
|
||||
<td>„Gleiche Objekte nicht doppelt zählen“</td>
|
||||
<td><a href="dekomposition.html#kap-dekomposition">Kapitel 10</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>B21</td>
|
||||
<td>Worst-Case-Abzug</td>
|
||||
<td>„Gegen Schätzfehler absichern“</td>
|
||||
<td>„Gegen <a href="anhang-glossar.md#gloss:schaetzfehler" class="glossar-link">Schätzfehler</a> absichern“</td>
|
||||
<td><a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
|
|
@ -297,7 +297,7 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td>B22</td>
|
||||
<td>Flusserhaltung</td>
|
||||
<td><a href="anhang-glossar.md#gloss:flusserhaltung" class="glossar-link">Flusserhaltung</a></td>
|
||||
<td>„Was reinkommt, geht raus“</td>
|
||||
<td><a href="graphen.html#kap-graphen">Kapitel 8</a></td>
|
||||
</tr>
|
||||
|
|
@ -309,7 +309,7 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td>B24</td>
|
||||
<td>Subtour-Eliminierung</td>
|
||||
<td><a href="anhang-glossar.md#gloss:subtour" class="glossar-link">Subtour</a>-Eliminierung</td>
|
||||
<td>„Keine isolierten Kreise“</td>
|
||||
<td><a href="graphen.html#kap-graphen">Kapitel 8</a></td>
|
||||
</tr>
|
||||
|
|
@ -327,7 +327,7 @@
|
|||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>modell.Add(x <span class="op"><=</span> M <span class="op">*</span> y) <span class="co"># CP-SAT</span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="co"># LP/MILP: Zeile x - M*y <= 0</span></span></code></pre></div>
|
||||
<blockquote>
|
||||
<p>⚠️ <strong><span class="math inline">M</span> so klein wie möglich</strong> — idealerweise die ohnehin vorhandene Kapazitätsgrenze von <span class="math inline">x</span>. Zu großes <span class="math inline">M</span> macht die LP-Relaxation wertlos (<a href="milp.html#sec:milp-modellierungstricks-big-m-und-logische-bedingungen">Abschnitt 6.5</a>).</p>
|
||||
<p>⚠️ <strong><span class="math inline">M</span> so klein wie möglich</strong> — idealerweise die ohnehin vorhandene Kapazitätsgrenze von <span class="math inline">x</span>. Zu großes <span class="math inline">M</span> macht die <a href="anhang-glossar.md#gloss:lp-relaxation" class="glossar-link">LP-Relaxation</a> wertlos (<a href="milp.html#sec:milp-modellierungstricks-big-m-und-logische-bedingungen">Abschnitt 6.5</a>).</p>
|
||||
</blockquote>
|
||||
<h3 id="b2-semikontinuierliche-variable">B2 — Semikontinuierliche Variable</h3>
|
||||
<p><strong>Regel.</strong> „Entweder gar nicht oder mindestens <span class="math inline">L</span> (und höchstens <span class="math inline">U</span>).“</p>
|
||||
|
|
@ -400,19 +400,19 @@
|
|||
<p>⚠️ <strong>Die häufigste Verwechslung:</strong> <span class="math inline">L\,y_t \le x_t</span> <strong>je Periode</strong> (B2) ist ein <em>anderes</em> Modell — es verlangt in jeder einzelnen Periode eine Mindestmenge und ist erheblich strenger. Wer den Jahresvertrag so formuliert, erzeugt ein unlösbares Modell und sucht den Fehler dann in den Daten.</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p>⚠️ <strong>Die obere Kopplung nicht vergessen.</strong> Ohne <span class="math inline">\sum_t x_t \le U\,y</span> kann das Modell <span class="math inline">y = 0</span> setzen und trotzdem einkaufen — der Vertrag gilt dann als nicht geschlossen, die Ware fließt aber. Das ist der <em>Trickle Flow</em> aus <a href="milp.html#sec:milp-modellierungstricks-big-m-und-logische-bedingungen">Abschnitt 6.5</a>, nur andersherum. <span class="math inline">U</span> ist die Jahreskapazität des Lieferanten, keine runde Zahl.</p>
|
||||
<p>⚠️ <strong>Die obere Kopplung nicht vergessen.</strong> Ohne <span class="math inline">\sum_t x_t \le U\,y</span> kann das Modell <span class="math inline">y = 0</span> setzen und trotzdem einkaufen — der Vertrag gilt dann als nicht geschlossen, die Ware fließt aber. Das ist der <em><a href="anhang-glossar.md#gloss:trickle-flow" class="glossar-link">Trickle Flow</a></em> aus <a href="milp.html#sec:milp-modellierungstricks-big-m-und-logische-bedingungen">Abschnitt 6.5</a>, nur andersherum. <span class="math inline">U</span> ist die Jahreskapazität des Lieferanten, keine runde Zahl.</p>
|
||||
</blockquote>
|
||||
<h3 id="b27-budgetlimit">B27 — Budgetlimit</h3>
|
||||
<p><strong>Regel.</strong> „Alle Maßnahmen zusammen dürfen 2 Mio. € nicht überschreiten.“</p>
|
||||
<p><span class="math display">\sum_i c_i x_i \le B</span></p>
|
||||
<p>Mit <span class="math inline">x_i \in \{0,1\}</span> ist das ein <strong>Rucksackproblem</strong> — dasselbe Muster, das <a href="milp.html#kap-milp">Kapitel 6</a> an <code>Rucksack.py</code> vorrechnet und <a href="dekomposition.html#kap-dekomposition">Kapitel 10</a> als Pricing-Teilproblem wiederverwendet.</p>
|
||||
<p>Mit <span class="math inline">x_i \in \{0,1\}</span> ist das ein <strong><a href="anhang-glossar.md#gloss:rucksackproblem" class="glossar-link">Rucksackproblem</a></strong> — dasselbe Muster, das <a href="milp.html#kap-milp">Kapitel 6</a> an <code>Rucksack.py</code> vorrechnet und <a href="dekomposition.html#kap-dekomposition">Kapitel 10</a> als Pricing-Teilproblem wiederverwendet.</p>
|
||||
<div class="sourceCode" id="cb8"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>modell.Add(<span class="bu">sum</span>(KOSTEN[i] <span class="op">*</span> x[i] <span class="cf">for</span> i <span class="kw">in</span> massnahmen) <span class="op"><=</span> BUDGET)</span>
|
||||
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="co"># Mehrere Toepfe: je Topf eine Zeile - NICHT die Summe ueber alle Toepfe</span></span>
|
||||
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> topf, grenze <span class="kw">in</span> BUDGETS.items():</span>
|
||||
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> modell.Add(<span class="bu">sum</span>(KOSTEN[i] <span class="op">*</span> x[i] <span class="cf">for</span> i <span class="kw">in</span> massnahmen</span>
|
||||
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> TOPF[i] <span class="op">==</span> topf) <span class="op"><=</span> grenze)</span></code></pre></div>
|
||||
<blockquote>
|
||||
<p>💡 <strong>Der Schattenpreis des Budgets ist die Zahl, nach der die Geschäftsführung fragt:</strong> „Was bringt der nächste Euro?“ Bei einem <strong>LP</strong> ist er direkt ablesbar. Bei <strong>Ganzzahligkeit gibt es ihn nicht</strong> — die Dualwerte der Relaxation sind keine gültige Antwort. Rechnen Sie stattdessen mit erhöhtem Budget neu und vergleichen Sie die Zielwerte (<a href="lp.html#sec:lp-entartung">Abschnitt 5.9</a>).</p>
|
||||
<p>💡 <strong>Der <a href="anhang-glossar.md#gloss:schattenpreis" class="glossar-link">Schattenpreis</a> des Budgets ist die Zahl, nach der die Geschäftsführung fragt:</strong> „Was bringt der nächste Euro?“ Bei einem <strong><a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a></strong> ist er direkt ablesbar. Bei <strong>Ganzzahligkeit gibt es ihn nicht</strong> — die Dualwerte der <a href="anhang-glossar.md#gloss:relaxation" class="glossar-link">Relaxation</a> sind keine gültige Antwort. Rechnen Sie stattdessen mit erhöhtem Budget neu und vergleichen Sie die Zielwerte (<a href="lp.html#sec:lp-entartung">Abschnitt 5.9</a>).</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p>⚠️ <strong>Die LP-Relaxation verspricht zu viel.</strong> Sie darf die letzte Maßnahme anteilig kaufen und liefert deshalb eine Schranke, die spürbar über dem tatsächlich Erreichbaren liegen kann. Wer sie als Prognose berichtet, verspricht Geld, das nicht kommt.</p>
|
||||
|
|
@ -426,7 +426,7 @@
|
|||
<h3 id="b14-nichtüberlappung">B14 — Nichtüberlappung</h3>
|
||||
<p><strong>Regel.</strong> „Eine Maschine bearbeitet nur einen Job gleichzeitig.“</p>
|
||||
<div class="sourceCode" id="cb9"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>modell.AddNoOverlap([intervall_1, intervall_2, ...])</span></code></pre></div>
|
||||
<p>In MILP bräuchte man je Paar eine Disjunktion (B4) — bei <span class="math inline">k</span> Jobs sind das <span class="math inline">\binom{k}{2}</span> Konstruktionen. <strong>Nehmen Sie hier CP-SAT.</strong></p>
|
||||
<p>In <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> bräuchte man je Paar eine Disjunktion (B4) — bei <span class="math inline">k</span> Jobs sind das <span class="math inline">\binom{k}{2}</span> Konstruktionen. <strong>Nehmen Sie hier <a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a>.</strong></p>
|
||||
<h3 id="b15-kumulative-ressource">B15 — Kumulative Ressource</h3>
|
||||
<p><strong>Regel.</strong> „Zu keinem Zeitpunkt dürfen mehr als 3 Arbeiten gleichzeitig laufen“ bzw. „die Stromlast darf 500 kW nie übersteigen“.</p>
|
||||
<div class="sourceCode" id="cb10"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>modell.AddCumulative(intervalle, bedarfe, kapazitaet)</span></code></pre></div>
|
||||
|
|
@ -458,7 +458,7 @@
|
|||
<p><strong>Das wichtigste Muster für den Produktivbetrieb.</strong></p>
|
||||
<p><strong>Regel.</strong> „Diese Bedingung soll gelten — aber lieber ein schlechter Plan als gar keiner.“</p>
|
||||
<p><span class="math display">\sum_p x_{p,s} + u_s = 1,\qquad u_s\in\{0,1\}</span> Zielfunktion: <span class="math inline">\dots + 10\,000\cdot u_s</span></p>
|
||||
<p>Die Strafe muss <strong>hoch genug</strong> sein, dass der Solver sie nur im Notfall in Kauf nimmt, aber <strong>endlich</strong>, damit es überhaupt eine Lösung gibt. Faustregel: eine Größenordnung über der Summe aller weichen Ziele.</p>
|
||||
<p>Die Strafe muss <strong>hoch genug</strong> sein, dass der <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> sie nur im Notfall in Kauf nimmt, aber <strong>endlich</strong>, damit es überhaupt eine Lösung gibt. Faustregel: eine Größenordnung über der Summe aller weichen Ziele.</p>
|
||||
<h3 id="b19-hierarchische-ziele-lexikografisch">B19 — Hierarchische Ziele (lexikografisch)</h3>
|
||||
<p><strong>Regel.</strong> „Erst die Besetzung sicherstellen, dann die Fairness optimieren.“</p>
|
||||
<p><strong>Variante A — Gewichtung:</strong> Strafen um Größenordnungen staffeln (<span class="math inline">10\,000 \gg 100 \gg 1</span>). Einfach, aber bei extremen Skalenunterschieden numerisch heikel.</p>
|
||||
|
|
@ -475,7 +475,7 @@
|
|||
<h3 id="b20-symmetriebrechung">B20 — Symmetriebrechung</h3>
|
||||
<p><strong>Regel.</strong> „Drei identische Maschinen — der Solver soll nicht alle Vertauschungen durchprobieren.“</p>
|
||||
<p><span class="math display">\text{start}_1 \le \text{start}_2 \le \text{start}_3 \qquad\text{bzw.}\qquad \sum_j x_{1j} \ge \sum_j x_{2j}</span></p>
|
||||
<p>Ohne Symmetriebrechung durchsucht Branch-and-Bound <span class="math inline">k!</span> gleichwertige Lösungen. <strong>Eine einzige Ordnungsbedingung kann die Laufzeit um Größenordnungen senken.</strong></p>
|
||||
<p>Ohne Symmetriebrechung durchsucht <a href="anhang-glossar.md#gloss:branch-and-bound" class="glossar-link">Branch-and-Bound</a> <span class="math inline">k!</span> gleichwertige Lösungen. <strong>Eine einzige Ordnungsbedingung kann die Laufzeit um Größenordnungen senken.</strong></p>
|
||||
<h3 id="b21-worst-case-abzug-robuste-formulierung">B21 — Worst-Case-Abzug (robuste Formulierung)</h3>
|
||||
<p><strong>Regel.</strong> „Rechne nicht mit dem geschätzten Wert, sondern mit dem ungünstigsten plausiblen.“</p>
|
||||
<p>Bei Box-Unsicherheit <span class="math inline">\mu_i \in [\hat\mu_i - \delta_i, \hat\mu_i + \delta_i]</span> und <span class="math inline">w \ge 0</span>: <span class="math display">\hat{\boldsymbol{\mu}}^\top\mathbf{w} \;\longrightarrow\; \hat{\boldsymbol{\mu}}^\top\mathbf{w} - \boldsymbol{\delta}^\top\mathbf{w}</span></p>
|
||||
|
|
@ -490,11 +490,11 @@
|
|||
<p></p>
|
||||
<p><span class="math display">\sum_j x_{ij} = 1\ \forall i,\qquad \sum_i x_{ij} = 1\ \forall j,\qquad x_{ij} \ge 0</span></p>
|
||||
<blockquote>
|
||||
<p>💡 <strong>Ganzzahligkeit nicht fordern!</strong> Die Matrix ist total unimodular; ein LP-Solver liefert automatisch 0/1-Lösungen. Für reine Zuordnungen ist <code>scipy.optimize.linear_sum_assignment</code> (Ungarischer Algorithmus, <span class="math inline">O(n^3)</span>) noch deutlich schneller.</p>
|
||||
<p>💡 <strong>Ganzzahligkeit nicht fordern!</strong> Die Matrix ist total unimodular; ein LP-Solver liefert automatisch 0/1-Lösungen. Für reine Zuordnungen ist <code>scipy.optimize.linear_sum_assignment</code> (<a href="anhang-glossar.md#gloss:ungarischer-algorithmus" class="glossar-link">Ungarischer Algorithmus</a>, <span class="math inline">O(n^3)</span>) noch deutlich schneller.</p>
|
||||
</blockquote>
|
||||
<h3 id="b24-subtour-eliminierung">B24 — Subtour-Eliminierung</h3>
|
||||
<p><strong>MTZ (einfach, aber schwach):</strong> <span class="math display">u_i - u_j + C x_{ij} \le C - d_j \qquad \forall i\ne j</span></p>
|
||||
<p><strong>Besser in der Praxis:</strong> <code>AddCircuit</code> in CP-SAT oder die Routing-Bibliothek von OR-Tools.</p>
|
||||
<p><strong>Besser in der Praxis:</strong> <code>AddCircuit</code> in <a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a> oder die <a href="anhang-glossar.md#gloss:routing-bibliothek" class="glossar-link">Routing-Bibliothek</a> von <a href="anhang-glossar.md#gloss:or-tools" class="glossar-link">OR-Tools</a>.</p>
|
||||
<hr />
|
||||
<h2 id="ein-wort-zur-auswahl">Ein Wort zur Auswahl</h2>
|
||||
<p>Wenn mehrere Muster passen, entscheiden Sie nach dieser Reihenfolge:</p>
|
||||
|
|
|
|||
16
OR_HTML_04/anhang-spickzettel.html
generated
16
OR_HTML_04/anhang-spickzettel.html
generated
|
|
@ -105,13 +105,13 @@
|
|||
</blockquote>
|
||||
<p><strong>Alle Schnipsel lösen dasselbe Problem</strong> — das Produktionsprogramm aus <a href="oekosystem.html#sec:oekosystem-schnellstart">Abschnitt 3.1</a> mit dem bekannten Optimum <strong>530</strong> und den Schattenpreisen <strong>12</strong> und <strong>1</strong>:</p>
|
||||
<p><span class="math display">\max\; 10x_1 + 15x_2 + 25x_3 \quad\text{u.d.N.}\quad x_1 + x_2 + 2x_3 \le 40,\;\; 2x_1 + 3x_2 + x_3 \le 50,\;\; x \ge 0</span></p>
|
||||
<p>Damit ist jeder Schnipsel selbstprüfend: Kommt bei Ihnen etwas anderes als 530 heraus, liegt es an der Übertragung, nicht am Modell. (Die Ausnahme ist CP-SAT — ein rein stetiges LP ist dort das falsche Werkzeug; die Seite zeigt stattdessen die CP-SAT-eigenen Bausteine.)</p>
|
||||
<p>Damit ist jeder Schnipsel selbstprüfend: Kommt bei Ihnen etwas anderes als 530 heraus, liegt es an der Übertragung, nicht am Modell. (Die Ausnahme ist <a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a> — ein rein stetiges <a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a> ist dort das falsche Werkzeug; die Seite zeigt stattdessen die <a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a>-eigenen Bausteine.)</p>
|
||||
<blockquote>
|
||||
<p><strong>Was dieser Anhang <em>nicht</em> ist.</strong> Kein Vergleich und keine Empfehlung. Welche Bibliothek für welche Aufgabe taugt, steht in <a href="oekosystem.html#sec:oekosystem-wann-lohnt-sich-welche-ebene">Abschnitt 3.6</a>; denselben Fall in vier Bibliotheken <em>nebeneinander</em> zeigt <code>Ein_System_Vier_Ansaetze.py</code>, die beiden Modellierungssprachen <code>Modellierungsschichten.py</code>. Hier geht es allein ums Nachschlagen.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="d1-scipy-linprog-und-milp">D1 — SciPy: <code>linprog</code> und <code>milp</code></h2>
|
||||
<p><strong>Wofür.</strong> Die Einstiegsschicht: keine zusätzliche Installation, HiGHS als Unterbau, ideal für lineare und gemischt-ganzzahlige Probleme in Matrixform. <strong>Wofür nicht:</strong> alles, was sich nicht als Matrix schreiben lässt, und jede nichtlineare Zielfunktion.</p>
|
||||
<p><strong>Wofür.</strong> Die Einstiegsschicht: keine zusätzliche Installation, <a href="anhang-glossar.md#gloss:highs" class="glossar-link">HiGHS</a> als Unterbau, ideal für lineare und gemischt-ganzzahlige Probleme in Matrixform. <strong>Wofür nicht:</strong> alles, was sich nicht als Matrix schreiben lässt, und jede nichtlineare <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a>.</p>
|
||||
<h3 id="lineares-programm">Lineares Programm</h3>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> linprog</span>
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
</ol>
|
||||
<hr />
|
||||
<h2 id="d2-highs-über-highspy">D2 — HiGHS über <code>highspy</code></h2>
|
||||
<p><strong>Wofür.</strong> Derselbe Solver wie unter SciPy, aber direkt gesteuert: Optionen, Warm-Starts, inkrementelles Ändern eines bestehenden Modells. <strong>Wofür nicht:</strong> schnelles Hinschreiben — die CSR-Matrixübergabe ist fehleranfällig.</p>
|
||||
<p><strong>Wofür.</strong> Derselbe <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> wie unter <a href="anhang-glossar.md#gloss:scipy" class="glossar-link">SciPy</a>, aber direkt gesteuert: Optionen, Warm-Starts, inkrementelles Ändern eines bestehenden Modells. <strong>Wofür nicht:</strong> schnelles Hinschreiben — die CSR-Matrixübergabe ist fehleranfällig.</p>
|
||||
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||||
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> highspy</span>
|
||||
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
|
||||
|
|
@ -205,12 +205,12 @@
|
|||
<h3 id="die-drei-häufigsten-stolpersteine-1">Die drei häufigsten Stolpersteine</h3>
|
||||
<ol type="1">
|
||||
<li><strong>Nicht zusammen mit <code>ortools</code> importieren.</strong> Beide bringen eine eigene HiGHS-Kopie mit; im selben Prozess endet das in <code>undefined symbol</code> (<a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a>, C9). Auch <code>cvxpy</code> zieht <code>highspy</code> bei der Solver-Erkennung mit hinein.</li>
|
||||
<li><strong>Das CSR-Format stimmt oder es stimmt still nicht.</strong> <code>starts</code> hat so viele Einträge wie Zeilen, <code>indices</code> und <code>values</code> so viele wie Nichtnullen. Ein falscher <code>starts</code>-Eintrag erzeugt ein <em>anderes</em>, aber lösbares Modell — es fällt nur durch ein falsches Ergebnis auf.</li>
|
||||
<li><strong>Das <a href="anhang-glossar.md#gloss:csr-format" class="glossar-link">CSR-Format</a> stimmt oder es stimmt still nicht.</strong> <code>starts</code> hat so viele Einträge wie Zeilen, <code>indices</code> und <code>values</code> so viele wie Nichtnullen. Ein falscher <code>starts</code>-Eintrag erzeugt ein <em>anderes</em>, aber lösbares Modell — es fällt nur durch ein falsches Ergebnis auf.</li>
|
||||
<li><strong><code>output_flag</code> abschalten</strong>, sonst überschwemmt das Solverprotokoll jede Ausgabe.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
<h2 id="d3-or-tools-pywraplp">D3 — OR-Tools: <code>pywraplp</code></h2>
|
||||
<p><strong>Wofür.</strong> Bequeme algebraische Schreibweise für LP und MILP mit umschaltbarem Backend (<code>GLOP</code>, <code>SCIP</code>, <code>CBC</code>, <code>SAT</code>). <strong>Wofür nicht:</strong> Scheduling und kombinatorische Bedingungen — dafür ist CP-SAT (D4) da.</p>
|
||||
<p><strong>Wofür.</strong> Bequeme algebraische Schreibweise für LP und <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> mit umschaltbarem Backend (<code>GLOP</code>, <code>SCIP</code>, <code>CBC</code>, <code>SAT</code>). <strong>Wofür nicht:</strong> <a href="anhang-glossar.md#gloss:scheduling" class="glossar-link">Scheduling</a> und kombinatorische Bedingungen — dafür ist CP-SAT (D4) da.</p>
|
||||
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> ortools.linear_solver <span class="im">import</span> pywraplp</span>
|
||||
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="co"># "GLOP" = LP, "SCIP" oder "CBC" = MILP, "SAT" = CP-SAT als MILP-Backend</span></span>
|
||||
|
|
@ -290,7 +290,7 @@
|
|||
</ol>
|
||||
<hr />
|
||||
<h2 id="d5-cvxpy">D5 — CVXPY</h2>
|
||||
<p><strong>Wofür.</strong> Konvexe Probleme: quadratische Ziele, Normen, CVaR, alles mit Regularisierungstermen. <strong>Wofür nicht:</strong> große kombinatorische Modelle — der Aufbau der Ausdrücke wird dann selbst zum Engpass.</p>
|
||||
<p><strong>Wofür.</strong> Konvexe Probleme: quadratische Ziele, Normen, <a href="anhang-glossar.md#gloss:conditional-value-at-risk-cvar" class="glossar-link">CVaR</a>, alles mit Regularisierungstermen. <strong>Wofür nicht:</strong> große kombinatorische Modelle — der Aufbau der Ausdrücke wird dann selbst zum Engpass.</p>
|
||||
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||||
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> cvxpy <span class="im">as</span> cp</span>
|
||||
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
|
||||
|
|
@ -319,13 +319,13 @@
|
|||
<span id="cb6-26"><a href="#cb6-26" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Solverfehler:"</span>, problem.status)</span></code></pre></div>
|
||||
<h3 id="die-drei-häufigsten-stolpersteine-4">Die drei häufigsten Stolpersteine</h3>
|
||||
<ol type="1">
|
||||
<li><strong>DCP-Regeln vor dem Lösen prüfen.</strong> <code>problem.is_dcp()</code> und dann die einzelnen Bedingungen — das nennt die Schuldige, statt einen <code>DCPError</code> ohne Ort zu werfen (<a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a>, C8).</li>
|
||||
<li><strong><a href="anhang-glossar.md#gloss:dcp-disciplined-convex-programming" class="glossar-link">DCP</a>-Regeln vor dem Lösen prüfen.</strong> <code>problem.is_dcp()</code> und dann die einzelnen Bedingungen — das nennt die Schuldige, statt einen <code>DCPError</code> ohne Ort zu werfen (<a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a>, C8).</li>
|
||||
<li><strong><code>OPTIMAL_INACCURATE</code> ist kein Erfolg.</strong> Der Solver hat aufgegeben und meldet das leise. Diesen Fall immer eigens behandeln.</li>
|
||||
<li><strong>Der Aufbau kann teurer sein als das Lösen.</strong> Schleifen über Szenarien durch Vektorausdrücke ersetzen; <code>Parameter</code> statt Neuaufbau, wenn sich nur Zahlen ändern.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
<h2 id="d6-modellierungssprachen-pyomo-und-linopy">D6 — Modellierungssprachen: Pyomo und Linopy</h2>
|
||||
<p><strong>Wofür.</strong> Beide trennen <em>Modell</em> von <em>Solver</em>: dasselbe Modell läuft ohne Änderung unter HiGHS, CBC, Gurobi. Pyomo denkt in <strong>Mengen und Indizes</strong> wie eine mathematische Formulierung; Linopy denkt in <strong>beschrifteten Arrays</strong> und baut Nebenbedingungen als Matrixoperation statt in Python-Schleifen. <strong>Wofür nicht:</strong> ein Modell mit zehn Nebenbedingungen — dort ist der Aufwand höher als der Nutzen.</p>
|
||||
<p><strong>Wofür.</strong> Beide trennen <em>Modell</em> von <em>Solver</em>: dasselbe Modell läuft ohne Änderung unter HiGHS, CBC, <a href="anhang-glossar.md#gloss:gurobi" class="glossar-link">Gurobi</a>. <a href="anhang-glossar.md#gloss:pyomo" class="glossar-link">Pyomo</a> denkt in <strong>Mengen und Indizes</strong> wie eine mathematische Formulierung; <a href="anhang-glossar.md#gloss:linopy" class="glossar-link">Linopy</a> denkt in <strong>beschrifteten Arrays</strong> und baut Nebenbedingungen als Matrixoperation statt in Python-Schleifen. <strong>Wofür nicht:</strong> ein Modell mit zehn Nebenbedingungen — dort ist der Aufwand höher als der Nutzen.</p>
|
||||
<h3 id="pyomo">Pyomo</h3>
|
||||
<div class="sourceCode" id="cb7"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pyomo.environ <span class="im">as</span> pyo</span>
|
||||
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
|
|
|
|||
12
OR_HTML_04/assets/site.css
generated
12
OR_HTML_04/assets/site.css
generated
|
|
@ -209,6 +209,18 @@ article h2[id$="-zusammenfassung"]::before { content: "📌 "; }
|
|||
article a { color: var(--accent); text-decoration: none; }
|
||||
article a:hover { text-decoration: underline; }
|
||||
article a[target="_blank"]::after { content: " \2197"; font-size: .82em; color: var(--cyan); text-decoration: none; }
|
||||
/* Glossar-Links: dezent (gestrichelte Unterstreichung, nicht blau) —
|
||||
sie sollen auffindbar, aber nicht wie Navigationslinks aussehen. */
|
||||
article a.glossar-link {
|
||||
color: inherit;
|
||||
text-decoration: underline dotted var(--accent);
|
||||
text-decoration-thickness: 1px;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
article a.glossar-link:hover {
|
||||
color: var(--accent);
|
||||
text-decoration: underline solid var(--accent);
|
||||
}
|
||||
article p { margin: .75em 0; }
|
||||
article hr { border: 0; border-top: 1px solid var(--border); margin: 2.2em 0; }
|
||||
article figure { margin: 2em 0; text-align: center; }
|
||||
|
|
|
|||
113
OR_HTML_04/bilder_04/titelseite.svg
generated
113
OR_HTML_04/bilder_04/titelseite.svg
generated
|
|
@ -2444,7 +2444,7 @@ z
|
|||
</g>
|
||||
</g>
|
||||
<g id="text_14">
|
||||
<!-- Stand: 10. September 2026 v16.09 -->
|
||||
<!-- Stand: 10. September 2026 v17.38 -->
|
||||
<g style="fill: #c7d2fe" transform="translate(71.4528 818.05749) scale(0.12 -0.12)">
|
||||
<defs>
|
||||
<path id="DejaVuSans-31" d="M 794 531
|
||||
|
|
@ -2536,34 +2536,85 @@ Q 2619 4750 2861 4703
|
|||
Q 3103 4656 3366 4563
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-39" d="M 703 97
|
||||
L 703 672
|
||||
Q 941 559 1184 500
|
||||
Q 1428 441 1663 441
|
||||
Q 2288 441 2617 861
|
||||
Q 2947 1281 2994 2138
|
||||
Q 2813 1869 2534 1725
|
||||
Q 2256 1581 1919 1581
|
||||
Q 1219 1581 811 2004
|
||||
Q 403 2428 403 3163
|
||||
Q 403 3881 828 4315
|
||||
Q 1253 4750 1959 4750
|
||||
Q 2769 4750 3195 4129
|
||||
Q 3622 3509 3622 2328
|
||||
Q 3622 1225 3098 567
|
||||
Q 2575 -91 1691 -91
|
||||
Q 1453 -91 1209 -44
|
||||
Q 966 3 703 97
|
||||
<path id="DejaVuSans-37" d="M 525 4666
|
||||
L 3525 4666
|
||||
L 3525 4397
|
||||
L 1831 0
|
||||
L 1172 0
|
||||
L 2766 4134
|
||||
L 525 4134
|
||||
L 525 4666
|
||||
z
|
||||
M 1959 2075
|
||||
Q 2384 2075 2632 2365
|
||||
Q 2881 2656 2881 3163
|
||||
Q 2881 3666 2632 3958
|
||||
Q 2384 4250 1959 4250
|
||||
Q 1534 4250 1286 3958
|
||||
Q 1038 3666 1038 3163
|
||||
Q 1038 2656 1286 2365
|
||||
Q 1534 2075 1959 2075
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-33" d="M 2597 2516
|
||||
Q 3050 2419 3304 2112
|
||||
Q 3559 1806 3559 1356
|
||||
Q 3559 666 3084 287
|
||||
Q 2609 -91 1734 -91
|
||||
Q 1441 -91 1130 -33
|
||||
Q 819 25 488 141
|
||||
L 488 750
|
||||
Q 750 597 1062 519
|
||||
Q 1375 441 1716 441
|
||||
Q 2309 441 2620 675
|
||||
Q 2931 909 2931 1356
|
||||
Q 2931 1769 2642 2001
|
||||
Q 2353 2234 1838 2234
|
||||
L 1294 2234
|
||||
L 1294 2753
|
||||
L 1863 2753
|
||||
Q 2328 2753 2575 2939
|
||||
Q 2822 3125 2822 3475
|
||||
Q 2822 3834 2567 4026
|
||||
Q 2313 4219 1838 4219
|
||||
Q 1578 4219 1281 4162
|
||||
Q 984 4106 628 3988
|
||||
L 628 4550
|
||||
Q 988 4650 1302 4700
|
||||
Q 1616 4750 1894 4750
|
||||
Q 2613 4750 3031 4423
|
||||
Q 3450 4097 3450 3541
|
||||
Q 3450 3153 3228 2886
|
||||
Q 3006 2619 2597 2516
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-38" d="M 2034 2216
|
||||
Q 1584 2216 1326 1975
|
||||
Q 1069 1734 1069 1313
|
||||
Q 1069 891 1326 650
|
||||
Q 1584 409 2034 409
|
||||
Q 2484 409 2743 651
|
||||
Q 3003 894 3003 1313
|
||||
Q 3003 1734 2745 1975
|
||||
Q 2488 2216 2034 2216
|
||||
z
|
||||
M 1403 2484
|
||||
Q 997 2584 770 2862
|
||||
Q 544 3141 544 3541
|
||||
Q 544 4100 942 4425
|
||||
Q 1341 4750 2034 4750
|
||||
Q 2731 4750 3128 4425
|
||||
Q 3525 4100 3525 3541
|
||||
Q 3525 3141 3298 2862
|
||||
Q 3072 2584 2669 2484
|
||||
Q 3125 2378 3379 2068
|
||||
Q 3634 1759 3634 1313
|
||||
Q 3634 634 3220 271
|
||||
Q 2806 -91 2034 -91
|
||||
Q 1263 -91 848 271
|
||||
Q 434 634 434 1313
|
||||
Q 434 1759 690 2068
|
||||
Q 947 2378 1403 2484
|
||||
z
|
||||
M 1172 3481
|
||||
Q 1172 3119 1398 2916
|
||||
Q 1625 2713 2034 2713
|
||||
Q 2441 2713 2670 2916
|
||||
Q 2900 3119 2900 3481
|
||||
Q 2900 3844 2670 4047
|
||||
Q 2441 4250 2034 4250
|
||||
Q 1625 4250 1398 4047
|
||||
Q 1172 3844 1172 3481
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
</defs>
|
||||
|
|
@ -2596,10 +2647,10 @@ z
|
|||
<use xlink:href="#DejaVuSans-20" transform="translate(1417.919922 0)"/>
|
||||
<use xlink:href="#DejaVuSans-76" transform="translate(1449.707031 0)"/>
|
||||
<use xlink:href="#DejaVuSans-31" transform="translate(1508.886719 0)"/>
|
||||
<use xlink:href="#DejaVuSans-36" transform="translate(1572.509766 0)"/>
|
||||
<use xlink:href="#DejaVuSans-37" transform="translate(1572.509766 0)"/>
|
||||
<use xlink:href="#DejaVuSans-2e" transform="translate(1636.132812 0)"/>
|
||||
<use xlink:href="#DejaVuSans-30" transform="translate(1667.919922 0)"/>
|
||||
<use xlink:href="#DejaVuSans-39" transform="translate(1731.542969 0)"/>
|
||||
<use xlink:href="#DejaVuSans-33" transform="translate(1667.919922 0)"/>
|
||||
<use xlink:href="#DejaVuSans-38" transform="translate(1731.542969 0)"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="text_15">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 89 KiB |
20
OR_HTML_04/bruecke.html
generated
20
OR_HTML_04/bruecke.html
generated
|
|
@ -111,7 +111,7 @@
|
|||
<blockquote>
|
||||
<p><strong>📌 Für wen dieser Teil gedacht ist</strong></p>
|
||||
<p>Die Finanzkapitel ab <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> sind eine <strong>Vertiefungsdomäne</strong>, kein Pflichtstoff. Wer beruflich mit Logistik, Produktion oder Energie zu tun hat, liest die ersten beiden Kapitel dieses Teils und kann den Rest überspringen, ohne dass etwas fehlt — die Methoden sind dieselben.</p>
|
||||
<p><strong>Lesen Sie ihn trotzdem, wenn Sie eines der folgenden Themen brauchen:</strong> 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.</p>
|
||||
<p><strong>Lesen Sie ihn trotzdem, wenn Sie eines der folgenden Themen brauchen:</strong> <a href="anhang-glossar.md#gloss:schaetzfehler" class="glossar-link">Schätzfehler</a> 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.</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
<p><strong>Ein Hinweis vorweg:</strong> Die Kapitel ab <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> laden aktuelle Kursdaten über <code>yfinance</code> und brauchen dafür einen <strong>Internetzugang</strong>. Weil die Daten sich täglich ändern, sind die abgedruckten Zahlen dort <em>Beispielläufe</em>, keine reproduzierbaren Werte — anders als im übrigen Buch. Das Brückenkapitel kommt ohne Internet aus.</p>
|
||||
|
|
@ -121,7 +121,7 @@
|
|||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um den Nachweis, dass die Verfahren aus Teil II und III unverändert in der Finanzwelt funktionieren — und um die drei Stellen, an denen die Analogie endet.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> (Allokation als LP), <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a> (Szenarien) und <a href="praxisfallen.html#sec:praxisfallen-or-kern">Abschnitt 22.6</a> (<code>or_kern.py</code>).</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> (Allokation als <a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a>), <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a> (Szenarien) und <a href="praxisfallen.html#sec:praxisfallen-or-kern">Abschnitt 22.6</a> (<code>or_kern.py</code>).</p>
|
||||
<p><strong>Danach können Sie:</strong> ein betriebswirtschaftliches Modell in die andere Domäne übersetzen, ohne den Modellcode anzufassen; Schattenpreise in beiden Welten lesen; und benennen, welche Annahmen dabei <strong>nicht</strong> mitwandern.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 2,5 Stunden.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
|
|
@ -195,18 +195,18 @@
|
|||
</blockquote>
|
||||
</div>
|
||||
<p><strong>Und jetzt der Punkt.</strong> Die Klasse heißt <code>Produktionsproblem</code>, und das Depot passt hinein, ohne dass eine Zeile geändert wurde. Kein Adapter, keine Unterklasse, keine Fallunterscheidung — die Struktur ist dieselbe, weil das Problem dasselbe ist: <em>knappe Größen auf konkurrierende Verwendungen verteilen.</em></p>
|
||||
<p>Der interessanteste Teil steht in der zweiten Zeile der Ausgabe. <strong>60,26 € je Einheit Risikobudget</strong> — 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 <strong>Preis des Risikos</strong>. Es ist nicht bloß eine Analogie, es ist derselbe Schattenpreis aus <a href="lp.html#kap-lp">Kapitel 5</a>.</p>
|
||||
<p>Der interessanteste Teil steht in der zweiten Zeile der Ausgabe. <strong>60,26 € je Einheit Risikobudget</strong> — 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 <strong>Preis des Risikos</strong>. Es ist nicht bloß eine Analogie, es ist derselbe <a href="anhang-glossar.md#gloss:schattenpreis" class="glossar-link">Schattenpreis</a> aus <a href="lp.html#kap-lp">Kapitel 5</a>.</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Wenn zwei Probleme dieselbe Struktur haben, brauchen sie nicht zwei Modelle, sondern zwei Datensätze. Ob das der Fall ist, erkennt man daran, dass derselbe Code ohne Änderung läuft — nicht daran, dass eine Tabelle es behauptet.</p>
|
||||
</blockquote>
|
||||
<p><strong>Warum funktioniert das?</strong> 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, Kilogramm oder Risikobeiträge stehen, kommt darin nicht vor.</p>
|
||||
<p><strong>Warum funktioniert das?</strong> Weil ein LP nichts über die Bedeutung seiner Zahlen weiß. Es sieht eine Matrix, einen <a href="anhang-glossar.md#gloss:kapazitaetsvektor" class="glossar-link">Kapazitätsvektor</a> und einen Zielvektor. Ob in der Matrix Stunden, Kilogramm oder Risikobeiträge stehen, kommt darin nicht vor.</p>
|
||||
<hr />
|
||||
<h2 id="sec:bruecke-lernziele">16.2 Lernziele</h2>
|
||||
<p>Nach diesem Kapitel können Sie …</p>
|
||||
<ol type="1">
|
||||
<li>… ein Allokationsproblem aus der einen Domäne in die andere übersetzen, indem Sie die Daten austauschen statt des Codes.</li>
|
||||
<li>… den Schattenpreis in beiden Welten deuten — als Wert einer Ressource und als Preis des Risikos.</li>
|
||||
<li>… erklären, warum die CVaR-Formulierung aus <a href="cvar.html#kap-cvar">Kapitel 20</a> auf Lieferverzüge genauso passt wie auf Kursverluste.</li>
|
||||
<li>… erklären, warum die <a href="anhang-glossar.md#gloss:conditional-value-at-risk-cvar" class="glossar-link">CVaR</a>-Formulierung aus <a href="cvar.html#kap-cvar">Kapitel 20</a> auf Lieferverzüge genauso passt wie auf Kursverluste.</li>
|
||||
<li>… die drei Stellen benennen, an denen die Analogie <strong>nicht</strong> trägt — und begründen, warum das Übertragen von Methoden dort gefährlich wird.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
|
|
@ -681,7 +681,7 @@ u_s \ge \ell_s^\top w - \gamma, \quad u_s \ge 0
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><span class="math inline">\gamma</span></td>
|
||||
<td>der VaR: „so schlimm wird es an 95 % der Tage höchstens”</td>
|
||||
<td>der <a href="anhang-glossar.md#gloss:value-at-risk-var" class="glossar-link">VaR</a>: „so schlimm wird es an 95 % der Tage höchstens”</td>
|
||||
<td>„so viele Tage Verzug höchstens bei 95 % der Bestellungen”</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -733,8 +733,8 @@ u_s \ge \ell_s^\top w - \gamma, \quad u_s \ge 0
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>Ob Teilbarkeit erlaubt ist</strong></td>
|
||||
<td>37,4 % eines Lieferanten gibt es nicht: Verträge, Mindestabnahmen, Rüstzeiten → MILP</td>
|
||||
<td>37,4 % eines Fonds sind ein normaler Auftrag → LP/QP genügt</td>
|
||||
<td>37,4 % eines Lieferanten gibt es nicht: Verträge, Mindestabnahmen, Rüstzeiten → <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a></td>
|
||||
<td>37,4 % eines Fonds sind ein normaler Auftrag → LP/<a href="anhang-glossar.md#gloss:quadratische-programmierung-qp" class="glossar-link">QP</a> genügt</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -751,7 +751,7 @@ u_s \ge \ell_s^\top w - \gamma, \quad u_s \ge 0
|
|||
</blockquote>
|
||||
<p><strong>Aufgabe 16.1 ⭐ — Die dritte Ressource.</strong> Ergänzen Sie im Depot eine dritte knappe Größe: „Liquidität” (wie schnell sich eine Anlage verkaufen lässt). Was entspricht ihr in der Werkstatt?</p>
|
||||
<p><strong>Aufgabe 16.2 ⭐ — Den Schattenpreis lesen.</strong> Das Risikobudget hat einen Schattenpreis von 60,26 €. Die Aufsicht bietet an, es gegen eine Gebühr um 10 Einheiten zu erhöhen. Bis zu welcher Gebühr lohnt sich das — und welche Einschränkung dieser Aussage kennen Sie aus <a href="lp.html#sec:lp-entartung">Abschnitt 5.9</a>?</p>
|
||||
<p><strong>Aufgabe 16.3 ⭐⭐ — Die Brücke rückwärts.</strong> Übertragen Sie die Ledoit-Wolf-Shrinkage aus <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> auf Lieferzeiten: Wo genau träte dort dasselbe Problem auf, und welche Daten bräuchten Sie?</p>
|
||||
<p><strong>Aufgabe 16.3 ⭐⭐ — Die Brücke rückwärts.</strong> Übertragen Sie die <a href="anhang-glossar.md#gloss:ledoit-wolf-shrinkage" class="glossar-link">Ledoit-Wolf-Shrinkage</a> aus <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> auf Lieferzeiten: Wo genau träte dort dasselbe Problem auf, und welche Daten bräuchten Sie?</p>
|
||||
<p><strong>Aufgabe 16.4 ⭐⭐ — CVaR mit Ganzzahligkeit.</strong> Der Einkauf darf höchstens <strong>drei</strong> Lieferanten beauftragen. Ergänzen Sie die entsprechende Kardinalitätsbedingung (<a href="milp.html#kap-milp">Kapitel 6</a>, Muster 5) und vergleichen Sie den CVaR mit dem teilbaren Fall. Was kostet die Ganzzahligkeit?</p>
|
||||
<p><strong>Aufgabe 16.5 ⭐⭐⭐ — Die eigene Brücke.</strong> Nehmen Sie ein Modell aus Ihrem Arbeitsumfeld und suchen Sie die Entsprechung in der jeweils anderen Welt. Prüfen Sie mit der Tabelle aus <a href="#sec:bruecke-grenzen">Abschnitt 16.5</a>, ob die Übertragung trägt — und schreiben Sie auf, welche der drei Zeilen im Weg steht.</p>
|
||||
<hr />
|
||||
|
|
@ -761,7 +761,7 @@ u_s \ge \ell_s^\top w - \gamma, \quad u_s \ge 0
|
|||
<p><strong>🐛 „Das ist doch dasselbe Problem”</strong></p>
|
||||
<p>Eine Logistikerin liest dieses Kapitel und überträgt es zurück. Ihre Aufgabe: Aus 40 möglichen Lieferanten sollen die besten ausgewählt und Bestellmengen zugeteilt werden. Sie geht vor wie im Portfoliomanagement:</p>
|
||||
<blockquote>
|
||||
<p><em>„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 > angewendet: minimiere die Varianz der Gesamtlieferzeit bei vorgegebener mittlerer > Lieferzeit. Das Ergebnis ist ein sauber diversifiziertes Lieferantenportfolio.”</em></p>
|
||||
<p><em>„Ich habe für jeden Lieferanten aus den letzten drei Jahren die mittlere Lieferzeit und > die <a href="anhang-glossar.md#gloss:kovarianzmatrix" class="glossar-link">Kovarianzmatrix</a> 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.”</em></p>
|
||||
</blockquote>
|
||||
<p>Das Vorgehen ist methodisch sauber, die Rechnung stimmt, und das Ergebnis sieht plausibel aus.</p>
|
||||
<p><strong>Zwei Dinge daran sind falsch — und das eine ist genau der Fehler, vor dem dieses Kapitel warnt, das andere ein zusätzlicher, den es nicht behandelt. Welche?</strong></p>
|
||||
|
|
|
|||
36
OR_HTML_04/cpsat.html
generated
36
OR_HTML_04/cpsat.html
generated
|
|
@ -105,7 +105,7 @@
|
|||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um ein völlig anderes Denkmodell: Statt algebraischer Ungleichungen arbeitet Constraint Programming mit <strong>Wertebereichen</strong> und <strong>logischen Regeln</strong>. Für Dienstpläne, Zuordnungen und Reihenfolgen ist das die mit Abstand produktivste Methode.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="milp.html#kap-milp">Kapitel 6</a> (Binärvariablen, logische Bedingungen).</p>
|
||||
<p><strong>Danach können Sie:</strong> Zuweisungs-, Scheduling- und Reihenfolgeprobleme mit CP-SAT modellieren, globale Constraints einsetzen, weiche Ziele über Strafkosten steuern — und alle fünf Solver-Antworten auseinanderhalten, statt nur auf <code>OPTIMAL</code> zu prüfen.</p>
|
||||
<p><strong>Danach können Sie:</strong> Zuweisungs-, <a href="anhang-glossar.md#gloss:scheduling" class="glossar-link">Scheduling</a>- und Reihenfolgeprobleme mit <a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a> modellieren, globale Constraints einsetzen, weiche Ziele über <a href="anhang-glossar.md#gloss:strafkosten" class="glossar-link">Strafkosten</a> steuern — und alle fünf <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a>-Antworten auseinanderhalten, statt nur auf <code>OPTIMAL</code> zu prüfen.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 6,5 Stunden.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>Propagation_Demo.py</code><br />
|
||||
|
|
@ -151,7 +151,7 @@ Do -> Bux
|
|||
Fr -> Abel</code></pre>
|
||||
</blockquote>
|
||||
</div>
|
||||
<p><strong>Elf Zeilen Modell, und der Plan steht.</strong> Beachten Sie besonders die Zeile <code>m.AddExactlyOne(...)</code>. Sie sagt wörtlich, was gemeint ist: <em>genau eine</em> Person je Tag. In MILP hätte man dafür eine Gleichung <span class="math inline">\sum_p x_{p,d} = 1</span> aufgestellt — machbar, aber schon eine Übersetzungsleistung. Bei Regeln wie „diese beiden Dienste nicht direkt hintereinander“ oder „höchstens eine Nachtschicht pro Woche“ wächst dieser Übersetzungsaufwand rasch; in CP-SAT bleibt er eine Zeile.</p>
|
||||
<p><strong>Elf Zeilen Modell, und der Plan steht.</strong> Beachten Sie besonders die Zeile <code>m.AddExactlyOne(...)</code>. Sie sagt wörtlich, was gemeint ist: <em>genau eine</em> Person je Tag. In <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> hätte man dafür eine Gleichung <span class="math inline">\sum_p x_{p,d} = 1</span> aufgestellt — machbar, aber schon eine Übersetzungsleistung. Bei Regeln wie „diese beiden Dienste nicht direkt hintereinander“ oder „höchstens eine Nachtschicht pro Woche“ wächst dieser Übersetzungsaufwand rasch; in <a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a> bleibt er eine Zeile.</p>
|
||||
<p><strong>Und jetzt sehen Sie sich das Ergebnis genau an.</strong> <em>Cor bekommt keinen einzigen Dienst.</em> Dane arbeitet Montag <strong>und</strong> Dienstag hintereinander. Ist das ein Fehler?</p>
|
||||
<p>Nein — und das ist die wichtigste Lektion dieses Kapitels. Der Plan erfüllt <strong>jede</strong> Regel, die wir aufgeschrieben haben. Wir haben nur nie nach Fairness gefragt, und wir haben nie gesagt, dass Dienste nicht aufeinanderfolgen sollen. Ein Solver liefert exakt das Bestellte — nicht das Gemeinte.</p>
|
||||
<blockquote>
|
||||
|
|
@ -162,17 +162,17 @@ Fr -> Abel</code></pre>
|
|||
<p>Nach diesem Kapitel können Sie …</p>
|
||||
<ol type="1">
|
||||
<li>… erklären, wodurch sich Constraint Programming von MILP unterscheidet.</li>
|
||||
<li>… die Wirkung von <strong>Constraint Propagation</strong> an einem Beispiel nachvollziehen.</li>
|
||||
<li>… die Wirkung von <strong><a href="anhang-glossar.md#gloss:constraint-propagation" class="glossar-link">Constraint Propagation</a></strong> an einem Beispiel nachvollziehen.</li>
|
||||
<li>… die wichtigsten globalen Constraints einsetzen: <code>AddExactlyOne</code>, <code>AddAllDifferent</code>, <code>AddNoOverlap</code>, <code>AddCumulative</code>.</li>
|
||||
<li>… mit <strong>Intervallvariablen</strong> ein Maschinenbelegungsproblem modellieren.</li>
|
||||
<li>… harte Regeln und weiche Ziele in einem Modell kombinieren und gewichten.</li>
|
||||
<li>… die fünf CP-SAT-Statusfälle unterscheiden — insbesondere <code>INFEASIBLE</code> (es gibt keine Lösung) von <code>UNKNOWN</code> (es wurde keine gefunden) und <code>MODEL_INVALID</code> (Ihr Code ist fehlerhaft).</li>
|
||||
<li>… begründen, warum <code>num_workers = 1</code> für einen reproduzierbaren Lauf nötig ist und ein fester <code>random_seed</code> allein nicht genügt — und was ein Test deshalb prüfen darf.</li>
|
||||
<li>… begründen, warum ein Strafgewicht ein <strong>Wechselkurs</strong> ist, und welche Regeln deshalb niemals in die Zielfunktion gehören.</li>
|
||||
<li>… begründen, warum ein Strafgewicht ein <strong>Wechselkurs</strong> ist, und welche Regeln deshalb niemals in die <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a> gehören.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
<h2 id="sec:cpsat-ein-anderes-denkmodell">7.3 Ein anderes Denkmodell</h2>
|
||||
<p>Während LP und MILP auf algebraischen Gleichungen und Simplex-Matrizen beruhen, kommt <strong>Constraint Programming (CP)</strong> aus der künstlichen Intelligenz:</p>
|
||||
<p>Während <a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a> und MILP auf algebraischen Gleichungen und Simplex-Matrizen beruhen, kommt <strong>Constraint Programming (CP)</strong> aus der künstlichen Intelligenz:</p>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 33%" />
|
||||
|
|
@ -199,7 +199,7 @@ Fr -> Abel</code></pre>
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Suchprinzip</td>
|
||||
<td>Relaxation + Verzweigen + Schranken</td>
|
||||
<td><a href="anhang-glossar.md#gloss:relaxation" class="glossar-link">Relaxation</a> + Verzweigen + Schranken</td>
|
||||
<td><strong>Propagation</strong> + Verzweigen + Konfliktlernen</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -214,7 +214,7 @@ Fr -> Abel</code></pre>
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Der <strong>CP-SAT-Solver</strong> von Google OR-Tools verbindet Constraint Programming mit modernen <strong>SAT-Techniken</strong> (<em>Boolean Satisfiability</em>, Erfüllbarkeitsproblem der Aussagenlogik), insbesondere <strong>CDCL</strong> (<em>Conflict-Driven Clause Learning</em>, konfliktgetriebenes Klausellernen). Er gehört zu den weltweit leistungsfähigsten Engines für Schichtpläne, Vertretungsplanung, Projektterminierung und Job-Shop-Scheduling.</p>
|
||||
<p>Der <strong><a href="anhang-glossar.md#gloss:cp-sat-solver" class="glossar-link">CP-SAT-Solver</a></strong> von Google <a href="anhang-glossar.md#gloss:or-tools" class="glossar-link">OR-Tools</a> verbindet Constraint Programming mit modernen <strong>SAT-Techniken</strong> (<em>Boolean Satisfiability</em>, Erfüllbarkeitsproblem der Aussagenlogik), insbesondere <strong><a href="anhang-glossar.md#gloss:cdcl" class="glossar-link">CDCL</a></strong> (<em>Conflict-Driven Clause Learning</em>, konfliktgetriebenes Klausellernen). Er gehört zu den weltweit leistungsfähigsten Engines für Schichtpläne, Vertretungsplanung, Projektterminierung und <a href="anhang-glossar.md#gloss:job-shop-scheduling" class="glossar-link">Job-Shop-Scheduling</a>.</p>
|
||||
<h3 id="was-propagation-leistet">Was Propagation leistet</h3>
|
||||
<figure>
|
||||
<img src="bilder_04/kap06_cp_sat_propagation.svg" alt="Abb. 7.1: CP-SAT – Propagation und Conflict Learning" />
|
||||
|
|
@ -365,7 +365,7 @@ Fr -> Abel</code></pre>
|
|||
<tr class="odd">
|
||||
<td><code>AddCircuit(arcs)</code></td>
|
||||
<td>Die gewählten Kanten bilden <strong>einen</strong> Rundweg</td>
|
||||
<td>TSP-artige Reihenfolgeprobleme</td>
|
||||
<td><a href="anhang-glossar.md#gloss:tsp-traveling-salesperson-problem" class="glossar-link">TSP</a>-artige Reihenfolgeprobleme</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>.OnlyEnforceIf(bool)</code></td>
|
||||
|
|
@ -377,7 +377,7 @@ Fr -> Abel</code></pre>
|
|||
<div class="card card-formel">
|
||||
<blockquote>
|
||||
<p><strong>🔤 Formel-Übersetzer: was ein globales Constraint zusichert</strong></p>
|
||||
<p>Globale Constraints tragen englische Methodennamen, meinen aber alltägliche Regeln. Links die mathematische Zusicherung, rechts der Satz, den Sie im Planungsgespräch sagen würden:</p>
|
||||
<p><a href="anhang-glossar.md#gloss:globale-constraints" class="glossar-link">Globale Constraints</a> tragen englische Methodennamen, meinen aber alltägliche Regeln. Links die mathematische Zusicherung, rechts der Satz, den Sie im Planungsgespräch sagen würden:</p>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 50%" />
|
||||
|
|
@ -424,7 +424,7 @@ Fr -> Abel</code></pre>
|
|||
</blockquote>
|
||||
</div>
|
||||
<blockquote>
|
||||
<p><strong>💡 Warum globale Constraints so viel bringen</strong> <code>AddAllDifferent</code> über 9 Variablen ersetzt <span class="math inline">\binom{9}{2} = 36</span> paarweise Ungleichheitsbedingungen — und propagiert <strong>stärker</strong> als die 36 Einzelbedingungen zusammen, weil der Propagator die Struktur als Ganzes betrachtet (er nutzt Matching-Theorie auf bipartiten Graphen). Ein MILP-Modell derselben Regel bräuchte Big-M-Konstruktionen und würde deutlich langsamer laufen.</p>
|
||||
<p><strong>💡 Warum globale Constraints so viel bringen</strong> <code>AddAllDifferent</code> über 9 Variablen ersetzt <span class="math inline">\binom{9}{2} = 36</span> paarweise Ungleichheitsbedingungen — und propagiert <strong>stärker</strong> als die 36 Einzelbedingungen zusammen, weil der Propagator die Struktur als Ganzes betrachtet (er nutzt Matching-Theorie auf bipartiten <a href="anhang-glossar.md#gloss:graphen" class="glossar-link">Graphen</a>). Ein MILP-Modell derselben Regel bräuchte Big-M-Konstruktionen und würde deutlich langsamer laufen.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:cpsat-praxisfall-dynamisches-vertretungssystem">7.5 Praxisfall: Dynamisches Vertretungssystem</h2>
|
||||
|
|
@ -724,10 +724,10 @@ Suchstatistik: 113 Verzweigungen, 3 Konflikte, 0.006 s
|
|||
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>modell.AddBoolOr([x[p,s].Not(), x[p,s<span class="op">+</span><span class="dv">1</span>], x[p,s<span class="op">+</span><span class="dv">2</span>].Not()]).OnlyEnforceIf(loch.Not())</span></code></pre></div>
|
||||
<p>koppeln die Hilfsvariable <code>loch</code> <strong>in beide Richtungen</strong> an das Muster „arbeitet–frei–arbeitet“. Die erste Zeile erzwingt: <em>wenn</em> <code>loch = 1</code>, <em>dann</em> liegt das Muster vor. Die zweite: <em>wenn</em> <code>loch = 0</code>, <em>dann</em> liegt es nicht vor. In diesem Modell genügte streng genommen die erste Zeile, weil <code>loch</code> nur mit positiven Strafkosten vorkommt und der Minimierer es daher von selbst auf 0 drückt — die zweite Zeile macht das Modell aber robust gegen spätere Änderungen und ist selbstdokumentierend.</p>
|
||||
<p><strong>2. Fairness über Spannweite (W3).</strong> <code>AddMaxEquality</code> und <code>AddMinEquality</code> sind CP-SAT-Konstrukte, die in MILP mehrere Big-M-Ungleichungen bräuchten. Die Spannweite <span class="math inline">\max - \min</span> zu minimieren ist ein Standardrezept für „gleichmäßig verteilen“.</p>
|
||||
<p><strong>3. Kostenzerlegung.</strong> Der Block „Woraus bestehen die Strafkosten?“ ist kein Beiwerk. In der Praxis ist die erste Frage jedes Anwenders: <em>„Warum bekomme <strong>ich</strong> die Stunde?“</em> Wer darauf keine Antwort hat, dessen System wird nicht benutzt (<a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a>, <em>Explainable OR</em>).</p>
|
||||
<p><strong>3. <a href="anhang-glossar.md#gloss:kostenzerlegung" class="glossar-link">Kostenzerlegung</a>.</strong> Der Block „Woraus bestehen die Strafkosten?“ ist kein Beiwerk. In der Praxis ist die erste Frage jedes Anwenders: <em>„Warum bekomme <strong>ich</strong> die Stunde?“</em> Wer darauf keine Antwort hat, dessen System wird nicht benutzt (<a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a>, <em><a href="anhang-glossar.md#gloss:explainable-or" class="glossar-link">Explainable OR</a></em>).</p>
|
||||
<p><strong>4. Statusauswertung ohne CP-SAT-Vokabular.</strong> Nach <code>Solve()</code> steht nur eine einzige Zeile mit einer CP-SAT-Konstante darin:</p>
|
||||
<div class="sourceCode" id="cb7"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>status <span class="op">=</span> status_von_cpsat(rohstatus)</span></code></pre></div>
|
||||
<p>Danach heißen die Fälle <code>status.modellfehler</code> (die Regeln widersprechen sich — das Modell muss geändert werden) und <code>status.brauchbar</code> (es liegt etwas Ausführbares vor). Das ist <strong>dieselbe</strong> Fallunterscheidung wie bei HiGHS in <a href="milp.html#kap-milp">Kapitel 6</a> und bei GLOP in <a href="lp.html#kap-lp">Kapitel 5</a>; nur die eine Übersetzerzeile weiß, welcher Solver gerechnet hat. Wer den Auswertungscode direkt gegen <code>cp_model.INFEASIBLE</code> schreibt, kann ihn bei einem Solverwechsel wegwerfen — <a href="praxisfallen.html#sec:praxisfallen-solverwechsel">Abschnitt 22.7</a> führt genau diesen Wechsel vor.</p>
|
||||
<p>Danach heißen die Fälle <code>status.modellfehler</code> (die Regeln widersprechen sich — das Modell muss geändert werden) und <code>status.brauchbar</code> (es liegt etwas Ausführbares vor). Das ist <strong>dieselbe</strong> Fallunterscheidung wie bei <a href="anhang-glossar.md#gloss:highs" class="glossar-link">HiGHS</a> in <a href="milp.html#kap-milp">Kapitel 6</a> und bei <a href="anhang-glossar.md#gloss:glop" class="glossar-link">GLOP</a> in <a href="lp.html#kap-lp">Kapitel 5</a>; nur die eine Übersetzerzeile weiß, welcher Solver gerechnet hat. Wer den Auswertungscode direkt gegen <code>cp_model.INFEASIBLE</code> schreibt, kann ihn bei einem Solverwechsel wegwerfen — <a href="praxisfallen.html#sec:praxisfallen-solverwechsel">Abschnitt 22.7</a> führt genau diesen Wechsel vor.</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Typische Fehler</strong></p>
|
||||
|
|
@ -740,7 +740,7 @@ Suchstatistik: 113 Verzweigungen, 3 Konflikte, 0.006 s
|
|||
<hr />
|
||||
<h2 id="sec:cpsat-intervallvariablen-job-shop-scheduling">7.6 Intervallvariablen: Job-Shop-Scheduling</h2>
|
||||
<p>Die Königsdisziplin von CP-SAT sind Zeitplanungsprobleme. Intervallvariablen sind dabei das zentrale Werkzeug.</p>
|
||||
<p><strong>Problem.</strong> Drei Aufträge, je drei Arbeitsgänge auf drei Maschinen. Jeder Auftrag muss seine Gänge in fester Reihenfolge durchlaufen; jede Maschine kann nur einen Gang gleichzeitig bearbeiten. Gesucht: der Plan mit der kürzesten Gesamtdauer (<em>Makespan</em>).</p>
|
||||
<p><strong>Problem.</strong> Drei Aufträge, je drei Arbeitsgänge auf drei Maschinen. Jeder Auftrag muss seine Gänge in fester Reihenfolge durchlaufen; jede Maschine kann nur einen Gang gleichzeitig bearbeiten. Gesucht: der Plan mit der kürzesten Gesamtdauer (<em><a href="anhang-glossar.md#gloss:makespan" class="glossar-link">Makespan</a></em>).</p>
|
||||
<div class="sourceCode" id="cb8"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||||
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="co"># JobShop_Intervalle.py</span></span>
|
||||
|
|
@ -1154,12 +1154,12 @@ random_seed = 1 in JEDEM Lauf, 4 Wiederholungen je Arbeiterzahl.
|
|||
deshalb eine Entscheidung fuer den Test, nicht fuer den Betrieb.
|
||||
==============================================================================</code></pre>
|
||||
<h3 id="was-die-messung-zeigt">Was die Messung zeigt</h3>
|
||||
<p><strong>Erstens: Die Beschleunigung ist überlinear.</strong> Acht Arbeiter sind im abgedruckten Lauf nicht achtmal, sondern <strong>gut zwölfmal</strong> schneller als einer. Das sieht nach Messfehler aus, ist aber die korrekte Beschreibung dessen, was CP-SAT tut: Es lässt <strong>nicht</strong> achtmal dieselbe Suche auf verschiedenen Kernen laufen, sondern <strong>verschiedene Strategien nebeneinander</strong> — Suche mit 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.</p>
|
||||
<p><strong>Erstens: Die Beschleunigung ist überlinear.</strong> Acht Arbeiter sind im abgedruckten Lauf nicht achtmal, sondern <strong>gut zwölfmal</strong> schneller als einer. Das sieht nach Messfehler aus, ist aber die korrekte Beschreibung dessen, was CP-SAT tut: Es lässt <strong>nicht</strong> achtmal dieselbe Suche auf verschiedenen Kernen laufen, sondern <strong>verschiedene Strategien nebeneinander</strong> — Suche mit <a href="anhang-glossar.md#gloss:lp-relaxation" class="glossar-link">LP-Relaxation</a>, 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.</p>
|
||||
<p>Daraus folgt zweierlei. Ein Speedup über der Kernzahl ist bei CP-SAT normal und kein Grund zum Misstrauen. Und der Zugewinn flacht ab: Zwischen vier und acht Arbeitern lag in unseren Wiederholungen mal das eine, mal das andere vorn — ab einer gewissen Zahl kosten Abstimmung und Speicherbandbreite mehr, als ein weiterer Suchstrang einbringt. Auch hier gilt: messen, nicht schätzen.</p>
|
||||
<p><strong>Zweitens — und das ist der Befund, der die Testpraxis bestimmt: Der Seed genügt nicht.</strong> Bei einem Arbeiter liefern vier Läufe <strong>einen</strong> Plan. Schon bei <strong>zwei</strong> Arbeitern liefern vier Läufe <strong>drei verschiedene</strong> — bei identischem <code>random_seed</code> und identischem Zielwert 183.</p>
|
||||
<p>Es braucht also keine acht Arbeiter, um die Reproduzierbarkeit zu verlieren. Zwei genügen. Der Grund ist einfach, sobald man ihn ausspricht: Der Seed legt fest, wie ein <strong>einzelner</strong> Suchstrang würfelt. Er legt nicht fest, <strong>welcher von mehreren zuerst fertig wird</strong> — das entscheidet die Uhr, und die ist bei jedem Lauf anders.</p>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ <code>random_seed</code> allein macht nichts reproduzierbar</strong> Ein häufiger Irrtum: „Ich habe doch einen Seed gesetzt.“ Für einen Zufallsgenerator stimmt das. Für einen <strong>parallelen</strong> Solver nicht — dort ist die zweite Zufallsquelle die Ausführungsreihenfolge, und die lässt sich nicht mit einem Parameter festnageln. Reproduzierbar wird der Lauf erst mit <code>num_workers = 1</code> <strong>und</strong> Seed. Wer nur eines von beidem setzt, hat einen Test, der gelegentlich grundlos rot wird.</p>
|
||||
<p><strong>⚠️ <code>random_seed</code> allein macht nichts reproduzierbar</strong> Ein häufiger Irrtum: „Ich habe doch einen Seed gesetzt.“ Für einen Zufallsgenerator stimmt das. Für einen <strong>parallelen</strong> Solver nicht — dort ist die zweite Zufallsquelle die Ausführungsreihenfolge, und die lässt sich nicht mit einem <a href="anhang-glossar.md#gloss:parameter" class="glossar-link">Parameter</a> festnageln. Reproduzierbar wird der Lauf erst mit <code>num_workers = 1</code> <strong>und</strong> Seed. Wer nur eines von beidem setzt, hat einen Test, der gelegentlich grundlos rot wird.</p>
|
||||
</blockquote>
|
||||
<h3 id="was-daraus-für-tests-folgt">Was daraus für Tests folgt</h3>
|
||||
<p>Der Zielwert war in <strong>allen</strong> sechzehn Läufen derselbe: 183. Die Gestalt der Lösung war es nicht. Genau daran entscheidet sich, was ein Test prüfen darf:</p>
|
||||
|
|
@ -1576,7 +1576,7 @@ genau die Information, die zur Fehlersuche noetig waere.
|
|||
<p><strong>Aufgabe 7.1 ⭐ — Propagation nachvollziehen.</strong> <span class="math inline">x_1 \in \{1,\dots,6\}</span>, <span class="math inline">x_2 \in \{1,\dots,6\}</span>, Bedingungen: <span class="math inline">x_1 < x_2</span> und <span class="math inline">x_1 + x_2 = 8</span>. Reduzieren Sie beide Wertebereiche von Hand so weit wie möglich.</p>
|
||||
<p><strong>Aufgabe 7.2 ⭐ — Hart oder weich?</strong> Klassifizieren Sie und begründen Sie, welche Strafhöhe Sie ansetzen würden: (a) Gesetzliche Mindestruhezeit. (b) „Herr Bauer möchte montags frei.“ (c) „In jeder Schicht mindestens eine examinierte Kraft.“ (d) „Möglichst keine geteilten Dienste.“ (e) „Kein Dienst länger als 10 Stunden.“</p>
|
||||
<p><strong>Aufgabe 7.3 ⭐⭐ — Regeln ergänzen.</strong> Erweitern Sie das Vertretungssystem um: (a) Frau Albrecht ist ab Slot 3 nicht mehr verfügbar. (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).</p>
|
||||
<p><strong>Aufgabe 7.4 ⭐⭐ — Infeasibility erzeugen und diagnostizieren.</strong> Setzen Sie <code>MAX_VERTRETUNGEN = 0</code>. Was meldet das Programm? Bauen Sie anschließend eine <strong>Schlupfvariable</strong> 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?</p>
|
||||
<p><strong>Aufgabe 7.4 ⭐⭐ — <a href="anhang-glossar.md#gloss:infeasibility" class="glossar-link">Infeasibility</a> erzeugen und diagnostizieren.</strong> Setzen Sie <code>MAX_VERTRETUNGEN = 0</code>. Was meldet das Programm? Bauen Sie anschließend eine <strong>Schlupfvariable</strong> 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?</p>
|
||||
<p><strong>Aufgabe 7.5 ⭐⭐ — Sudoku.</strong> Lösen Sie ein 9×9-Sudoku mit CP-SAT. Sie brauchen nur <code>NewIntVar(1, 9, ...)</code> und <code>AddAllDifferent</code> für Zeilen, Spalten und die neun 3×3-Blöcke. Wie viele Zeilen Modellcode benötigen Sie?</p>
|
||||
<p><strong>Aufgabe 7.6 ⭐⭐ — Die Grenze der Parallelität finden.</strong> <code>Parallele_Suche.py</code> misst 1, 2, 4 und 8 Arbeiter. (a) Ergänzen Sie 16 und 24 (bzw. die Kernzahl Ihres Rechners). Ab wo bringt ein weiterer Arbeiter nichts mehr — und wird es irgendwann wieder schlechter? (b) Setzen Sie <code>random_seed</code> bei jedem Lauf auf einen <strong>anderen</strong> Wert, aber <code>num_workers = 1</code>. Wie viele verschiedene Pläne kommen jetzt heraus? Was folgt daraus für die Frage, welcher der beiden Parameter die Reproduzierbarkeit sichert? (c) Vergrößern Sie die Instanz auf 15 Aufträge. Ab welcher Größe erreicht der Lauf mit einem Arbeiter das Zeitlimit, während acht noch <code>OPTIMAL</code> melden?</p>
|
||||
<p><strong>Aufgabe 7.7 ⭐⭐⭐ — Job-Shop erweitern.</strong> Ergänzen Sie <code>JobShop_Intervalle.py</code> um: (a) Rüstzeiten von 1 Zeiteinheit zwischen zwei Aufträgen auf derselben Maschine. (b) Fälligkeitstermine je Auftrag mit Strafkosten für Verspätung. (c) Eine zweite Fräse (Kapazität 2 statt 1) mit <code>AddCumulative</code>.</p>
|
||||
|
|
@ -1777,7 +1777,7 @@ Nebenbedingungen. Alles, was einen Preis hat, wird irgendwann gekauft.
|
|||
<ul>
|
||||
<li><strong>Gewichte nach Bauchgefühl setzen.</strong> Rechnen Sie stattdessen die Tabelle wie oben und lassen Sie den Auftraggeber die Zeile aussuchen. Das dauert eine Stunde und ersetzt drei Abstimmungsrunden.</li>
|
||||
<li><strong>Eine unverhandelbare Regel weich modellieren.</strong> Alles, was einen Preis hat, wird irgendwann gekauft. Gesetzliche Ruhezeiten, Qualifikationsanforderungen und Betriebsvereinbarungen gehören unter die <strong>harten</strong> Nebenbedingungen — auch wenn das Modell dann <code>INFEASIBLE</code> melden kann. Dieses <code>INFEASIBLE</code> ist die ehrliche Antwort: Der Plan ist mit dem vorhandenen Personal nicht zulässig zu machen.</li>
|
||||
<li><strong>Gewichte in verschiedenen Einheiten mischen.</strong> Euro neben „Unzufriedenheitspunkten“ neben Minuten ergibt eine Zielfunktion, die niemand interpretieren kann — und deren Konditionszahl obendrein leidet (<a href="fundament.html#sec:fundament-kondition">Abschnitt 2.7</a>).</li>
|
||||
<li><strong>Gewichte in verschiedenen Einheiten mischen.</strong> Euro neben „Unzufriedenheitspunkten“ neben Minuten ergibt eine Zielfunktion, die niemand interpretieren kann — und deren <a href="anhang-glossar.md#gloss:konditionszahl" class="glossar-link">Konditionszahl</a> obendrein leidet (<a href="fundament.html#sec:fundament-kondition">Abschnitt 2.7</a>).</li>
|
||||
<li><strong>Nur ein Gewicht ausprobieren.</strong> 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.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
|
@ -1810,7 +1810,7 @@ Nebenbedingungen. Alles, was einen Preis hat, wird irgendwann gekauft.
|
|||
<h2 id="sec:cpsat-zusammenfassung">7.13 Zusammenfassung</h2>
|
||||
<ul>
|
||||
<li><p><strong>CP denkt in Wertebereichen und Regeln</strong>, nicht in Ungleichungen und Schranken.</p></li>
|
||||
<li><p><strong>Propagation</strong> streicht unmögliche Werte, bevor gesucht wird; <strong>Conflict Learning</strong> verhindert, dieselbe Sackgasse zweimal zu betreten.</p></li>
|
||||
<li><p><strong>Propagation</strong> streicht unmögliche Werte, bevor gesucht wird; <strong><a href="anhang-glossar.md#gloss:conflict-learning" class="glossar-link">Conflict Learning</a></strong> verhindert, dieselbe Sackgasse zweimal zu betreten.</p></li>
|
||||
<li><p><strong>Globale Constraints</strong> wie , und ersetzen ganze Blöcke von Big-M-Ungleichungen und propagieren stärker.</p></li>
|
||||
<li><p><strong>Intervallvariablen</strong> sind das Werkzeug für Zeitplanung; <code>AddNoOverlap</code> erledigt in einer Zeile, was in MILP dutzende Disjunktionen kostet.</p></li>
|
||||
<li><p><strong>Weiche Ziele mit Strafkosten</strong> machen Modelle robust gegen <code>INFEASIBLE</code> — und die <strong>Kostenzerlegung</strong> macht sie erklärbar.</p></li>
|
||||
|
|
|
|||
36
OR_HTML_04/cvar.html
generated
36
OR_HTML_04/cvar.html
generated
|
|
@ -104,8 +104,8 @@
|
|||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um zwei Schwächen des Markowitz-Modells: Es unterschätzt Extremverluste und ignoriert die Kosten des Umschichtens. Beide lassen sich mit konvexen Mitteln beheben.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="markowitz.html#kap-markowitz">Kapitel 19</a>, <a href="lp.html#kap-lp">Kapitel 5</a> (LP-Formulierungen).</p>
|
||||
<p><strong>Danach können Sie:</strong> VaR und CVaR unterscheiden, den CVaR nach Rockafellar/Uryasev als lineares Programm formulieren, Turnover über die <span class="math inline">L_1</span>-Norm bestrafen — und begründen, warum VaR-Kennzahlen nicht über Einheiten addiert werden dürfen.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="markowitz.html#kap-markowitz">Kapitel 19</a>, <a href="lp.html#kap-lp">Kapitel 5</a> (<a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a>-Formulierungen).</p>
|
||||
<p><strong>Danach können Sie:</strong> <a href="anhang-glossar.md#gloss:value-at-risk-var" class="glossar-link">VaR</a> und <a href="anhang-glossar.md#gloss:conditional-value-at-risk-cvar" class="glossar-link">CVaR</a> unterscheiden, den CVaR nach Rockafellar/Uryasev als lineares Programm formulieren, Turnover über die <span class="math inline">L_1</span>-Norm bestrafen — und begründen, warum VaR-Kennzahlen nicht über Einheiten addiert werden dürfen.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 5 Stunden.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>VaR_CVaR_Demo.py</code><br />
|
||||
|
|
@ -179,11 +179,11 @@ Anlage B: VaR(95) 3.00 % CVaR(95) 9.17 %</code></pre>
|
|||
<ol type="1">
|
||||
<li>… erklären, warum Marktrenditen keine Normalverteilung haben und was daraus folgt.</li>
|
||||
<li>… VaR und CVaR definieren und begründen, warum nur der CVaR kohärent ist.</li>
|
||||
<li>… das Rockafellar-Uryasev-Theorem anwenden, um den CVaR linear zu formulieren.</li>
|
||||
<li>… Transaktionskosten über die <span class="math inline">L_1</span>-Norm modellieren.</li>
|
||||
<li>… das <a href="anhang-glossar.md#gloss:rockafellar-uryasev-theorem" class="glossar-link">Rockafellar-Uryasev-Theorem</a> anwenden, um den CVaR linear zu formulieren.</li>
|
||||
<li>… <a href="anhang-glossar.md#gloss:transaktionskosten" class="glossar-link">Transaktionskosten</a> über die <span class="math inline">L_1</span>-Norm modellieren.</li>
|
||||
<li>… Einheiten konsistent halten und Nebenbedingungen vektorisieren.</li>
|
||||
<li>… erklären, warum zwei Anlagen mit identischem VaR völlig verschiedene Extremverluste haben können.</li>
|
||||
<li>… die Folgen fehlender Subadditivität für die Verteilung von Risikobudgets benennen.</li>
|
||||
<li>… die Folgen fehlender <a href="anhang-glossar.md#gloss:subadditivitaet" class="glossar-link">Subadditivität</a> für die Verteilung von Risikobudgets benennen.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
<h2 id="sec:cvar-die-zwei-schwaechen-des-markowitz-modells">20.3 Die zwei Schwächen des Markowitz-Modells</h2>
|
||||
|
|
@ -319,7 +319,7 @@ VaR: Portfolio 98.00 vs. Summe -4.00 -> VERLETZT die Subadditivitaet!
|
|||
CVaR: Portfolio 101.33 vs. Summe 159.24 -> subadditiv (kohaerent)
|
||||
========================================================================================</code></pre>
|
||||
<p><strong>Die 6-Sigma-Zeile setzt die Sache ins Verhältnis:</strong> Unter Normalverteilung wäre ein solcher Tag ein Ereignis von einmal in <strong>zwei Millionen Jahren</strong>. Unter der t-Verteilung mit drei Freiheitsgraden — die realen Aktienrenditen deutlich näher kommt — passiert er etwa alle <strong>zwei Jahre</strong>. Der Faktor beträgt fast <strong>eine Million</strong>.</p>
|
||||
<p>Und Teil 2 zeigt das Grundproblem des VaR an einem Beispiel, das Sie von Hand nachrechnen können: Einzeln meldet er für jede Anleihe einen <em>Gewinn</em> von 2 €, im Portfolio einen <em>Verlust</em> von 98 €. Diversifikation hätte demnach das Risiko um 102 € erhöht. Der CVaR dagegen verhält sich korrekt: 101,33 € im Portfolio gegenüber 159,24 € bei getrennter Betrachtung — die Streuung <strong>senkt</strong> das Risiko, wie es sein muss.</p>
|
||||
<p>Und Teil 2 zeigt das Grundproblem des VaR an einem Beispiel, das Sie von Hand nachrechnen können: Einzeln meldet er für jede Anleihe einen <em>Gewinn</em> von 2 €, im Portfolio einen <em>Verlust</em> von 98 €. <a href="anhang-glossar.md#gloss:diversifikation" class="glossar-link">Diversifikation</a> hätte demnach das Risiko um 102 € erhöht. Der CVaR dagegen verhält sich korrekt: 101,33 € im Portfolio gegenüber 159,24 € bei getrennter Betrachtung — die Streuung <strong>senkt</strong> das Risiko, wie es sein muss.</p>
|
||||
<figure>
|
||||
<img src="bilder_04/kap_cvar_subadditivitaet.svg" alt="Abb. 20.1: Dieselbe Tabelle als Bild, gerechnet mit denselben Ziehungen wie VaR_CVaR_Demo.py. Erzeugt von bilder_04/erzeuge_var_vs_cvar.py." />
|
||||
<figcaption aria-hidden="true">Abb. 20.1: Dieselbe Tabelle als Bild, gerechnet mit denselben Ziehungen wie <code>VaR_CVaR_Demo.py</code>. Erzeugt von <code>bilder_04/erzeuge_var_vs_cvar.py</code>.</figcaption>
|
||||
|
|
@ -336,7 +336,7 @@ CVaR: Portfolio 101.33 vs. Summe 159.24 -> subadditiv (kohaerent)
|
|||
<figcaption aria-hidden="true">Abb. 20.2: Der VaR ist eine Schwelle, der CVaR ein Mittelwert. 20 000 simulierte Tagesrenditen aus dem Fat-Tail-Modell dieses Kapitels (<span class="math inline">t</span>-Verteilung mit drei Freiheitsgraden). Der schraffierte Bereich sind die schlechtesten 5 % der Tage; der VaR markiert nur ihren Rand, der CVaR ihren Mittelwert. Erzeugt von <code>bilder_04/erzeuge_var_cvar.py</code>.</figcaption>
|
||||
</figure>
|
||||
<p><strong>Value at Risk (<span class="math inline">\text{VaR}_\alpha</span>):</strong> Der Verlust, der mit Wahrscheinlichkeit <span class="math inline">\alpha</span> nicht überschritten wird.</p>
|
||||
<p><strong>Conditional Value at Risk (<span class="math inline">\text{CVaR}_\alpha</span>, auch <em>Expected Shortfall</em>):</strong> Der <strong>durchschnittliche Verlust in den schlimmsten <span class="math inline">(1-\alpha)</span> Prozent</strong> der Fälle.</p>
|
||||
<p><strong>Conditional Value at Risk (<span class="math inline">\text{CVaR}_\alpha</span>, auch <em><a href="anhang-glossar.md#gloss:expected-shortfall" class="glossar-link">Expected Shortfall</a></em>):</strong> Der <strong>durchschnittliche Verlust in den schlimmsten <span class="math inline">(1-\alpha)</span> Prozent</strong> der Fälle.</p>
|
||||
<blockquote>
|
||||
<p><strong>📐 Der Unterschied in einem Satz</strong> Der VaR sagt: <em>„In 95 % der Tage verlieren Sie höchstens 1,86 %.“</em> Der CVaR sagt: <em>„Und wenn es doch schiefgeht, verlieren Sie im Mittel 2,99 %.“</em></p>
|
||||
<p>Beide Zahlen stammen aus der Verteilung oben — nachzurechnen mit <code>bilder_04/erzeuge_var_cvar.py</code>.</p>
|
||||
|
|
@ -367,7 +367,7 @@ CVaR: Portfolio 101.33 vs. Summe 159.24 -> subadditiv (kohaerent)
|
|||
<td>✓ ja</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Kohärentes Risikomaß</td>
|
||||
<td><a href="anhang-glossar.md#gloss:kohaerentes-risikomass" class="glossar-link">Kohärentes Risikomaß</a></td>
|
||||
<td>✗ nein</td>
|
||||
<td>✓ ja</td>
|
||||
</tr>
|
||||
|
|
@ -399,7 +399,7 @@ CVaR: Portfolio 101.33 vs. Summe 159.24 -> subadditiv (kohaerent)
|
|||
<blockquote>
|
||||
<p><strong>📐 Formel-Lesehilfe — der Trick in drei Schritten</strong> * <span class="math inline">\gamma</span> ist eine <strong>Hilfsvariable</strong>, die im Optimum automatisch den VaR annimmt. Man muss ihn also <strong>nicht vorher kennen</strong> — das ist der eigentliche Durchbruch. * <span class="math inline">-\mathbf{R}_s^\top\mathbf{w}</span> ist der <strong>Verlust</strong> im Szenario <span class="math inline">s</span> (Rendite mit negativem Vorzeichen). * <span class="math inline">u_s \ge \text{Verlust}_s - \gamma</span> zusammen mit <span class="math inline">u_s \ge 0</span> bedeutet: <span class="math inline">u_s = \max(\text{Verlust}_s - \gamma,\ 0)</span> — der <strong>Überschuss über die Schwelle</strong>. Liegt der Verlust unter <span class="math inline">\gamma</span>, ist <span class="math inline">u_s = 0</span> und das Szenario zählt nicht.</p>
|
||||
<p><strong>Ohne Formel gesagt:</strong> „Wähle eine Schwelle <span class="math inline">\gamma</span>. Zähle für jedes Szenario, wie weit der Verlust darüber hinausgeht. Der CVaR ist die Schwelle plus der gemittelte Überschuss — und zwar für diejenige Schwelle, bei der diese Summe minimal wird.“</p>
|
||||
<p><strong>Warum <span class="math inline">u_s</span> automatisch das Maximum wird:</strong> Die Zielfunktion minimiert die Summe der <span class="math inline">u_s</span>. Jedes <span class="math inline">u_s</span> wird also so klein wie möglich gedrückt — bis an die Grenze, die die beiden Ungleichungen erlauben. Das ist genau das Maximum der beiden Untergrenzen.</p>
|
||||
<p><strong>Warum <span class="math inline">u_s</span> automatisch das Maximum wird:</strong> Die <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a> minimiert die Summe der <span class="math inline">u_s</span>. Jedes <span class="math inline">u_s</span> wird also so klein wie möglich gedrückt — bis an die Grenze, die die beiden Ungleichungen erlauben. Das ist genau das Maximum der beiden Untergrenzen.</p>
|
||||
</blockquote>
|
||||
<div class="card card-formel">
|
||||
<blockquote>
|
||||
|
|
@ -449,7 +449,7 @@ CVaR: Portfolio 101.33 vs. Summe 159.24 -> subadditiv (kohaerent)
|
|||
</table>
|
||||
<p><strong>In einem Satz:</strong> <em>Der CVaR ist der Mittelwert der schlimmsten <span class="math inline">1-\alpha</span> Prozent — der Bruch vor der Summe sorgt allein dafür, dass durch die richtige Anzahl geteilt wird.</em></p>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Die teuerste Verwechslung des Kapitels</strong> > <span class="math inline">\alpha</span> und <span class="math inline">1-\alpha</span> zu vertauschen führt zu <strong>keiner Fehlermeldung</strong>. Das Modell > rechnet weiter, nur eben über die falsche Menge. An 2 000 simulierten Tagesrenditen mit > Fat Tails gemessen: > > | Rechnung | gemittelt über | CVaR | > | — | — | — | > | richtig (<span class="math inline">\alpha = 0{,}95</span>, Rand 5 %) | 100 von 2 000 Szenarien | <strong>3,43 %</strong> | > | vertauscht (Rand 95 %) | 1 900 von 2 000 Szenarien | <strong>0,18 %</strong> | > > Ein Faktor <strong>19</strong> — und die zweite Zahl ist kein schlecht geschätztes Randrisiko, sondern > überhaupt kein Randmaß mehr: Sie mittelt über fast alle Tage und schließt die schlimmen > gerade nicht ein. Der größte Einzelverlust der Stichprobe beträgt 21,4 %. > > <strong>Die Gegenprobe kostet eine Zeile:</strong> Ist der berechnete CVaR nicht deutlich größer als > der mittlere Verlust, stimmt <span class="math inline">\alpha</span> nicht.</p>
|
||||
<p><strong>⚠️ Die teuerste Verwechslung des Kapitels</strong> > <span class="math inline">\alpha</span> und <span class="math inline">1-\alpha</span> zu vertauschen führt zu <strong>keiner Fehlermeldung</strong>. Das Modell > rechnet weiter, nur eben über die falsche Menge. An 2 000 simulierten Tagesrenditen mit > <a href="anhang-glossar.md#gloss:fat-tails" class="glossar-link">Fat Tails</a> gemessen: > > | Rechnung | gemittelt über | CVaR | > | — | — | — | > | richtig (<span class="math inline">\alpha = 0{,}95</span>, Rand 5 %) | 100 von 2 000 Szenarien | <strong>3,43 %</strong> | > | vertauscht (Rand 95 %) | 1 900 von 2 000 Szenarien | <strong>0,18 %</strong> | > > Ein Faktor <strong>19</strong> — und die zweite Zahl ist kein schlecht geschätztes Randrisiko, sondern > überhaupt kein Randmaß mehr: Sie mittelt über fast alle Tage und schließt die schlimmen > gerade nicht ein. Der größte Einzelverlust der Stichprobe beträgt 21,4 %. > > <strong>Die Gegenprobe kostet eine Zeile:</strong> Ist der berechnete CVaR nicht deutlich größer als > der mittlere Verlust, stimmt <span class="math inline">\alpha</span> nicht.</p>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
</div>
|
||||
|
|
@ -469,7 +469,7 @@ CVaR: Portfolio 101.33 vs. Summe 159.24 -> subadditiv (kohaerent)
|
|||
<p><strong>Ohne Formel gesagt:</strong> „Wenn du 5 % von A verkaufst und 5 % von B kaufst, hast du 10 % Umschlag und zahlst darauf Gebühren.“</p>
|
||||
<p><strong>Warum <span class="math inline">L_1</span> und nicht <span class="math inline">L_2</span>?</strong> Die <span class="math inline">L_1</span>-Norm ist konvex (also optimierbar) und erzeugt zusätzlich <strong>dünn besetzte Änderungen</strong>: Sie bevorzugt wenige große Umschichtungen gegenüber vielen kleinen. Das entspricht genau dem, was man in der Praxis will — nicht 50 Kleinstorders mit je 3 € Mindestgebühr.</p>
|
||||
</blockquote>
|
||||
<p>In CVXPY schreibt man einfach <code>cp.norm1(w - w_alt)</code>; intern wird das in lineare Hilfsvariablen zerlegt.</p>
|
||||
<p>In <a href="anhang-glossar.md#gloss:cvxpy" class="glossar-link">CVXPY</a> schreibt man einfach <code>cp.norm1(w - w_alt)</code>; intern wird das in lineare Hilfsvariablen zerlegt.</p>
|
||||
<hr />
|
||||
<h2 id="sec:cvar-implementierung-cvar-portfolio-mit-reibung">20.6 Implementierung: CVaR-Portfolio mit Reibung</h2>
|
||||
<blockquote>
|
||||
|
|
@ -478,7 +478,7 @@ CVaR: Portfolio 101.33 vs. Summe 159.24 -> subadditiv (kohaerent)
|
|||
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>mu <span class="op">=</span> returns_df.mean().values <span class="op">*</span> <span class="dv">252</span> <span class="co"># ANNUALISIERT</span></span>
|
||||
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>cvar <span class="op">=</span> gamma <span class="op">+</span> (<span class="dv">1</span><span class="op">/</span>(S<span class="op">*</span>(<span class="dv">1</span><span class="op">-</span>alpha))) <span class="op">*</span> cp.<span class="bu">sum</span>(u) <span class="co"># TAEGLICH</span></span>
|
||||
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>objective <span class="op">=</span> cp.Maximize(mu <span class="op">@</span> w <span class="op">-</span> lambda_risk <span class="op">*</span> cvar <span class="op">-</span> trans_costs)</span></code></pre></div>
|
||||
<p>Der Risikoterm ist dadurch faktisch um Faktor 252 zu schwach gewichtet: <code>lambda_risk = 1.5</code> bedeutet dann effektiv eine Risikoaversion von <span class="math inline">1{,}5/252 \approx 0{,}006</span>. Das Modell ist nicht falsch im Sinne von unlösbar — aber der Parameter bedeutet nicht, was er zu bedeuten scheint, und lässt sich daher nicht sinnvoll einstellen.</p>
|
||||
<p>Der Risikoterm ist dadurch faktisch um Faktor 252 zu schwach gewichtet: <code>lambda_risk = 1.5</code> bedeutet dann effektiv eine Risikoaversion von <span class="math inline">1{,}5/252 \approx 0{,}006</span>. Das Modell ist nicht falsch im Sinne von unlösbar — aber der <a href="anhang-glossar.md#gloss:parameter" class="glossar-link">Parameter</a> bedeutet nicht, was er zu bedeuten scheint, und lässt sich daher nicht sinnvoll einstellen.</p>
|
||||
<p><strong>Dieses Programm rechnet deshalb durchgehend auf Tagesbasis</strong> und annualisiert erst in der Ausgabe.</p>
|
||||
</blockquote>
|
||||
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||||
|
|
@ -676,20 +676,20 @@ CVaR: Portfolio 101.33 vs. Summe 159.24 -> subadditiv (kohaerent)
|
|||
<p>statt</p>
|
||||
<div class="sourceCode" id="cb8"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> s <span class="kw">in</span> <span class="bu">range</span>(S):</span>
|
||||
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> bedingungen.append(u[s] <span class="op">>=</span> <span class="op">-</span>R[s] <span class="op">@</span> w <span class="op">-</span> gamma) <span class="co"># S einzelne Bedingungen</span></span></code></pre></div>
|
||||
<p>Beide beschreiben <strong>dasselbe Modell</strong>. Der Unterschied liegt im Aufbau: CVXPY muss im zweiten Fall 500 einzelne Ausdrucksbäume erzeugen, prüfen und zusammensetzen. Bei einem Backtest mit 60 Rebalancings (<a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a>) summiert sich das erheblich.</p>
|
||||
<p><strong>Die allgemeine Regel:</strong> Wenn Sie in einer Modellierungssprache eine Python-Schleife über Datenzeilen schreiben, prüfen Sie, ob sich dasselbe als Matrixoperation ausdrücken lässt. Der Solver rechnet ohnehin mit Matrizen — der Umweg über einzelne Ausdrücke kostet nur Aufbauzeit.</p>
|
||||
<p>Beide beschreiben <strong>dasselbe Modell</strong>. Der Unterschied liegt im Aufbau: CVXPY muss im zweiten Fall 500 einzelne Ausdrucksbäume erzeugen, prüfen und zusammensetzen. Bei einem <a href="anhang-glossar.md#gloss:backtest" class="glossar-link">Backtest</a> mit 60 Rebalancings (<a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a>) summiert sich das erheblich.</p>
|
||||
<p><strong>Die allgemeine Regel:</strong> Wenn Sie in einer Modellierungssprache eine Python-Schleife über Datenzeilen schreiben, prüfen Sie, ob sich dasselbe als Matrixoperation ausdrücken lässt. Der <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> rechnet ohnehin mit Matrizen — der Umweg über einzelne Ausdrücke kostet nur Aufbauzeit.</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Die Standardabweichung ist in CVXPY keine Wurzel</strong></p>
|
||||
<p>Im Vergleichsmodell <code>optimiere_varianz()</code> steht die Standardabweichung als</p>
|
||||
<div class="sourceCode" id="cb9"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>L <span class="op">=</span> np.linalg.cholesky(sigma <span class="op">+</span> <span class="fl">1e-12</span> <span class="op">*</span> np.eye(N))</span>
|
||||
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>risiko <span class="op">=</span> cp.norm2(L.T <span class="op">@</span> w) <span class="co"># = sqrt(w' sigma w)</span></span></code></pre></div>
|
||||
<p>und <strong>nicht</strong> als das Naheliegende, <code>cp.sqrt(cp.quad_form(w, sigma))</code>. Der naheliegende Ausdruck ist nicht DCP und wird von CVXPY mit einem <code>DCPError</code> abgelehnt: <code>cp.sqrt</code> ist konkav und verlangt deshalb ein <strong>konkaves</strong> Argument, <code>quad_form</code> ist aber konvex. Die Regel wird verletzt, obwohl die Funktion als ganze mathematisch völlig harmlos ist — <span class="math inline">\sqrt{w^\top \Sigma w}</span> ist konvex, DCP kann es nur nicht <em>sehen</em>.</p>
|
||||
<p>und <strong>nicht</strong> als das Naheliegende, <code>cp.sqrt(cp.quad_form(w, sigma))</code>. Der naheliegende Ausdruck ist nicht <a href="anhang-glossar.md#gloss:dcp-disciplined-convex-programming" class="glossar-link">DCP</a> und wird von CVXPY mit einem <code>DCPError</code> abgelehnt: <code>cp.sqrt</code> ist konkav und verlangt deshalb ein <strong>konkaves</strong> Argument, <code>quad_form</code> ist aber konvex. Die Regel wird verletzt, obwohl die Funktion als ganze mathematisch völlig harmlos ist — <span class="math inline">\sqrt{w^\top \Sigma w}</span> ist konvex, DCP kann es nur nicht <em>sehen</em>.</p>
|
||||
<p>Wichtig ist die Fehlerdiagnose dahinter, weil sie leicht in die Irre geht: <code>cp.psd_wrap(sigma)</code> sieht nach der Lösung aus und ist keine. Es unterdrückt die <strong>numerische</strong> Beanstandung, dass <span class="math inline">\Sigma</span> nicht als positiv semidefinit erkannt wird — gegen die <strong>strukturelle</strong> Regelverletzung im Aufbau hilft es nicht.</p>
|
||||
<p>Der Ausweg ist immer derselbe: Zerlegen Sie <span class="math inline">\Sigma = LL^\top</span> (Cholesky). Dann ist <span class="math inline">w^\top \Sigma w = \lVert L^\top w\rVert_2^2</span>, und die Standardabweichung wird zur 2-Norm eines <strong>affinen</strong> Ausdrucks — konvex, regelkonform und für den Solver sogar die bessere Formulierung, weil sie direkt ein Kegelproblem ist. Der winzige Diagonalzuschlag <span class="math inline">10^{-12}</span> fängt den Fall ab, dass <span class="math inline">\Sigma</span> numerisch nur halbdefinit ist (mehr Titel als Handelstage, duplizierte Spalten). Die vollständige Fehlertabelle steht in <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a>.</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p><strong>💡 Zur Annualisierung von VaR und CVaR</strong> Ein häufiger Fehler skaliert den täglichen CVaR mit <span class="math inline">\sqrt{252}</span>. Diese <strong>Wurzel-Zeit-Regel</strong> gilt streng nur für <strong>Standardabweichungen</strong> unabhängig identisch verteilter Größen ohne Drift. Der CVaR ist ein Erwartungswert über einen Verteilungsrand — für ihn ist die Regel eine grobe Näherung, die bei fetten Rändern und Autokorrelation systematisch danebenliegt.</p>
|
||||
<p><strong>💡 Zur Annualisierung von VaR und CVaR</strong> Ein häufiger Fehler skaliert den täglichen CVaR mit <span class="math inline">\sqrt{252}</span>. Diese <strong><a href="anhang-glossar.md#gloss:wurzel-zeit-regel" class="glossar-link">Wurzel-Zeit-Regel</a></strong> gilt streng nur für <strong>Standardabweichungen</strong> unabhängig identisch verteilter Größen ohne Drift. Der CVaR ist ein Erwartungswert über einen Verteilungsrand — für ihn ist die Regel eine grobe Näherung, die bei fetten Rändern und Autokorrelation systematisch danebenliegt.</p>
|
||||
<p><strong>Dieses Buch weist VaR und CVaR deshalb als Tageswerte aus</strong> und benennt die Skalierungsproblematik ausdrücklich. Wer Mehrtageshorizonte braucht, simuliert sie (Monte-Carlo aus <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a>) statt zu skalieren.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
|
|
@ -701,7 +701,7 @@ CVaR: Portfolio 101.33 vs. Summe 159.24 -> subadditiv (kohaerent)
|
|||
<p><strong>Aufgabe 20.2 ⭐ — Warum kohärent?</strong> Erklären Sie in eigenen Worten, warum ein Risikomaß subadditiv sein sollte. Was bedeutet es wirtschaftlich, wenn diese Eigenschaft verletzt ist?</p>
|
||||
<p><strong>Aufgabe 20.3 ⭐⭐ — Rockafellar-Uryasev nachvollziehen.</strong> Zeigen Sie für die drei Szenarien mit Verlusten <span class="math inline">(1, 4, 9)</span> und <span class="math inline">\alpha = 2/3</span>: (a) Was ist der empirische CVaR? (b) Werten Sie <span class="math inline">\gamma + \frac{1}{S(1-\alpha)}\sum_s \max(\text{Verlust}_s-\gamma, 0)</span> für <span class="math inline">\gamma \in \{0, 1, 4, 5, 9\}</span> aus. (c) Bei welchem <span class="math inline">\gamma</span> ist der Ausdruck minimal, und stimmt das Minimum mit (a) überein?</p>
|
||||
<p><strong>Aufgabe 20.4 ⭐⭐ — Einheiten prüfen.</strong> Angenommen, ein Modell verrechnet Jahresrendite gegen Tages-CVaR (siehe die Warnung in <a href="#sec:cvar-implementierung-cvar-portfolio-mit-reibung">Abschnitt 20.6</a>). Berechnen Sie: Welchem „effektiven“ täglichen <span class="math inline">\lambda</span> entspräche <code>lambda_risk = 1.5</code> dadurch? Welchen Wert müsste man stattdessen setzen, um dieselbe Wirkung wie <code>RISIKOAVERSION = 1.5</code> im konsistenten Tagesmodell zu erzielen?</p>
|
||||
<p><strong>Aufgabe 20.5 ⭐⭐⭐ — Risikoaversion kalibrieren.</strong> Variieren Sie <code>RISIKOAVERSION</code> von 0 bis 20 und tragen Sie Rendite, Volatilität, CVaR und Turnover gegeneinander auf. (a) Wie sieht die „Effizienzgrenze“ im Rendite-CVaR-Raum aus? (b) Bei welchem Wert entspricht das CVaR-Portfolio ungefähr dem Varianz-Portfolio? (c) Welchen Wert würden Sie einem konservativen Stiftungsfonds empfehlen — und wie begründen Sie ihn ohne Fachjargon?</p>
|
||||
<p><strong>Aufgabe 20.5 ⭐⭐⭐ — Risikoaversion kalibrieren.</strong> Variieren Sie <code>RISIKOAVERSION</code> von 0 bis 20 und tragen Sie Rendite, <a href="anhang-glossar.md#gloss:volatilitaet" class="glossar-link">Volatilität</a>, CVaR und Turnover gegeneinander auf. (a) Wie sieht die „Effizienzgrenze“ im Rendite-CVaR-Raum aus? (b) Bei welchem Wert entspricht das CVaR-Portfolio ungefähr dem Varianz-Portfolio? (c) Welchen Wert würden Sie einem konservativen Stiftungsfonds empfehlen — und wie begründen Sie ihn ohne Fachjargon?</p>
|
||||
<p><strong>Aufgabe 20.6 ⭐⭐⭐ — Turnover-Grenze statt Strafe.</strong> Ersetzen Sie den Kostenterm durch eine <strong>harte Grenze</strong> <span class="math inline">\lVert\mathbf{w}-\mathbf{w}_{\text{alt}}\rVert_1 \le \tau</span> und variieren Sie <span class="math inline">\tau \in \{0{,}05;\ 0{,}1;\ 0{,}25;\ 0{,}5;\ 1{,}0\}</span>. (a) Wie verändert sich die erreichbare Rendite? (b) Was ist der Vorteil einer Grenze gegenüber einer Strafe — und was der Nachteil? (c) Wann würden Sie was einsetzen?</p>
|
||||
<hr />
|
||||
<h2 id="sec:cvar-denkfehler">20.8 Finde den Denkfehler</h2>
|
||||
|
|
@ -766,7 +766,7 @@ CVaR: Portfolio 101.33 vs. Summe 159.24 -> subadditiv (kohaerent)
|
|||
<li><strong>Einheiten konsistent halten.</strong> Tägliche Renditen zu täglichem Risiko; annualisiert wird erst in der Ausgabe.</li>
|
||||
<li><strong>Vektorisieren Sie Szenario-Bedingungen</strong> — das spart bei wiederholten Läufen erheblich Zeit.</li>
|
||||
</ul>
|
||||
<p><strong>Ausblick.</strong> <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a> fügt alles zusammen: Datenpipeline, Signal, Optimierung, Rebalancing und ein Walk-Forward-Backtest ohne Lookahead-Bias.</p>
|
||||
<p><strong>Ausblick.</strong> <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a> fügt alles zusammen: Datenpipeline, Signal, Optimierung, <a href="anhang-glossar.md#gloss:rebalancing" class="glossar-link">Rebalancing</a> und ein <a href="anhang-glossar.md#gloss:walk-forward-backtest" class="glossar-link">Walk-Forward-Backtest</a> ohne <a href="anhang-glossar.md#gloss:lookahead-bias" class="glossar-link">Lookahead-Bias</a>.</p>
|
||||
|
||||
</article>
|
||||
<button type="button" class="fortschritt-knopf" data-kapitel="cvar.html"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg> <span>Als gelesen markieren</span></button>
|
||||
|
|
|
|||
16
OR_HTML_04/dekomposition.html
generated
16
OR_HTML_04/dekomposition.html
generated
|
|
@ -103,7 +103,7 @@
|
|||
<div class="card card-blick">
|
||||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um die andere Antwort auf die Frage aus <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a>: Was tun, wenn der Solver an der Größe scheitert? Statt die Lösung zu approximieren, formuliert man das Modell so um, dass exaktes Lösen wieder möglich wird.</p>
|
||||
<p><strong>Worum geht es?</strong> Um die andere Antwort auf die Frage aus <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a>: Was tun, wenn der <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> an der Größe scheitert? Statt die Lösung zu approximieren, formuliert man das Modell so um, dass exaktes Lösen wieder möglich wird.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="lp.html#sec:lp-dualitaet-und-schattenpreise">Abschnitt 5.6</a> (Dualwerte) und <a href="milp.html#kap-milp">Kapitel 6</a> (<code>Rucksack.py</code>). Beides wird gebraucht, aber nicht neu erklärt.</p>
|
||||
<p><strong>Danach können Sie:</strong> ein Problem in Master und Teilproblem zerlegen; die Spaltengenerierungsschleife selbst schreiben; und begründen, wann sich der Aufwand lohnt — die Antwort hängt an einer einzigen Kennzahl der Instanz.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 3 Stunden.</p>
|
||||
|
|
@ -121,7 +121,7 @@
|
|||
<p>Die naheliegende Frage — <em>„welches Stück kommt auf welche Rolle?“</em> — führt zu 35 Einzelentscheidungen. Die bessere Frage lautet: <em>„Wie oft schneide ich welches Muster?“</em></p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> itertools</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> linprog</span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> [linprog](anhang<span class="op">-</span>glossar.md<span class="co">#gloss:linprog){.glossar-link}</span></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>ROLLE <span class="op">=</span> <span class="dv">1000</span> <span class="co"># mm Mutterrolle</span></span>
|
||||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>breiten, bedarf <span class="op">=</span> [<span class="dv">420</span>, <span class="dv">310</span>, <span class="dv">250</span>], [<span class="dv">9</span>, <span class="dv">12</span>, <span class="dv">14</span>]</span>
|
||||
|
|
@ -151,7 +151,7 @@
|
|||
<p><strong>Und jetzt der Punkt.</strong> Sehen Sie sich an, was da herauskommt: <strong>drei Schnittmuster</strong>. Kein Zuordnungsplan für 35 Stücke, sondern eine Anweisung, die an der Maschine hängen kann — neunmal dieses Muster, zweimal jenes, einmal das dritte.</p>
|
||||
<p>Das ist kein kosmetischer Unterschied. Das Modell hat <strong>eine Variable je Muster</strong> statt einer je Stück-und-Rolle, und es kennt gar keine einzelnen Rollen mehr. Damit verschwindet ein Problem, das das naheliegende Modell praktisch unlösbar macht — dazu gleich mehr.</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Die schwierigste Arbeit an einem Optimierungsmodell ist selten die Zielfunktion. Es ist die Frage, <strong>worüber</strong> die Variablen laufen.</p>
|
||||
<p><strong>🎯 Merksatz</strong> Die schwierigste Arbeit an einem Optimierungsmodell ist selten die <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a>. Es ist die Frage, <strong>worüber</strong> die Variablen laufen.</p>
|
||||
</blockquote>
|
||||
<p><strong>Warum funktioniert das?</strong> Weil hier alle 16 möglichen Muster aufzählbar waren. Bei drei Breiten und einer 1 000-mm-Rolle sind es 16; bei dreizehn Breiten und 5 600 mm sind es zehntausende, und bei einer echten Papierfabrik mehr, als sich speichern lässt. Das ganze Kapitel handelt davon, wie man mit Mustern rechnet, ohne sie aufzuschreiben.</p>
|
||||
<hr />
|
||||
|
|
@ -160,7 +160,7 @@
|
|||
<ol type="1">
|
||||
<li>… erklären, warum das naheliegende Zuordnungsmodell an <strong>Symmetrie</strong> scheitert.</li>
|
||||
<li>… ein Problem in <strong>Master</strong> und <strong>Pricing-Teilproblem</strong> zerlegen.</li>
|
||||
<li>… die Schleife schreiben: Master-LP lösen, Dualwerte auslesen, Teilproblem lösen, Spalte hinzufügen.</li>
|
||||
<li>… die Schleife schreiben: Master-<a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a> lösen, Dualwerte auslesen, Teilproblem lösen, Spalte hinzufügen.</li>
|
||||
<li>… das Abbruchkriterium über die <strong>reduzierten Kosten</strong> begründen.</li>
|
||||
<li>… an einer Kennzahl der Instanz abschätzen, ob sich das Verfahren lohnt.</li>
|
||||
</ol>
|
||||
|
|
@ -169,7 +169,7 @@
|
|||
<p>Der erste Entwurf eines Zuschnittmodells sieht fast immer so aus: eine Binärvariable <span class="math inline">z_{jr}</span> für „Stück <span class="math inline">j</span> liegt auf Rolle <span class="math inline">r</span>“, dazu <span class="math inline">y_r</span> für „Rolle <span class="math inline">r</span> wird benutzt”.</p>
|
||||
<p>Zwei Dinge gehen dabei schief.</p>
|
||||
<p><strong>Die Größe.</strong> Bei 219 Zuschnitten und höchstens 82 Rollen sind das knapp 18 000 Binärvariablen — unangenehm, aber allein noch kein Hindernis.</p>
|
||||
<p><strong>Die Symmetrie.</strong> Das ist das eigentliche Problem. Alle Mutterrollen sind <strong>gleich</strong>. 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 und arbeitet sie einzeln ab.</p>
|
||||
<p><strong>Die Symmetrie.</strong> Das ist das eigentliche Problem. Alle Mutterrollen sind <strong>gleich</strong>. Jede Lösung existiert deshalb in unzähligen Umbenennungen: Vertauscht man Rolle 3 und Rolle 47, entsteht eine formal andere, inhaltlich identische Lösung. <a href="anhang-glossar.md#gloss:branch-and-bound" class="glossar-link">Branch-and-Bound</a> weiß das nicht und arbeitet sie einzeln ab.</p>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Woran man ein Symmetrieproblem erkennt</strong></p>
|
||||
<p>Der Suchbaum wächst, aber die <strong>Schranke bewegt sich nicht.</strong> Im Protokoll aus <a href="milp.html#sec:milp-gap">Abschnitt 6.8</a> 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.</p>
|
||||
|
|
@ -229,7 +229,7 @@
|
|||
<blockquote>
|
||||
<p>Fange mit wenigen Mustern an. Frage nach jeder Lösung, ob es ein <strong>noch nicht bekanntes</strong> Muster gibt, das sich lohnen würde — und wenn ja, nimm nur dieses eine dazu.</p>
|
||||
</blockquote>
|
||||
<p>Die Frage „lohnt sich noch ein Muster?” beantworten die <strong>Dualwerte</strong> des Master-LPs. Der Dualwert <span class="math inline">\pi_i</span> zur Bedarfszeile <span class="math inline">i</span> ist genau der Schattenpreis aus <a href="lp.html#sec:lp-dualitaet-und-schattenpreise">Abschnitt 5.6</a>: Er sagt, wie viele Rollen ein zusätzliches Stück der Breite <span class="math inline">i</span> kostet.</p>
|
||||
<p>Die Frage „lohnt sich noch ein Muster?” beantworten die <strong>Dualwerte</strong> des Master-LPs. Der Dualwert <span class="math inline">\pi_i</span> zur Bedarfszeile <span class="math inline">i</span> ist genau der <a href="anhang-glossar.md#gloss:schattenpreis" class="glossar-link">Schattenpreis</a> aus <a href="lp.html#sec:lp-dualitaet-und-schattenpreise">Abschnitt 5.6</a>: Er sagt, wie viele Rollen ein zusätzliches Stück der Breite <span class="math inline">i</span> kostet.</p>
|
||||
<figure>
|
||||
<img src="bilder_04/kap_dekomposition_regelkreis.svg" alt="Abb. 10.1: Der Kreislauf zwischen Master-LP und Pricing-Problem. Erzeugt von bilder_04/erzeuge_spaltengenerierung_flow.py." />
|
||||
<figcaption aria-hidden="true">Abb. 10.1: Der Kreislauf zwischen Master-LP und Pricing-Problem. Erzeugt von <code>bilder_04/erzeuge_spaltengenerierung_flow.py</code>.</figcaption>
|
||||
|
|
@ -277,7 +277,7 @@
|
|||
<p>Die letzte Zeile ist der Grund, warum das Verfahren <strong>exakt</strong> ist und nicht heuristisch: Wenn kein Muster mehr lohnende reduzierte Kosten hat, ist die LP-Lösung über <em>allen</em> Mustern optimal — auch über den nie erzeugten.</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
<p><strong>Und wie findet man das beste neue Muster?</strong> Man sucht die Zusammenstellung von Stücken mit dem größten Gesamtwert, die noch in die Rolle passt. Das ist ein <strong>Rucksackproblem</strong>:</p>
|
||||
<p><strong>Und wie findet man das beste neue Muster?</strong> Man sucht die Zusammenstellung von Stücken mit dem größten Gesamtwert, die noch in die Rolle passt. Das ist ein <strong><a href="anhang-glossar.md#gloss:rucksackproblem" class="glossar-link">Rucksackproblem</a></strong>:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
|
|
@ -811,7 +811,7 @@ Mutterrolle 5,600 mm, 13 bestellte Breiten, 219 Zuschnitte.
|
|||
<hr />
|
||||
<h2 id="sec:dekomposition-selbsttest">10.10 Selbsttest</h2>
|
||||
<ol type="1">
|
||||
<li>Erklären Sie Symmetrie in einem MILP an einem Beispiel aus Ihrem Arbeitsumfeld.</li>
|
||||
<li>Erklären Sie Symmetrie in einem <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> an einem Beispiel aus Ihrem Arbeitsumfeld.</li>
|
||||
<li>Was ist beim Zuschnitt eine „Spalte”, und was steht darin?</li>
|
||||
<li>Woher kommen die Preise, mit denen das Teilproblem rechnet?</li>
|
||||
<li>Warum ist das Verfahren exakt, obwohl es fast alle Muster nie ansieht?</li>
|
||||
|
|
|
|||
20
OR_HTML_04/dynamische-programmierung.html
generated
20
OR_HTML_04/dynamische-programmierung.html
generated
|
|
@ -103,9 +103,9 @@
|
|||
<div class="card card-blick">
|
||||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um Entscheidungsketten: Was heute klug ist, hängt davon ab, was morgen noch möglich sein wird. Die Bellman-Gleichung löst solche Probleme durch Rückwärtsrechnen.</p>
|
||||
<p><strong>Worum geht es?</strong> Um Entscheidungsketten: Was heute klug ist, hängt davon ab, was morgen noch möglich sein wird. Die <a href="anhang-glossar.md#gloss:bellman-gleichung" class="glossar-link">Bellman-Gleichung</a> löst solche Probleme durch Rückwärtsrechnen.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a> (Erwartungswerte). Rekursion in Python.</p>
|
||||
<p><strong>Danach können Sie:</strong> Ein mehrperiodiges Problem in Zustände und Stufen zerlegen, die Wertfunktion durch Rückwärtsinduktion berechnen, die optimale Strategie ableiten — und prüfen, ob Ihr Zustand vollständig genug ist.</p>
|
||||
<p><strong>Danach können Sie:</strong> Ein mehrperiodiges Problem in Zustände und Stufen zerlegen, die Wertfunktion durch <a href="anhang-glossar.md#gloss:rueckwaertsinduktion" class="glossar-link">Rückwärtsinduktion</a> berechnen, die optimale Strategie ableiten — und prüfen, ob Ihr Zustand vollständig genug ist.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 5 Stunden.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>Bellman_Minimalbeispiel.py</code><br />
|
||||
|
|
@ -225,7 +225,7 @@ Restkosten je Ort: {'Ziel': 0, 'Ost': 5, 'West': 8, '
|
|||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Eine Entscheidung ist nie für sich zu bewerten, sondern nur <strong>zusammen mit allem, was danach kommt</strong>. Genau das leistet die Wertfunktion: Sie fasst die gesamte Zukunft eines Zustands in einer einzigen Zahl zusammen. Und weil man die Zukunft kennen muss, bevor man die Gegenwart bewerten kann, rechnet dynamische Programmierung <strong>rückwärts</strong>.</p>
|
||||
</blockquote>
|
||||
<p><strong>Warum funktioniert das?</strong> 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 <strong>Bellmansches Optimalitätsprinzip</strong> 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.</p>
|
||||
<p><strong>Warum funktioniert das?</strong> 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 <strong>Bellmansches <a href="anhang-glossar.md#gloss:optimalitaetsprinzip" class="glossar-link">Optimalitätsprinzip</a></strong> 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.</p>
|
||||
<hr />
|
||||
<h2 id="sec:dynamische-programmierung-lernziele">13.2 Lernziele</h2>
|
||||
<p>Nach diesem Kapitel können Sie …</p>
|
||||
|
|
@ -234,9 +234,9 @@ Restkosten je Ort: {'Ziel': 0, 'Ost': 5, 'West': 8, '
|
|||
<li>… Zustand, Stufe, Aktion und Wertfunktion für ein gegebenes Problem benennen.</li>
|
||||
<li>… eine Rückwärtsinduktion von Hand für ein kleines Problem durchführen.</li>
|
||||
<li>… das Almgren-Chriss-Ausführungsproblem lösen und die Lösung interpretieren.</li>
|
||||
<li>… einschätzen, wann DP funktioniert und wann der „Fluch der Dimensionalität“ zuschlägt.</li>
|
||||
<li>… einschätzen, wann <a href="anhang-glossar.md#gloss:dynamische-programmierung-dp" class="glossar-link">DP</a> funktioniert und wann der „<a href="anhang-glossar.md#gloss:fluch-der-dimensionalitaet" class="glossar-link">Fluch der Dimensionalität</a>“ zuschlägt.</li>
|
||||
<li>… die Wertfunktion als <strong>Nachschlagetabelle</strong> lesen: Sie liefert keine Planfolge, sondern eine Regel, die auch bei Abweichungen gilt.</li>
|
||||
<li>… einen Zustandsraum auf Vollständigkeit prüfen und erkennen, wann eine Kostenart Vorgeschichte erfordert.</li>
|
||||
<li>… einen <a href="anhang-glossar.md#gloss:zustandsraum" class="glossar-link">Zustandsraum</a> auf Vollständigkeit prüfen und erkennen, wann eine Kostenart Vorgeschichte erfordert.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
<h2 id="sec:dynamische-programmierung-das-bellmansche-optimalitaetsprinzip">13.3 Das Bellmansche Optimalitätsprinzip</h2>
|
||||
|
|
@ -553,7 +553,7 @@ V_t(S_t) = \min_{a_t\in\mathcal{A}(S_t)}\Big\{\,C(S_t,a_t) \;+\; \gamma\cdot\mat
|
|||
C(n_t, X_t) = \underbrace{\eta\,n_t^2}_{\text{Marktauswirkung}} \;+\; \underbrace{\lambda\,\sigma^2 X_t^2}_{\text{Risiko des Restbestands}}
|
||||
</span></p>
|
||||
<blockquote>
|
||||
<p><strong>📐 Formel-Lesehilfe</strong> * <span class="math inline">n_t</span> — in Periode <span class="math inline">t</span> verkaufte Stückzahl. Quadriert, weil doppelte Menge mehr als doppelten Preisdruck erzeugt. * <span class="math inline">\eta</span> („eta“) — Slippage-Koeffizient. Wie stark reagiert der Markt auf Volumen? * <span class="math inline">X_t</span> — Restbestand <strong>nach</strong> dem Verkauf. Quadriert, weil Varianz quadratisch mit der Positionsgröße wächst. * <span class="math inline">\lambda</span> — Risikoaversion: Wie sehr stört mich Schwankung im Vergleich zu Slippage? * <span class="math inline">\sigma</span> — Volatilität je Periode.</p>
|
||||
<p><strong>📐 Formel-Lesehilfe</strong> * <span class="math inline">n_t</span> — in Periode <span class="math inline">t</span> verkaufte Stückzahl. Quadriert, weil doppelte Menge mehr als doppelten Preisdruck erzeugt. * <span class="math inline">\eta</span> („eta“) — Slippage-Koeffizient. Wie stark reagiert der Markt auf Volumen? * <span class="math inline">X_t</span> — Restbestand <strong>nach</strong> dem Verkauf. Quadriert, weil Varianz quadratisch mit der Positionsgröße wächst. * <span class="math inline">\lambda</span> — Risikoaversion: Wie sehr stört mich Schwankung im Vergleich zu Slippage? * <span class="math inline">\sigma</span> — <a href="anhang-glossar.md#gloss:volatilitaet" class="glossar-link">Volatilität</a> je Periode.</p>
|
||||
<p><strong>Ohne Formel gesagt:</strong> „Schnell verkaufen kostet Preisabschlag. Langsam verkaufen kostet Nervenkitzel. Finde die Mitte.“</p>
|
||||
<p><strong>Die zwei Extremfälle:</strong> * <span class="math inline">\lambda \to 0</span> (risikoneutral): gleichmäßiges Aufteilen auf alle Perioden minimiert <span class="math inline">\sum n_t^2</span> bei fester Summe. * <span class="math inline">\lambda \to \infty</span> (extrem risikoscheu): sofort alles verkaufen, um kein Risiko zu tragen.</p>
|
||||
</blockquote>
|
||||
|
|
@ -561,7 +561,7 @@ C(n_t, X_t) = \underbrace{\eta\,n_t^2}_{\text{Marktauswirkung}} \;+\; \underbrac
|
|||
<p><strong>⚠️ Zur Kalibrierung des Risikoparameters</strong></p>
|
||||
<p>Ein häufiger Fehler ist ein undokumentierter Skalierungsfaktor im Risikoterm, etwa:</p>
|
||||
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>holding_risk <span class="op">=</span> risk_aversion <span class="op">*</span> (sigma_period <span class="op">**</span> <span class="dv">2</span>) <span class="op">*</span> (remaining <span class="op">**</span> <span class="dv">2</span>) <span class="op">*</span> <span class="fl">1e5</span></span></code></pre></div>
|
||||
<p>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 <code>risk_aversion = 1e-6</code> würde dann in Wahrheit <span class="math inline">0{,}1</span> bedeuten. Solche „magischen Zahlen“ machen ein Modell unkalibrierbar: Niemand kann sagen, ob 1e-6 viel oder wenig ist.</p>
|
||||
<p>Woher eine solche Zahl kommt, bleibt dann unklar. Faktisch wirkt sie als versteckte Erhöhung der Risikoaversion um fünf Größenordnungen — ein <a href="anhang-glossar.md#gloss:parameter" class="glossar-link">Parameter</a> wie <code>risk_aversion = 1e-6</code> würde dann in Wahrheit <span class="math inline">0{,}1</span> bedeuten. Solche „magischen Zahlen“ machen ein Modell unkalibrierbar: Niemand kann sagen, ob 1e-6 viel oder wenig ist.</p>
|
||||
<p><strong>Der Parameter lässt sich stattdessen herleiten.</strong> Beide Kostenterme werden in <strong>Euro</strong> gerechnet: * Marktauswirkung: <span class="math inline">\eta \cdot n_t^2</span> mit <span class="math inline">\eta</span> in €/Stück². * Risiko: <span class="math inline">\tfrac{\lambda}{2}\cdot \sigma_{\text{Periode}}^2 \cdot P_0^2 \cdot X_t^2</span> — die Varianz des Werts der offenen Position, multipliziert mit der Risikoaversion.</p>
|
||||
<p>Durch die Multiplikation mit <span class="math inline">P_0^2</span> (dem Quadrat des Aktienkurses) stimmen die Einheiten, und <span class="math inline">\lambda</span> wird interpretierbar: Es ist der Preis, den man je Einheit Wertvarianz zu zahlen bereit ist.</p>
|
||||
</blockquote>
|
||||
|
|
@ -819,7 +819,7 @@ Abweichung DP zur analytischen Loesung: 5.788 % (Diskretisierung: 1000 Stueck)
|
|||
1e-03 | 97,000 ( 97.0 %) | fast alles sofort
|
||||
====================================================================================</code></pre>
|
||||
<p><strong>Die Lösung ist <em>front-loaded</em>:</strong> 41 % im ersten Schritt, dann fallend (25 %, 16 %, 10 %, 8 %). Das ist die typische Form — man baut Risiko früh ab, aber nicht abrupt. Die Sensitivitätstabelle zeigt, wie <span class="math inline">\lambda</span> zwischen den beiden Extremen steuert: Bei <span class="math inline">\lambda = 10^{-7}</span> verkauft das Modell gleichmäßig (Risiko ist egal), bei <span class="math inline">\lambda = 10^{-3}</span> praktisch alles sofort (Risiko dominiert).</p>
|
||||
<p>Der Vergleich beziffert den Nutzen: Gegenüber der naiven TWAP-Strategie (gleiche Tranchen) spart die optimierte Ausführung <strong>2 976 €</strong> oder 6 Basispunkte — bei einer Position von 5 Mio. €. Gegenüber „alles sofort“ sind es 14 734 €.</p>
|
||||
<p>Der Vergleich beziffert den Nutzen: Gegenüber der naiven <a href="anhang-glossar.md#gloss:twap" class="glossar-link">TWAP</a>-Strategie (gleiche Tranchen) spart die optimierte Ausführung <strong>2 976 €</strong> oder 6 Basispunkte — bei einer Position von 5 Mio. €. Gegenüber „alles sofort“ sind es 14 734 €.</p>
|
||||
<blockquote>
|
||||
<p><strong>💻 Code-Durchgang: die analytische Gegenprobe und was ihre Abweichung bedeutet</strong></p>
|
||||
<p>Das Almgren-Chriss-Problem hat eine <strong>geschlossene Lösung</strong>: <span class="math display">X_t = X_0\,\frac{\sinh(\kappa(T-t))}{\sinh(\kappa T)}, \qquad \kappa = \operatorname{arcosh}\!\Big(\tfrac{\tilde\kappa^2}{2}+1\Big),\qquad \tilde\kappa^2 = \frac{\lambda\,\sigma^2 P_0^2}{\eta}</span></p>
|
||||
|
|
@ -876,7 +876,7 @@ Abweichung DP zur analytischen Loesung: 5.788 % (Diskretisierung: 1000 Stueck)
|
|||
</tbody>
|
||||
</table>
|
||||
<p><strong>Das ist der Fluch der Dimensionalität</strong> (Bellmans eigener Begriff): Jede zusätzliche Zustandsvariable <strong>multipliziert</strong> den Aufwand.</p>
|
||||
<p><strong>Gegenmittel:</strong> * <strong>Zustandsraum</strong> <strong>verkleinern:</strong> gröber diskretisieren, irrelevante Variablen weglassen. * <strong>Approximate Dynamic Programming</strong><strong>:</strong> <span class="math inline">V_t</span> durch eine parametrische Funktion annähern statt tabellarisch zu speichern. * <strong>Reinforcement Learning</strong><strong>:</strong> dieselbe Bellman-Gleichung, aber <span class="math inline">V</span> wird aus Erfahrung gelernt (Q-Learning) statt vollständig berechnet. * <strong>Nach geschlossenen Lösungen suchen</strong> — wie bei Almgren-Chriss. Wo eine Formel existiert, ist sie unschlagbar.</p>
|
||||
<p><strong>Gegenmittel:</strong> * <strong>Zustandsraum</strong> <strong>verkleinern:</strong> gröber diskretisieren, irrelevante Variablen weglassen. * <strong><a href="anhang-glossar.md#gloss:approximate-dynamic-programming" class="glossar-link">Approximate Dynamic Programming</a></strong><strong>:</strong> <span class="math inline">V_t</span> durch eine parametrische Funktion annähern statt tabellarisch zu speichern. * <strong><a href="anhang-glossar.md#gloss:reinforcement-learning" class="glossar-link">Reinforcement Learning</a></strong><strong>:</strong> dieselbe Bellman-Gleichung, aber <span class="math inline">V</span> wird aus Erfahrung gelernt (<a href="anhang-glossar.md#gloss:q-learning" class="glossar-link">Q-Learning</a>) statt vollständig berechnet. * <strong>Nach geschlossenen Lösungen suchen</strong> — wie bei Almgren-Chriss. Wo eine Formel existiert, ist sie unschlagbar.</p>
|
||||
<hr />
|
||||
<h2 id="sec:dynamische-programmierung-uebungsaufgaben">13.6 Übungsaufgaben</h2>
|
||||
<blockquote>
|
||||
|
|
@ -885,7 +885,7 @@ Abweichung DP zur analytischen Loesung: 5.788 % (Diskretisierung: 1000 Stueck)
|
|||
<p><strong>Aufgabe 13.1 ⭐ — Bausteine benennen.</strong> Ein Wanderer plant eine 5-Tages-Tour und muss täglich entscheiden, wie weit er läuft. Bestimmen Sie Stufe, Zustand, Aktion und Wertfunktion. Was gehört <strong>nicht</strong> in den Zustand?</p>
|
||||
<p><strong>Aufgabe 13.2 ⭐ — Optimalitätsprinzip anwenden.</strong> Warum folgt aus dem Optimalitätsprinzip, dass man rückwärts rechnen darf? Was würde schiefgehen, wenn die Kosten einer Periode auch von <strong>früheren</strong> Aktionen abhängen (und nicht nur vom aktuellen Zustand)?</p>
|
||||
<p><strong>Aufgabe 13.3 ⭐⭐ — Rückwärtsinduktion von Hand.</strong> 5 Einheiten in 3 Perioden, Kosten <span class="math inline">C(n) = n^2 + 2n</span>. Erstellen Sie die vollständige Wertfunktionstabelle und bestimmen Sie den optimalen Pfad. Prüfen Sie mit <code>Bellman_Minimalbeispiel.py</code> (angepasst).</p>
|
||||
<p><strong>Aufgabe 13.4 ⭐⭐ — Rucksackproblem als DP.</strong> Lösen Sie das Rucksackproblem aus <a href="milp.html#kap-milp">Kapitel 6</a> mit dynamischer Programmierung statt MILP. (Zustand: verbleibende Kapazität; Stufe: betrachteter Gegenstand.) Vergleichen Sie Laufzeit und Ergebnis mit dem MILP-Solver.</p>
|
||||
<p><strong>Aufgabe 13.4 ⭐⭐ — <a href="anhang-glossar.md#gloss:rucksackproblem" class="glossar-link">Rucksackproblem</a> als DP.</strong> Lösen Sie das Rucksackproblem aus <a href="milp.html#kap-milp">Kapitel 6</a> mit dynamischer Programmierung statt <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a>. (Zustand: verbleibende Kapazität; Stufe: betrachteter Gegenstand.) Vergleichen Sie Laufzeit und Ergebnis mit dem MILP-<a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a>.</p>
|
||||
<p><strong>Aufgabe 13.5 ⭐⭐⭐ — Risikoaversion kalibrieren.</strong> Untersuchen Sie mit <code>Mehrperiodige_Order_Execution.py</code>: (a) Bei welchem <span class="math inline">\lambda</span> verkauft das Modell in der ersten Periode mehr als 50 %? (b) Stellen Sie den Zusammenhang zwischen <span class="math inline">\lambda</span> und den erwarteten Gesamtkosten dar. (c) Ein Händler sagt: „Ich will höchstens 20 % Marktauswirkungskosten und den Rest an Risiko.“ Welches <span class="math inline">\lambda</span> setzen Sie?</p>
|
||||
<p><strong>Aufgabe 13.6 ⭐⭐⭐ — Zustandsraum erweitern.</strong> Erweitern Sie das Ausführungsmodell um einen zweiten Zustand: die aktuelle <strong>Orderbuchtiefe</strong> (3 Stufen: dünn/normal/tief), die mit gegebenen Übergangswahrscheinlichkeiten wechselt und <span class="math inline">\eta</span> um Faktor 2 / 1 / 0,5 skaliert. Wie ändert sich die Strategie? Wie stark wächst die Rechenzeit?</p>
|
||||
<hr />
|
||||
|
|
|
|||
32
OR_HTML_04/einfuehrung.html
generated
32
OR_HTML_04/einfuehrung.html
generated
|
|
@ -107,7 +107,7 @@
|
|||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Was Operations Research ist, warum Ausprobieren ab einer gewissen Problemgröße hoffnungslos wird, und aus welchen vier Bausteinen <em>jedes</em> Optimierungsmodell besteht. Los geht es mit einem Problem, das Sie in fünf Minuten selbst lösen.</p>
|
||||
<p><strong>Voraussetzungen:</strong> Keine. Dies ist der Einstieg.</p>
|
||||
<p><strong>Danach können Sie:</strong> 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.</p>
|
||||
<p><strong>Danach können Sie:</strong> Ein Alltagsproblem in Entscheidungsvariablen, <a href="anhang-glossar.md#gloss:parameter" class="glossar-link">Parameter</a>, <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a> und Nebenbedingungen zerlegen, ein erstes Modell mit Google <a href="anhang-glossar.md#gloss:or-tools" class="glossar-link">OR-Tools</a> lösen — und die Daten dafür aus einer Excel-Mappe holen und das Ergebnis dorthin zurückschreiben.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 3,5 Stunden inklusive Übungen.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>Bot_Allokation.py</code><br />
|
||||
|
|
@ -153,7 +153,7 @@
|
|||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>produkt <span class="op">=</span> {<span class="st">"Tisch"</span>: (<span class="dv">240</span>, <span class="fl">3.0</span>, <span class="fl">6.0</span>), <span class="st">"Stuhl"</span>: (<span class="dv">60</span>, <span class="fl">1.0</span>, <span class="fl">1.0</span>)} <span class="co"># DB, Stunden, m²</span></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>vorrat <span class="op">=</span> {<span class="st">"Montagestunden"</span>: <span class="dv">150</span>, <span class="st">"Plattenmaterial"</span>: <span class="dv">240</span>}</span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>s <span class="op">=</span> pywraplp.Solver.CreateSolver(<span class="st">"GLOP"</span>)</span>
|
||||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>s <span class="op">=</span> pywraplp.[Solver](anhang<span class="op">-</span>glossar.md<span class="co">#gloss:solver){.glossar-link}.CreateSolver("[GLOP](anhang-glossar.md#gloss:glop){.glossar-link}")</span></span>
|
||||
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>x <span class="op">=</span> {p: s.NumVar(<span class="dv">0</span>, s.infinity(), p) <span class="cf">for</span> p <span class="kw">in</span> produkt}</span>
|
||||
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>s.Add(<span class="bu">sum</span>(x[p] <span class="op">*</span> produkt[p][<span class="dv">1</span>] <span class="cf">for</span> p <span class="kw">in</span> produkt) <span class="op"><=</span> vorrat[<span class="st">"Montagestunden"</span>])</span>
|
||||
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>s.Add(<span class="bu">sum</span>(x[p] <span class="op">*</span> produkt[p][<span class="dv">2</span>] <span class="cf">for</span> p <span class="kw">in</span> produkt) <span class="op"><=</span> vorrat[<span class="st">"Plattenmaterial"</span>])</span>
|
||||
|
|
@ -222,7 +222,7 @@ Deckungsbeitrag: 10800 EUR</code></pre>
|
|||
<li>Eine Klinik muss 200 Pflegekräfte einteilen — unter Berücksichtigung von 15 gesetzlichen Arbeitszeitregeln, Urlaubsanträgen, Qualifikationsstufen und Notfallreserven.</li>
|
||||
<li>Ein Fondsmanager muss 10 Millionen Euro so auf 50 Aktien aufteilen, dass bei einer erwarteten Mindestrendite von 8 % das Verlustrisiko im schlechtesten Marktszenario minimal bleibt.</li>
|
||||
</ul>
|
||||
<p>Ein naiver Ansatz — <em>Brute Force</em>, das vollständige Durchrechnen aller Möglichkeiten — würde selbst auf den schnellsten Supercomputern der Welt Milliarden Jahre dauern.</p>
|
||||
<p>Ein naiver Ansatz — <em><a href="anhang-glossar.md#gloss:brute-force" class="glossar-link">Brute Force</a></em>, das vollständige Durchrechnen aller Möglichkeiten — würde selbst auf den schnellsten Supercomputern der Welt Milliarden Jahre dauern.</p>
|
||||
<blockquote>
|
||||
<p><strong>📖 Definition: Operations Research</strong></p>
|
||||
<p><strong>Operations Research (OR)</strong>, deutsch etwa <em>Unternehmensforschung</em> oder <em>mathematische Entscheidungsoptimierung</em>, ist die wissenschaftliche Disziplin, reale Entscheidungsprobleme in formale mathematische Modelle zu überführen und mithilfe exakter oder heuristischer Algorithmen (<em>Solver</em>) die beweisbar beste (<strong>optimale</strong>) oder eine messbar hochwertige Lösung zu finden.</p>
|
||||
|
|
@ -333,7 +333,7 @@ Deckungsbeitrag: 10800 EUR</code></pre>
|
|||
</figure>
|
||||
<p><strong>Was Sie in der Abbildung sehen.</strong> Der markierte Streifen zwischen <span class="math inline">n = 15</span> und <span class="math inline">n = 20</span> ist der eigentliche Befund: Dort wird aus einer Kaffeepause ein Menschenleben. Wer eine Maschine kauft, die tausendmal schneller rechnet, verschiebt diese Wand um genau zwei Aufträge.</p>
|
||||
<p>Und die Rechnung ist noch geschönt: Ein schnellerer Rechner hilft praktisch nicht. Selbst eine Beschleunigung um den Faktor <strong>eine Million</strong> verschiebt die Grenze von <span class="math inline">n=20</span> nur auf etwa <span class="math inline">n=24</span>. Gegen kombinatorisches Wachstum ist Hardware machtlos.</p>
|
||||
<p>Das folgende Programm macht diesen Effekt erfahrbar. Es löst dasselbe Zuordnungsproblem zweimal — einmal durch vollständiges Durchprobieren, einmal mit einem OR-Solver — und vergleicht die Laufzeiten.</p>
|
||||
<p>Das folgende Programm macht diesen Effekt erfahrbar. Es löst dasselbe <a href="anhang-glossar.md#gloss:zuordnungsproblem" class="glossar-link">Zuordnungsproblem</a> zweimal — einmal durch vollständiges Durchprobieren, einmal mit einem OR-Solver — und vergleicht die Laufzeiten.</p>
|
||||
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Brute_Force_Vergleich.py</span></span>
|
||||
|
|
@ -514,10 +514,10 @@ Der Solver löst dieselbe Instanz in Sekundenbruchteilen.
|
|||
<hr />
|
||||
<h2 id="sec:einfuehrung-historischer-kontext-und-evolution">1.5 Historischer Kontext und Evolution</h2>
|
||||
<p>Der Begriff entstand im Vorfeld des Zweiten Weltkriegs in Großbritannien. Militärische Führungsstäbe standen vor neuartigen logistischen und strategischen Fragen: Wie platziert man die neu entwickelten Radaranlagen an der Küste optimal? Wie groß müssen Schiffskonvois sein, um U-Boot-Angriffe bei minimalem Geleitschutzaufwand abzuwehren?</p>
|
||||
<p>Wissenschaftler wie <strong>George Dantzig</strong>, <strong>Patrick Blackett</strong> und <strong>John von Neumann</strong> entwickelten daraufhin mathematische Formalismen. 1947 erfand George Dantzig den <strong>Simplex-Algorithmus</strong> zur Lösung linearer Programme — ein Durchbruch, der die industrielle Planung in den 1950er-Jahren revolutionierte und den wir in <a href="lp.html#kap-lp">Kapitel 5</a> selbst programmieren werden.</p>
|
||||
<p>Wissenschaftler wie <strong>George Dantzig</strong>, <strong>Patrick Blackett</strong> und <strong>John von Neumann</strong> entwickelten daraufhin mathematische Formalismen. 1947 erfand George Dantzig den <strong><a href="anhang-glossar.md#gloss:simplex-algorithmus" class="glossar-link">Simplex-Algorithmus</a></strong> zur Lösung linearer Programme — ein Durchbruch, der die industrielle Planung in den 1950er-Jahren revolutionierte und den wir in <a href="lp.html#kap-lp">Kapitel 5</a> selbst programmieren werden.</p>
|
||||
<p>Heute treibt OR die Kernsysteme moderner Industrien an:</p>
|
||||
<ul>
|
||||
<li><strong>Tech-Konzerne:</strong> Server-Scheduling, Datenrouting in Glasfasernetzen, Werbeplatzierungsauktionen.</li>
|
||||
<li><strong>Tech-Konzerne:</strong> Server-<a href="anhang-glossar.md#gloss:scheduling" class="glossar-link">Scheduling</a>, Datenrouting in Glasfasernetzen, Werbeplatzierungsauktionen.</li>
|
||||
<li><strong>Luftfahrt & Logistik:</strong> Crew-Scheduling, Flugzeugumlaufplanung, Paketlogistik (etwa das System <em>ORION</em> von UPS, das durch Routenoptimierung jährlich zweistellige Millionenbeträge an Treibstoff einspart).</li>
|
||||
<li><strong>Energie:</strong> Kraftwerkseinsatzplanung, Netzausbau, Speicherbewirtschaftung.</li>
|
||||
<li><strong>Gesundheitswesen:</strong> OP-Saal-Belegung, Dienstpläne, Rettungsmittel-Standorte.</li>
|
||||
|
|
@ -552,13 +552,13 @@ Der Solver löst dieselbe Instanz in Sekundenbruchteilen.
|
|||
<td>Kontinuierlich</td>
|
||||
<td><span class="math inline">x \in \mathbb{R}</span></td>
|
||||
<td>Investitionsbetrag in Euro, Fördermenge in Litern</td>
|
||||
<td>LP — leicht</td>
|
||||
<td><a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a> — leicht</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>Ganzzahlig</td>
|
||||
<td><span class="math inline">x \in \mathbb{Z}</span></td>
|
||||
<td>Anzahl produzierter Maschinen, Anzahl Mitarbeiter</td>
|
||||
<td>MILP — schwer</td>
|
||||
<td><a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> — schwer</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Binär</td>
|
||||
|
|
@ -574,7 +574,7 @@ Der Solver löst dieselbe Instanz in Sekundenbruchteilen.
|
|||
<h3 id="baustein-2-parameter-eingabedaten-c-a-b">Baustein 2 — Parameter / Eingabedaten (<span class="math inline">c, A, b</span>)</h3>
|
||||
<p>Die <strong>unveränderlichen Fakten</strong> der Realität: historische Renditen, Maschinenstundensätze, Lagerkapazitäten, Steuerquoten, Entfernungen, Qualifikationen.</p>
|
||||
<blockquote>
|
||||
<p><strong>Die Leitfrage:</strong> <em>Was ist gegeben und wird nicht entschieden?</em> Parameter sind der Ort, an dem Datenqualität über Modellqualität entscheidet. <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> zeigt am Beispiel der Kovarianzmatrix, wie ein schlecht geschätzter Parameter ein mathematisch perfektes Modell wertlos macht.</p>
|
||||
<p><strong>Die Leitfrage:</strong> <em>Was ist gegeben und wird nicht entschieden?</em> Parameter sind der Ort, an dem Datenqualität über Modellqualität entscheidet. <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> zeigt am Beispiel der <a href="anhang-glossar.md#gloss:kovarianzmatrix" class="glossar-link">Kovarianzmatrix</a>, wie ein schlecht geschätzter Parameter ein mathematisch perfektes Modell wertlos macht.</p>
|
||||
</blockquote>
|
||||
<h3 id="baustein-3-zielfunktion-fx">Baustein 3 — Zielfunktion (<span class="math inline">f(x)</span>)</h3>
|
||||
<p>Ein mathematischer Ausdruck, der die <strong>Güte</strong> einer Lösung zu <strong>einer einzigen Zahl</strong> verdichtet:</p>
|
||||
|
|
@ -599,7 +599,7 @@ Der Solver löst dieselbe Instanz in Sekundenbruchteilen.
|
|||
g_i(\mathbf{x}) \le b_i \qquad \text{bzw.} \qquad h_j(\mathbf{x}) = 0
|
||||
</span></p>
|
||||
<p><strong>Harte Nebenbedingungen (<em>hard constraints</em>)</strong> sind zwingend: gesetzliche Ruhezeit <span class="math inline">\ge 11</span> Stunden, Summe der Portfoliogewichte <span class="math inline">= 100\,\%</span>, maximales Verlustrisiko <span class="math inline">\le 5\,\%</span>. Wird eine einzige harte Bedingung verletzt, ist die Lösung mathematisch <strong>unzulässig</strong> (<em>infeasible</em>) — sie existiert für den Solver schlicht nicht.</p>
|
||||
<p><strong>Weiche Nebenbedingungen (<em>soft constraints</em>)</strong> sind Wünsche: Mitarbeiterpräferenzen, möglichst wenig Umschichtung, gleichmäßige Lastverteilung. Sie werden über <strong>Strafkosten</strong> (<em>penalties</em>) in die Zielfunktion integriert und dürfen im Notfall verletzt werden — es kostet dann eben.</p>
|
||||
<p><strong>Weiche Nebenbedingungen (<em>soft constraints</em>)</strong> sind Wünsche: Mitarbeiterpräferenzen, möglichst wenig Umschichtung, gleichmäßige Lastverteilung. Sie werden über <strong><a href="anhang-glossar.md#gloss:strafkosten" class="glossar-link">Strafkosten</a></strong> (<em>penalties</em>) in die Zielfunktion integriert und dürfen im Notfall verletzt werden — es kostet dann eben.</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Harte Bedingung = „darf nicht“. Weiche Bedingung = „soll möglichst nicht, sonst kostet es X“. Die Entscheidung zwischen beiden ist eine der folgenreichsten im ganzen Modell: Zu viele harte Bedingungen erzeugen unlösbare Modelle (<a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a>), zu wenige erzeugen Lösungen, die niemand akzeptiert.</p>
|
||||
</blockquote>
|
||||
|
|
@ -1073,12 +1073,12 @@ Vorteil der Optimierung: 300.00 EUR pro Tag (15.0 %)
|
|||
<tr class="odd">
|
||||
<td><code>modell.Add(x_a <= MAX_ARBITRAGE)</code></td>
|
||||
<td>Marktlimit als <strong>Nebenbedingung</strong></td>
|
||||
<td>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</td>
|
||||
<td>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 <a href="anhang-glossar.md#gloss:schattenpreis" class="glossar-link">Schattenpreis</a> abfragen</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>loeser.StatusName(status)</code></td>
|
||||
<td>echter Status statt fester Text</td>
|
||||
<td>Ein fest codierter Text wie „OPTIMAL“ würde unabhängig vom tatsächlichen Ergebnis ausgegeben — deshalb immer den echten Solver-Status auswerten</td>
|
||||
<td>Ein fest codierter Text wie „OPTIMAL“ würde unabhängig vom tatsächlichen Ergebnis ausgegeben — deshalb immer den echten <a href="anhang-glossar.md#gloss:solver-status" class="glossar-link">Solver-Status</a> auswerten</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>assert ...</code></td>
|
||||
|
|
@ -1149,7 +1149,7 @@ Vorteil der Optimierung: 300.00 EUR pro Tag (15.0 %)
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Simplex-LP / GRG / Evolutionär</td>
|
||||
<td>GLOP / SLSQP / CP-SAT</td>
|
||||
<td>GLOP / <a href="anhang-glossar.md#gloss:slsqp" class="glossar-link">SLSQP</a> / <a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a></td>
|
||||
<td>In Excel drei Auswahlpunkte, in Python drei Bibliotheken (<a href="oekosystem.html#kap-oekosystem">Kapitel 3</a>).</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -1352,7 +1352,7 @@ Ergebnis geschrieben nach: produktionsmix_ergebnis.xlsx</code></pre>
|
|||
<p><strong>Aufgabe 1.2 ⭐ — Hart oder weich?</strong> Entscheiden Sie für jede Bedingung eines Klinik-Dienstplans, ob sie 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. (c) In jeder Nachtschicht muss mindestens eine examinierte Fachkraft anwesend sein. (d) Die Dienste sollen gleichmäßig über das Team verteilt sein. (e) Niemand arbeitet mehr als 10 Tage am Stück.</p>
|
||||
<p><strong>Aufgabe 1.3 ⭐⭐ — Kombinatorik selbst rechnen.</strong> Ein Speditionsdisponent muss 12 Aufträge auf einen einzigen Lkw in eine Reihenfolge bringen. (a) Wie viele Reihenfolgen gibt es? (b) Der Rechner prüft 5 Millionen Reihenfolgen pro Sekunde. Wie lange dauert das vollständige Durchprobieren? (c) Wie lange dauert es bei 13 Aufträgen? Um welchen Faktor ist das mehr? (d) Wie viele Aufträge könnte man in einer Stunde noch vollständig durchprobieren?</p>
|
||||
<p><strong>Aufgabe 1.4 ⭐⭐ — Modell lesen.</strong> Gegeben sei das Modell <span class="math display">\max\ 3x_1 + 5x_2 \quad \text{u. d. N.} \quad x_1 \le 4,\ \ 2x_2 \le 12,\ \ 3x_1 + 2x_2 \le 18,\ \ x_1, x_2 \ge 0.</span> (a) Benennen Sie die vier Bausteine. (b) Ist <span class="math inline">(2, 6)</span> zulässig? Ist <span class="math inline">(4, 3)</span> zulässig? Berechnen Sie jeweils <span class="math inline">Z</span>. (c) Finden Sie durch Probieren die beste ganzzahlige Lösung.</p>
|
||||
<p><strong>Aufgabe 1.5 ⭐⭐⭐ — Die Bäckerei programmieren.</strong> Setzen Sie das Bäckerei-Problem der Handrechnung <em>Zerlegen Sie dieses Problem</em> mit CP-SAT um. Geben Sie die optimale Produktionsmenge, den Deckungsbeitrag und die Auslastung von Mehl und Ofen aus. Prüfen Sie Ihr Ergebnis mit <code>assert</code>-Anweisungen.</p>
|
||||
<p><strong>Aufgabe 1.5 ⭐⭐⭐ — Die Bäckerei programmieren.</strong> Setzen Sie das Bäckerei-Problem der Handrechnung <em>Zerlegen Sie dieses Problem</em> mit <a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a> um. Geben Sie die optimale Produktionsmenge, den Deckungsbeitrag und die Auslastung von Mehl und Ofen aus. Prüfen Sie Ihr Ergebnis mit <code>assert</code>-Anweisungen.</p>
|
||||
<p><strong>Aufgabe 1.6 ⭐⭐⭐ — Sensitivität durch Ausprobieren.</strong> Erweitern Sie <code>Bot_Allokation.py</code> so, dass es das Modell in einer Schleife für RAM-Kapazitäten von 54 bis 72 GB (in Schritten von 2) löst und eine Tabelle <code>RAM | x_A | x_B | Gewinn | Gewinnzuwachs pro zusätzlichem GB</code> ausgibt. (a) Ab welcher RAM-Menge steigt der Gewinn nicht mehr? Warum? (b) Was sagt Ihnen der „Gewinnzuwachs pro GB“ intuitiv? (Der Begriff dafür — <em>Schattenpreis</em> — folgt in <a href="lp.html#kap-lp">Kapitel 5</a>.)</p>
|
||||
<p><strong>Aufgabe 1.7 ⭐⭐⭐ — Eigenes Problem zerlegen.</strong> Wählen Sie ein Entscheidungsproblem aus Ihrem eigenen Alltag oder Beruf (Beispiele: Wochenplan für Sportkurse, Sitzordnung bei einer Feier, Aufteilung eines Budgets auf Projekte, Reihenfolge von Hausarbeiten). Füllen Sie die Vorlage aus <a href="#sec:einfuehrung-die-vier-universellen-bausteine-jedes-or">Abschnitt 1.6</a> vollständig aus. Notieren Sie außerdem: Woher kämen die Daten? Wer müsste das Ergebnis akzeptieren? — Heben Sie diese Notiz auf; sie ist der Ausgangspunkt für Ihr eigenes Projekt in der <a href="projektwerkstatt.html">Projektwerkstatt</a>.</p>
|
||||
<hr />
|
||||
|
|
@ -1416,13 +1416,13 @@ Deckungsbeitrag: 18600 EUR</code></pre>
|
|||
<h2 id="sec:einfuehrung-zusammenfassung">1.13 Zusammenfassung</h2>
|
||||
<ul>
|
||||
<li><strong>Operations Research ist präskriptiv:</strong> Es beantwortet nicht, was war oder was kommt, sondern was zu tun ist.</li>
|
||||
<li><strong>Kombinatorische Explosion</strong> <strong>ist eine Wand, keine Steigung.</strong> Zwischen „in Minuten machbar“ und „in Jahrmillionen unmöglich“ liegen oft nur wenige zusätzliche Objekte. Solver umgehen das nicht durch Geschwindigkeit, sondern durch Struktur.</li>
|
||||
<li><strong><a href="anhang-glossar.md#gloss:kombinatorische-explosion" class="glossar-link">Kombinatorische Explosion</a></strong> <strong>ist eine Wand, keine Steigung.</strong> Zwischen „in Minuten machbar“ und „in Jahrmillionen unmöglich“ liegen oft nur wenige zusätzliche Objekte. Solver umgehen das nicht durch Geschwindigkeit, sondern durch Struktur.</li>
|
||||
<li><strong>Jedes Modell besteht aus vier Bausteinen:</strong> Entscheidungsvariablen, Parameter, Zielfunktion, Nebenbedingungen. Diese Zerlegung ist die eigentliche Arbeit; die Solverwahl ergibt sich danach fast von selbst.</li>
|
||||
<li><strong>Harte und weiche Bedingungen sind eine Entwurfsentscheidung</strong> mit großen Folgen für Lösbarkeit und Akzeptanz.</li>
|
||||
<li><strong>Ihre Daten liegen schon in Excel.</strong> <code>pandas.read_excel()</code> holt sie ab, der Solver rechnet, <code>to_excel()</code> gibt das Ergebnis im gewohnten Format zurück. Der Gewinn gegenüber einer Solver-Mappe ist nicht Rechenleistung, sondern Nachvollziehbarkeit: versionierbar, testbar, hundertmal in einer Schleife ausführbar.</li>
|
||||
<li><strong>Prüfen Sie jedes Ergebnis</strong> — gegen eine Handrechnung, gegen <code>assert</code>-Anweisungen und gegen eine naive Vergleichsstrategie. Ein unerwartet gutes Ergebnis ist ein Fehlerverdacht, keine gute Nachricht.</li>
|
||||
</ul>
|
||||
<p><strong>Ausblick.</strong> <a href="fundament.html#kap-fundament">Kapitel 2</a> 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: <strong>Konvexität</strong>.</p>
|
||||
<p><strong>Ausblick.</strong> <a href="fundament.html#kap-fundament">Kapitel 2</a> 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: <strong><a href="anhang-glossar.md#gloss:konvexitaet" class="glossar-link">Konvexität</a></strong>.</p>
|
||||
|
||||
</article>
|
||||
<button type="button" class="fortschritt-knopf" data-kapitel="einfuehrung.html"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg> <span>Als gelesen markieren</span></button>
|
||||
|
|
|
|||
18
OR_HTML_04/finanzdaten.html
generated
18
OR_HTML_04/finanzdaten.html
generated
|
|
@ -105,7 +105,7 @@
|
|||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um die Eingangsdaten der Portfoliooptimierung — und darum, warum sie trügerisch sind. Wer historische Kovarianzen ungefiltert in einen Optimierer gibt, optimiert Rauschen.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a> (Eigenwerte, positive Definitheit), Grundlagen der Statistik.</p>
|
||||
<p><strong>Danach können Sie:</strong> Kursdaten korrekt laden, diskrete und logarithmische Renditen unterscheiden, das Schätzfehlerproblem erklären, Ledoit-Wolf-Shrinkage anwenden — und erkennen, wann eine Kovarianzmatrix aus zu wenigen Beobachtungen stammt.</p>
|
||||
<p><strong>Danach können Sie:</strong> Kursdaten korrekt laden, diskrete und logarithmische Renditen unterscheiden, das Schätzfehlerproblem erklären, <a href="anhang-glossar.md#gloss:ledoit-wolf-shrinkage" class="glossar-link">Ledoit-Wolf-Shrinkage</a> anwenden — und erkennen, wann eine <a href="anhang-glossar.md#gloss:kovarianzmatrix" class="glossar-link">Kovarianzmatrix</a> aus zu wenigen Beobachtungen stammt.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 5 Stunden.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>Renditen_Vergleich.py</code><br />
|
||||
|
|
@ -176,7 +176,7 @@ Mittelwert log 4.56 % -> hochgerechnet 120.00</code></pre>
|
|||
<tr class="even">
|
||||
<td>Wofür also</td>
|
||||
<td>Portfoliogewichtung, Kennzahlen je Periode</td>
|
||||
<td>Zeitreihenanalyse, Volatilität, Modelle</td>
|
||||
<td>Zeitreihenanalyse, <a href="anhang-glossar.md#gloss:volatilitaet" class="glossar-link">Volatilität</a>, Modelle</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -189,9 +189,9 @@ Mittelwert log 4.56 % -> hochgerechnet 120.00</code></pre>
|
|||
<p>Nach diesem Kapitel können Sie …</p>
|
||||
<ol type="1">
|
||||
<li>… erklären, wann man diskrete und wann logarithmische Renditen verwendet.</li>
|
||||
<li>… beschreiben, warum die Stichproben-Kovarianzmatrix bei vielen Titeln unbrauchbar wird.</li>
|
||||
<li>… den <strong>Error-Maximizer-Effekt</strong> an einem Experiment nachweisen.</li>
|
||||
<li>… Ledoit-Wolf-Shrinkage anwenden und ihre Wirkung an Eigenwerten und Konditionszahl messen.</li>
|
||||
<li>… beschreiben, warum die <a href="anhang-glossar.md#gloss:stichproben-kovarianzmatrix" class="glossar-link">Stichproben-Kovarianzmatrix</a> bei vielen Titeln unbrauchbar wird.</li>
|
||||
<li>… den <strong><a href="anhang-glossar.md#gloss:error-maximizer-effekt" class="glossar-link">Error-Maximizer-Effekt</a></strong> an einem Experiment nachweisen.</li>
|
||||
<li>… Ledoit-Wolf-Shrinkage anwenden und ihre Wirkung an Eigenwerten und <a href="anhang-glossar.md#gloss:konditionszahl" class="glossar-link">Konditionszahl</a> messen.</li>
|
||||
<li>… Kursdaten so laden, dass die Spaltenreihenfolge garantiert stimmt.</li>
|
||||
<li>… begründen, warum eine Schätzung aus <span class="math inline">T < N</span> Beobachtungen dem Optimierer risikofreie Richtungen vorgaukelt — und welche drei Gegenmittel es gibt.</li>
|
||||
<li>… ein Portfolio <strong>außerhalb</strong> des Schätzzeitraums bewerten statt darin.</li>
|
||||
|
|
@ -333,7 +333,7 @@ r_{i,0\to T} = \sum_{t=1}^T r_{i,t}
|
|||
<p><span class="math display">
|
||||
\mathbf{S} = \frac{1}{T-1}\mathbf{X}^\top\mathbf{X}
|
||||
</span></p>
|
||||
<p>Das Problem: <span class="math inline">\mathbf{S}</span> hat <span class="math inline">\frac{N(N+1)}{2}</span> zu schätzende Parameter, aber nur <span class="math inline">T \cdot N</span> Datenpunkte. Bei <span class="math inline">N = 50</span> Titeln sind das <strong>1275 Parameter</strong> — geschätzt aus einem Jahr Daten (<span class="math inline">T = 252</span>).</p>
|
||||
<p>Das Problem: <span class="math inline">\mathbf{S}</span> hat <span class="math inline">\frac{N(N+1)}{2}</span> zu schätzende <a href="anhang-glossar.md#gloss:parameter" class="glossar-link">Parameter</a>, aber nur <span class="math inline">T \cdot N</span> Datenpunkte. Bei <span class="math inline">N = 50</span> Titeln sind das <strong>1275 Parameter</strong> — geschätzt aus einem Jahr Daten (<span class="math inline">T = 252</span>).</p>
|
||||
<figure>
|
||||
<img src="bilder_04/kap11_ledoit_wolf_shrinkage.svg" alt="Abb. 18.1: Ledoit-Wolf-Kovarianz-Shrinkage" />
|
||||
<figcaption aria-hidden="true">Abb. 18.1: Ledoit-Wolf-Kovarianz-Shrinkage</figcaption>
|
||||
|
|
@ -364,7 +364,7 @@ r_{i,0\to T} = \sum_{t=1}^T r_{i,t}
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Die <strong>Zufallsmatrizentheorie</strong> (<em>Random Matrix Theory</em>, Marchenko-Pastur-Gesetz) zeigt: Die kleinsten Eigenwerte von <span class="math inline">\mathbf{S}</span> werden <strong>systematisch unterschätzt</strong>, die größten überschätzt. Und genau das ist fatal, denn:</p>
|
||||
<p>Die <strong><a href="anhang-glossar.md#gloss:zufallsmatrizentheorie" class="glossar-link">Zufallsmatrizentheorie</a></strong> (<em>Random Matrix Theory</em>, <a href="anhang-glossar.md#gloss:marchenko-pastur-gesetz" class="glossar-link">Marchenko-Pastur-Gesetz</a>) zeigt: Die kleinsten Eigenwerte von <span class="math inline">\mathbf{S}</span> werden <strong>systematisch unterschätzt</strong>, die größten überschätzt. Und genau das ist fatal, denn:</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Der Error-Maximizer-Effekt</strong> Ein Risikominimierer sucht die Richtungen mit der <strong>kleinsten</strong> Varianz — also genau jene Eigenrichtungen, deren Eigenwerte am stärksten <strong>nach unten verzerrt</strong> sind. Die Optimierung greift damit zielsicher in das Schätzrauschen hinein. Markowitz-Optimierung ist deshalb kein Fehlerdämpfer, sondern ein <strong>Fehlerverstärker</strong>.</p>
|
||||
</blockquote>
|
||||
|
|
@ -481,7 +481,7 @@ Bestmoegliche Volatilitaet bei perfektem Wissen: 11.84 % p.a.
|
|||
504 | 12.6 | 12.33 % +4.1 % | 12.30 % +3.9 % | 0.012
|
||||
1260 | 31.5 | 12.03 % +1.6 % | 12.02 % +1.6 % | 0.005
|
||||
--------------------------------------------------------------------------------------------</code></pre>
|
||||
<p><strong>Diese Tabelle ist das Kernargument des ganzen Kapitels.</strong> Lesen Sie die erste Zeile: Bei nur 60 Beobachtungen für 40 Titel trägt das „risikominimale“ Portfolio in Wahrheit <strong>75,5 % mehr Risiko</strong> als nötig. Der Optimierer hat nicht das Risiko minimiert, sondern das <strong>geschätzte</strong> Risiko — und die Differenz ist der Schätzfehler, in den er hineinoptimiert hat.</p>
|
||||
<p><strong>Diese Tabelle ist das Kernargument des ganzen Kapitels.</strong> Lesen Sie die erste Zeile: Bei nur 60 Beobachtungen für 40 Titel trägt das „risikominimale“ Portfolio in Wahrheit <strong>75,5 % mehr Risiko</strong> als nötig. Der Optimierer hat nicht das Risiko minimiert, sondern das <strong>geschätzte</strong> Risiko — und die Differenz ist der <a href="anhang-glossar.md#gloss:schaetzfehler" class="glossar-link">Schätzfehler</a>, in den er hineinoptimiert hat.</p>
|
||||
<p>Drei Beobachtungen:</p>
|
||||
<ol type="1">
|
||||
<li><strong>Der Schaden wächst dramatisch, je knapper die Daten.</strong> Von <span class="math inline">T/N = 31{,}5</span> (+1,6 %) bis <span class="math inline">T/N = 1{,}5</span> (+75,5 %) ist es kein gleitender Übergang, sondern eine Explosion.</li>
|
||||
|
|
@ -713,7 +713,7 @@ prices.columns: ['AAPL', 'AMZN', 'CVX', 'GS', &
|
|||
<p><strong>Aufgabe 18.2 ⭐ — Mittelwertfalle.</strong> Ein Fonds meldet Jahresrenditen von <span class="math inline">+60\,\%</span>, <span class="math inline">-40\,\%</span>, <span class="math inline">+60\,\%</span>, <span class="math inline">-40\,\%</span>. (a) Wie hoch ist das arithmetische Mittel? (b) Wie viel Kapital hat ein Anleger nach 4 Jahren aus 10 000 €? (c) Welche jährliche Rendite entspricht dem tatsächlich?</p>
|
||||
<p><strong>Aufgabe 18.3 ⭐⭐ — Konditionszahl verstehen.</strong> Erzeugen Sie eine Kovarianzmatrix für <span class="math inline">N = 30</span> Titel aus <span class="math inline">T = 40</span>, <span class="math inline">T = 100</span> und <span class="math inline">T = 1000</span> simulierten Beobachtungen. Berechnen Sie jeweils kleinsten Eigenwert und Konditionszahl. Ab welchem <span class="math inline">T</span> wird die Matrix brauchbar?</p>
|
||||
<p><strong>Aufgabe 18.4 ⭐⭐ — Spaltenreihenfolge prüfen.</strong> Laden Sie fünf Ticker in einer bewusst unsortierten Reihenfolge. Zeigen Sie, dass <code>raw["Close"].columns</code> abweicht, und dass <code>raw["Close"][tickers]</code> das behebt. Was passiert, wenn ein Ticker nicht existiert?</p>
|
||||
<p><strong>Aufgabe 18.5 ⭐⭐⭐ — Beide Shrinkage-Ziele vergleichen.</strong> Implementieren Sie das Konstant-Korrelations-Ziel vollständig (inklusive eigener Berechnung von <span class="math inline">\delta</span> nach Ledoit/Wolf 2003 oder per Kreuzvalidierung). Vergleichen Sie mit <code>sklearn</code> anhand: (a) der Konditionszahl, (b) der Out-of-Sample-Volatilität eines GMV-Portfolios (nach dem Muster von <code>Schaetzrauschen_Demo.py</code>), (c) der Stabilität der Gewichte über rollierende Fenster.</p>
|
||||
<p><strong>Aufgabe 18.5 ⭐⭐⭐ — Beide Shrinkage-Ziele vergleichen.</strong> Implementieren Sie das Konstant-Korrelations-Ziel vollständig (inklusive eigener Berechnung von <span class="math inline">\delta</span> nach Ledoit/Wolf 2003 oder per Kreuzvalidierung). Vergleichen Sie mit <code>sklearn</code> anhand: (a) der Konditionszahl, (b) der Out-of-Sample-Volatilität eines <a href="anhang-glossar.md#gloss:global-minimum-variance-portfolio-gmv" class="glossar-link">GMV</a>-Portfolios (nach dem Muster von <code>Schaetzrauschen_Demo.py</code>), (c) der Stabilität der Gewichte über rollierende Fenster.</p>
|
||||
<p><strong>Aufgabe 18.6 ⭐⭐⭐ — Error-Maximizer selbst messen.</strong> Erweitern Sie <code>Schaetzrauschen_Demo.py</code> um eine dritte Variante: die <strong>Gleichgewichtung</strong> (<span class="math inline">w_i = 1/N</span>), die überhaupt keine Schätzung benötigt. (a) Ab welchem <span class="math inline">T/N</span> schlägt die Stichproben-Optimierung die Gleichgewichtung? (b) Ab welchem <span class="math inline">T/N</span> schlägt Ledoit-Wolf sie? (c) Was folgt daraus für die Praxis?</p>
|
||||
<hr />
|
||||
<h2 id="sec:finanzdaten-denkfehler">18.8 Finde den Denkfehler</h2>
|
||||
|
|
|
|||
32
OR_HTML_04/fundament.html
generated
32
OR_HTML_04/fundament.html
generated
|
|
@ -103,7 +103,7 @@
|
|||
<div class="card card-blick">
|
||||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um die Sprache, in der Optimierungsmodelle aufgeschrieben werden, und um die eine Eigenschaft, die darüber entscheidet, ob ein Problem verlässlich lösbar ist: Konvexität.</p>
|
||||
<p><strong>Worum geht es?</strong> Um die Sprache, in der Optimierungsmodelle aufgeschrieben werden, und um die eine Eigenschaft, die darüber entscheidet, ob ein Problem verlässlich lösbar ist: <a href="anhang-glossar.md#gloss:konvexitaet" class="glossar-link">Konvexität</a>.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a>. Lineare Algebra wird hier von Grund auf wiederholt.</p>
|
||||
<p><strong>Danach können Sie:</strong> Ein Modell in 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.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 5 Stunden.</p>
|
||||
|
|
@ -117,7 +117,7 @@
|
|||
</div>
|
||||
<hr />
|
||||
<h2 id="sec:fundament-schnellstart">2.1 In 5 Minuten gelöst</h2>
|
||||
<p>Dieses Kapitel handelt von Geometrie. Bevor wir Vektoren und Matrizen einführen, sehen Sie die zentrale Einsicht in Aktion — ganz ohne Solver, mit acht Zeilen NumPy.</p>
|
||||
<p>Dieses Kapitel handelt von Geometrie. Bevor wir Vektoren und Matrizen einführen, sehen Sie die zentrale Einsicht in Aktion — ganz ohne <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a>, mit acht Zeilen <a href="anhang-glossar.md#gloss:numpy" class="glossar-link">NumPy</a>.</p>
|
||||
<div class="card card-schnellstart">
|
||||
<blockquote>
|
||||
<p><strong>🚀 In 5 Minuten gelöst: Das Optimum sitzt immer in einer Ecke</strong></p>
|
||||
|
|
@ -146,8 +146,8 @@ Ecke (6.0, 0.0) -> Z = 18.00
|
|||
Ecke (0.0, 0.0) -> Z = 0.00</code></pre>
|
||||
</blockquote>
|
||||
</div>
|
||||
<p><strong>Das Optimum lautet <span class="math inline">(0, 8)</span> mit <span class="math inline">Z = 40</span></strong> — und Sie haben es gefunden, ohne einen einzigen Solver zu starten. Vier Kandidaten statt unendlich vieler Punkte: Das ist der <strong>Fundamentalsatz der linearen Optimierung</strong>, und er ist der Grund, warum sich lineare Programme überhaupt zuverlässig lösen lassen.</p>
|
||||
<p><strong>Warum funktioniert das?</strong> Weil der zulässige Bereich ein <strong>konvexes Polyeder</strong> ist — ein Vielflächner ohne Diagonalen nach innen — und weil eine lineare Zielfunktion darauf ihren größten Wert immer am Rand annimmt, genauer: in einer Ecke. Beides begründet dieses Kapitel. Der Simplex-Algorithmus in <a href="lp.html#kap-lp">Kapitel 5</a> 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.</p>
|
||||
<p><strong>Das Optimum lautet <span class="math inline">(0, 8)</span> mit <span class="math inline">Z = 40</span></strong> — und Sie haben es gefunden, ohne einen einzigen Solver zu starten. Vier Kandidaten statt unendlich vieler Punkte: Das ist der <strong><a href="anhang-glossar.md#gloss:fundamentalsatz-der-linearen-optimierung" class="glossar-link">Fundamentalsatz der linearen Optimierung</a></strong>, und er ist der Grund, warum sich lineare Programme überhaupt zuverlässig lösen lassen.</p>
|
||||
<p><strong>Warum funktioniert das?</strong> Weil der zulässige Bereich ein <strong>konvexes <a href="anhang-glossar.md#gloss:polyeder" class="glossar-link">Polyeder</a></strong> ist — ein Vielflächner ohne Diagonalen nach innen — und weil eine lineare <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a> darauf ihren größten Wert immer am Rand annimmt, genauer: in einer Ecke. Beides begründet dieses Kapitel. Der <a href="anhang-glossar.md#gloss:simplex-algorithmus" class="glossar-link">Simplex-Algorithmus</a> in <a href="lp.html#kap-lp">Kapitel 5</a> 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.</p>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Und wo ist der Haken?</strong> Bei zwei Variablen gibt es 6 Eckenkandidaten, bei 50 Variablen und 50 Bedingungen sind es <span class="math inline">\binom{100}{50} \approx 10^{29}</span>. Der Fundamentalsatz sagt uns <em>wo</em> wir suchen müssen — nicht, dass die Suche leicht wird.</p>
|
||||
</blockquote>
|
||||
|
|
@ -160,7 +160,7 @@ Ecke (0.0, 0.0) -> Z = 0.00</code></pre>
|
|||
<li>… den Fundamentalsatz der linearen Optimierung anwenden, um Kandidaten für das Optimum zu finden, ohne alles durchzuprobieren.</li>
|
||||
<li>… prüfen, ob eine Menge bzw. eine Funktion konvex ist, und begründen, warum das für die Lösbarkeit entscheidend ist.</li>
|
||||
<li>… einen zweidimensionalen Lösungsraum mit <code>matplotlib</code> zeichnen und daraus die optimale Ecke ablesen.</li>
|
||||
<li>… die <strong>Konditionszahl</strong> <span class="math inline">\kappa(\mathbf{A})</span> berechnen, ihren Wert deuten und ein schlecht skaliertes Modell mit Ruiz-Equilibrierung wieder rechenbar machen.</li>
|
||||
<li>… die <strong><a href="anhang-glossar.md#gloss:konditionszahl" class="glossar-link">Konditionszahl</a></strong> <span class="math inline">\kappa(\mathbf{A})</span> berechnen, ihren Wert deuten und ein schlecht skaliertes Modell mit <a href="anhang-glossar.md#gloss:ruiz-equilibrierung" class="glossar-link">Ruiz-Equilibrierung</a> wieder rechenbar machen.</li>
|
||||
<li>… erklären, warum ein Solver-Ergebnis von <code>0.99999998</code> niemals mit <code>int()</code> in eine ganze Zahl verwandelt werden darf.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
|
|
@ -169,7 +169,7 @@ Ecke (0.0, 0.0) -> Z = 0.00</code></pre>
|
|||
<p>Die lineare Algebra löst dieses Problem, indem sie <strong>viele gleichartige Zahlen zu einem Objekt bündelt</strong>. Das ist derselbe Gedanke wie eine Liste in Python: Statt <code>preis_1</code>, <code>preis_2</code>, …, <code>preis_1000</code> schreibt man <code>preise</code> und arbeitet mit dem Ganzen.</p>
|
||||
<h3 id="die-bausteine">Die Bausteine</h3>
|
||||
<p>Sei <span class="math inline">n</span> die Anzahl der Entscheidungsvariablen und <span class="math inline">m</span> die Anzahl der Nebenbedingungen.</p>
|
||||
<p><strong>Entscheidungsvektor</strong> — was wir festlegen:</p>
|
||||
<p><strong><a href="anhang-glossar.md#gloss:entscheidungsvektor" class="glossar-link">Entscheidungsvektor</a></strong> — was wir festlegen:</p>
|
||||
<p><span class="math display">
|
||||
\mathbf{x} = \begin{pmatrix} x_1 \\ x_2 \\ \vdots \\ x_n \end{pmatrix} \in \mathbb{R}^n
|
||||
</span></p>
|
||||
|
|
@ -177,7 +177,7 @@ Ecke (0.0, 0.0) -> Z = 0.00</code></pre>
|
|||
<p><span class="math display">
|
||||
\mathbf{c} = \begin{pmatrix} c_1 \\ c_2 \\ \vdots \\ c_n \end{pmatrix} \in \mathbb{R}^n
|
||||
</span></p>
|
||||
<p><strong>Zielfunktion als Skalarprodukt:</strong></p>
|
||||
<p><strong>Zielfunktion als <a href="anhang-glossar.md#gloss:skalarprodukt" class="glossar-link">Skalarprodukt</a>:</strong></p>
|
||||
<p><span class="math display">
|
||||
f(\mathbf{x}) = \mathbf{c}^\top \mathbf{x} = \sum_{j=1}^n c_j x_j
|
||||
</span></p>
|
||||
|
|
@ -185,7 +185,7 @@ f(\mathbf{x}) = \mathbf{c}^\top \mathbf{x} = \sum_{j=1}^n c_j x_j
|
|||
<p><strong>📐 Formel-Lesehilfe</strong> * <span class="math inline">\mathbf{c}^\top</span> — der Ertragsvektor, „umgekippt“ zu einer Zeile. * <span class="math inline">\mathbf{c}^\top \mathbf{x}</span> — <strong>Skalarprodukt</strong>: Multipliziere jedes <span class="math inline">c_j</span> mit dem zugehörigen <span class="math inline">x_j</span> und addiere alles. Das Ergebnis ist <strong>eine einzige Zahl</strong>. * <span class="math inline">\sum_{j=1}^n</span> — „addiere für <span class="math inline">j = 1</span> bis <span class="math inline">j = n</span>“.</p>
|
||||
<p><strong>Ohne Formel gesagt:</strong> „Nimm von jedem Produkt die hergestellte Menge mal den Gewinn pro Stück und zähle alles zusammen.“ Im Bot-Beispiel: <span class="math inline">\mathbf{c} = (150, 250)^\top</span>, <span class="math inline">\mathbf{x} = (7, 5)^\top</span>, also <span class="math inline">\mathbf{c}^\top\mathbf{x} = 150 \cdot 7 + 250 \cdot 5 = 2300</span>.</p>
|
||||
</blockquote>
|
||||
<p><strong>Technologiematrix</strong> — wer verbraucht wie viel wovon:</p>
|
||||
<p><strong><a href="anhang-glossar.md#gloss:technologiematrix" class="glossar-link">Technologiematrix</a></strong> — wer verbraucht wie viel wovon:</p>
|
||||
<p><span class="math display">
|
||||
\mathbf{A} = \begin{pmatrix}
|
||||
a_{11} & a_{12} & \cdots & a_{1n} \\
|
||||
|
|
@ -198,7 +198,7 @@ a_{m1} & a_{m2} & \cdots & a_{mn}
|
|||
<p><strong>📐 Formel-Lesehilfe</strong> <strong>Jede Zeile ist eine Ressource, jede Spalte eine Variable.</strong> Der Eintrag <span class="math inline">a_{ij}</span> beantwortet: „Wie viel von Ressource <span class="math inline">i</span> verbraucht eine Einheit von Variable <span class="math inline">j</span>?“</p>
|
||||
<p>Im Bot-Beispiel: <span class="math display">\mathbf{A} = \begin{pmatrix} 2 & 5 \\ 4 & 6 \\ 1 & 0 \end{pmatrix} \begin{matrix} \leftarrow \text{vCPU} \\ \leftarrow \text{RAM} \\ \leftarrow \text{Liquidität} \end{matrix}</span> Die erste Zeile <span class="math inline">(2, 5)</span> heißt: Ein A-Bot braucht 2 vCPUs, ein B-Bot braucht 5. Die dritte Zeile <span class="math inline">(1, 0)</span> heißt: Die Liquiditätsgrenze zählt nur A-Bots, B-Bots gar nicht.</p>
|
||||
</blockquote>
|
||||
<p><strong>Kapazitätsvektor (rechte Seite)</strong>:</p>
|
||||
<p><strong><a href="anhang-glossar.md#gloss:kapazitaetsvektor" class="glossar-link">Kapazitätsvektor</a> (rechte Seite)</strong>:</p>
|
||||
<p><span class="math display">
|
||||
\mathbf{b} = \begin{pmatrix} b_1 \\ b_2 \\ \vdots \\ b_m \end{pmatrix} \in \mathbb{R}^m
|
||||
\qquad \text{im Beispiel } \begin{pmatrix} 40 \\ 60 \\ 8 \end{pmatrix}
|
||||
|
|
@ -436,7 +436,7 @@ f(\theta\mathbf{x} + (1-\theta)\mathbf{y}) \le \theta f(\mathbf{x}) + (1-\theta)
|
|||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td>Lineares Programm (LP)</td>
|
||||
<td>Lineares Programm (<a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a>)</td>
|
||||
<td><strong>ja</strong></td>
|
||||
<td>Globales Optimum, Sekunden bis Minuten selbst bei <span class="math inline">10^6</span> Variablen</td>
|
||||
</tr>
|
||||
|
|
@ -446,17 +446,17 @@ f(\theta\mathbf{x} + (1-\theta)\mathbf{y}) \le \theta f(\mathbf{x}) + (1-\theta)
|
|||
<td>Globales Optimum, effizient (<a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a>, <a href="markowitz.html#kap-markowitz">Kapitel 19</a>)</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Ganzzahlige Variablen (MILP)</td>
|
||||
<td>Ganzzahlige Variablen (<a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a>)</td>
|
||||
<td><strong>nein</strong></td>
|
||||
<td>Der zulässige Bereich ist ein Punktgitter, keine zusammenhängende Menge — NP-schwer (<a href="milp.html#kap-milp">Kapitel 6</a>)</td>
|
||||
<td>Der zulässige Bereich ist ein Punktgitter, keine zusammenhängende Menge — <a href="anhang-glossar.md#gloss:np-schwer" class="glossar-link">NP-schwer</a> (<a href="milp.html#kap-milp">Kapitel 6</a>)</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>Quadratisches Programm mit indefinitem <span class="math inline">\mathbf{P}</span></td>
|
||||
<td><strong>nein</strong></td>
|
||||
<td>Nur lokale Optima; eine ungültige Kovarianzmatrix ist ein typischer Auslöser (siehe <a href="qp-nlp.html#sec:qp-nlp-nichtlineare-optimierung-mit-scipy-optimize-minimize">Abschnitt 11.5</a>)</td>
|
||||
<td>Nur lokale Optima; eine ungültige <a href="anhang-glossar.md#gloss:kovarianzmatrix" class="glossar-link">Kovarianzmatrix</a> ist ein typischer Auslöser (siehe <a href="qp-nlp.html#sec:qp-nlp-nichtlineare-optimierung-mit-scipy-optimize-minimize">Abschnitt 11.5</a>)</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Allgemeines NLP mit beliebigen Funktionen</td>
|
||||
<td>Allgemeines <a href="anhang-glossar.md#gloss:nichtlineare-programmierung-nlp" class="glossar-link">NLP</a> mit beliebigen Funktionen</td>
|
||||
<td>meist <strong>nein</strong></td>
|
||||
<td><code>scipy.optimize</code> liefert nur ein lokales Optimum, abhängig vom Startpunkt</td>
|
||||
</tr>
|
||||
|
|
@ -890,7 +890,7 @@ Preis der Ganzzahligkeit: 75.00 EUR (3.16 %)
|
|||
<p>mit Diagonalmatrizen <span class="math inline">\mathbf{D}_r</span> (Zeilen) und <span class="math inline">\mathbf{D}_c</span> (Spalten). Das <strong>Ruiz-Verfahren</strong> bestimmt diese Faktoren iterativ: In jedem Durchlauf wird jede Zeile durch die Wurzel ihres größten Betrags geteilt, danach jede Spalte. Nach wenigen Durchläufen liegen alle Zeilen- und Spaltenmaxima bei 1.</p>
|
||||
<p>Wirtschaftlich passiert dabei nichts: Eine Zeilenskalierung heißt „diese Nebenbedingung in einer anderen Einheit messen“, eine Spaltenskalierung „diese Variable in einer anderen Einheit messen“. Die Lösung rechnet man mit <span class="math inline">\mathbf{x} = \mathbf{D}_c\,\tilde{\mathbf{x}}</span> zurück.</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Jeder ernsthafte Solver skaliert intern selbst — HiGHS, Gurobi, 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.</p>
|
||||
<p><strong>🎯 Merksatz</strong> Jeder ernsthafte Solver skaliert intern selbst — <a href="anhang-glossar.md#gloss:highs" class="glossar-link">HiGHS</a>, <a href="anhang-glossar.md#gloss:gurobi" class="glossar-link">Gurobi</a>, <a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a> 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.</p>
|
||||
</blockquote>
|
||||
<h3 id="das-experiment">Das Experiment</h3>
|
||||
<p>Das folgende Programm führt beides vor — die Fehlerverstärkung und ihre Behebung — und schließt mit der praktischen Konsequenz, die Sie in <a href="milp.html#kap-milp">Kapitel 6</a> wieder brauchen werden: warum eine Binärvariable mit dem Wert <code>0.99999998</code> niemals mit <code>int()</code> gerundet werden darf.</p>
|
||||
|
|
@ -1233,7 +1233,7 @@ und runden Sie Solver-Ergebnisse NIE ohne Toleranzpruefung.
|
|||
<p><span class="math display">\max\ 3x_1 + 5x_2 \quad \text{u. d. N.}\quad \underbrace{\begin{pmatrix} 1 & 2 \\ 3 & 1 \end{pmatrix}}_{\mathbf{A}} \begin{pmatrix} x_1 \\ x_2\end{pmatrix} \le \begin{pmatrix} 8 \\ 12 \end{pmatrix}</span></p>
|
||||
<p>Beim Abtippen aus der Tabelle liest er sie spaltenweise statt zeilenweise ein:</p>
|
||||
<div class="sourceCode" id="cb11"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||||
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> linprog</span>
|
||||
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> [linprog](anhang<span class="op">-</span>glossar.md<span class="co">#gloss:linprog){.glossar-link}</span></span>
|
||||
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>c <span class="op">=</span> np.array([<span class="fl">3.0</span>, <span class="fl">5.0</span>])</span>
|
||||
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>A <span class="op">=</span> np.array([[<span class="fl">1.0</span>, <span class="fl">3.0</span>], <span class="co"># spaltenweise abgetippt statt zeilenweise</span></span>
|
||||
|
|
|
|||
1725
OR_HTML_04/gesamtdokument.html
generated
1725
OR_HTML_04/gesamtdokument.html
generated
File diff suppressed because it is too large
Load diff
30
OR_HTML_04/graphen.html
generated
30
OR_HTML_04/graphen.html
generated
|
|
@ -184,7 +184,7 @@ Engel -> West (44 min)
|
|||
Gesamtfahrzeit: 118 min</code></pre>
|
||||
</blockquote>
|
||||
</div>
|
||||
<p><strong>Eine Zeile Code, und das Problem ist beweisbar optimal gelöst</strong> — <code>linear_sum_assignment</code> ist die Ungarische Methode, ein Spezialalgorithmus, der ohne jeden Solver auskommt.</p>
|
||||
<p><strong>Eine Zeile Code, und das Problem ist beweisbar optimal gelöst</strong> — <code>linear_sum_assignment</code> ist die Ungarische Methode, ein Spezialalgorithmus, der ohne jeden <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> auskommt.</p>
|
||||
<p>Interessanter ist aber, was der Algorithmus <strong>nicht</strong> tut. Der kleinste Wert der ganzen Tabelle ist die 18 bei <em>Cakir → Nord</em>. Die naheliegende Vorgehensweise — „nimm immer das günstigste noch freie Paar“ — beginnt also genau dort:</p>
|
||||
<table>
|
||||
<colgroup>
|
||||
|
|
@ -216,7 +216,7 @@ Gesamtfahrzeit: 118 min</code></pre>
|
|||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Der beste erste Zug ist selten Teil der besten Gesamtlösung. Genau deshalb gibt es Operations Research: Optimierung heißt, Entscheidungen <strong>gemeinsam</strong> zu treffen statt nacheinander. Bei vier Monteuren kostet die gierige Regel 8 %; bei vierzig kostet sie regelmäßig ein Vielfaches.</p>
|
||||
</blockquote>
|
||||
<p><strong>Warum funktioniert das?</strong> Weil das Zuordnungsproblem eine besondere Struktur hat: Seine Nebenbedingungsmatrix ist <strong>total unimodular</strong>. Das bedeutet — wir kommen in <a href="#sec:graphen-bipartites-matching-das-zuordnungsproblem">Abschnitt 8.4</a> 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 angenehm lösbar, und damit beginnt das Kapitel.</p>
|
||||
<p><strong>Warum funktioniert das?</strong> Weil das <a href="anhang-glossar.md#gloss:zuordnungsproblem" class="glossar-link">Zuordnungsproblem</a> eine besondere Struktur hat: Seine Nebenbedingungsmatrix ist <strong>total unimodular</strong>. Das bedeutet — wir kommen in <a href="#sec:graphen-bipartites-matching-das-zuordnungsproblem">Abschnitt 8.4</a> darauf zurück —, dass die <a href="anhang-glossar.md#gloss:lp-relaxation" class="glossar-link">LP-Relaxation</a> von ganz allein ganzzahlige Lösungen liefert. Man braucht hier also weder <a href="anhang-glossar.md#gloss:branch-and-bound" class="glossar-link">Branch-and-Bound</a> noch Binärvariablen. Dieselbe Eigenschaft macht auch Flussprobleme so angenehm lösbar, und damit beginnt das Kapitel.</p>
|
||||
<hr />
|
||||
<h2 id="sec:graphen-lernziele">8.2 Lernziele</h2>
|
||||
<p>Nach diesem Kapitel können Sie …</p>
|
||||
|
|
@ -224,14 +224,14 @@ Gesamtfahrzeit: 118 min</code></pre>
|
|||
<li>… ein Transportproblem als Graph mit Quellen, Senken und Kapazitäten modellieren.</li>
|
||||
<li>… den <strong>Flusserhaltungssatz</strong> aufstellen und seine Bedeutung erklären.</li>
|
||||
<li>… begründen, warum Zuordnungsprobleme <strong>ohne</strong> Ganzzahligkeitsbedingung ganzzahlig lösbar sind (totale Unimodularität).</li>
|
||||
<li>… ein Vehicle Routing Problem mit Kapazitäten und Zeitfenstern mit OR-Tools lösen.</li>
|
||||
<li>… einschätzen, wann ein spezialisierter Algorithmus einem allgemeinen MILP überlegen ist.</li>
|
||||
<li>… ein Vehicle Routing Problem mit Kapazitäten und Zeitfenstern mit <a href="anhang-glossar.md#gloss:or-tools" class="glossar-link">OR-Tools</a> lösen.</li>
|
||||
<li>… einschätzen, wann ein spezialisierter Algorithmus einem allgemeinen <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> überlegen ist.</li>
|
||||
<li>… begründen, warum eine gierige Zuordnung systematisch schlechter ist als eine gemeinsame Optimierung.</li>
|
||||
<li>… einen Tourenplan gegen die Wirklichkeit prüfen — unabhängig von den Bausteinen, aus denen das Modell gebaut wurde.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
<h2 id="sec:graphen-graphen-als-modellsprache">8.3 Graphen als Modellsprache</h2>
|
||||
<p>Viele reale Probleme in Logistik, Kommunikation und Finanzströmen sind keine flachen Ungleichungssysteme, sondern <strong>Graphen</strong> <span class="math inline">G = (V, E)</span>:</p>
|
||||
<p>Viele reale Probleme in Logistik, Kommunikation und Finanzströmen sind keine flachen Ungleichungssysteme, sondern <strong><a href="anhang-glossar.md#gloss:graphen" class="glossar-link">Graphen</a></strong> <span class="math inline">G = (V, E)</span>:</p>
|
||||
<ul>
|
||||
<li><span class="math inline">V</span> — die <strong>Knoten</strong> (<em>vertices</em>): Server, Depots, Kunden, Konten, Lager.</li>
|
||||
<li><span class="math inline">E</span> — die gerichteten <strong>Kanten</strong> (<em>edges</em>): Datenleitungen, Straßen, Überweisungswege.</li>
|
||||
|
|
@ -240,7 +240,7 @@ Gesamtfahrzeit: 118 min</code></pre>
|
|||
<p><strong>Minimum-Cost Network Flow Problem</strong> — deutsch: <em>kostenminimales Flussproblem</em>. Es ist das mathematische Fundament für Transportketten, Liquiditätsrouting und Datenverteilung.</p>
|
||||
<figure>
|
||||
<img src="bilder_04/kap_graphen_min_cost_flow.svg" alt="Abb. 8.1: Das Netzwerk aus Min_Cost_Flow.py samt Lösung: 140 € für 30 Einheiten. Die billige 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 bilder_04/erzeuge_min_cost_flow.py." />
|
||||
<figcaption aria-hidden="true">Abb. 8.1: Das Netzwerk aus <code>Min_Cost_Flow.py</code> samt Lösung: 140 € für 30 Einheiten. Die billige 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 <code>bilder_04/erzeuge_min_cost_flow.py</code>.</figcaption>
|
||||
<figcaption aria-hidden="true">Abb. 8.1: Das Netzwerk aus <code>Min_Cost_Flow.py</code> samt Lösung: 140 € für 30 Einheiten. Die billige 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 <a href="anhang-glossar.md#gloss:flusserhaltung" class="glossar-link">Flusserhaltung</a>. Erzeugt von <code>bilder_04/erzeuge_min_cost_flow.py</code>.</figcaption>
|
||||
</figure>
|
||||
<p>Sei <span class="math inline">x_{ij} \ge 0</span> der Fluss über Kante <span class="math inline">(i,j)</span>, <span class="math inline">c_{ij}</span> die Kosten je Einheit und <span class="math inline">u_{ij}</span> die Kapazität:</p>
|
||||
<p><span class="math display">
|
||||
|
|
@ -424,7 +424,7 @@ Umschlag -> Kunde_2 5.0 10 3.00 15.00
|
|||
<blockquote>
|
||||
<p><strong>Satz.</strong> Die Extrempunkte der Menge aller doppelt-stochastischen Matrizen (alle Zeilensummen <span class="math inline">= 1</span>, alle Spaltensummen <span class="math inline">= 1</span>, <span class="math inline">x_{ij} \ge 0</span>) sind <strong>genau</strong> die Permutationsmatrizen (alle <span class="math inline">x_{ij} \in \{0,1\}</span>).</p>
|
||||
</blockquote>
|
||||
<p><strong>Warum das praktisch enorm wichtig ist:</strong> Nach dem Fundamentalsatz aus <a href="fundament.html#kap-fundament">Kapitel 2</a> liegt das LP-Optimum in einer Ecke. Die Ecken sind hier laut Satz automatisch 0/1-wertig. Also gilt:</p>
|
||||
<p><strong>Warum das praktisch enorm wichtig ist:</strong> Nach dem Fundamentalsatz aus <a href="fundament.html#kap-fundament">Kapitel 2</a> liegt das <a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a>-Optimum in einer Ecke. Die Ecken sind hier laut Satz automatisch 0/1-wertig. Also gilt:</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Beim Zuordnungsproblem müssen Sie die Ganzzahligkeit <strong>nicht</strong> fordern — ein gewöhnlicher LP-Solver liefert von selbst eine 0/1-Lösung. Sie sparen sich damit die NP-Schwere von Branch-and-Bound vollständig.</p>
|
||||
</blockquote>
|
||||
|
|
@ -459,7 +459,7 @@ Umschlag -> Kunde_2 5.0 10 3.00 15.00
|
|||
</tbody>
|
||||
</table>
|
||||
<p><strong>Die praktische Folge in einem Satz:</strong> <em>Bei Zuordnungs- und Flussproblemen dürfen Sie die Ganzzahligkeit weglassen und trotzdem ganzzahlige Lösungen erwarten — Sie sparen sich die NP-Schwere von Branch-and-Bound vollständig.</em></p>
|
||||
<p><strong>Und die Warnung dazu:</strong> 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 das, bevor Sie sich auf die Struktur verlassen.</p>
|
||||
<p><strong>Und die Warnung dazu:</strong> Diese Eigenschaft ist zerbrechlich. Eine einzige zusätzliche Nebenbedingung, die nicht in das Schema passt — „höchstens drei Fahrzeuge insgesamt“, eine Fixkostenkopplung, eine <a href="anhang-glossar.md#gloss:mindestabnahmemenge" class="glossar-link">Mindestabnahmemenge</a> — zerstört die totale Unimodularität. Dann liefert die <a href="anhang-glossar.md#gloss:relaxation" class="glossar-link">Relaxation</a> wieder Brüche, und Sie brauchen doch ein MILP. Prüfen Sie das, bevor Sie sich auf die Struktur verlassen.</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||||
|
|
@ -574,7 +574,7 @@ Umschlag -> Kunde_2 5.0 10 3.00 15.00
|
|||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:graphen-das-vehicle-routing-problem-mit-zeitfenstern">8.5 Das Vehicle Routing Problem mit Zeitfenstern</h2>
|
||||
<p>Das <strong>Traveling Salesperson Problem (TSP)</strong>, deutsch <em>Problem des Handlungsreisenden</em>, fragt nach der kürzesten Rundreise durch <span class="math inline">N</span> Städte. Das <strong>Capacitated Vehicle Routing Problem with Time Windows (CVRPTW)</strong> erweitert es auf eine <strong>Flotte</strong> mit Kapazitätsgrenzen und Kundenzeitfenstern <span class="math inline">[e_i, l_i]</span>.</p>
|
||||
<p>Das <strong>Traveling Salesperson Problem (<a href="anhang-glossar.md#gloss:tsp-traveling-salesperson-problem" class="glossar-link">TSP</a>)</strong>, deutsch <em>Problem des Handlungsreisenden</em>, fragt nach der kürzesten Rundreise durch <span class="math inline">N</span> Städte. Das <strong>Capacitated Vehicle Routing Problem with Time Windows (<a href="anhang-glossar.md#gloss:cvrptw" class="glossar-link">CVRPTW</a>)</strong> erweitert es auf eine <strong>Flotte</strong> mit Kapazitätsgrenzen und Kundenzeitfenstern <span class="math inline">[e_i, l_i]</span>.</p>
|
||||
<figure>
|
||||
<img src="bilder_04/kap_graphen_vrp_touren.svg" alt="Abb. 8.2: Die Lösung der Instanz aus VRP_Flotten_Routing.py: 16 Kunden, vier Fahrzeuge, 619 km. Beachten Sie, dass sich die Touren kreuzen. Bei einem reinen Tourenproblem wäre das ein sicheres Zeichen für eine verbesserbare Lösung — hier ist es keines: Die Zeitfenster erzwingen die Reihenfolge, und wer die Kreuzungen auflöst, kommt zu spät. Erzeugt von bilder_04/erzeuge_vrp_touren.py." />
|
||||
<figcaption aria-hidden="true">Abb. 8.2: Die Lösung der Instanz aus <code>VRP_Flotten_Routing.py</code>: 16 Kunden, vier Fahrzeuge, 619 km. <strong>Beachten Sie, dass sich die Touren kreuzen.</strong> Bei einem reinen Tourenproblem wäre das ein sicheres Zeichen für eine verbesserbare Lösung — hier ist es keines: Die Zeitfenster erzwingen die Reihenfolge, und wer die Kreuzungen auflöst, kommt zu spät. Erzeugt von <code>bilder_04/erzeuge_vrp_touren.py</code>.</figcaption>
|
||||
|
|
@ -583,7 +583,7 @@ Umschlag -> Kunde_2 5.0 10 3.00 15.00
|
|||
<p><strong>Was Sie auf der Karte sehen — und was nicht.</strong> Die Instanz ist synthetisch: 17 zufällige Punkte auf einem Quadrat von 100 × 100 km. Für die Karte wurden sie <em>lagegetreu</em> auf eine reale Region gelegt — mit einer azimutal-äquidistanten Projektion, die alle 136 Abstände zwischen den Punkten bis auf <strong>0,001 %</strong> erhält. Die Karte zeigt also dieselbe Instanz, mit der das Modell rechnet, nur an geographischen Koordinaten statt auf einem Zahlenraster; kein Wert in diesem Kapitel ändert sich dadurch.</p>
|
||||
<p>Die Touren sind aus demselben Grund <strong>Luftlinien und keine Straßenrouten</strong>: Das Modell kennt keine Straßen, es rechnet mit den Abständen der Distanzmatrix. Eine Linie, die einer echten Straße folgte, wäre hübscher und würde eine Genauigkeit vortäuschen, die das Modell nicht hat. Wer Straßenentfernungen braucht, ersetzt die Matrix — <a href="#sec:graphen-denkfehler">Abschnitt 8.7</a> sagt, was dabei zu beachten ist.</p>
|
||||
<h3 id="kurzzyklen-verhindern">Kurzzyklen verhindern</h3>
|
||||
<p>Ein naives Modell erlaubt <strong>Subtouren</strong>: isolierte Kreise, die das Depot nie anfahren. Die klassische Gegenmaßnahme ist die <strong>MTZ-Formulierung</strong> nach Miller, Tucker und Zemlin. Man führt Rangvariablen <span class="math inline">u_i</span> ein (die Position des Knotens in der Tour):</p>
|
||||
<p>Ein naives Modell erlaubt <strong>Subtouren</strong>: isolierte Kreise, die das Depot nie anfahren. Die klassische Gegenmaßnahme ist die <strong><a href="anhang-glossar.md#gloss:mtz-formulierung" class="glossar-link">MTZ-Formulierung</a></strong> nach Miller, Tucker und Zemlin. Man führt Rangvariablen <span class="math inline">u_i</span> ein (die Position des Knotens in der Tour):</p>
|
||||
<figure>
|
||||
<img src="bilder_04/kap_graphen_subtouren.svg" alt="Abb. 8.3: Links eine Lösung, die jede Gradbedingung erfüllt und trotzdem unbrauchbar ist; rechts dieselbe Instanz mit Kurzzyklus-Bedingungen. Erzeugt von bilder_04/erzeuge_vrp_subtours.py." />
|
||||
<figcaption aria-hidden="true">Abb. 8.3: Links eine Lösung, die jede Gradbedingung erfüllt und trotzdem unbrauchbar ist; rechts dieselbe Instanz mit Kurzzyklus-Bedingungen. Erzeugt von <code>bilder_04/erzeuge_vrp_subtours.py</code>.</figcaption>
|
||||
|
|
@ -597,7 +597,7 @@ u_i - u_j + C \cdot x_{ij} \le C - d_j \qquad \forall i \ne j
|
|||
<p>Wird die Kante nicht benutzt (<span class="math inline">x_{ij} = 0</span>), reduziert sich die Ungleichung auf <span class="math inline">u_i - u_j \le C - d_j</span>, was durch hinreichend großes <span class="math inline">C</span> immer erfüllt ist — das Big-M-Muster aus <a href="milp.html#kap-milp">Kapitel 6</a>.</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p><strong>💡 In der Praxis: nicht selbst modellieren</strong> 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 OR-Tools, <strong>spezialisierte Metaheuristiken</strong>. Nutzen Sie für Routing die <strong>Routing-Bibliothek</strong>, nicht ein selbstgebautes MILP.</p>
|
||||
<p><strong>💡 In der Praxis: nicht selbst modellieren</strong> 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 <a href="anhang-glossar.md#gloss:subtour" class="glossar-link">Subtour</a>-Eliminationsschnitte oder, wie OR-Tools, <strong>spezialisierte Metaheuristiken</strong>. Nutzen Sie für Routing die <strong><a href="anhang-glossar.md#gloss:routing-bibliothek" class="glossar-link">Routing-Bibliothek</a></strong>, nicht ein selbstgebautes MILP.</p>
|
||||
</blockquote>
|
||||
<h3 id="praxisbeispiel-flotten-routing">Praxisbeispiel: Flotten-Routing</h3>
|
||||
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||||
|
|
@ -766,7 +766,7 @@ u_i - u_j + C \cdot x_{ij} \le C - d_j \qquad \forall i \ne j
|
|||
<span id="cb6-164"><a href="#cb6-164" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="va">__name__</span> <span class="op">==</span> <span class="st">"__main__"</span>:</span>
|
||||
<span id="cb6-165"><a href="#cb6-165" aria-hidden="true" tabindex="-1"></a> loese_cvrptw()</span></code></pre></div>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Typische Fehler beim VRP</strong></p>
|
||||
<p><strong>⚠️ Typische Fehler beim <a href="anhang-glossar.md#gloss:vehicle-routing-problem-vrp" class="glossar-link">VRP</a></strong></p>
|
||||
<ul>
|
||||
<li><strong><code>Min(CumulVar)</code> mit „Ankunftszeit“ verwechseln.</strong> Der Solver liefert ein <em>Intervall</em> möglicher Zeiten. <code>Min()</code> ist die früheste, <code>Max()</code> die späteste zulässige Zeit — die tatsächliche Fahrt kann irgendwo dazwischen starten.</li>
|
||||
<li><strong>Servicezeit im Depot mitzählen.</strong> Beim Start am Depot fällt keine Servicezeit an, sonst verschiebt sich der ganze Plan.</li>
|
||||
|
|
@ -1020,7 +1020,7 @@ plausibel aussieht.
|
|||
<ul>
|
||||
<li><strong>Eine Dimension vergessen.</strong> Ladung, Lenkzeit, Kühlkette, Gewicht <em>und</em> Volumen — jede Größe, die begrenzt ist, braucht ihre eigene Dimension. Zählen Sie sie vor dem Modellieren auf einem Blatt Papier auf.</li>
|
||||
<li><strong>Die Prüfung aus denselben Bausteinen bauen wie das Modell.</strong> Wer die Ladung mit <code>loesung.Value(ladungs_dimension.CumulVar(...))</code> prüft, fragt das Modell, ob es sich an sich selbst hält. Rechnen Sie stattdessen aus der <strong>ausgegebenen Tour</strong> neu nach.</li>
|
||||
<li><strong>Zwei Läufe nur an der Zielfunktion vergleichen.</strong> 326 gegen 572 km sagt nichts, solange nicht feststeht, dass beide Pläne überhaupt fahrbar sind.</li>
|
||||
<li><strong>Zwei Läufe nur an der <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a> vergleichen.</strong> 326 gegen 572 km sagt nichts, solange nicht feststeht, dass beide Pläne überhaupt fahrbar sind.</li>
|
||||
<li><strong>Unbenutzte Fahrzeuge übersehen.</strong> Drei Fahrzeuge, die im Depot stehen, während eines alles fährt, sind fast immer ein Zeichen für eine fehlende Beschränkung.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
|
@ -1052,14 +1052,14 @@ plausibel aussieht.
|
|||
<ul>
|
||||
<li><strong>Graphen</strong> sind die natürliche Sprache für Transport-, Zuordnungs- und Routenprobleme.</li>
|
||||
<li><strong>Flusserhaltung</strong> ist die Kirchhoff-Regel des Operations Research: Was hineingeht, kommt heraus — abzüglich des Knotensaldos.</li>
|
||||
<li><strong>Totale Unimodularität</strong> macht Fluss- und Zuordnungsprobleme „von selbst“ ganzzahlig. Wer hier <code>integrality</code> setzt, verschenkt Laufzeit ohne Gegenwert.</li>
|
||||
<li><strong><a href="anhang-glossar.md#gloss:totale-unimodularitaet" class="glossar-link">Totale Unimodularität</a></strong> macht Fluss- und Zuordnungsprobleme „von selbst“ ganzzahlig. Wer hier <code>integrality</code> setzt, verschenkt Laufzeit ohne Gegenwert.</li>
|
||||
<li><strong>Spezialisierte Algorithmen schlagen allgemeine Solver</strong> deutlich: Der Ungarische Algorithmus löst in <span class="math inline">O(n^3)</span>, wofür ein MILP-Solver Branch-and-Bound bräuchte.</li>
|
||||
<li><strong>Für Routing gilt: Nutzen Sie die Routing-Bibliothek.</strong> Metaheuristiken liefern in Sekunden sehr gute Touren; exakte Optimalität ist bei realistischen Größen unrealistisch und praktisch entbehrlich.</li>
|
||||
<li><strong>Die Routing-Bibliothek kennt nur Dimensionen.</strong> Ladung, Lenkzeit, Kühlkette, Gewicht — jede begrenzte Größe braucht ihre eigene. Was nicht als Dimension angelegt ist, wird nicht begrenzt, und der Solver meldet stolz eine kürzere Strecke.</li>
|
||||
<li><strong>Totale Unimodularität ist zerbrechlich.</strong> Eine einzige zusätzliche Bedingung, die nicht ins Schema passt — Kardinalität, Fixkosten, Mindestmenge —, zerstört sie. Prüfen Sie das, bevor Sie sich auf die Struktur verlassen.</li>
|
||||
<li><strong>Der beste erste Zug ist selten Teil der besten Gesamtlösung.</strong> Gierige Regeln kosten schon bei vier Zuordnungen 8 %.</li>
|
||||
</ul>
|
||||
<p><strong>Ausblick.</strong> <a href="qp-nlp.html#teil-nichtlinear">Teil III</a> verlässt die lineare Welt. <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a> führt quadratische Zielfunktionen und die KKT-Bedingungen ein — das mathematische Fundament der Portfoliooptimierung.</p>
|
||||
<p><strong>Ausblick.</strong> <a href="qp-nlp.html#teil-nichtlinear">Teil III</a> verlässt die lineare Welt. <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a> führt quadratische Zielfunktionen und die <a href="anhang-glossar.md#gloss:karush-kuhn-tucker-bedingungen-kkt" class="glossar-link">KKT</a>-Bedingungen ein — das mathematische Fundament der Portfoliooptimierung.</p>
|
||||
|
||||
</article>
|
||||
<button type="button" class="fortschritt-knopf" data-kapitel="graphen.html"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg> <span>Als gelesen markieren</span></button>
|
||||
|
|
|
|||
18
OR_HTML_04/handelsmaschine.html
generated
18
OR_HTML_04/handelsmaschine.html
generated
|
|
@ -103,9 +103,9 @@
|
|||
<div class="card card-blick">
|
||||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um das Zusammenführen von allem: Datenpipeline, Signal, Optimierung, Rebalancing, Kostenverbuchung und ein Backtest, der nicht lügt.</p>
|
||||
<p><strong>Worum geht es?</strong> Um das Zusammenführen von allem: Datenpipeline, Signal, Optimierung, <a href="anhang-glossar.md#gloss:rebalancing" class="glossar-link">Rebalancing</a>, Kostenverbuchung und ein <a href="anhang-glossar.md#gloss:backtest" class="glossar-link">Backtest</a>, der nicht lügt.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> bis <a href="cvar.html#kap-cvar">Kapitel 20</a>.</p>
|
||||
<p><strong>Danach können Sie:</strong> Eine Walk-Forward-Backtest-Architektur bauen, Lookahead-Bias vermeiden, Ergebnisse gegen eine Benchmark bewerten und typische Backtest-Fallen erkennen.</p>
|
||||
<p><strong>Danach können Sie:</strong> Eine <a href="anhang-glossar.md#gloss:walk-forward-backtest" class="glossar-link">Walk-Forward-Backtest</a>-Architektur bauen, <a href="anhang-glossar.md#gloss:lookahead-bias" class="glossar-link">Lookahead-Bias</a> vermeiden, Ergebnisse gegen eine Benchmark bewerten und typische Backtest-Fallen erkennen.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 6 Stunden.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>QuantitativeTradingEngine.py</code><br />
|
||||
|
|
@ -162,7 +162,7 @@ geballt Jahresrendite 8.88 % Sharpe 0.61 max. Rueckschlag -98.7 %</code></
|
|||
<li>… die sechs Bausteine einer quantitativen Engine benennen und ihre Reihenfolge begründen.</li>
|
||||
<li>… einen Walk-Forward-Backtest ohne Lookahead-Bias implementieren.</li>
|
||||
<li>… Rebalancing-Termine korrekt auf Handelstage abbilden.</li>
|
||||
<li>… Transaktionskosten und Gewichtsdrift realistisch verbuchen.</li>
|
||||
<li>… <a href="anhang-glossar.md#gloss:transaktionskosten" class="glossar-link">Transaktionskosten</a> und Gewichtsdrift realistisch verbuchen.</li>
|
||||
<li>… Backtest-Ergebnisse kritisch prüfen und die typischen Selbsttäuschungen erkennen.</li>
|
||||
<li>… den maximalen Rückschlag als eigenständige Kennzahl berichten und begründen, warum Rendite und Sharpe allein nichts über den Verlauf aussagen.</li>
|
||||
<li>… die Zahl der ausprobierten Varianten protokollieren und die Signifikanzschwelle entsprechend korrigieren.</li>
|
||||
|
|
@ -714,7 +714,7 @@ FEHLER 1+2+3 kombiniert 25.41 % +19.80 %
|
|||
<p><strong>Lesen Sie diese Tabelle sehr genau.</strong> Die zugrunde liegenden Daten sind <strong>reiner Zufall</strong> — es gibt keinerlei Prognosekraft, kein Signal, keine Struktur. Trotzdem:</p>
|
||||
<ul>
|
||||
<li><strong>Lookahead</strong> erzeugt eine scheinbare Überrendite von <strong>15,4 Prozentpunkten pro Jahr</strong>. Ein einziger falscher Index — <code>iloc[t+1]</code> statt <code>iloc[t]</code> — verwandelt Rauschen in eine scheinbar brillante Strategie.</li>
|
||||
<li><strong>Survivorship-Bias</strong> liefert <strong>13,1 Prozentpunkte</strong> allein dadurch, dass man das Universum im Nachhinein auf die Gewinner beschränkt.</li>
|
||||
<li><strong><a href="anhang-glossar.md#gloss:survivorship-bias" class="glossar-link">Survivorship-Bias</a></strong> liefert <strong>13,1 Prozentpunkte</strong> allein dadurch, dass man das Universum im Nachhinein auf die Gewinner beschränkt.</li>
|
||||
<li>Selbst die <strong>ehrliche</strong> Variante zeigt noch +1,1 Prozentpunkte — reines Rauschen, das aber ohne Weiteres als „leichte Outperformance“ verkauft werden könnte.</li>
|
||||
</ul>
|
||||
<p><strong>Die Lehre:</strong> Wenn Sie in einem Backtest eine Überrendite von 15 % sehen, ist die erste Frage nicht „Wie kann ich das nutzen?“, sondern <strong>„Wo ist mein Fehler?“</strong>. Und wenn Sie keinen finden, suchen Sie weiter — die Wahrscheinlichkeit, dass Sie tatsächlich eine Goldader entdeckt haben, ist deutlich kleiner als die, dass ein Index verrutscht ist.</p>
|
||||
|
|
@ -755,15 +755,15 @@ FEHLER 1+2+3 kombiniert 25.41 % +19.80 %
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td>4</td>
|
||||
<td><strong>Overfitting</strong></td>
|
||||
<td>Parameter auf die Vergangenheit getrimmt</td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:overfitting" class="glossar-link">Overfitting</a></strong></td>
|
||||
<td><a href="anhang-glossar.md#gloss:parameter" class="glossar-link">Parameter</a> auf die Vergangenheit getrimmt</td>
|
||||
<td>Out-of-Sample-Zeitraum strikt zurückhalten</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>5</td>
|
||||
<td><strong>Data Snooping</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:data-snooping" class="glossar-link">Data Snooping</a></strong></td>
|
||||
<td>Viele Varianten getestet, beste berichtet</td>
|
||||
<td>Zahl der Versuche protokollieren; Deflated Sharpe Ratio</td>
|
||||
<td>Zahl der Versuche protokollieren; Deflated <a href="anhang-glossar.md#gloss:sharpe-ratio" class="glossar-link">Sharpe Ratio</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -805,7 +805,7 @@ FEHLER 1+2+3 kombiniert 25.41 % +19.80 %
|
|||
<tr class="even">
|
||||
<td><strong>Betriebsrisiken</strong></td>
|
||||
<td>Was, wenn der Datenfeed ausfällt?</td>
|
||||
<td>Fallback-Strategie, Monitoring</td>
|
||||
<td><a href="anhang-glossar.md#gloss:fallback-strategie" class="glossar-link">Fallback-Strategie</a>, Monitoring</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>Regulatorik</strong></td>
|
||||
|
|
|
|||
2
OR_HTML_04/index.html
generated
2
OR_HTML_04/index.html
generated
|
|
@ -115,7 +115,7 @@
|
|||
<p class="hero-anwendungen">Mit Python planen, optimieren und entscheiden: von Personal, Schichten und Logistik über Energie, Ressourcen und Netzwerke bis zur Portfoliooptimierung an den Finanzmärkten.</p>
|
||||
<p class="hero-autor">Autor / Herausgeber: Dieter Schlüter<br>
|
||||
<dieter(dot)schlueter(atsign)linix(dot)de><br>
|
||||
Stand: 10. September 2026 v16.11</p>
|
||||
Stand: 10. September 2026 v17.39</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="einstieg">
|
||||
|
|
|
|||
30
OR_HTML_04/lp.html
generated
30
OR_HTML_04/lp.html
generated
|
|
@ -107,17 +107,17 @@
|
|||
<figcaption aria-hidden="true">Entscheidungsdiagramm: Welches Werkzeug passt zu meinem Problem? (Teil II)</figcaption>
|
||||
</figure>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Merksatz zum Diagramm</strong> Die erste Frage ist die wichtigste — und sie lautet <strong>nicht</strong> „welcher Solver ist der schnellste?“, sondern „welche <strong>Struktur</strong> hat mein Problem?“. Ein Zuordnungsproblem braucht keinen MILP-Solver, sondern eine Zeile <code>linear_sum_assignment</code>. Ein Dienstplan gehört nicht in ein LP, sondern zu CP-SAT. Wer die Struktur erkennt, hat die halbe Laufzeit gespart, bevor die erste Zeile Code geschrieben ist.</p>
|
||||
<p><strong>🎯 Merksatz zum Diagramm</strong> Die erste Frage ist die wichtigste — und sie lautet <strong>nicht</strong> „welcher <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> ist der schnellste?“, sondern „welche <strong>Struktur</strong> hat mein Problem?“. Ein <a href="anhang-glossar.md#gloss:zuordnungsproblem" class="glossar-link">Zuordnungsproblem</a> braucht keinen <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a>-Solver, sondern eine Zeile <code>linear_sum_assignment</code>. Ein Dienstplan gehört nicht in ein <a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a>, sondern zu <a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a>. Wer die Struktur erkennt, hat die halbe Laufzeit gespart, bevor die erste Zeile Code geschrieben ist.</p>
|
||||
</blockquote>
|
||||
<p>Fällt Ihr Problem durch das Diagramm hindurch — nichtlineare Zielfunktion, unsichere Daten, Entscheidungen über mehrere Zeitstufen —, dann ist <a href="qp-nlp.html#teil-nichtlinear">Teil III</a> der richtige Ort. Dort steht ein zweites Diagramm für genau diese Fälle.</p>
|
||||
<p>Fällt Ihr Problem durch das Diagramm hindurch — nichtlineare <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a>, unsichere Daten, Entscheidungen über mehrere Zeitstufen —, dann ist <a href="qp-nlp.html#teil-nichtlinear">Teil III</a> der richtige Ort. Dort steht ein zweites Diagramm für genau diese Fälle.</p>
|
||||
<hr />
|
||||
<h1 id="kap-lp">Kapitel 5: Lineare Programmierung — Simplex, Dualität und Schattenpreise</h1>
|
||||
<div class="card card-blick">
|
||||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um das Kernverfahren des Operations Research. Wir bauen den Simplex-Algorithmus selbst — nicht um ihn zu verwenden, sondern um zu verstehen, woher <strong>Schattenpreise</strong> kommen. Sie sind das wertvollste Nebenprodukt jeder Optimierung.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="fundament.html#kap-fundament">Kapitel 2</a> (Matrixform, Polyeder, Ecken).</p>
|
||||
<p><strong>Danach können Sie:</strong> Ein LP in Standardform bringen, den Simplex von Hand rechnen, Dualwerte interpretieren, daraus wirtschaftliche Handlungsempfehlungen ableiten — und erkennen, wann ein Schattenpreis eine Entscheidung <strong>nicht</strong> tragen darf.</p>
|
||||
<p><strong>Worum geht es?</strong> Um das Kernverfahren des Operations Research. Wir bauen den <a href="anhang-glossar.md#gloss:simplex-algorithmus" class="glossar-link">Simplex-Algorithmus</a> selbst — nicht um ihn zu verwenden, sondern um zu verstehen, woher <strong>Schattenpreise</strong> kommen. Sie sind das wertvollste Nebenprodukt jeder Optimierung.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="fundament.html#kap-fundament">Kapitel 2</a> (Matrixform, <a href="anhang-glossar.md#gloss:polyeder" class="glossar-link">Polyeder</a>, Ecken).</p>
|
||||
<p><strong>Danach können Sie:</strong> Ein LP in Standardform bringen, den Simplex von Hand rechnen, Dualwerte interpretieren, daraus wirtschaftliche Handlungsempfehlungen ableiten — und erkennen, wann ein <a href="anhang-glossar.md#gloss:schattenpreis" class="glossar-link">Schattenpreis</a> eine Entscheidung <strong>nicht</strong> tragen darf.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 7 Stunden — das umfangreichste Kapitel von <a href="#teil-kernverfahren">Teil II</a>.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>Simplex_Tableau_LP.py</code><br />
|
||||
|
|
@ -162,7 +162,7 @@
|
|||
</tbody>
|
||||
</table>
|
||||
<p>Der Betriebsrat hat 20 Überstunden genehmigt. <strong>In welchem Bereich sollen sie eingesetzt werden?</strong></p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> linprog</span>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> [linprog](anhang<span class="op">-</span>glossar.md<span class="co">#gloss:linprog){.glossar-link}</span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Deckungsbeitrag je Stueck (negiert, weil linprog minimiert)</span></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>c <span class="op">=</span> [<span class="op">-</span><span class="dv">90</span>, <span class="op">-</span><span class="dv">140</span>]</span>
|
||||
|
|
@ -198,9 +198,9 @@
|
|||
<li>… eine Simplex-Iteration von Hand rechnen: Pivotspalte, Pivotzeile, Basistausch.</li>
|
||||
<li>… erklären, warum das Verfahren terminiert und warum es das Optimum findet.</li>
|
||||
<li>… das duale Problem zu einem gegebenen primalen aufstellen.</li>
|
||||
<li>… <strong>Schattenpreise</strong> korrekt auslesen und interpretieren — inklusive der Vorzeichenfalle, die einer der häufigsten Fehler bei der Sensitivitätsanalyse ist.</li>
|
||||
<li>… <strong>Schattenpreise</strong> korrekt auslesen und interpretieren — inklusive der Vorzeichenfalle, die einer der häufigsten Fehler bei der <a href="anhang-glossar.md#gloss:sensitivitaetsanalyse" class="glossar-link">Sensitivitätsanalyse</a> ist.</li>
|
||||
<li>… aus einer Sensitivitätsanalyse eine begründete Kaufentscheidung ableiten.</li>
|
||||
<li>… ein Modell auf <strong>Entartung</strong> prüfen und statt eines nicht eindeutigen Schattenpreises dessen belastbare Spanne berechnen.</li>
|
||||
<li>… ein Modell auf <strong><a href="anhang-glossar.md#gloss:entartung" class="glossar-link">Entartung</a></strong> prüfen und statt eines nicht eindeutigen Schattenpreises dessen belastbare Spanne berechnen.</li>
|
||||
<li>… erklären, warum Zulässigkeit immer gegen eine Toleranz und nie mit <code>== 0</code> geprüft wird.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
|
|
@ -251,7 +251,7 @@
|
|||
<p>Der von George Dantzig 1947 formulierte Simplex-Algorithmus nutzt den Fundamentalsatz aus <a href="fundament.html#kap-fundament">Kapitel 2</a>: <strong>Das Optimum liegt in einer Ecke.</strong> Statt alle Ecken aufzuzählen, wandert er von Ecke zu Ecke — und zwar immer in Richtung Verbesserung.</p>
|
||||
<figure>
|
||||
<img src="bilder_04/kap_lp_simplex_ecken.svg" alt="Abb. 5.1: Derselbe zulässige Bereich, aber der Weg der Handrechnung weiter unten: vom Ursprung über (0; 8) zum Optimum (7,5; 5). Drei der fünf Ecken werden besucht, keine zweimal — das ist der ganze Gewinn gegenüber dem Aufzählen aller Ecken. Punktiert die Niveaulinien der Zielfunktion, der Pfeil ihr Gradient \mathbf{c}. Erzeugt von bilder_04/erzeuge_polyeder.py." />
|
||||
<figcaption aria-hidden="true">Abb. 5.1: Derselbe zulässige Bereich, aber der Weg der Handrechnung weiter unten: vom Ursprung über (0; 8) zum Optimum (7,5; 5). Drei der fünf Ecken werden besucht, keine zweimal — das ist der ganze Gewinn gegenüber dem Aufzählen aller Ecken. Punktiert die Niveaulinien der Zielfunktion, der Pfeil ihr Gradient <span class="math inline">\mathbf{c}</span>. Erzeugt von <code>bilder_04/erzeuge_polyeder.py</code>.</figcaption>
|
||||
<figcaption aria-hidden="true">Abb. 5.1: Derselbe zulässige Bereich, aber der Weg der Handrechnung weiter unten: vom Ursprung über (0; 8) zum Optimum (7,5; 5). Drei der fünf Ecken werden besucht, keine zweimal — das ist der ganze Gewinn gegenüber dem Aufzählen aller Ecken. Punktiert die Niveaulinien der Zielfunktion, der Pfeil ihr <a href="anhang-glossar.md#gloss:gradient" class="glossar-link">Gradient</a> <span class="math inline">\mathbf{c}</span>. Erzeugt von <code>bilder_04/erzeuge_polyeder.py</code>.</figcaption>
|
||||
</figure>
|
||||
<p><strong>Was Sie in der Abbildung sehen.</strong> 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 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.</p>
|
||||
<h3 id="der-ablauf">Der Ablauf</h3>
|
||||
|
|
@ -682,7 +682,7 @@ Optimum nach 2 Pivotschritten erreicht.
|
|||
<ul>
|
||||
<li><strong>Negative rechte Seite.</strong> <span class="math inline">-3x_1 - 2x_2 \le -12</span> (aus einer „<span class="math inline">\ge</span>“-Bedingung entstanden) macht den Ursprung unzulässig. Dann braucht man Phase 1 mit künstlichen Variablen. Dieser Solver meldet das jetzt ehrlich.</li>
|
||||
<li><strong>Zyklen bei Entartung.</strong> Wenn mehrere Quotienten gleich sind, kann der Simplex theoretisch endlos kreisen. In der Praxis extrem selten; Bland’s Regel verhindert es beweisbar.</li>
|
||||
<li><strong>Den Simplex selbst produktiv einsetzen.</strong> Diese Implementierung ist ein Lehrmodell. HiGHS ist um Größenordnungen schneller und numerisch stabiler.</li>
|
||||
<li><strong>Den Simplex selbst produktiv einsetzen.</strong> Diese Implementierung ist ein Lehrmodell. <a href="anhang-glossar.md#gloss:highs" class="glossar-link">HiGHS</a> ist um Größenordnungen schneller und numerisch stabiler.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<hr />
|
||||
|
|
@ -1120,7 +1120,7 @@ Pruefung: komplementaerer Schlupf fuer alle Ressourcen erfuellt.
|
|||
<ol type="1">
|
||||
<li><strong><code>schattenpreise = -ergebnis.ineqlin.marginals</code></strong> — die eigentliche Korrektur.</li>
|
||||
<li><strong>Numerische Gegenprobe:</strong> Das Modell wird mit <span class="math inline">b_3 + 1</span> 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.</li>
|
||||
<li><strong>Komplementärer Schlupf:</strong> <span class="math inline">s_i \cdot y_i = 0</span> muss für alle <span class="math inline">i</span> gelten.</li>
|
||||
<li><strong><a href="anhang-glossar.md#gloss:komplementaerer-schlupf" class="glossar-link">Komplementärer Schlupf</a>:</strong> <span class="math inline">s_i \cdot y_i = 0</span> muss für alle <span class="math inline">i</span> gelten.</li>
|
||||
</ol>
|
||||
<p><strong>Übernehmen Sie dieses Muster in eigene Projekte.</strong> Der Aufwand ist eine Handvoll Zeilen, der Nutzen ist die Gewissheit, dass Ihre Handlungsempfehlung nicht das Gegenteil des Richtigen sagt.</p>
|
||||
</blockquote>
|
||||
|
|
@ -1158,7 +1158,7 @@ Pruefung: komplementaerer Schlupf fuer alle Ressourcen erfuellt.
|
|||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td>Dual Simplex</td>
|
||||
<td><a href="anhang-glossar.md#gloss:dual-simplex" class="glossar-link">Dual Simplex</a></td>
|
||||
<td><span class="math inline">(0{,}33;\ 0{,}33;\ 0)</span></td>
|
||||
<td>„Fräse und Schleiferei sind die Engpässe, die Prüfung ist wertlos.“</td>
|
||||
</tr>
|
||||
|
|
@ -1190,7 +1190,7 @@ Pruefung: komplementaerer Schlupf fuer alle Ressourcen erfuellt.
|
|||
<tr class="odd">
|
||||
<td><strong>Primale Zulässigkeit</strong></td>
|
||||
<td>Wie weit darf <span class="math inline">\mathbf{A}\mathbf{x}</span> die Schranke <span class="math inline">\mathbf{b}</span> überschreiten?</td>
|
||||
<td><span class="math inline">10^{-7}</span> (HiGHS), <span class="math inline">10^{-6}</span> (CP-SAT)</td>
|
||||
<td><span class="math inline">10^{-7}</span> (HiGHS), <span class="math inline">10^{-6}</span> (<a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a>)</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>Duale Zulässigkeit</strong> (Optimalität)</td>
|
||||
|
|
@ -1534,7 +1534,7 @@ brauchbare Aussage. Ein erfundener Einzelwert ist es nicht.</code></pre>
|
|||
<p><strong>Aufgabe 5.1 ⭐ — Schlupf deuten.</strong> Ein LP liefert <span class="math inline">s = (0;\ 12{,}5;\ 0;\ 3)</span> und <span class="math inline">y = (4{,}2;\ 0;\ 9{,}8;\ 0)</span>. (a) Welche Ressourcen sind Engpässe? (b) Ist die Lösung mit dem Satz vom komplementären Schlupf verträglich? (c) In welche Ressource würden Sie zuerst investieren?</p>
|
||||
<p><strong>Aufgabe 5.2 ⭐ — Vorzeichen prüfen.</strong> Ein Kollege maximiert Gewinn mit <code>linprog</code> und meldet: „Der Schattenpreis der Engpassmaschine ist <span class="math inline">-45</span> €.“ Was ist passiert, und wie lautet der korrekte Wert?</p>
|
||||
<p><strong>Aufgabe 5.3 ⭐⭐ — Simplex von Hand.</strong> Lösen Sie mit dem Tableau-Verfahren vollständig von Hand: <span class="math display">\max\ 5x_1 + 4x_2 \quad \text{u. d. N.}\quad 6x_1+4x_2 \le 24,\quad x_1+2x_2 \le 6,\quad x_1,x_2\ge0</span> Geben Sie jedes Zwischentableau an und lesen Sie am Ende Lösung <strong>und</strong> Schattenpreise ab. Prüfen Sie mit <code>scipy.optimize.linprog</code>.</p>
|
||||
<p><strong>Aufgabe 5.4 ⭐⭐ — Duales Problem aufstellen.</strong> Stellen Sie zum Modell aus der Aufgabe <em>Simplex von Hand</em> das duale Problem auf, lösen Sie es mit <code>linprog</code> und weisen Sie den starken Dualitätssatz numerisch nach.</p>
|
||||
<p><strong>Aufgabe 5.4 ⭐⭐ — <a href="anhang-glossar.md#gloss:duales-problem" class="glossar-link">Duales Problem</a> aufstellen.</strong> Stellen Sie zum Modell aus der Aufgabe <em>Simplex von Hand</em> das duale Problem auf, lösen Sie es mit <code>linprog</code> und weisen Sie den starken Dualitätssatz numerisch nach.</p>
|
||||
<p><strong>Aufgabe 5.5 ⭐⭐ — Unbeschränktheit erkennen.</strong> Was liefert <code>SimplexTableauSolver</code> für <span class="math inline">\max x_1 + x_2</span> u. d. N. <span class="math inline">x_1 - x_2 \le 5</span>, <span class="math inline">x_1, x_2 \ge 0</span>? Erklären Sie die Fehlermeldung geometrisch.</p>
|
||||
<p><strong>Aufgabe 5.6 ⭐⭐⭐ — Gültigkeitsbereich des Schattenpreises.</strong> Erweitern Sie <code>Sensitivitaetsanalyse.py</code>: Lösen Sie das Modell für Prüfkapazitäten von 30 bis 120 Stunden (Schrittweite 5) und tragen Sie Gewinn und Schattenpreis gegen die Kapazität auf. (a) Ab welcher Kapazität fällt der Schattenpreis auf einen niedrigeren Wert? Warum? (b) Wie viele Stunden sollte der Betrieb bei einem Angebotspreis von 18 €/h <strong>maximal</strong> zukaufen? (c) Zeichnen Sie den Gewinnverlauf. Was für eine Kurvenform ergibt sich, und warum?</p>
|
||||
<p><strong>Aufgabe 5.7 ⭐⭐⭐ — Phase 1 ergänzen.</strong> Erweitern Sie den <code>SimplexTableauSolver</code> um eine Phase-1-Rechnung mit künstlichen Variablen, sodass auch <span class="math inline">b_i < 0</span> verarbeitet werden kann. Testen Sie an: <span class="math display">\max\ 3x_1+2x_2 \quad\text{u. d. N.}\quad x_1+x_2 \ge 4,\quad x_1+3x_2 \le 12,\quad x_1,x_2\ge0</span></p>
|
||||
|
|
@ -1594,7 +1594,7 @@ brauchbare Aussage. Ein erfundener Einzelwert ist es nicht.</code></pre>
|
|||
<li><strong>Schattenpreise</strong> beantworten die Managementfrage schlechthin: Wo ist der Engpass, und was ist seine Beseitigung wert?</li>
|
||||
<li><strong>Vorzeichen prüfen!</strong> Nach einer Negation der Zielfunktion müssen die Dualwerte zurücknegiert werden. Die numerische Gegenprobe („Kapazität um 1 erhöhen und neu lösen“) ist die sicherste Kontrolle.</li>
|
||||
</ul>
|
||||
<p><strong>Ausblick.</strong> <a href="milp.html#kap-milp">Kapitel 6</a> 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.</p>
|
||||
<p><strong>Ausblick.</strong> <a href="milp.html#kap-milp">Kapitel 6</a> 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 <a href="anhang-glossar.md#gloss:branch-and-bound" class="glossar-link">Branch-and-Bound</a> kennen.</p>
|
||||
|
||||
</article>
|
||||
<button type="button" class="fortschritt-knopf" data-kapitel="lp.html"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg> <span>Als gelesen markieren</span></button>
|
||||
|
|
|
|||
26
OR_HTML_04/markowitz.html
generated
26
OR_HTML_04/markowitz.html
generated
|
|
@ -104,8 +104,8 @@
|
|||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um das Modell, das 1952 die quantitative Finanzwirtschaft begründete — und um die Restriktionen, ohne die es in der Praxis unbrauchbar bleibt.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a> (QP, KKT), <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> (Kovarianz, Shrinkage).</p>
|
||||
<p><strong>Danach können Sie:</strong> Die Effizienzgrenze berechnen, das Maximum-Sharpe-Portfolio über die Korn-Transformation bestimmen, institutionelle Nebenbedingungen einbauen — und beurteilen, wann eine Renditeschätzung das Ergebnis wertlos macht.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a> (<a href="anhang-glossar.md#gloss:quadratische-programmierung-qp" class="glossar-link">QP</a>, <a href="anhang-glossar.md#gloss:karush-kuhn-tucker-bedingungen-kkt" class="glossar-link">KKT</a>), <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> (Kovarianz, Shrinkage).</p>
|
||||
<p><strong>Danach können Sie:</strong> Die Effizienzgrenze berechnen, das Maximum-Sharpe-Portfolio über die <a href="anhang-glossar.md#gloss:korn-transformation" class="glossar-link">Korn-Transformation</a> bestimmen, institutionelle Nebenbedingungen einbauen — und beurteilen, wann eine Renditeschätzung das Ergebnis wertlos macht.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 6 Stunden.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>Diversifikation_Demo.py</code><br />
|
||||
|
|
@ -153,9 +153,9 @@
|
|||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>mu <span class="op">=</span> np.array([<span class="fl">0.03</span>, <span class="fl">0.08</span>, <span class="fl">0.055</span>]) <span class="co"># erwartete Rendite</span></span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>sig <span class="op">=</span> np.array([<span class="fl">0.05</span>, <span class="fl">0.18</span>, <span class="fl">0.11</span>]) <span class="co"># Schwankung</span></span>
|
||||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>R <span class="op">=</span> np.array([[<span class="fl">1.0</span>, <span class="fl">0.1</span>, <span class="fl">0.2</span>], [<span class="fl">0.1</span>, <span class="fl">1.0</span>, <span class="fl">0.5</span>], [<span class="fl">0.2</span>, <span class="fl">0.5</span>, <span class="fl">1.0</span>]])</span>
|
||||
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>S <span class="op">=</span> np.outer(sig, sig) <span class="op">*</span> R <span class="co"># Kovarianzmatrix</span></span>
|
||||
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>S <span class="op">=</span> np.outer(sig, sig) <span class="op">*</span> R <span class="co"># [Kovarianzmatrix](anhang-glossar.md#gloss:kovarianzmatrix){.glossar-link}</span></span>
|
||||
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>w, ziel <span class="op">=</span> cp.Variable(<span class="dv">3</span>, nonneg<span class="op">=</span><span class="va">True</span>), cp.Parameter(nonneg<span class="op">=</span><span class="va">True</span>)</span>
|
||||
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>w, ziel <span class="op">=</span> cp.Variable(<span class="dv">3</span>, nonneg<span class="op">=</span><span class="va">True</span>), cp.[Parameter](anhang<span class="op">-</span>glossar.md<span class="co">#gloss:parameter){.glossar-link}(nonneg=True)</span></span>
|
||||
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>problem <span class="op">=</span> cp.Problem(cp.Minimize(cp.quad_form(w, S)),</span>
|
||||
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a> [cp.<span class="bu">sum</span>(w) <span class="op">==</span> <span class="dv">1</span>, mu <span class="op">@</span> w <span class="op">>=</span> ziel])</span>
|
||||
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a></span>
|
||||
|
|
@ -179,13 +179,13 @@
|
|||
<ul>
|
||||
<li>Bei 3 % Zielrendite: 0,69 — das Portfolio ist sicher, aber lässt Ertrag liegen.</li>
|
||||
<li>Bei <strong>4 %</strong>: <strong>0,75</strong> — das beste Verhältnis.</li>
|
||||
<li>Bei 8 %: 0,44 — das renditestärkste Portfolio ist das <strong>schlechteste</strong> je Risikoeinheit. Und es besteht zu 100 % aus Aktien: Wer die höchste Rendite fordert, bekommt zwangsläufig gar keine Diversifikation mehr.</li>
|
||||
<li>Bei 8 %: 0,44 — das renditestärkste Portfolio ist das <strong>schlechteste</strong> je Risikoeinheit. Und es besteht zu 100 % aus Aktien: Wer die höchste Rendite fordert, bekommt zwangsläufig gar keine <a href="anhang-glossar.md#gloss:diversifikation" class="glossar-link">Diversifikation</a> mehr.</li>
|
||||
</ul>
|
||||
<p>Von 3 % auf 8 % Rendite ist ein Zuwachs um Faktor 2,7 — das Risiko steigt dabei um Faktor 3,7. Die letzten Prozentpunkte Rendite sind die teuersten.</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Ein Optimierer beantwortet nicht die Frage „was soll ich tun?“, sondern „was ist erreichbar?“. Die Effizienzlinie ist eine <strong>Speisekarte</strong>, keine Empfehlung. Welche Zeile die richtige ist, hängt von der Risikotragfähigkeit ab — und das ist keine mathematische, sondern eine unternehmerische Frage.</p>
|
||||
</blockquote>
|
||||
<p><strong>Warum funktioniert das?</strong> Weil <code>cp.Parameter</code> das Modell nur <strong>einmal</strong> aufbaut und dann sechsmal mit verschiedenen Zielwerten löst. Genau dafür gibt es Parameter in CVXPY: Bei 200 Punkten auf der Linie spart das den 200-fachen Kompilierungsaufwand (<a href="oekosystem.html#sec:oekosystem-vektorisierung">Abschnitt 3.8</a>). Der Rest dieses Kapitels führt die Effizienzlinie sauber aus, zeigt, wie man das beste Verhältnis direkt berechnet statt es abzulesen — und warum das Ganze mit geschätzten Renditen gefährlicher ist, als es hier aussieht.</p>
|
||||
<p><strong>Warum funktioniert das?</strong> Weil <code>cp.Parameter</code> das Modell nur <strong>einmal</strong> aufbaut und dann sechsmal mit verschiedenen Zielwerten löst. Genau dafür gibt es Parameter in <a href="anhang-glossar.md#gloss:cvxpy" class="glossar-link">CVXPY</a>: Bei 200 Punkten auf der Linie spart das den 200-fachen Kompilierungsaufwand (<a href="oekosystem.html#sec:oekosystem-vektorisierung">Abschnitt 3.8</a>). Der Rest dieses Kapitels führt die Effizienzlinie sauber aus, zeigt, wie man das beste Verhältnis direkt berechnet statt es abzulesen — und warum das Ganze mit geschätzten Renditen gefährlicher ist, als es hier aussieht.</p>
|
||||
<hr />
|
||||
<h2 id="sec:markowitz-lernziele">19.2 Lernziele</h2>
|
||||
<p>Nach diesem Kapitel können Sie …</p>
|
||||
|
|
@ -345,7 +345,7 @@ obwohl Formel und Simulation nichts voneinander wissen.</code></pre>
|
|||
<tr class="odd">
|
||||
<td><span class="math inline">0</span></td>
|
||||
<td>Risiko zählt allein</td>
|
||||
<td><strong>GMV</strong> — Global Minimum Variance Portfolio</td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:global-minimum-variance-portfolio-gmv" class="glossar-link">GMV</a></strong> — Global Minimum Variance Portfolio</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>mittel</td>
|
||||
|
|
@ -440,12 +440,12 @@ obwohl Formel und Simulation nichts voneinander wissen.</code></pre>
|
|||
<img src="bilder_04/kap12_efficient_frontier.svg" alt="Abb. 19.1: Efficient Frontier und Tangential-Portfolio" />
|
||||
<figcaption aria-hidden="true">Abb. 19.1: Efficient Frontier und Tangential-Portfolio</figcaption>
|
||||
</figure>
|
||||
<p>Das <strong>Tangentialportfolio</strong> maximiert die <strong>Sharpe Ratio</strong>:</p>
|
||||
<p>Das <strong><a href="anhang-glossar.md#gloss:tangentialportfolio" class="glossar-link">Tangentialportfolio</a></strong> maximiert die <strong><a href="anhang-glossar.md#gloss:sharpe-ratio" class="glossar-link">Sharpe Ratio</a></strong>:</p>
|
||||
<p><span class="math display">
|
||||
\text{SR}(\mathbf{w}) = \frac{\mathbf{w}^\top\boldsymbol{\mu} - r_f}{\sqrt{\mathbf{w}^\top\boldsymbol{\Sigma}\mathbf{w}}}
|
||||
</span></p>
|
||||
<blockquote>
|
||||
<p><strong>📐 Formel-Lesehilfe</strong> Zähler: <strong>Überrendite</strong> über den risikolosen Zins <span class="math inline">r_f</span>. Nenner: die Volatilität.</p>
|
||||
<p><strong>📐 Formel-Lesehilfe</strong> Zähler: <strong>Überrendite</strong> über den risikolosen Zins <span class="math inline">r_f</span>. Nenner: die <a href="anhang-glossar.md#gloss:volatilitaet" class="glossar-link">Volatilität</a>.</p>
|
||||
<p><strong>Ohne Formel gesagt:</strong> „Wie viel Mehrertrag bekomme ich je Einheit Risiko, die ich eingehe?“ Eine Sharpe Ratio von 0,8 heißt: Für jeden Prozentpunkt Volatilität gibt es 0,8 Prozentpunkte Überrendite.</p>
|
||||
</blockquote>
|
||||
<h3 id="die-korn-transformation">Die Korn-Transformation</h3>
|
||||
|
|
@ -504,7 +504,7 @@ obwohl Formel und Simulation nichts voneinander wissen.</code></pre>
|
|||
<tr class="odd">
|
||||
<td><strong>Turnover-Grenze</strong></td>
|
||||
<td><span class="math inline">\|\mathbf{w}-\mathbf{w}_{\text{alt}}\|_1 \le \tau</span></td>
|
||||
<td>Transaktionskosten dämpfen</td>
|
||||
<td><a href="anhang-glossar.md#gloss:transaktionskosten" class="glossar-link">Transaktionskosten</a> dämpfen</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -841,7 +841,7 @@ obwohl Formel und Simulation nichts voneinander wissen.</code></pre>
|
|||
<p><strong>⚠️ Zur Reproduzierbarkeit</strong> Dieses Programm lädt Live-Daten. <strong>Ihre Zahlen werden abweichen.</strong> Prüfen Sie stattdessen die <strong>Struktur</strong> des Ergebnisses: Hält die Sektorgrenze? Summieren sich die Gewichte auf 100 %? Liegt die Sharpe Ratio des Max-Sharpe-Portfolios über der des GMV? Genau dafür sind die <code>assert</code>-Prüfungen da.</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Der Realitätscheck: Gleichgewichtung</strong> Das Programm vergleicht immer mit dem <strong>1/N-Portfolio</strong>. Das ist kein Scherz: DeMiguel, Garlappi und Uppal zeigten 2009 in einer viel beachteten Studie, dass die naive Gleichgewichtung viele optimierte Strategien out of sample schlägt — weil sie keinerlei Schätzung benötigt und damit auch keinen Schätzfehler enthält. <strong>Wenn Ihre Optimierung 1/N nicht schlägt, ist sie ihren Aufwand nicht wert.</strong> Diese Messlatte sollte in jedem Portfolioprojekt stehen.</p>
|
||||
<p><strong>🎯 Der Realitätscheck: Gleichgewichtung</strong> Das Programm vergleicht immer mit dem <strong>1/N-Portfolio</strong>. Das ist kein Scherz: DeMiguel, Garlappi und Uppal zeigten 2009 in einer viel beachteten Studie, dass die naive Gleichgewichtung viele optimierte Strategien out of sample schlägt — weil sie keinerlei Schätzung benötigt und damit auch keinen <a href="anhang-glossar.md#gloss:schaetzfehler" class="glossar-link">Schätzfehler</a> enthält. <strong>Wenn Ihre Optimierung 1/N nicht schlägt, ist sie ihren Aufwand nicht wert.</strong> Diese Messlatte sollte in jedem Portfolioprojekt stehen.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:markowitz-uebungsaufgaben">19.7 Übungsaufgaben</h2>
|
||||
|
|
@ -853,11 +853,11 @@ obwohl Formel und Simulation nichts voneinander wissen.</code></pre>
|
|||
<p><strong>Aufgabe 19.3 ⭐⭐ — Korn-Transformation nachvollziehen.</strong> Zeigen Sie rechnerisch, dass die Sharpe Ratio invariant gegenüber positiver Skalierung ist: <span class="math inline">\text{SR}(c\,\mathbf{w}) = \text{SR}(\mathbf{w})</span> für <span class="math inline">c > 0</span>. Warum gilt das <strong>nicht</strong>, wenn die Nebenbedingung <span class="math inline">\sum w_i = 1</span> mitgeführt wird — und wie löst die Transformation dieses Problem?</p>
|
||||
<p><strong>Aufgabe 19.4 ⭐⭐ — Restriktionen kosten Rendite.</strong> Lassen Sie <code>Markowitz_CVXPY.py</code> mit <code>MAX_GEWICHT</code> von 1,0 (keine Grenze) bis 0,10 in Schritten von 0,05 laufen. Tabellieren Sie Sharpe Ratio und maximal erreichbare Rendite. (a) Was kostet die 20-%-Grenze an Sharpe Ratio? (b) Ab welcher Grenze wird das Problem unlösbar? Warum?</p>
|
||||
<p><strong>Aufgabe 19.5 ⭐⭐ — Den Sektorfehler nachstellen.</strong> Bauen Sie den Fehler bewusst nach: Verwenden Sie <code>tech_indices = [0,1,2,3]</code> auf den alphabetisch sortierten Spalten. Vergleichen Sie das Ergebnis mit der korrekten Version. (a) Welche Titel werden tatsächlich beschränkt? (b) Wie stark unterscheiden sich die Portfoliogewichte? (c) Fällt der Fehler in den ausgegebenen Kennzahlen auf?</p>
|
||||
<p><strong>Aufgabe 19.6 ⭐⭐⭐ — Kardinalität ergänzen.</strong> Erweitern Sie das Modell um „höchstens <span class="math inline">K = 5</span> Titel“ mit Binärvariablen. CVXPY braucht dafür <code>cp.Variable(n, boolean=True)</code> und einen MIQP-fähigen Solver (z. B. <code>SCIP</code> über <code>cp.SCIP</code> oder <code>ECOS_BB</code>). Vergleichen Sie Sharpe Ratio und Rechenzeit mit dem unbeschränkten Fall.</p>
|
||||
<p><strong>Aufgabe 19.6 ⭐⭐⭐ — Kardinalität ergänzen.</strong> Erweitern Sie das Modell um „höchstens <span class="math inline">K = 5</span> Titel“ mit Binärvariablen. CVXPY braucht dafür <code>cp.Variable(n, boolean=True)</code> und einen <a href="anhang-glossar.md#gloss:miqp" class="glossar-link">MIQP</a>-fähigen <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> (z. B. <code>SCIP</code> über <code>cp.SCIP</code> oder <code>ECOS_BB</code>). Vergleichen Sie Sharpe Ratio und Rechenzeit mit dem unbeschränkten Fall.</p>
|
||||
<p><strong>Aufgabe 19.7 ⭐⭐⭐ — Out-of-Sample-Test.</strong> Teilen Sie die Historie in zwei Hälften. Optimieren Sie auf der ersten, bewerten Sie auf der zweiten. Vergleichen Sie GMV, Max Sharpe und 1/N. (a) Welches Portfolio gewinnt out of sample? (b) Wie ändert sich das Bild mit Ledoit-Wolf gegenüber der Stichprobenkovarianz? (c) Welche Schlussfolgerung ziehen Sie für die Praxis?</p>
|
||||
<hr />
|
||||
<h2 id="sec:markowitz-denkfehler">19.8 Finde den Denkfehler</h2>
|
||||
<p><a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> hat gezeigt, was eine schlecht geschätzte <strong>Kovarianzmatrix</strong> anrichtet. Bei den erwarteten <strong>Renditen</strong> ist es schlimmer — und weil sie in der Zielfunktion stehen statt in der Nebenbedingung, fällt es schwerer auf.</p>
|
||||
<p><a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> hat gezeigt, was eine schlecht geschätzte <strong>Kovarianzmatrix</strong> anrichtet. Bei den erwarteten <strong>Renditen</strong> ist es schlimmer — und weil sie in der <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a> stehen statt in der Nebenbedingung, fällt es schwerer auf.</p>
|
||||
<div class="card card-denkfehler">
|
||||
<blockquote>
|
||||
<p><strong>🐛 Finde den Denkfehler: Zwölf gleiche Anlagen, ein sehr ungleiches Portfolio</strong></p>
|
||||
|
|
|
|||
14
OR_HTML_04/mehrziel.html
generated
14
OR_HTML_04/mehrziel.html
generated
|
|
@ -105,7 +105,7 @@
|
|||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um den Normalfall, den die bisherigen Kapitel umgangen haben: Es gibt nicht <em>ein</em> Ziel, sondern zwei, die gegeneinander stehen. Kosten und CO₂, Termintreue und Bestand, Rendite und Risiko.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="modellierung.html#kap-modellierung">Kapitel 4</a> (die Zielgröße als Entscheidung) und <a href="milp.html#kap-milp">Kapitel 6</a>. Für den Denkfehler hilft <a href="markowitz.html#kap-markowitz">Kapitel 19</a>.</p>
|
||||
<p><strong>Danach können Sie:</strong> begründen, warum eine gewichtete Summe bei ganzzahligen Modellen Kompromisse <strong>grundsätzlich</strong> nicht erreichen kann; eine vollständige Pareto-Front mit dem ε-Constraint-Verfahren berechnen; und einer Geschäftsführung eine Entscheidung vorlegen, die sie tatsächlich treffen kann.</p>
|
||||
<p><strong>Danach können Sie:</strong> begründen, warum eine gewichtete Summe bei ganzzahligen Modellen Kompromisse <strong>grundsätzlich</strong> nicht erreichen kann; eine vollständige <a href="anhang-glossar.md#gloss:pareto-front" class="glossar-link">Pareto-Front</a> mit dem ε-Constraint-Verfahren berechnen; und einer Geschäftsführung eine Entscheidung vorlegen, die sie tatsächlich treffen kann.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 4 Stunden.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>Mehrziel_Pareto.py</code></p>
|
||||
|
|
@ -120,7 +120,7 @@
|
|||
<p>Eine Spedition vergibt fünf Sendungen an LKW, Bahn oder Kombinierten Verkehr. Der LKW ist billig und schmutzig, die Bahn teuer und sauber — und es sind nur zwei Trassen frei.</p>
|
||||
<p>Statt zu fragen „wie wichtig ist uns CO₂?” fragen wir: <strong>Was bekommen wir für zwei Prozent mehr Geld?</strong></p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> linprog</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> [linprog](anhang<span class="op">-</span>glossar.md<span class="co">#gloss:linprog){.glossar-link}</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="co"># LKW Bahn Kombi LKW billig+schmutzig, Bahn teuer+sauber</span></span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>kosten <span class="op">=</span> np.array([[ <span class="dv">900</span>, <span class="dv">1150</span>, <span class="dv">1020</span>], [ <span class="dv">620</span>, <span class="dv">790</span>, <span class="dv">700</span>], [<span class="dv">1300</span>, <span class="dv">1660</span>, <span class="dv">1470</span>],</span>
|
||||
|
|
@ -637,10 +637,10 @@ dem CO2-Preis, den das Unternehmen ohnehin ansetzt.
|
|||
</div>
|
||||
<p><strong>Warum es keine Frage des Rasters ist.</strong> „<span class="math inline">c(x) + w\,e(x)</span> minimieren” heißt geometrisch: eine Gerade der Steigung <span class="math inline">-1/w</span> von links unten an die Punktwolke schieben und schauen, welchen Punkt sie zuerst berührt. Eine Gerade berührt immer einen <strong>Eckpunkt der unteren konvexen Hülle</strong>. Punkte, die oberhalb der Hülle liegen, werden von keiner Geraden zuerst getroffen — für kein <span class="math inline">w</span>, bei beliebig feiner Abstufung.</p>
|
||||
<p>Das Programm rechnet diese Hülle in <code>untere_huelle()</code> unabhängig aus und vergleicht: Genau die vier Punkte, die das Gewichtsraster verfehlt, liegen strikt oberhalb. Die Gegenprobe steht in der Ausgabe.</p>
|
||||
<p><strong>Was Sie in der Abbildung sehen.</strong> Die beiden Geraden haben dieselbe Steigung, also dasselbe Gewicht <span class="math inline">w</span>. Die untere berührt die Hülle in zwei Ecken — eine von beiden meldet der Solver als Optimum. Die obere geht durch einen pareto-optimalen Punkt, der damit für dieses Gewicht chancenlos ist, und zwar nicht knapp: Er liegt eine ganze Stufe darüber. Verschieben Sie die Steigung, verschiebt sich die Berührung von einer Ecke zur nächsten — über den Punkt dazwischen springt sie hinweg. Die waagerechte Linie zeigt den Ausweg, um den es in <a href="#sec:mehrziel-epsilon">Abschnitt 14.7</a> geht: Eine Schranke für den CO₂-Ausstoß statt eines Gewichts findet genau diesen Punkt.</p>
|
||||
<p><strong>Was Sie in der Abbildung sehen.</strong> Die beiden Geraden haben dieselbe Steigung, also dasselbe Gewicht <span class="math inline">w</span>. Die untere berührt die Hülle in zwei Ecken — eine von beiden meldet der <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> als Optimum. Die obere geht durch einen pareto-optimalen Punkt, der damit für dieses Gewicht chancenlos ist, und zwar nicht knapp: Er liegt eine ganze Stufe darüber. Verschieben Sie die Steigung, verschiebt sich die Berührung von einer Ecke zur nächsten — über den Punkt dazwischen springt sie hinweg. Die waagerechte Linie zeigt den Ausweg, um den es in <a href="#sec:mehrziel-epsilon">Abschnitt 14.7</a> geht: Eine Schranke für den CO₂-Ausstoß statt eines Gewichts findet genau diesen Punkt.</p>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Der Grund liegt in der Ganzzahligkeit</strong></p>
|
||||
<p>Bei einem reinen LP ist der zulässige Bereich konvex, und die Pareto-Front liegt vollständig auf ihrer eigenen konvexen Hülle — dort findet die gewichtete Summe alles. Sobald Entscheidungen <strong>ganzzahlig</strong> werden (welcher Träger, welches Lager, welche Schicht), zerfällt der Bereich in einzelne Punkte, und zwischen ihnen entstehen Einbuchtungen.</p>
|
||||
<p>Bei einem reinen <a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a> ist der zulässige Bereich konvex, und die Pareto-Front liegt vollständig auf ihrer eigenen konvexen Hülle — dort findet die gewichtete Summe alles. Sobald Entscheidungen <strong>ganzzahlig</strong> werden (welcher Träger, welches Lager, welche Schicht), zerfällt der Bereich in einzelne Punkte, und zwischen ihnen entstehen Einbuchtungen.</p>
|
||||
<p>Deshalb betrifft dieses Problem praktisch jedes betriebliche Mehrzielmodell. Wer mit Gewichten arbeitet, verliert nicht ein paar Nachkommastellen, sondern <strong>ganze Alternativen</strong> — im Beispiel 40 % der Front.</p>
|
||||
</blockquote>
|
||||
<h3 id="das-gewicht-ist-keine-feineinstellung">Das Gewicht ist keine Feineinstellung</h3>
|
||||
|
|
@ -717,7 +717,7 @@ e(x) \le \varepsilon
|
|||
\text{Schattenpreis`\index{Schattenpreis}`{=latex}} = \frac{\text{Aufpreis gegenüber dem Kostenminimum}}
|
||||
{\text{eingesparte Kilogramm}}
|
||||
</span></p>
|
||||
<p>Diese Zahl ist mit etwas vergleichbar, das das Unternehmen ohnehin kennt: dem internen CO₂-Preis oder dem Zertifikatspreis. Liegt der Schattenpreis darunter, ist die Entscheidung kaufmännisch schon getroffen.</p>
|
||||
<p>Diese Zahl ist mit etwas vergleichbar, das das Unternehmen ohnehin kennt: dem internen CO₂-Preis oder dem Zertifikatspreis. Liegt der <a href="anhang-glossar.md#gloss:schattenpreis" class="glossar-link">Schattenpreis</a> darunter, ist die Entscheidung kaufmännisch schon getroffen.</p>
|
||||
<blockquote>
|
||||
<p><strong>💻 Code-Durchgang: die drei Bausteine</strong></p>
|
||||
<table>
|
||||
|
|
@ -756,7 +756,7 @@ e(x) \le \varepsilon
|
|||
<p><strong>Aufgabe 14.1 ⭐ — Dominanz prüfen.</strong> Plan P kostet 14 000 € und stößt 6 000 kg aus, Plan Q kostet 13 800 € und stößt 6 100 kg aus. Dominiert einer den anderen? Und wie steht es mit R (14 000 €, 6 100 kg)?</p>
|
||||
<p><strong>Aufgabe 14.2 ⭐ — Der Schattenpreis in der Praxis.</strong> Der interne CO₂-Preis des Unternehmens beträgt 0,90 € je Kilogramm. Welchen Punkt der Front würden Sie empfehlen — und wie begründen Sie ihn in einem Satz?</p>
|
||||
<p><strong>Aufgabe 14.3 ⭐⭐ — Mehr Trassen.</strong> Erhöhen Sie <code>BAHN_TRASSEN</code> von 5 auf 8. Was passiert mit der Länge der Front und mit der Zahl der unerreichbaren Punkte? Erklären Sie den Zusammenhang.</p>
|
||||
<p><strong>Aufgabe 14.4 ⭐⭐ — Die Front der Relaxation.</strong> Lassen Sie <code>integrality</code> 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?</p>
|
||||
<p><strong>Aufgabe 14.4 ⭐⭐ — Die Front der <a href="anhang-glossar.md#gloss:relaxation" class="glossar-link">Relaxation</a>.</strong> Lassen Sie <code>integrality</code> 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?</p>
|
||||
<p><strong>Aufgabe 14.5 ⭐⭐⭐ — Drei Ziele.</strong> Ergänzen Sie die Laufzeit als drittes Ziel (LKW schnell, Bahn langsam). Die Front wird zu einer Fläche. Wie ändert sich das ε-Verfahren, und warum wächst der Aufwand so schnell?</p>
|
||||
<hr />
|
||||
<h2 id="sec:mehrziel-denkfehler">14.10 Finde den Denkfehler</h2>
|
||||
|
|
@ -786,7 +786,7 @@ e(x) \le \varepsilon
|
|||
<h2 id="sec:mehrziel-selbsttest">14.12 Selbsttest</h2>
|
||||
<ol type="1">
|
||||
<li>Erklären Sie Pareto-Dominanz an einem Beispiel aus Ihrem Arbeitsumfeld.</li>
|
||||
<li>Warum ist „gewichtete Summe” bei einem reinen LP unproblematisch und bei einem MILP nicht?</li>
|
||||
<li>Warum ist „gewichtete Summe” bei einem reinen LP unproblematisch und bei einem <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> nicht?</li>
|
||||
<li>Ein Kollege sagt: „Ich nehme <span class="math inline">w = 0{,}5</span>, das ist neutral.” Was ist daran falsch?</li>
|
||||
<li>Beschreiben Sie das ε-Constraint-Verfahren in drei Sätzen, ohne Formeln.</li>
|
||||
<li>Sie legen einer Geschäftsführung eine Front mit zwölf Punkten vor. Welche Spalte brauchen Sie, damit die Entscheidung fallen kann?</li>
|
||||
|
|
|
|||
22
OR_HTML_04/metaheuristiken.html
generated
22
OR_HTML_04/metaheuristiken.html
generated
|
|
@ -103,9 +103,9 @@
|
|||
<div class="card card-blick">
|
||||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um den Fall, für den die bisherigen Kapitel keine Antwort haben: Das Problem ist zu groß, der Solver kommt im Zeitlimit nicht zu einem brauchbaren Ergebnis — und eine Entscheidung muss trotzdem heute fallen.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="milp.html#kap-milp">Kapitel 6</a> und <a href="cpsat.html#kap-cpsat">Kapitel 7</a>, insbesondere <a href="milp.html#sec:milp-gap">Abschnitt 6.8</a> (MIP-Gap und Schranke).</p>
|
||||
<p><strong>Danach können Sie:</strong> eine lokale Suche mit ihrer entscheidenden Zutat — der Kostenänderung in O(1) — selbst schreiben, die Temperatur eines Simulated Annealing ausmessen statt raten, den Umschlagpunkt zwischen exakt und heuristisch für Ihr eigenes Problem bestimmen, und mit Large Neighborhood Search beides kombinieren.</p>
|
||||
<p><strong>Worum geht es?</strong> Um den Fall, für den die bisherigen Kapitel keine Antwort haben: Das Problem ist zu groß, der <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> kommt im Zeitlimit nicht zu einem brauchbaren Ergebnis — und eine Entscheidung muss trotzdem heute fallen.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="milp.html#kap-milp">Kapitel 6</a> und <a href="cpsat.html#kap-cpsat">Kapitel 7</a>, insbesondere <a href="milp.html#sec:milp-gap">Abschnitt 6.8</a> (<a href="anhang-glossar.md#gloss:mip-gap" class="glossar-link">MIP-Gap</a> und Schranke).</p>
|
||||
<p><strong>Danach können Sie:</strong> eine lokale Suche mit ihrer entscheidenden Zutat — der Kostenänderung in O(1) — selbst schreiben, die Temperatur eines <a href="anhang-glossar.md#gloss:simulated-annealing" class="glossar-link">Simulated Annealing</a> ausmessen statt raten, den Umschlagpunkt zwischen exakt und heuristisch für Ihr eigenes Problem bestimmen, und mit Large Neighborhood Search beides kombinieren.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 5 Stunden.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>Simulated_Annealing.py</code><br />
|
||||
|
|
@ -223,7 +223,7 @@ Optimal : Weiss -> Elfenbein -> Beige -> Rot -> Dunkelrot -> Sc
|
|||
<ol type="1">
|
||||
<li>… erklären, warum eine lokale Suche ohne <strong>Kostenänderung in O(1)</strong> praktisch wertlos ist.</li>
|
||||
<li>… Simulated Annealing implementieren und seine Starttemperatur <strong>an der Zuggröße</strong> kalibrieren statt am Zielfunktionswert.</li>
|
||||
<li>… den Beitrag der Metaheuristik gegen die einfachere Alternative abgrenzen — reines Bergsteigen — statt ihn ihr gutzuschreiben.</li>
|
||||
<li>… den Beitrag der <a href="anhang-glossar.md#gloss:metaheuristik" class="glossar-link">Metaheuristik</a> gegen die einfachere Alternative abgrenzen — reines Bergsteigen — statt ihn ihr gutzuschreiben.</li>
|
||||
<li>… den <strong>Umschlagpunkt</strong> bestimmen, ab dem eine Metaheuristik den exakten Solver schlägt, und begründen, warum diese Zahl problemspezifisch ist.</li>
|
||||
<li>… erklären, warum ein exakter Lauf auch dann dazugehört, wenn Sie am Ende die heuristische Lösung einsetzen.</li>
|
||||
<li>… Large Neighborhood Search aufsetzen: zerstören, exakt reparieren, übernehmen.</li>
|
||||
|
|
@ -278,14 +278,14 @@ Optimal : Weiss -> Elfenbein -> Beige -> Rot -> Dunkelrot -> Sc
|
|||
<p><strong>Ohne Formel gesagt:</strong> „Sortiere die Aufträge so, dass möglichst wenig geputzt werden muss.“</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
<p>Wer die Aufgabe als Graph liest, erkennt sie wieder: Es ist ein <strong>asymmetrisches Rundreiseproblem</strong> (<a href="graphen.html#kap-graphen">Kapitel 8</a>) 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.</p>
|
||||
<p>Wer die Aufgabe als Graph liest, erkennt sie wieder: Es ist ein <strong>asymmetrisches Rundreiseproblem</strong> (<a href="graphen.html#kap-graphen">Kapitel 8</a>) 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 <a href="anhang-glossar.md#gloss:np-schwer" class="glossar-link">NP-schwer</a> ist.</p>
|
||||
<blockquote>
|
||||
<p><strong>📖 Definition: Metaheuristik</strong></p>
|
||||
<p>Ein <strong>Verfahrensrahmen</strong>, der eine vorhandene Lösung schrittweise verändert und dabei steuert, welche Veränderungen übernommen werden. „Meta“, weil der Rahmen nichts über das Problem weiß: Er braucht nur eine Startlösung, einen Zug und eine Bewertung. Dieselbe Mechanik läuft über Tourenplanung, Personaleinsatz und Portfolioauswahl.</p>
|
||||
<p>Der Preis dafür steht in derselben Zeile: Ein Verfahren, das nichts über das Problem weiß, kann auch nichts über die Güte seines Ergebnisses sagen. Es liefert eine Lösung, <strong>keine Schranke</strong>.</p>
|
||||
</blockquote>
|
||||
<h3 id="die-instanz">Die Instanz</h3>
|
||||
<p>Alle Programme dieses Kapitels benutzen dieselbe Aufgabe. Die 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.</p>
|
||||
<p>Alle Programme dieses Kapitels benutzen dieselbe Aufgabe. Die <a href="anhang-glossar.md#gloss:ruestzeit" class="glossar-link">Rüstzeit</a> setzt sich aus zwei Teilen zusammen: einem unregelmäßigen Reinigungsaufwand zwischen den Produktfamilien und einem Zuschlag für den Wechsel von Dunkel nach Hell.</p>
|
||||
<p>Eine Feinheit der Instanz ist wichtiger, als sie aussieht: Die <strong>Zahl der Produktfamilien wächst mit der Auftragszahl</strong> (eine Familie je zehn Aufträge). Bei fester Familienzahl würde das Problem mit wachsendem <span class="math inline">n</span> nämlich <em>leichter</em> — der Plan bestünde irgendwann aus ein paar großen Blöcken, und jede Faustregel fände ihn. Beim ersten Entwurf dieses Kapitels ist mir genau das passiert: Die Metaheuristik verbesserte bei 60 Aufträgen um 30 %, bei 200 Aufträgen um 0 %. Nicht weil sie versagte, sondern weil es nichts mehr zu verbessern gab.</p>
|
||||
<hr />
|
||||
<h2 id="sec:metaheuristiken-lokale-suche">9.4 Lokale Suche: der Zug und seine Kosten</h2>
|
||||
|
|
@ -1052,7 +1052,7 @@ Und warum die Starttemperatur ausgemessen gehoert:
|
|||
<span id="cb6-230"><a href="#cb6-230" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"exakter Lauf dazu, wenn man am Ende die heuristische Loesung einsetzt:"</span>)</span>
|
||||
<span id="cb6-231"><a href="#cb6-231" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"nicht wegen seiner Loesung, sondern wegen seiner Schranke."</span>)</span>
|
||||
<span id="cb6-232"><a href="#cb6-232" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">88</span>)</span></code></pre></div>
|
||||
<p><strong>Erwartete Ausgabe</strong> (die CP-SAT-Spalten sind hardwareabhängig, siehe Programmkopf):</p>
|
||||
<p><strong>Erwartete Ausgabe</strong> (die <a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a>-Spalten sind hardwareabhängig, siehe Programmkopf):</p>
|
||||
<pre><code>========================================================================================
|
||||
AB WANN LOHNT SICH DIE METAHEURISTIK?
|
||||
========================================================================================
|
||||
|
|
@ -1106,7 +1106,7 @@ nicht wegen seiner Loesung, sondern wegen seiner Schranke.
|
|||
<tbody>
|
||||
<tr class="odd">
|
||||
<td style="text-align: right;">60</td>
|
||||
<td><strong>Exakt.</strong> CP-SAT beweist das Optimum in 2 Sekunden. Die Metaheuristik liegt 3,8 % daneben — und wüsste es nicht.</td>
|
||||
<td><strong>Exakt.</strong> <a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a> beweist das Optimum in 2 Sekunden. Die Metaheuristik liegt 3,8 % daneben — und wüsste es nicht.</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td style="text-align: right;">200</td>
|
||||
|
|
@ -1128,7 +1128,7 @@ nicht wegen seiner Loesung, sondern wegen seiner Schranke.
|
|||
<hr />
|
||||
<h2 id="sec:metaheuristiken-lns">9.7 Large Neighborhood Search</h2>
|
||||
<p>Die Tabelle oben endet mit einem Widerspruch. Bei 500 Aufträgen scheitert der exakte Solver an der <strong>Größe</strong>; die Metaheuristik scheitert an der <strong>Kleinheit ihrer Züge</strong> — sie verschiebt jeweils einen einzigen Auftrag und kann eine ganze Passage nicht auf einmal umbauen.</p>
|
||||
<p><strong>Large Neighborhood Search</strong> (LNS) setzt beide ein, jeden für das, was er kann:</p>
|
||||
<p><strong>Large Neighborhood Search</strong> (<a href="anhang-glossar.md#gloss:large-neighborhood-search-lns" class="glossar-link">LNS</a>) setzt beide ein, jeden für das, was er kann:</p>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 50%" />
|
||||
|
|
@ -1616,7 +1616,7 @@ Abstand zum Optimum.
|
|||
<td>Wenn es eine natürliche „Kreuzung“ zweier Lösungen gibt. Für Reihenfolgen ist genau das der schwierige Teil. Bibliothek: <code>pymoo</code>.</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>Tabu-Suche</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:tabu-suche" class="glossar-link">Tabu-Suche</a></strong></td>
|
||||
<td>Bergsteigen, das zuletzt gemachte Züge eine Zeit lang verbietet.</td>
|
||||
<td>Wenn die Suche zwischen zwei Zuständen pendelt. Oft mit weniger Kalibrierung als Annealing.</td>
|
||||
</tr>
|
||||
|
|
@ -1676,7 +1676,7 @@ Abstand zum Optimum.
|
|||
<h2 id="sec:metaheuristiken-zusammenfassung">9.13 Zusammenfassung</h2>
|
||||
<ul>
|
||||
<li>Eine <strong>Faustregel</strong> ist selten dumm, aber immer kurzsichtig: Sie bewertet einen Schritt danach, was er kostet, nicht danach, was er übrig lässt.</li>
|
||||
<li><strong>Lokale Suche</strong> steht und fällt mit der Kostenänderung in <span class="math inline">O(1)</span>. Wer den Zug über die volle Zielfunktion bewertet, misst am Ende seine Implementierung statt des Verfahrens.</li>
|
||||
<li><strong>Lokale Suche</strong> steht und fällt mit der Kostenänderung in <span class="math inline">O(1)</span>. Wer den Zug über die volle <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a> bewertet, misst am Ende seine Implementierung statt des Verfahrens.</li>
|
||||
<li><strong>Simulated Annealing</strong> nimmt Verschlechterungen mit <span class="math inline">e^{-\Delta/T}</span> an. <span class="math inline">T</span> und <span class="math inline">\Delta</span> haben dieselbe Einheit — die Temperatur gehört an der <strong>Zuggröße</strong> kalibriert, nicht am Zielfunktionswert. Die verbreitete Regel „20 bis 50 % Annahmequote“ war auf dieser Aufgabe falsch.</li>
|
||||
<li>Der <strong>schlechteste Zwischenwert</strong> ist die beste Diagnosezahl eines Annealing-Laufs: Er zeigt eine zu heiße Starttemperatur sofort, ohne dass man das Ergebnis abwarten muss.</li>
|
||||
<li>Rechnen Sie <strong>immer</strong> das simple Bergsteigen mit. Hier lieferte es 93 % des Ertrags.</li>
|
||||
|
|
|
|||
26
OR_HTML_04/milp.html
generated
26
OR_HTML_04/milp.html
generated
|
|
@ -104,8 +104,8 @@
|
|||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um Entscheidungen, die nicht teilbar sind: ganze Maschinen, Ja/Nein, „höchstens fünf davon“. Wir zeigen mit einem konkreten Gegenbeispiel, warum Runden <strong>falsch</strong> ist, und lernen die Modellierungstricks, mit denen sich logische Regeln in lineare Ungleichungen übersetzen lassen.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="lp.html#kap-lp">Kapitel 5</a> (LP, Relaxation, Schranken).</p>
|
||||
<p><strong>Danach können Sie:</strong> 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 Auftraggeber lesen — und ein Ergebnis erkennen, das nur deshalb gut aussieht, weil das Big-M zu groß gewählt war.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="lp.html#kap-lp">Kapitel 5</a> (<a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a>, <a href="anhang-glossar.md#gloss:relaxation" class="glossar-link">Relaxation</a>, Schranken).</p>
|
||||
<p><strong>Danach können Sie:</strong> Fixkosten, Entweder-Oder, Wenn-Dann und Kardinalitätsgrenzen modellieren, ein <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> mit <a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a> oder <a href="anhang-glossar.md#gloss:highs" class="glossar-link">HiGHS</a> lösen, den <a href="anhang-glossar.md#gloss:mip-gap" class="glossar-link">MIP-Gap</a> als Zusage an den Auftraggeber lesen — und ein Ergebnis erkennen, das nur deshalb gut aussieht, weil das Big-M zu groß gewählt war.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 6,5 Stunden.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>Runden_Gegenbeispiel.py</code><br />
|
||||
|
|
@ -167,7 +167,7 @@
|
|||
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>nb <span class="op">=</span> LinearConstraint(A, [<span class="dv">100</span>, <span class="op">-</span>np.inf, <span class="op">-</span>np.inf, <span class="op">-</span>np.inf], [<span class="dv">100</span>, <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span>])</span>
|
||||
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>grenzen <span class="op">=</span> Bounds([<span class="dv">0</span>] <span class="op">*</span> <span class="dv">6</span>, <span class="bu">list</span>(kap) <span class="op">+</span> [<span class="dv">1</span>, <span class="dv">1</span>, <span class="dv">1</span>])</span>
|
||||
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> name, ganzzahlig <span class="kw">in</span> [(<span class="st">"LP-Relaxation"</span>, [<span class="dv">0</span>] <span class="op">*</span> <span class="dv">6</span>), (<span class="st">"MILP"</span>, [<span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">1</span>, <span class="dv">1</span>])]:</span>
|
||||
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> name, ganzzahlig <span class="kw">in</span> [(<span class="st">"[LP-Relaxation](anhang-glossar.md#gloss:lp-relaxation){.glossar-link}"</span>, [<span class="dv">0</span>] <span class="op">*</span> <span class="dv">6</span>), (<span class="st">"MILP"</span>, [<span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">1</span>, <span class="dv">1</span>])]:</span>
|
||||
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a> r <span class="op">=</span> milp(c<span class="op">=</span>np.concatenate([var, fix]), constraints<span class="op">=</span>[nb],</span>
|
||||
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a> integrality<span class="op">=</span>ganzzahlig, bounds<span class="op">=</span>grenzen)</span>
|
||||
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="sc">{</span>name<span class="sc">:14}</span><span class="ss"> </span><span class="sc">{</span>r<span class="sc">.</span>fun<span class="sc">:7.2f}</span><span class="ss"> EUR Mengen </span><span class="sc">{</span>np<span class="sc">.</span><span class="bu">round</span>(r.x[:<span class="dv">3</span>], <span class="dv">1</span>)<span class="sc">}</span><span class="ss"> "</span></span>
|
||||
|
|
@ -209,7 +209,7 @@ MILP 882.00 EUR Mengen [10. 0. 90.] Schalter [ 1. -0. 1. ]
|
|||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Die LP-Relaxation ist keine ungefähre Antwort, die man nur noch glattziehen muss. Sie ist eine Antwort auf eine <strong>andere Frage</strong> — nämlich die, bei der man Lager auch zu 14,3 % eröffnen darf. Ihr Wert liegt nicht in ihrer Lösung, sondern in ihrer <strong>Schranke</strong>: Weniger als 724,14 € kann die richtige Antwort nicht kosten.</p>
|
||||
</blockquote>
|
||||
<p>Genau diese Schranke ist der Hebel, mit dem Branch-and-Bound arbeitet. Wie, zeigt der Abschnitt <a href="#sec:milp-branch-and-bound">Abschnitt 6.4</a>.</p>
|
||||
<p>Genau diese Schranke ist der Hebel, mit dem <a href="anhang-glossar.md#gloss:branch-and-bound" class="glossar-link">Branch-and-Bound</a> arbeitet. Wie, zeigt der Abschnitt <a href="#sec:milp-branch-and-bound">Abschnitt 6.4</a>.</p>
|
||||
<hr />
|
||||
<h2 id="sec:milp-lernziele">6.2 Lernziele</h2>
|
||||
<p>Nach diesem Kapitel können Sie …</p>
|
||||
|
|
@ -220,8 +220,8 @@ MILP 882.00 EUR Mengen [10. 0. 90.] Schalter [ 1. -0. 1. ]
|
|||
<li>… begründen, warum <span class="math inline">M</span> so klein wie möglich gewählt werden muss.</li>
|
||||
<li>… ein Portfolioproblem mit Ordergebühren und Höchstzahl an Positionen lösen.</li>
|
||||
<li>… <strong>Incumbent, Schranke und MIP-Gap</strong> unterscheiden und aus einem abgebrochenen Solverlauf eine belastbare Aussage ableiten.</li>
|
||||
<li>… alle Solver-Statusfälle explizit behandeln, statt <code>OPTIMAL</code> vorauszusetzen.</li>
|
||||
<li>… einen <strong>Warm-Start</strong> setzen — und messen, ob er auf Ihrer Problemklasse überhaupt etwas bringt.</li>
|
||||
<li>… alle <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a>-Statusfälle explizit behandeln, statt <code>OPTIMAL</code> vorauszusetzen.</li>
|
||||
<li>… einen <strong><a href="anhang-glossar.md#gloss:warm-start" class="glossar-link">Warm-Start</a></strong> setzen — und messen, ob er auf Ihrer Problemklasse überhaupt etwas bringt.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
<h2 id="sec:milp-warum-runden-fundamental-scheitert">6.3 Warum Runden fundamental scheitert</h2>
|
||||
|
|
@ -230,7 +230,7 @@ MILP 882.00 EUR Mengen [10. 0. 90.] Schalter [ 1. -0. 1. ]
|
|||
<p>Der verlockende Gedanke lautet: <em>„Wir lösen das Problem kontinuierlich und runden.“</em> Eine verbreitete, aber unbelegte Behauptung dazu lautet, man verliere dadurch „oft 20–50 % des Gewinns“. Rechnen wir es nach, statt es zu behaupten.</p>
|
||||
<figure>
|
||||
<img src="bilder_04/kap_milp_runden.svg" alt="Abb. 6.1: Links die Handrechnung von unten als Bild: Die Zielfunktion läuft parallel zur Restriktion, also ist die ganze Kante optimal. Aufrunden auf (1;1) führt aus dem zulässigen Bereich heraus, Abrunden auf (0;0) auf den Wert null. Rechts die Messung aus Runden_Gegenbeispiel.py über je 200 Zufallsinstanzen. Erzeugt von bilder_04/erzeuge_runden.py." />
|
||||
<figcaption aria-hidden="true">Abb. 6.1: Links die Handrechnung von unten als Bild: Die Zielfunktion läuft parallel zur Restriktion, also ist die ganze Kante optimal. Aufrunden auf <span class="math inline">(1;1)</span> führt aus dem zulässigen Bereich heraus, Abrunden auf <span class="math inline">(0;0)</span> auf den Wert null. Rechts die Messung aus <code>Runden_Gegenbeispiel.py</code> über je 200 Zufallsinstanzen. Erzeugt von <code>bilder_04/erzeuge_runden.py</code>.</figcaption>
|
||||
<figcaption aria-hidden="true">Abb. 6.1: Links die Handrechnung von unten als Bild: Die <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a> läuft parallel zur Restriktion, also ist die ganze Kante optimal. Aufrunden auf <span class="math inline">(1;1)</span> führt aus dem zulässigen Bereich heraus, Abrunden auf <span class="math inline">(0;0)</span> auf den Wert null. Rechts die Messung aus <code>Runden_Gegenbeispiel.py</code> über je 200 Zufallsinstanzen. Erzeugt von <code>bilder_04/erzeuge_runden.py</code>.</figcaption>
|
||||
</figure>
|
||||
<blockquote>
|
||||
<p><strong>✏️ Handrechnung 6.1: Ein Gegenbeispiel, das Sie im Kopf prüfen können</strong></p>
|
||||
|
|
@ -366,7 +366,7 @@ Loesung eine Nebenbedingung verletzt. 'Verlust' = Abstand zum exakten Op
|
|||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:milp-branch-and-bound">6.4 Branch-and-Bound</h2>
|
||||
<p>MILP-Probleme sind <strong>NP-schwer</strong>. Der Standardansatz moderner Solver (HiGHS, SCIP, Gurobi) heißt <strong>Branch-and-Cut</strong> — Branch-and-Bound plus Schnittebenen.</p>
|
||||
<p>MILP-Probleme sind <strong><a href="anhang-glossar.md#gloss:np-schwer" class="glossar-link">NP-schwer</a></strong>. Der Standardansatz moderner Solver (HiGHS, <a href="anhang-glossar.md#gloss:scip" class="glossar-link">SCIP</a>, <a href="anhang-glossar.md#gloss:gurobi" class="glossar-link">Gurobi</a>) heißt <strong><a href="anhang-glossar.md#gloss:branch-and-cut" class="glossar-link">Branch-and-Cut</a></strong> — Branch-and-Bound plus Schnittebenen.</p>
|
||||
<figure>
|
||||
<img src="bilder_04/kap_milp_suchbaum.svg" alt="Abb. 6.2: Der Suchbaum der Handrechnung weiter unten — nicht gezeichnet, sondern gerechnet: Das Skript löst die LP-Relaxationen und kappt nach denselben drei Regeln, die oben stehen. Ast B wird verworfen, weil sein Wert 18 den Incumbent 20 aus Ast A nicht schlägt. Erzeugt von bilder_04/erzeuge_branch_and_bound.py." />
|
||||
<figcaption aria-hidden="true">Abb. 6.2: Der Suchbaum der Handrechnung weiter unten — nicht gezeichnet, sondern gerechnet: Das Skript löst die LP-Relaxationen und kappt nach denselben drei Regeln, die oben stehen. Ast B wird verworfen, weil sein Wert 18 den Incumbent 20 aus Ast A nicht schlägt. Erzeugt von <code>bilder_04/erzeuge_branch_and_bound.py</code>.</figcaption>
|
||||
|
|
@ -576,7 +576,7 @@ Genau hier wuerde Branch-and-Bound verzweigen:
|
|||
<p><strong>Szenario.</strong> Ein Investor verteilt <span class="math inline">100\,000\,\text{€}</span> auf sechs Anlageklassen.</p>
|
||||
<ul>
|
||||
<li>Jede Transaktion kostet <strong>50 € Fixgebühr</strong>, unabhängig vom Betrag.</li>
|
||||
<li>Höchstens <strong>3 Positionen</strong> gleichzeitig (<em>Kardinalitätsbeschränkung</em>).</li>
|
||||
<li>Höchstens <strong>3 Positionen</strong> gleichzeitig (<em><a href="anhang-glossar.md#gloss:kardinalitaetsbeschraenkung" class="glossar-link">Kardinalitätsbeschränkung</a></em>).</li>
|
||||
<li>Wird eine Position eröffnet, dann mit <strong>mindestens 10 000 €</strong> (Mindestordergröße).</li>
|
||||
<li>Höchstens <strong>40 000 €</strong> pro Position.</li>
|
||||
</ul>
|
||||
|
|
@ -872,7 +872,7 @@ Abnahmepruefung: alle Nebenbedingungen geprueft und eingehalten.
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>status = status_von_scipy(ergebnis)</code></td>
|
||||
<td>übersetzt den SciPy-Rückgabewert in die gemeinsame Sprache aus <a href="praxisfallen.html#sec:praxisfallen-or-kern">Abschnitt 22.6</a> — die drei <code>if</code>-Zweige darunter behandeln Modellfehler, Abbruch ohne Lösung und „zulässig, aber unbewiesen“ getrennt</td>
|
||||
<td>übersetzt den <a href="anhang-glossar.md#gloss:scipy" class="glossar-link">SciPy</a>-Rückgabewert in die gemeinsame Sprache aus <a href="praxisfallen.html#sec:praxisfallen-or-kern">Abschnitt 22.6</a> — die drei <code>if</code>-Zweige darunter behandeln Modellfehler, Abbruch ohne Lösung und „zulässig, aber unbewiesen“ getrennt</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>schranke=-ergebnis.mip_dual_bound</code></td>
|
||||
|
|
@ -884,7 +884,7 @@ Abnahmepruefung: alle Nebenbedingungen geprueft und eingehalten.
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><strong>Warum das Ergebnis wirtschaftlich Sinn ergibt:</strong> Der Solver wählt die drei renditestärksten Anlagen (13 %, 11 %, 8 %) und füllt sie in dieser Reihenfolge bis zur Obergrenze von 40 000 €. Die drittbeste Position (EU-Aktien) erhält nur den Rest von 20 000 € — sie liegt über der Mindestordergröße von 10 000 €, ist also zulässig. Ohne Kardinalitätsgrenze läge alles im Bestwert (13 %); die Restriktionen kosten 15 % des theoretischen Ertrags. Genau diese Zahl braucht man, wenn man mit dem Risikomanagement über die Sinnhaftigkeit einer Regel diskutiert: „Die Obergrenze von 40 % je Position kostet uns 1 950 € pro Jahr — ist uns die Diversifikation das wert?“ Das ist eine beantwortbare Frage; „wir sollten breiter streuen“ ist es nicht.</p>
|
||||
<p><strong>Warum das Ergebnis wirtschaftlich Sinn ergibt:</strong> Der Solver wählt die drei renditestärksten Anlagen (13 %, 11 %, 8 %) und füllt sie in dieser Reihenfolge bis zur Obergrenze von 40 000 €. Die drittbeste Position (EU-Aktien) erhält nur den Rest von 20 000 € — sie liegt über der Mindestordergröße von 10 000 €, ist also zulässig. Ohne Kardinalitätsgrenze läge alles im Bestwert (13 %); die Restriktionen kosten 15 % des theoretischen Ertrags. Genau diese Zahl braucht man, wenn man mit dem Risikomanagement über die Sinnhaftigkeit einer Regel diskutiert: „Die Obergrenze von 40 % je Position kostet uns 1 950 € pro Jahr — ist uns die <a href="anhang-glossar.md#gloss:diversifikation" class="glossar-link">Diversifikation</a> das wert?“ Das ist eine beantwortbare Frage; „wir sollten breiter streuen“ ist es nicht.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:milp-gap">6.8 Wenn der Solver nicht fertig wird: Gap, Zeitlimit und Warm-Start</h2>
|
||||
|
|
@ -1440,7 +1440,7 @@ Instanz Variante Makespan Zeit Faktor
|
|||
<li><strong><code>if status == OPTIMAL: ... else: return None</code>.</strong> Wirft eine Lösung weg, die 9 % vom Optimum entfernt und damit vollkommen brauchbar ist. Werten Sie den Gap aus, nicht nur den Status.</li>
|
||||
<li><strong>Zeitlimit ohne Gap-Auswertung.</strong> Ein Limit erzwingt ein Ende, sagt aber nichts über die Qualität. Ohne den Gap wissen Sie nicht, ob Sie 0,1 % oder 60 % danebenliegen.</li>
|
||||
<li><strong>Warm-Start als Selbstverständlichkeit.</strong> Messen Sie ihn — auf Ihrer Instanzklasse, gegen den kalten Lauf. In der Hälfte der Fälle bringt er nichts.</li>
|
||||
<li><strong>Einen Hinweis für eine unzulässige Lösung geben.</strong> CP-SAT und HiGHS verwerfen ihn dann stillschweigend. Prüfen Sie Ihre Startlösung vorher auf Zulässigkeit — sonst messen Sie einen Effekt, den es gar nicht gibt.</li>
|
||||
<li><strong>Einen Hinweis für eine unzulässige Lösung geben.</strong> <a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a> und HiGHS verwerfen ihn dann stillschweigend. Prüfen Sie Ihre Startlösung vorher auf Zulässigkeit — sonst messen Sie einen Effekt, den es gar nicht gibt.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
|
|
@ -1784,7 +1784,7 @@ funktioniert immer.
|
|||
<li><strong>Runden ist keine Lösung:</strong> Aufrunden ist fast immer unzulässig (98–100 % der Fälle), Abrunden verliert im Mittel 10–26 %, im Extremfall alles.</li>
|
||||
<li><strong>Branch-and-Bound</strong> löst LP-Relaxationen, verzweigt an gebrochenen Variablen und kappt Äste anhand von Schranken. Der Preis: NP-Schwere.</li>
|
||||
<li><strong>Fünf Modellierungsmuster</strong> decken die meisten Praxisfälle ab: Fixkosten, Entweder-Oder, Wenn-Dann, Kardinalität, semikontinuierlich.</li>
|
||||
<li><strong><span class="math inline">M</span> so klein wie möglich</strong> — nicht nur wegen der Laufzeit. Ein übergroßes <span class="math inline">M</span> kann Binärvariablen bei <span class="math inline">10^{-8}</span> hängen lassen, wo sie dem Solver als 0 gelten: Anlagen produzieren, ohne dass ihre Fixkosten je verbucht werden (<em>Trickle Flow</em>).</li>
|
||||
<li><strong><span class="math inline">M</span> so klein wie möglich</strong> — nicht nur wegen der Laufzeit. Ein übergroßes <span class="math inline">M</span> kann Binärvariablen bei <span class="math inline">10^{-8}</span> hängen lassen, wo sie dem Solver als 0 gelten: Anlagen produzieren, ohne dass ihre Fixkosten je verbucht werden (<em><a href="anhang-glossar.md#gloss:trickle-flow" class="glossar-link">Trickle Flow</a></em>).</li>
|
||||
<li><strong><code>OPTIMAL</code> ist nicht der Normalfall.</strong> Werten Sie jeden Status aus und lesen Sie den <strong>MIP-Gap</strong> — er ist eine Garantie („höchstens 2,3 % vom Optimum“), keine Schätzung. Der Beweis der Optimalität kostet meist ein Vielfaches dessen, was das Finden der optimalen Lösung kostet.</li>
|
||||
<li><strong>Warm-Starts können nichts verfälschen, aber auch nichts versprechen.</strong> Ob ein Startwert hilft, hängt davon ab, ob er besser ist als das, was der Solver in derselben Zeit von allein findet — im Buch gemessen: einmal Faktor 2,2, einmal gar nichts.</li>
|
||||
<li><strong>Prüfen Sie jede modellierte Regel</strong> nach dem Lösen mit einer <code>assert</code>-Zeile — und rechnen Sie den Zielwert aus der Lösung nach, statt ihm zu glauben.</li>
|
||||
|
|
|
|||
38
OR_HTML_04/modellierung.html
generated
38
OR_HTML_04/modellierung.html
generated
|
|
@ -103,7 +103,7 @@
|
|||
<div class="card card-blick">
|
||||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um den Schritt, der vor jedem Solver kommt und über den kaum ein Lehrbuch spricht: aus einem Satz in einer Besprechung ein Modell zu machen. Genau hier scheitern Projekte — nicht an der Mathematik.</p>
|
||||
<p><strong>Worum geht es?</strong> Um den Schritt, der vor jedem <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> kommt und über den kaum ein Lehrbuch spricht: aus einem Satz in einer Besprechung ein Modell zu machen. Genau hier scheitern Projekte — nicht an der Mathematik.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> (die vier Bausteine eines Modells). Kein Solverwissen nötig; das ganze Kapitel kommt mit einer einzigen <code>linprog</code>-Zeile aus.</p>
|
||||
<p><strong>Danach können Sie:</strong> eine Anforderung daraufhin abklopfen, was sie <em>nicht</em> sagt; die Zielgröße so wählen, dass sie keinen Fehlanreiz setzt; harte von weichen Regeln unterscheiden — und begründen, warum diese Unterscheidung ein Jahr später über die Betriebsfähigkeit entscheidet.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 3 Stunden.</p>
|
||||
|
|
@ -167,7 +167,7 @@
|
|||
</tbody>
|
||||
</table>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> linprog</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> [linprog](anhang<span class="op">-</span>glossar.md<span class="co">#gloss:linprog){.glossar-link}</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="co"># Auftrag: A B C D E</span></span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>stunden <span class="op">=</span> np.array([ <span class="dv">60</span>, <span class="dv">30</span>, <span class="dv">30</span>, <span class="dv">25</span>, <span class="dv">15</span>], dtype<span class="op">=</span><span class="bu">float</span>)</span>
|
||||
|
|
@ -195,7 +195,7 @@ Deckungsbeitrag maximieren -> BD Umsatz 40,000 DB 19,000</code></pre>
|
|||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Ein Modell rechnet nicht aus, was man will, sondern was man aufgeschrieben hat. Die Differenz zwischen beidem ist die eigentliche Arbeit dieses Kapitels.</p>
|
||||
</blockquote>
|
||||
<p><strong>Warum funktioniert das?</strong> Weil eine Zielfunktion eine <strong>vollständige</strong> Aussage darüber ist, was zählt. Alles, was nicht darin steht, ist dem Modell gleichgültig — nicht „weniger wichtig”, sondern <strong>wertlos</strong>. Der Umsatzplan opfert den Deckungsbeitrag nicht aus Bosheit; er sieht ihn schlicht nicht.</p>
|
||||
<p><strong>Warum funktioniert das?</strong> Weil eine <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a> eine <strong>vollständige</strong> Aussage darüber ist, was zählt. Alles, was nicht darin steht, ist dem Modell gleichgültig — nicht „weniger wichtig”, sondern <strong>wertlos</strong>. Der Umsatzplan opfert den Deckungsbeitrag nicht aus Bosheit; er sieht ihn schlicht nicht.</p>
|
||||
<hr />
|
||||
<h2 id="sec:modellierung-lernziele">4.2 Lernziele</h2>
|
||||
<p>Nach diesem Kapitel können Sie …</p>
|
||||
|
|
@ -683,7 +683,7 @@ Drei Dinge, die deshalb vor dem ersten Modell geklaert gehoeren:
|
|||
</blockquote>
|
||||
<p>Wer sie nicht stellt, entscheidet sie trotzdem — nur unbewusst, beim Tippen.</p>
|
||||
<h3 id="teil-3-hart-oder-weich">Teil 3: Hart oder weich</h3>
|
||||
<p>Dieselbe Regel als Strafkosten je abgelehntem Stammkundenauftrag:</p>
|
||||
<p>Dieselbe Regel als <a href="anhang-glossar.md#gloss:strafkosten" class="glossar-link">Strafkosten</a> je abgelehntem Stammkundenauftrag:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
|
|
@ -758,7 +758,7 @@ Lesart C (weich): loesbar - 66,000 EUR Deckungsbeitrag, 1 Stammauftrag abgelehnt
|
|||
<tr class="even">
|
||||
<td>„Mehr als zwei Millionen gibt es nicht.”</td>
|
||||
<td>dasselbe, auf Geld</td>
|
||||
<td>Budgetlimit (B27)</td>
|
||||
<td><a href="anhang-glossar.md#gloss:budgetlimit" class="glossar-link">Budgetlimit</a> (B27)</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>„Möglichst nicht über 40 Stunden.”</td>
|
||||
|
|
@ -773,7 +773,7 @@ Lesart C (weich): loesbar - 66,000 EUR Deckungsbeitrag, 1 Stammauftrag abgelehnt
|
|||
<tr class="odd">
|
||||
<td>„Wenn wir die Anlage nutzen, fallen Fixkosten an.”</td>
|
||||
<td>Kosten, die erst ab der ersten Einheit anfallen</td>
|
||||
<td>Aktivierungsschalter (B1)</td>
|
||||
<td><a href="anhang-glossar.md#gloss:aktivierungsschalter" class="glossar-link">Aktivierungsschalter</a> (B1)</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>„Entweder gar nicht oder mindestens 50.”</td>
|
||||
|
|
@ -783,7 +783,7 @@ Lesart C (weich): loesbar - 66,000 EUR Deckungsbeitrag, 1 Stammauftrag abgelehnt
|
|||
<tr class="odd">
|
||||
<td>„Wenn wir A bauen, brauchen wir auch B.”</td>
|
||||
<td>eine Folgeverpflichtung</td>
|
||||
<td>Implikation (B3)</td>
|
||||
<td><a href="anhang-glossar.md#gloss:implikation" class="glossar-link">Implikation</a> (B3)</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>„Höchstens drei Positionen im Depot.”</td>
|
||||
|
|
@ -793,7 +793,7 @@ Lesart C (weich): loesbar - 66,000 EUR Deckungsbeitrag, 1 Stammauftrag abgelehnt
|
|||
<tr class="odd">
|
||||
<td>„Der Anteil muss mindestens 30 % betragen.”</td>
|
||||
<td>eine Bedingung auf ein <strong>Verhältnis</strong></td>
|
||||
<td>Verhältnis-Bedingung (B12)</td>
|
||||
<td><a href="anhang-glossar.md#gloss:verhaeltnis-bedingung" class="glossar-link">Verhältnis-Bedingung</a> (B12)</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>„Jeder Auftrag genau einem Mitarbeiter.”</td>
|
||||
|
|
@ -803,12 +803,12 @@ Lesart C (weich): loesbar - 66,000 EUR Deckungsbeitrag, 1 Stammauftrag abgelehnt
|
|||
<tr class="odd">
|
||||
<td>„Eine Maschine kann nur eines gleichzeitig.”</td>
|
||||
<td>zeitliche Ausschließlichkeit</td>
|
||||
<td>Nichtüberlappung (B14)</td>
|
||||
<td><a href="anhang-glossar.md#gloss:nichtueberlappung" class="glossar-link">Nichtüberlappung</a> (B14)</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>„B kann erst nach A.”</td>
|
||||
<td>eine Reihenfolge</td>
|
||||
<td>Vorrangbeziehung (B13)</td>
|
||||
<td><a href="anhang-glossar.md#gloss:vorrangbeziehung" class="glossar-link">Vorrangbeziehung</a> (B13)</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>„Höchstens fünf Tage am Stück.”</td>
|
||||
|
|
@ -818,12 +818,12 @@ Lesart C (weich): loesbar - 66,000 EUR Deckungsbeitrag, 1 Stammauftrag abgelehnt
|
|||
<tr class="even">
|
||||
<td>„Umstellen kostet uns eine halbe Stunde.”</td>
|
||||
<td>reihenfolgeabhängige Kosten</td>
|
||||
<td>Umrüstkosten (B17), Rüstzeit als Kapazität (B26)</td>
|
||||
<td><a href="anhang-glossar.md#gloss:umruestkosten" class="glossar-link">Umrüstkosten</a> (B17), <a href="anhang-glossar.md#gloss:ruestzeit" class="glossar-link">Rüstzeit</a> als Kapazität (B26)</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>„Was reinkommt, muss auch wieder raus.”</td>
|
||||
<td>Erhaltung an jedem Knoten</td>
|
||||
<td>Flusserhaltung (B22)</td>
|
||||
<td><a href="anhang-glossar.md#gloss:flusserhaltung" class="glossar-link">Flusserhaltung</a> (B22)</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>„Notfalls brechen wir die Regel.”</td>
|
||||
|
|
@ -843,15 +843,15 @@ Lesart C (weich): loesbar - 66,000 EUR Deckungsbeitrag, 1 Stammauftrag abgelehnt
|
|||
<tr class="odd">
|
||||
<td>„Was brächte uns eine zusätzliche Stunde?”</td>
|
||||
<td>die Frage nach dem Grenzwert einer Ressource</td>
|
||||
<td>Schattenpreis (<a href="lp.html#kap-lp">Kapitel 5</a>, <a href="praxisfallen.html#sec:praxisfallen-attribution">Abschnitt 22.4</a>)</td>
|
||||
<td><a href="anhang-glossar.md#gloss:schattenpreis" class="glossar-link">Schattenpreis</a> (<a href="lp.html#kap-lp">Kapitel 5</a>, <a href="praxisfallen.html#sec:praxisfallen-attribution">Abschnitt 22.4</a>)</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>„Mit 95 % Sicherheit muss es halten.”</td>
|
||||
<td>eine Zusage auf eine <strong>Quote</strong>, nicht auf einen Mittelwert</td>
|
||||
<td>Chance Constraint (<a href="unsicherheit.html#sec:unsicherheit-chance-constraints">Abschnitt 12.7</a>)</td>
|
||||
<td><a href="anhang-glossar.md#gloss:chance-constraint" class="glossar-link">Chance Constraint</a> (<a href="unsicherheit.html#sec:unsicherheit-chance-constraints">Abschnitt 12.7</a>)</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>„Wir sichern uns gegen Schätzfehler ab.”</td>
|
||||
<td>„Wir sichern uns gegen <a href="anhang-glossar.md#gloss:schaetzfehler" class="glossar-link">Schätzfehler</a> ab.”</td>
|
||||
<td>gegen die ungünstigste Parameterlage planen</td>
|
||||
<td>Worst-Case-Abzug (B21)</td>
|
||||
</tr>
|
||||
|
|
@ -927,15 +927,15 @@ Lesart C (weich): loesbar - 66,000 EUR Deckungsbeitrag, 1 Stammauftrag abgelehnt
|
|||
<td>„Besser als das hier geht es höchstens um 2 % — und die liegen unter unserer Datenungenauigkeit.”</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>CVaR</td>
|
||||
<td>„Wenn es schiefgeht, verlieren wir im Mittel so viel.” (Der VaR sagt nur, <strong>ob</strong> es schiefgeht.)</td>
|
||||
<td><a href="anhang-glossar.md#gloss:conditional-value-at-risk-cvar" class="glossar-link">CVaR</a></td>
|
||||
<td>„Wenn es schiefgeht, verlieren wir im Mittel so viel.” (Der <a href="anhang-glossar.md#gloss:value-at-risk-var" class="glossar-link">VaR</a> sagt nur, <strong>ob</strong> es schiefgeht.)</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>EVPI</td>
|
||||
<td><a href="anhang-glossar.md#gloss:evpi-expected-value-of-perfect-information" class="glossar-link">EVPI</a></td>
|
||||
<td>„Selbst eine perfekte Prognose wäre uns höchstens so viel wert.”</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Relaxation</td>
|
||||
<td><a href="anhang-glossar.md#gloss:relaxation" class="glossar-link">Relaxation</a></td>
|
||||
<td>„Wir haben die Regel probeweise gelockert, um zu sehen, was sie kostet.”</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
|
|||
108
OR_HTML_04/notation.html
generated
108
OR_HTML_04/notation.html
generated
|
|
@ -123,7 +123,7 @@
|
|||
<tr class="odd">
|
||||
<td><span class="math inline">x</span></td>
|
||||
<td>„iks“</td>
|
||||
<td><strong>Entscheidungsvariable(n)</strong> — das, was der Solver festlegen darf</td>
|
||||
<td><strong>Entscheidungsvariable(n)</strong> — das, was der <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> festlegen darf</td>
|
||||
<td>Anzahl gestarteter Trading-Bots (<a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a>)</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -147,19 +147,19 @@
|
|||
<tr class="odd">
|
||||
<td><span class="math inline">\mathbf{c}</span></td>
|
||||
<td>„Vektor ze“</td>
|
||||
<td><strong>Kosten- bzw. Ertragsvektor</strong> der Zielfunktion</td>
|
||||
<td><strong>Kosten- bzw. Ertragsvektor</strong> der <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a></td>
|
||||
<td>Gewinn je Bot-Typ: <span class="math inline">(150, 250)^\top</span></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><span class="math inline">\mathbf{A}</span></td>
|
||||
<td>„Matrix a“</td>
|
||||
<td><strong>Technologiematrix</strong> — wie viel Ressource verbraucht welche Variable</td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:technologiematrix" class="glossar-link">Technologiematrix</a></strong> — wie viel Ressource verbraucht welche Variable</td>
|
||||
<td>Zeile „RAM“: <span class="math inline">(4, 6)</span></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><span class="math inline">\mathbf{b}</span></td>
|
||||
<td>„Vektor be“</td>
|
||||
<td><strong>Kapazitätsvektor</strong>, „rechte Seite“ der Ungleichungen</td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:kapazitaetsvektor" class="glossar-link">Kapazitätsvektor</a></strong>, „rechte Seite“ der Ungleichungen</td>
|
||||
<td><span class="math inline">(40, 60)^\top</span> vCPU und GB</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -189,7 +189,7 @@
|
|||
<tr class="even">
|
||||
<td><span class="math inline">y_i,\ \lambda_i</span></td>
|
||||
<td>„y i“, „lambda i“</td>
|
||||
<td><strong>Dualvariable / Schattenpreis</strong> der Bedingung <span class="math inline">i</span></td>
|
||||
<td><strong>Dualvariable / <a href="anhang-glossar.md#gloss:schattenpreis" class="glossar-link">Schattenpreis</a></strong> der Bedingung <span class="math inline">i</span></td>
|
||||
<td>33,33 € je zusätzlicher Prüfstunde</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
|
|
@ -208,7 +208,7 @@
|
|||
<td><span class="math inline">\mathcal{F}</span></td>
|
||||
<td>„kalligrafisches ef“</td>
|
||||
<td><strong>Zulässiger Bereich</strong> — Menge aller erlaubten Lösungen</td>
|
||||
<td>das Polyeder aus <a href="fundament.html#kap-fundament">Kapitel 2</a></td>
|
||||
<td>das <a href="anhang-glossar.md#gloss:polyeder" class="glossar-link">Polyeder</a> aus <a href="fundament.html#kap-fundament">Kapitel 2</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><span class="math inline">Z,\ Z^*</span></td>
|
||||
|
|
@ -242,7 +242,7 @@
|
|||
<tr class="odd">
|
||||
<td><span class="math inline">\mathbb{R}</span></td>
|
||||
<td>Reelle Zahlen (beliebig teilbar)</td>
|
||||
<td>Variable darf 3,7 sein — <strong>LP</strong>, schnell lösbar</td>
|
||||
<td>Variable darf 3,7 sein — <strong><a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a></strong>, schnell lösbar</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><span class="math inline">\mathbb{R}^n</span></td>
|
||||
|
|
@ -252,7 +252,7 @@
|
|||
<tr class="odd">
|
||||
<td><span class="math inline">\mathbb{Z}</span></td>
|
||||
<td>Ganze Zahlen</td>
|
||||
<td>Variable muss 3 oder 4 sein — <strong>MILP</strong>, NP-schwer</td>
|
||||
<td>Variable muss 3 oder 4 sein — <strong><a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a></strong>, <a href="anhang-glossar.md#gloss:np-schwer" class="glossar-link">NP-schwer</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><span class="math inline">\mathbb{N}_0</span></td>
|
||||
|
|
@ -313,7 +313,7 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><span class="math inline">\mathbf{c}^\top \mathbf{x}</span></td>
|
||||
<td>Skalarprodukt</td>
|
||||
<td><a href="anhang-glossar.md#gloss:skalarprodukt" class="glossar-link">Skalarprodukt</a></td>
|
||||
<td>„<span class="math inline">c_1 x_1 + c_2 x_2 + \dots</span>“ — eine einzige Zahl</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
|
|
@ -338,7 +338,7 @@
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><span class="math inline">\nabla f</span></td>
|
||||
<td>„Nabla ef“, Gradient</td>
|
||||
<td>„Nabla ef“, <a href="anhang-glossar.md#gloss:gradient" class="glossar-link">Gradient</a></td>
|
||||
<td>Vektor aller partiellen Ableitungen — zeigt bergauf</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -420,12 +420,12 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><span class="math inline">\boldsymbol{\Sigma}</span></td>
|
||||
<td>„Sigma“ — <strong>Kovarianzmatrix</strong> der Renditen</td>
|
||||
<td>„Sigma“ — <strong><a href="anhang-glossar.md#gloss:kovarianzmatrix" class="glossar-link">Kovarianzmatrix</a></strong> der Renditen</td>
|
||||
<td><span class="math inline">N \times N</span>, Einheit Rendite²</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><span class="math inline">\sigma</span></td>
|
||||
<td>„sigma“ — <strong>Volatilität</strong> (Standardabweichung)</td>
|
||||
<td>„sigma“ — <strong><a href="anhang-glossar.md#gloss:volatilitaet" class="glossar-link">Volatilität</a></strong> (Standardabweichung)</td>
|
||||
<td><span class="math inline">0{,}20</span> = 20 % p. a.</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -455,12 +455,12 @@
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><span class="math inline">R_{i,t}</span></td>
|
||||
<td><strong>Diskrete Rendite</strong> von Titel <span class="math inline">i</span> am Tag <span class="math inline">t</span></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:diskrete-rendite" class="glossar-link">Diskrete Rendite</a></strong> von Titel <span class="math inline">i</span> am Tag <span class="math inline">t</span></td>
|
||||
<td><span class="math inline">P_t/P_{t-1} - 1</span></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><span class="math inline">r_{i,t}</span></td>
|
||||
<td><strong>Logarithmische Rendite</strong> (stetige Rendite)</td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:logarithmische-rendite" class="glossar-link">Logarithmische Rendite</a></strong> (stetige Rendite)</td>
|
||||
<td><span class="math inline">\ln(P_t/P_{t-1})</span></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
|
|
@ -475,7 +475,7 @@
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><span class="math inline">\alpha</span></td>
|
||||
<td>Konfidenzniveau bei VaR/CVaR</td>
|
||||
<td>Konfidenzniveau bei <a href="anhang-glossar.md#gloss:value-at-risk-var" class="glossar-link">VaR</a>/<a href="anhang-glossar.md#gloss:conditional-value-at-risk-cvar" class="glossar-link">CVaR</a></td>
|
||||
<td><span class="math inline">0{,}95</span> = „schlechteste 5 % der Tage“</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -548,7 +548,7 @@
|
|||
<tr class="odd">
|
||||
<td><span class="math inline">T</span></td>
|
||||
<td>„te“</td>
|
||||
<td><strong>Temperatur</strong> im Simulated Annealing — steuert, wie oft eine Verschlechterung angenommen wird</td>
|
||||
<td><strong>Temperatur</strong> im <a href="anhang-glossar.md#gloss:simulated-annealing" class="glossar-link">Simulated Annealing</a> — steuert, wie oft eine Verschlechterung angenommen wird</td>
|
||||
<td><a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -620,7 +620,7 @@
|
|||
</tbody>
|
||||
</table>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Achtung, Doppelbelegungen.</strong> In der Literatur — und deshalb auch hier — tragen einige Buchstaben je nach Kapitel verschiedene Bedeutungen. Die wichtigsten Fälle: <span class="math inline">\lambda</span> ist in <a href="lp.html#kap-lp">Kapitel 5</a> und <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a> ein <strong>Lagrange-Multiplikator/Schattenpreis</strong>, in <a href="markowitz.html#kap-markowitz">Kapitel 19</a> und <a href="cvar.html#kap-cvar">Kapitel 20</a> ein <strong>frei gewählter Risikoaversionsparameter</strong>. <span class="math inline">\gamma</span> ist in <a href="dynamische-programmierung.html#kap-dynamische-programmierung">Kapitel 13</a> der <strong>Diskontfaktor</strong>, in <a href="cvar.html#kap-cvar">Kapitel 20</a> die <strong>VaR-Hilfsvariable</strong>. <span class="math inline">S</span> bezeichnet als Matrix <span class="math inline">\mathbf{S}</span> die Stichprobenkovarianz, als Skalar <span class="math inline">S</span> die Szenarienzahl. <span class="math inline">\pi</span> ist in <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a> eine <strong>Reihenfolge</strong>, in <a href="dekomposition.html#kap-dekomposition">Kapitel 10</a> ein <strong>Dualpreis</strong> — beide Bedeutungen sind so verbreitet, dass ein Ausweichbuchstabe mehr verwirren als helfen würde. Der Kontext ist jeweils eindeutig, und die Kapitel weisen an der betreffenden Stelle darauf hin.</p>
|
||||
<p><strong>⚠️ Achtung, Doppelbelegungen.</strong> In der Literatur — und deshalb auch hier — tragen einige Buchstaben je nach Kapitel verschiedene Bedeutungen. Die wichtigsten Fälle: <span class="math inline">\lambda</span> ist in <a href="lp.html#kap-lp">Kapitel 5</a> und <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a> ein <strong><a href="anhang-glossar.md#gloss:lagrange-multiplikator" class="glossar-link">Lagrange-Multiplikator</a>/Schattenpreis</strong>, in <a href="markowitz.html#kap-markowitz">Kapitel 19</a> und <a href="cvar.html#kap-cvar">Kapitel 20</a> ein <strong>frei gewählter Risikoaversionsparameter</strong>. <span class="math inline">\gamma</span> ist in <a href="dynamische-programmierung.html#kap-dynamische-programmierung">Kapitel 13</a> der <strong>Diskontfaktor</strong>, in <a href="cvar.html#kap-cvar">Kapitel 20</a> die <strong>VaR-Hilfsvariable</strong>. <span class="math inline">S</span> bezeichnet als Matrix <span class="math inline">\mathbf{S}</span> die Stichprobenkovarianz, als Skalar <span class="math inline">S</span> die Szenarienzahl. <span class="math inline">\pi</span> ist in <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a> eine <strong>Reihenfolge</strong>, in <a href="dekomposition.html#kap-dekomposition">Kapitel 10</a> ein <strong>Dualpreis</strong> — beide Bedeutungen sind so verbreitet, dass ein Ausweichbuchstabe mehr verwirren als helfen würde. Der Kontext ist jeweils eindeutig, und die Kapitel weisen an der betreffenden Stelle darauf hin.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="abkürzungen-vollständig-ausgeschrieben">2. Abkürzungen — vollständig ausgeschrieben</h2>
|
||||
|
|
@ -672,55 +672,55 @@
|
|||
<td><a href="milp.html#kap-milp">Kapitel 6</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>QP</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:quadratische-programmierung-qp" class="glossar-link">QP</a></strong></td>
|
||||
<td>Quadratic Program(ming)</td>
|
||||
<td>Quadratische Optimierung</td>
|
||||
<td><a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>MIQP</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:miqp" class="glossar-link">MIQP</a></strong></td>
|
||||
<td>Mixed-Integer Quadratic Program(ming)</td>
|
||||
<td>Ganzzahlig-quadratische Optimierung</td>
|
||||
<td><a href="markowitz.html#kap-markowitz">Kapitel 19</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>NLP</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:nichtlineare-programmierung-nlp" class="glossar-link">NLP</a></strong></td>
|
||||
<td>Nonlinear Program(ming)</td>
|
||||
<td>Nichtlineare Optimierung</td>
|
||||
<td><a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>MINLP</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:minlp" class="glossar-link">MINLP</a></strong></td>
|
||||
<td>Mixed-Integer Nonlinear Program(ming)</td>
|
||||
<td>Ganzzahlig-nichtlineare Optimierung</td>
|
||||
<td><a href="oekosystem.html#kap-oekosystem">Kapitel 3</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>CP</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a></strong></td>
|
||||
<td>Constraint Programming</td>
|
||||
<td>Bedingungsprogrammierung</td>
|
||||
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>SAT</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a></strong></td>
|
||||
<td>Boolean <strong>Sat</strong>isfiability Problem</td>
|
||||
<td>Erfüllbarkeitsproblem der Aussagenlogik</td>
|
||||
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>CP-SAT</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a></strong></td>
|
||||
<td>Constraint Programming über SAT-Techniken</td>
|
||||
<td>Solver-Name von Google OR-Tools</td>
|
||||
<td>Solver-Name von Google <a href="anhang-glossar.md#gloss:or-tools" class="glossar-link">OR-Tools</a></td>
|
||||
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>CDCL</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:cdcl" class="glossar-link">CDCL</a></strong></td>
|
||||
<td>Conflict-Driven Clause Learning</td>
|
||||
<td>konfliktgetriebenes Klausellernen</td>
|
||||
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>DP</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:dynamische-programmierung-dp" class="glossar-link">DP</a></strong></td>
|
||||
<td>Dynamic Programming</td>
|
||||
<td>Dynamische Programmierung</td>
|
||||
<td><a href="dynamische-programmierung.html#kap-dynamische-programmierung">Kapitel 13</a></td>
|
||||
|
|
@ -738,13 +738,13 @@
|
|||
<td><a href="milp.html#kap-milp">Kapitel 6</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>KKT</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:karush-kuhn-tucker-bedingungen-kkt" class="glossar-link">KKT</a></strong></td>
|
||||
<td>Karush–Kuhn–Tucker (Bedingungen)</td>
|
||||
<td>Optimalitätsbedingungen bei Restriktionen</td>
|
||||
<td><a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>SLSQP</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:slsqp" class="glossar-link">SLSQP</a></strong></td>
|
||||
<td>Sequential Least Squares Programming</td>
|
||||
<td>sequentielle quadratische Optimierung</td>
|
||||
<td><a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a></td>
|
||||
|
|
@ -752,35 +752,35 @@
|
|||
<tr class="odd">
|
||||
<td><strong>RMT</strong></td>
|
||||
<td>Random Matrix Theory</td>
|
||||
<td>Zufallsmatrizentheorie</td>
|
||||
<td><a href="anhang-glossar.md#gloss:zufallsmatrizentheorie" class="glossar-link">Zufallsmatrizentheorie</a></td>
|
||||
<td><a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>SA</strong></td>
|
||||
<td>Simulated Annealing</td>
|
||||
<td>Simulierte Abkühlung — Metaheuristik, die Verschlechterungen mit fallender Wahrscheinlichkeit zulässt</td>
|
||||
<td>Simulierte Abkühlung — <a href="anhang-glossar.md#gloss:metaheuristik" class="glossar-link">Metaheuristik</a>, die Verschlechterungen mit fallender Wahrscheinlichkeit zulässt</td>
|
||||
<td><a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>LNS</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:large-neighborhood-search-lns" class="glossar-link">LNS</a></strong></td>
|
||||
<td>Large Neighborhood Search</td>
|
||||
<td>Große Nachbarschaftssuche: Teil der Lösung verwerfen, Rest exakt neu bauen</td>
|
||||
<td><a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>CG</strong></td>
|
||||
<td>Column Generation</td>
|
||||
<td><a href="anhang-glossar.md#gloss:column-generation" class="glossar-link">Column Generation</a></td>
|
||||
<td>Spaltengenerierung — Variablen erst erzeugen, wenn sie sich lohnen</td>
|
||||
<td><a href="dekomposition.html#kap-dekomposition">Kapitel 10</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>IIS</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:iis-irreducible-infeasible-subset" class="glossar-link">IIS</a></strong></td>
|
||||
<td>Irreducible Infeasible Subset</td>
|
||||
<td>Kleinste widersprüchliche Teilmenge von Bedingungen</td>
|
||||
<td><a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>MSE</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:mse" class="glossar-link">MSE</a></strong></td>
|
||||
<td>Mean Squared Error</td>
|
||||
<td>Mittlerer quadratischer Fehler — das Standardmaß für Prognosegüte</td>
|
||||
<td><a href="prognose.html#kap-prognose">Kapitel 15</a></td>
|
||||
|
|
@ -805,13 +805,13 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><strong>TSP</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:tsp-traveling-salesperson-problem" class="glossar-link">TSP</a></strong></td>
|
||||
<td>Traveling Salesperson Problem</td>
|
||||
<td>Problem des Handlungsreisenden</td>
|
||||
<td><a href="graphen.html#kap-graphen">Kapitel 8</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>VRP</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:vehicle-routing-problem-vrp" class="glossar-link">VRP</a></strong></td>
|
||||
<td>Vehicle Routing Problem</td>
|
||||
<td>Tourenplanungsproblem</td>
|
||||
<td><a href="graphen.html#kap-graphen">Kapitel 8</a></td>
|
||||
|
|
@ -829,7 +829,7 @@
|
|||
<td><a href="graphen.html#kap-graphen">Kapitel 8</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>CVRPTW</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:cvrptw" class="glossar-link">CVRPTW</a></strong></td>
|
||||
<td>Capacitated VRP with Time Windows</td>
|
||||
<td>mit Kapazitäten <em>und</em> Zeitfenstern</td>
|
||||
<td><a href="graphen.html#kap-graphen">Kapitel 8</a></td>
|
||||
|
|
@ -848,7 +848,7 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>JSSP</strong></td>
|
||||
<td>Job-Shop Scheduling Problem</td>
|
||||
<td>Job-Shop <a href="anhang-glossar.md#gloss:scheduling" class="glossar-link">Scheduling</a> Problem</td>
|
||||
<td>Werkstattfertigungs-Reihenfolgeproblem</td>
|
||||
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
|
||||
</tr>
|
||||
|
|
@ -878,7 +878,7 @@
|
|||
<td><a href="markowitz.html#kap-markowitz">Kapitel 19</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>GMV</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:global-minimum-variance-portfolio-gmv" class="glossar-link">GMV</a></strong></td>
|
||||
<td>Global Minimum Variance (Portfolio)</td>
|
||||
<td>Portfolio kleinstmöglicher Varianz</td>
|
||||
<td><a href="markowitz.html#kap-markowitz">Kapitel 19</a></td>
|
||||
|
|
@ -891,7 +891,7 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>SR</strong></td>
|
||||
<td>Sharpe Ratio</td>
|
||||
<td><a href="anhang-glossar.md#gloss:sharpe-ratio" class="glossar-link">Sharpe Ratio</a></td>
|
||||
<td>Überrendite je Einheit Volatilität</td>
|
||||
<td><a href="markowitz.html#kap-markowitz">Kapitel 19</a></td>
|
||||
</tr>
|
||||
|
|
@ -909,7 +909,7 @@
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>ES</strong></td>
|
||||
<td>Expected Shortfall</td>
|
||||
<td><a href="anhang-glossar.md#gloss:expected-shortfall" class="glossar-link">Expected Shortfall</a></td>
|
||||
<td>anderes Wort für CVaR</td>
|
||||
<td><a href="cvar.html#kap-cvar">Kapitel 20</a></td>
|
||||
</tr>
|
||||
|
|
@ -921,7 +921,7 @@
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>MDD</strong></td>
|
||||
<td>Maximum Drawdown</td>
|
||||
<td><a href="anhang-glossar.md#gloss:maximum-drawdown" class="glossar-link">Maximum Drawdown</a></td>
|
||||
<td>größter Rückgang vom Höchststand</td>
|
||||
<td><a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a></td>
|
||||
</tr>
|
||||
|
|
@ -963,7 +963,7 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><strong>HiGHS</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:highs" class="glossar-link">HiGHS</a></strong></td>
|
||||
<td><strong>Hi</strong>gh Performance <strong>G</strong>eneral-purpose <strong>S</strong>olver</td>
|
||||
<td>LP-, MILP- und QP-Solver in C++</td>
|
||||
<td>Open Source (MIT)</td>
|
||||
|
|
@ -975,25 +975,25 @@
|
|||
<td>Open Source (Apache 2.0)</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>CVXPY</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:cvxpy" class="glossar-link">CVXPY</a></strong></td>
|
||||
<td><strong>C</strong>on<strong>v</strong>e<strong>x</strong> <strong>Py</strong>thon</td>
|
||||
<td>Modellierungssprache für konvexe Optimierung</td>
|
||||
<td>Open Source (Apache 2.0)</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>SciPy</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:scipy" class="glossar-link">SciPy</a></strong></td>
|
||||
<td><strong>Sci</strong>entific <strong>Py</strong>thon</td>
|
||||
<td>Wissenschaftliches Python-Paket; <code>scipy.optimize</code> liefert LP- (über HiGHS), Zuordnungs- (<code>linear_sum_assignment</code>) und NLP-Solver (<code>minimize</code>)</td>
|
||||
<td>Open Source (BSD)</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>GLOP</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:glop" class="glossar-link">GLOP</a></strong></td>
|
||||
<td><strong>G</strong>oogle <strong>L</strong>inear <strong>Op</strong>timizer</td>
|
||||
<td>LP-Solver in OR-Tools</td>
|
||||
<td>Open Source</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>SCIP</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:scip" class="glossar-link">SCIP</a></strong></td>
|
||||
<td>Solving Constraint Integer Programs</td>
|
||||
<td>MILP/MINLP-Solver</td>
|
||||
<td>akademisch frei</td>
|
||||
|
|
@ -1035,7 +1035,7 @@
|
|||
<td>Open Source (EPL)</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>Gurobi</strong>, <strong>CPLEX</strong>, <strong>Xpress</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:gurobi" class="glossar-link">Gurobi</a></strong>, <strong>CPLEX</strong>, <strong>Xpress</strong></td>
|
||||
<td>—</td>
|
||||
<td>kommerzielle Hochleistungs-Solver</td>
|
||||
<td>kostenpflichtig</td>
|
||||
|
|
@ -1059,7 +1059,7 @@
|
|||
<td>—</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>GIL</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:gil-global-interpreter-lock" class="glossar-link">GIL</a></strong></td>
|
||||
<td>Global Interpreter Lock</td>
|
||||
<td>Pythons Sperre, die echte Parallelität von Python-Code verhindert — Solverbibliotheken in C++ geben sie frei (<a href="testing.html#kap-testing">Kapitel 23</a>)</td>
|
||||
<td>—</td>
|
||||
|
|
@ -1120,7 +1120,7 @@
|
|||
<td>Fehlende Nebenbedingung — Modell prüfen</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>MIP-Gap</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:mip-gap" class="glossar-link">MIP-Gap</a></strong></td>
|
||||
<td>Relativer Abstand beste Lösung ↔︎ beste Schranke</td>
|
||||
<td>1–2 % sind in der Praxis meist genug</td>
|
||||
</tr>
|
||||
|
|
@ -1130,7 +1130,7 @@
|
|||
<td>Referenz für das Pruning</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>Relaxation</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:relaxation" class="glossar-link">Relaxation</a></strong></td>
|
||||
<td>Modell mit weggelassener Ganzzahligkeit</td>
|
||||
<td>liefert die Schranke</td>
|
||||
</tr>
|
||||
|
|
@ -1145,9 +1145,9 @@
|
|||
<td>Slack = 0 → Engpass</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>Lookahead-Bias</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:lookahead-bias" class="glossar-link">Lookahead-Bias</a></strong></td>
|
||||
<td>Nutzung von Daten aus der Zukunft</td>
|
||||
<td>Backtest ist wertlos — <a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a></td>
|
||||
<td><a href="anhang-glossar.md#gloss:backtest" class="glossar-link">Backtest</a> ist wertlos — <a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
|||
54
OR_HTML_04/oekosystem.html
generated
54
OR_HTML_04/oekosystem.html
generated
|
|
@ -105,7 +105,7 @@
|
|||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Warum es für Optimierung in Python mehrere konkurrierende Bibliotheken gibt, was sie unterscheidet, und wie Sie in unter einer Minute die richtige auswählen.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> und <a href="fundament.html#kap-fundament">Kapitel 2</a>.</p>
|
||||
<p><strong>Danach können Sie:</strong> Für ein gegebenes Problem begründet einen Solver wählen, dasselbe Modell in verschiedenen Bibliotheken formulieren, die Ergebnisse gegeneinander prüfen — und messen, ob Ihre Laufzeit überhaupt im Solver entsteht oder schon davor.</p>
|
||||
<p><strong>Danach können Sie:</strong> Für ein gegebenes Problem begründet einen <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> wählen, dasselbe Modell in verschiedenen Bibliotheken formulieren, die Ergebnisse gegeneinander prüfen — und messen, ob Ihre Laufzeit überhaupt im Solver entsteht oder schon davor.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 4 Stunden.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>Ein_System_Vier_Ansaetze.py</code><br />
|
||||
|
|
@ -119,7 +119,7 @@
|
|||
<h2 id="sec:oekosystem-schnellstart">3.1 In 5 Minuten gelöst</h2>
|
||||
<div class="card card-schnellstart">
|
||||
<blockquote>
|
||||
<p><strong>🚀 In 5 Minuten gelöst: Ein LP ohne jede Installation</strong></p>
|
||||
<p><strong>🚀 In 5 Minuten gelöst: Ein <a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a> ohne jede Installation</strong></p>
|
||||
<p>Ein Futtermittelhersteller mischt zwei Rohstoffe zu möglichst geringen Kosten. Jeder Kilogramm Mischung muss mindestens 20 g Protein und 5 g Fett enthalten.</p>
|
||||
<table>
|
||||
<thead>
|
||||
|
|
@ -145,8 +145,8 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Sie brauchen dafür <strong>keine</strong> zusätzliche Bibliothek — SciPy genügt, und SciPy ist in jeder wissenschaftlichen Python-Installation schon da:</p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> linprog</span>
|
||||
<p>Sie brauchen dafür <strong>keine</strong> zusätzliche Bibliothek — <a href="anhang-glossar.md#gloss:scipy" class="glossar-link">SciPy</a> genügt, und SciPy ist in jeder wissenschaftlichen Python-Installation schon da:</p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> [linprog](anhang<span class="op">-</span>glossar.md<span class="co">#gloss:linprog){.glossar-link}</span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="co"># linprog MINIMIERT und kennt nur "<=". Mindestgehalte werden also negiert.</span></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>res <span class="op">=</span> linprog(c<span class="op">=</span>[<span class="fl">0.42</span>, <span class="fl">0.88</span>], <span class="co"># Kosten je kg</span></span>
|
||||
|
|
@ -158,19 +158,19 @@
|
|||
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(res.message)</span>
|
||||
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"Weizen </span><span class="sc">{</span>res<span class="sc">.</span>x[<span class="dv">0</span>]<span class="sc">:.3f}</span><span class="ss"> kg, Soja </span><span class="sc">{</span>res<span class="sc">.</span>x[<span class="dv">1</span>]<span class="sc">:.3f}</span><span class="ss"> kg -> </span><span class="sc">{</span>res<span class="sc">.</span>fun<span class="sc">:.4f}</span><span class="ss"> EUR/kg"</span>)</span></code></pre></div>
|
||||
<p><strong>Ausgabe:</strong></p>
|
||||
<pre><code>Optimization terminated successfully. (HiGHS Status 7: Optimal)
|
||||
<pre><code>Optimization terminated successfully. ([HiGHS](anhang-glossar.md#gloss:highs){.glossar-link} Status 7: Optimal)
|
||||
Weizen 0.750 kg, Soja 0.250 kg -> 0.5350 EUR/kg</code></pre>
|
||||
</blockquote>
|
||||
</div>
|
||||
<p><strong>Sie haben soeben HiGHS benutzt</strong> — denselben C++-Solver, der auch hinter <code>highspy</code>, hinter CVXPY und in vielen kommerziellen Systemen steckt. <code>scipy.optimize.linprog</code> ist nur die dünnste denkbare Hülle darum.</p>
|
||||
<p><strong>Sie haben soeben HiGHS benutzt</strong> — denselben C++-Solver, der auch hinter <code>highspy</code>, hinter <a href="anhang-glossar.md#gloss:cvxpy" class="glossar-link">CVXPY</a> und in vielen kommerziellen Systemen steckt. <code>scipy.optimize.linprog</code> ist nur die dünnste denkbare Hülle darum.</p>
|
||||
<p>Das ist die zentrale Botschaft dieses Kapitels: <strong>Modellierungsschicht und Solver sind zwei verschiedene Dinge.</strong> Die Bibliothek, in der Sie Ihr Modell hinschreiben, bestimmt, wie angenehm die Arbeit ist. Der Solver dahinter bestimmt, wie schnell gerechnet wird. Beide lassen sich unabhängig voneinander tauschen — und genau davon handelt der Rest des Kapitels.</p>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Zwei Stolpersteine stecken schon in diesen sechs Zeilen</strong></p>
|
||||
<ul>
|
||||
<li><code>linprog</code> <strong>minimiert immer</strong>. Wer maximieren will, negiert die Zielfunktion — und darf nicht vergessen, das Ergebnis zurückzudrehen.</li>
|
||||
<li><code>linprog</code> <strong>minimiert immer</strong>. Wer maximieren will, negiert die <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a> — und darf nicht vergessen, das Ergebnis zurückzudrehen.</li>
|
||||
<li><code>linprog</code> kennt <strong>nur <code><=</code></strong>. Ein Mindestgehalt „<span class="math inline">\ge 20</span>“ wird zu „<span class="math inline">-12x_1 - 44x_2 \le -20</span>“. Ein Vorzeichenfehler an dieser Stelle liefert eine perfekt aussehende Lösung, die das Gegenteil des Gewollten erfüllt.</li>
|
||||
</ul>
|
||||
<p>Beide Fallen verschwinden, sobald man eine Modellierungsschicht wie CVXPY oder Pyomo benutzt, in der <code>>=</code> einfach <code>>=</code> heißt. Das ist ein Hauptgrund, warum es sie gibt.</p>
|
||||
<p>Beide Fallen verschwinden, sobald man eine Modellierungsschicht wie CVXPY oder <a href="anhang-glossar.md#gloss:pyomo" class="glossar-link">Pyomo</a> benutzt, in der <code>>=</code> einfach <code>>=</code> heißt. Das ist ein Hauptgrund, warum es sie gibt.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:oekosystem-lernziele">3.2 Lernziele</h2>
|
||||
|
|
@ -181,15 +181,15 @@ Weizen 0.750 kg, Soja 0.250 kg -> 0.5350 EUR/kg</code></pre>
|
|||
<li>… dasselbe lineare Programm in <code>scipy.optimize</code>, <code>highspy</code>, <code>ortools</code> und <code>cvxpy</code> formulieren.</li>
|
||||
<li>… Ergebnisse verschiedener Solver gegeneinander validieren (<em>Cross-Check</em>).</li>
|
||||
<li>… einschätzen, wann sich der Aufwand einer Low-Level-Schnittstelle lohnt und wann nicht.</li>
|
||||
<li>… Pyomo und Linopy einordnen und begründen, wann sich der Umstieg auf sie lohnt.</li>
|
||||
<li>… Aufbau- und Lösezeit getrennt messen und einen Modellaufbau mit NumPy oder Polars vektorisieren, statt ihn in Python-Schleifen zu erzeugen.</li>
|
||||
<li>… Pyomo und <a href="anhang-glossar.md#gloss:linopy" class="glossar-link">Linopy</a> einordnen und begründen, wann sich der Umstieg auf sie lohnt.</li>
|
||||
<li>… Aufbau- und Lösezeit getrennt messen und einen Modellaufbau mit <a href="anhang-glossar.md#gloss:numpy" class="glossar-link">NumPy</a> oder <a href="anhang-glossar.md#gloss:polars" class="glossar-link">Polars</a> vektorisieren, statt ihn in Python-Schleifen zu erzeugen.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
<h2 id="sec:oekosystem-die-zwei-schichten-architektur">3.3 Die Zwei-Schichten-Architektur</h2>
|
||||
<p>Im modernen Operations Research schreibt man Optimierungsalgorithmen nicht selbst. Man nutzt eine <strong>zweischichtige Architektur</strong>:</p>
|
||||
<ol type="1">
|
||||
<li><strong>Modellierungsschicht (<em>Frontend</em>, DSL):</strong> Python-Bibliotheken, mit denen Entscheidungsvariablen, Zielfunktion und Nebenbedingungen in mathematiknaher Syntax formuliert werden. Hier arbeiten Sie.</li>
|
||||
<li><strong>Solver-Schicht (<em>Backend</em>, Engine):</strong> Hochoptimierte C++- oder Fortran-Bibliotheken, die das Modell in Matrixstrukturen übersetzen und mit spezialisierten Algorithmen lösen (Dual Simplex, Interior-Point, Branch-and-Cut, CDCL-SAT-Suche).</li>
|
||||
<li><strong>Solver-Schicht (<em>Backend</em>, Engine):</strong> Hochoptimierte C++- oder Fortran-Bibliotheken, die das Modell in Matrixstrukturen übersetzen und mit spezialisierten Algorithmen lösen (<a href="anhang-glossar.md#gloss:dual-simplex" class="glossar-link">Dual Simplex</a>, Interior-Point, <a href="anhang-glossar.md#gloss:branch-and-cut" class="glossar-link">Branch-and-Cut</a>, <a href="anhang-glossar.md#gloss:cdcl" class="glossar-link">CDCL</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a>-Suche).</li>
|
||||
</ol>
|
||||
<figure>
|
||||
<img src="bilder_04/kap03_solver_architektur.svg" alt="Abb. 3.1: Modellierungsschicht und Solver-Engines" />
|
||||
|
|
@ -198,7 +198,7 @@ Weizen 0.750 kg, Soja 0.250 kg -> 0.5350 EUR/kg</code></pre>
|
|||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Die Modellierungsschicht bestimmt, wie angenehm Sie arbeiten. Die Solver-Schicht bestimmt, wie schnell gerechnet wird. Beides ist entkoppelt — man kann dieselbe CVXPY-Formulierung mit fünf verschiedenen Solvern lösen.</p>
|
||||
</blockquote>
|
||||
<p><strong>Warum diese Trennung nützlich ist:</strong> Ein CVXPY-Modell, das heute mit dem freien Solver Clarabel läuft, läuft morgen ohne Codeänderung mit dem kommerziellen Gurobi — man tauscht ein Argument. Das schützt vor Herstellerbindung und erlaubt, im Projekt klein anzufangen.</p>
|
||||
<p><strong>Warum diese Trennung nützlich ist:</strong> Ein CVXPY-Modell, das heute mit dem freien Solver Clarabel läuft, läuft morgen ohne Codeänderung mit dem kommerziellen <a href="anhang-glossar.md#gloss:gurobi" class="glossar-link">Gurobi</a> — man tauscht ein Argument. Das schützt vor Herstellerbindung und erlaubt, im Projekt klein anzufangen.</p>
|
||||
<hr />
|
||||
<h2 id="sec:oekosystem-die-werkzeuge-im-vergleich">3.4 Die Werkzeuge im Vergleich</h2>
|
||||
<table>
|
||||
|
|
@ -225,27 +225,27 @@ Weizen 0.750 kg, Soja 0.250 kg -> 0.5350 EUR/kg</code></pre>
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>ortools</code> (Google)</td>
|
||||
<td>Diskrete Planung, Schichten, Vertretungspläne, Routing (VRP/TSP), kombinatorische Logik</td>
|
||||
<td>Diskrete Planung, Schichten, Vertretungspläne, Routing (<a href="anhang-glossar.md#gloss:vehicle-routing-problem-vrp" class="glossar-link">VRP</a>/<a href="anhang-glossar.md#gloss:tsp-traveling-salesperson-problem" class="glossar-link">TSP</a>), kombinatorische Logik</td>
|
||||
<td>Wenn diskrete Ja/Nein-Entscheidungen, Zeitfenster und Wenn-Dann-Regeln dominieren</td>
|
||||
<td>CP-SAT, GLOP, Routing Engine</td>
|
||||
<td><a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a>, <a href="anhang-glossar.md#gloss:glop" class="glossar-link">GLOP</a>, Routing Engine</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>cvxpy</code></td>
|
||||
<td>Konvexe Optimierung, quadratische Programme, Risikomodelle, Portfolios</td>
|
||||
<td><strong>Erste Wahl für Finanzoptimierung</strong>, Markowitz, CVaR, <span class="math inline">L_1</span>-Transaktionskosten</td>
|
||||
<td><strong>Erste Wahl für Finanzoptimierung</strong>, Markowitz, <a href="anhang-glossar.md#gloss:conditional-value-at-risk-cvar" class="glossar-link">CVaR</a>, <span class="math inline">L_1</span>-<a href="anhang-glossar.md#gloss:transaktionskosten" class="glossar-link">Transaktionskosten</a></td>
|
||||
<td>Clarabel, OSQP, ECOS, SCS, HiGHS</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>highspy</code></td>
|
||||
<td>Direkte Solver-Steuerung für LP/MILP, maximale Kontrolle</td>
|
||||
<td>Direkte Solver-Steuerung für LP/<a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a>, maximale Kontrolle</td>
|
||||
<td>Wenn Sie Modelle wiederholt und schnell aufbauen oder Solver-Details steuern müssen</td>
|
||||
<td>HiGHS</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>Pyomo</code></td>
|
||||
<td>Universelle Modellierungssprache (LP, MILP, MINLP)</td>
|
||||
<td>Universelle Modellierungssprache (LP, MILP, <a href="anhang-glossar.md#gloss:minlp" class="glossar-link">MINLP</a>)</td>
|
||||
<td>Industrielle Großmodelle mit strikter Trennung von Daten und Modell</td>
|
||||
<td>HiGHS, Gurobi, CPLEX, SCIP, IPOPT</td>
|
||||
<td>HiGHS, Gurobi, CPLEX, <a href="anhang-glossar.md#gloss:scip" class="glossar-link">SCIP</a>, IPOPT</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>Linopy</code></td>
|
||||
|
|
@ -258,7 +258,7 @@ Weizen 0.750 kg, Soja 0.250 kg -> 0.5350 EUR/kg</code></pre>
|
|||
<h3 id="die-entscheidung-in-drei-fragen">Die Entscheidung in drei Fragen</h3>
|
||||
<p>Statt die Tabelle auswendig zu lernen, beantworten Sie drei Fragen:</p>
|
||||
<blockquote>
|
||||
<p><strong>Frage 1: Gibt es Ja/Nein-Entscheidungen oder Reihenfolgen?</strong> → <strong>Ja:</strong> OR-Tools (CP-SAT) bei Zuweisung/Scheduling, oder MILP über HiGHS bei ökonomischen Fixkostenmodellen. → <strong>Nein:</strong> weiter zu Frage 2.</p>
|
||||
<p><strong>Frage 1: Gibt es Ja/Nein-Entscheidungen oder Reihenfolgen?</strong> → <strong>Ja:</strong> <a href="anhang-glossar.md#gloss:or-tools" class="glossar-link">OR-Tools</a> (<a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-SAT) bei Zuweisung/<a href="anhang-glossar.md#gloss:scheduling" class="glossar-link">Scheduling</a>, oder MILP über HiGHS bei ökonomischen Fixkostenmodellen. → <strong>Nein:</strong> weiter zu Frage 2.</p>
|
||||
<p><strong>Frage 2: Ist die Zielfunktion linear?</strong> → <strong>Ja:</strong> <code>scipy.optimize.linprog</code> (klein) oder <code>highspy</code> (groß, wiederholt). → <strong>Nein, aber konvex</strong> (Quadrate, Normen, <code>log</code>, <code>exp</code> in konvexer Kombination): <strong>CVXPY</strong>. → <strong>Nein und nicht konvex:</strong> <code>scipy.optimize.minimize</code> — im Bewusstsein, dass nur ein lokales Optimum herauskommt.</p>
|
||||
<p><strong>Frage 3: Ist es ein Routing-Problem mit Fahrzeugen, Depots und Zeitfenstern?</strong> → <strong>Ja:</strong> OR-Tools <strong>Routing Library</strong> (nicht CP-SAT von Hand nachbauen).</p>
|
||||
</blockquote>
|
||||
|
|
@ -448,7 +448,7 @@ Weizen 0.750 kg, Soja 0.250 kg -> 0.5350 EUR/kg</code></pre>
|
|||
<blockquote>
|
||||
<p><strong>⚠️ <code>max_tasks_per_child=1</code> ist nicht optional</strong> Ein Pool ohne diese Angabe ist der <strong>Normalfall</strong> — er soll seine Arbeiter ja wiederverwenden. Wer die Isolation über einen Pool herstellt und das vergisst, hat einen Prozesswechsel programmiert, aber keine Isolation gewonnen: Die zweite Aufgabe landet im selben Interpreter wie die erste. Der Absturz kommt dann nicht beim ersten Solver, sondern beim zweiten — und sieht aus wie ein Problem des zweiten.</p>
|
||||
</blockquote>
|
||||
<p>Denselben Aufbau verwenden <code>Solverwechsel_CPSAT_HiGHS.py</code> (<a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a>) und <code>Benchmark_Skalierung.py</code> (<a href="testing.html#kap-testing">Kapitel 23</a>). Dort wandern zusätzlich <strong>Datenobjekte</strong> über die Prozessgrenze statt Zeichenketten — möglich, weil Domänenmodell und Lösungs-DTO keinen Solver kennen (<a href="praxisfallen.html#sec:praxisfallen-or-kern">Abschnitt 22.6</a>).</p>
|
||||
<p>Denselben Aufbau verwenden <code>Solverwechsel_CPSAT_HiGHS.py</code> (<a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a>) und <code>Benchmark_Skalierung.py</code> (<a href="testing.html#kap-testing">Kapitel 23</a>). Dort wandern zusätzlich <strong>Datenobjekte</strong> über die Prozessgrenze statt Zeichenketten — möglich, weil Domänenmodell und Lösungs-<a href="anhang-glossar.md#gloss:dto-data-transfer-object" class="glossar-link">DTO</a> keinen Solver kennen (<a href="praxisfallen.html#sec:praxisfallen-or-kern">Abschnitt 22.6</a>).</p>
|
||||
<div class="sourceCode" id="cb6"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||||
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Ein_System_Vier_Ansaetze.py</span></span>
|
||||
|
|
@ -638,7 +638,7 @@ Alle Wege fuehren zum selben, von Hand bestaetigten Optimum.
|
|||
<tr class="even">
|
||||
<td><code>highspy</code></td>
|
||||
<td>~15</td>
|
||||
<td>Alles explizit, inklusive CSR-Format der dünnbesetzten Matrix. Aufwendig — dafür volle Kontrolle und kein Overhead beim wiederholten Lösen.</td>
|
||||
<td>Alles explizit, inklusive <a href="anhang-glossar.md#gloss:csr-format" class="glossar-link">CSR-Format</a> der dünnbesetzten Matrix. Aufwendig — dafür volle Kontrolle und kein Overhead beim wiederholten Lösen.</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>cvxpy</code></td>
|
||||
|
|
@ -697,7 +697,7 @@ Alle Wege fuehren zum selben, von Hand bestaetigten Optimum.
|
|||
<li><strong>Vergessen, dass <code>linprog</code> minimiert.</strong> Der häufigste Fehler überhaupt. Symptom: Der „optimale“ Gewinn ist erstaunlich niedrig oder null.</li>
|
||||
<li><strong>CVXPY für ein nicht-konvexes Problem verwenden.</strong> CVXPY lehnt das ab mit <code>DCPError: Problem does not follow DCP rules</code>. Das ist ein <strong>Feature</strong>, keine Einschränkung: Der Fehler sagt Ihnen, dass Ihre Formulierung keine Optimalitätsgarantie hätte.</li>
|
||||
<li><strong>CP-SAT mit kontinuierlichen Variablen füttern.</strong> CP-SAT kennt nur ganze Zahlen. Wer Euro-Beträge modelliert, rechnet in Cent (Ganzzahl) — oder nimmt einen LP-Solver.</li>
|
||||
<li><strong>Für jeden Lauf ein neues Modell bauen.</strong> Bei 60 Backtest-Rebalancings kostet das Aufbauen mehr Zeit als das Lösen. <code>highspy</code> und CVXPY-<code>Parameter</code> erlauben es, das Modell einmal zu bauen und nur Daten zu tauschen (siehe <a href="markowitz.html#kap-markowitz">Kapitel 19</a> und <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a>).</li>
|
||||
<li><strong>Für jeden Lauf ein neues Modell bauen.</strong> Bei 60 <a href="anhang-glossar.md#gloss:backtest" class="glossar-link">Backtest</a>-Rebalancings kostet das Aufbauen mehr Zeit als das Lösen. <code>highspy</code> und CVXPY-<code>Parameter</code> erlauben es, das Modell einmal zu bauen und nur Daten zu tauschen (siehe <a href="markowitz.html#kap-markowitz">Kapitel 19</a> und <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a>).</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<hr />
|
||||
|
|
@ -729,7 +729,7 @@ Alle Wege fuehren zum selben, von Hand bestaetigten Optimum.
|
|||
<tr class="odd">
|
||||
<td>Dienstpläne, Zuordnung, Reihenfolge</td>
|
||||
<td><strong>CP-SAT</strong></td>
|
||||
<td>Globale Constraints, Konfliktlernen</td>
|
||||
<td><a href="anhang-glossar.md#gloss:globale-constraints" class="glossar-link">Globale Constraints</a>, Konfliktlernen</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>Fahrzeugtouren</td>
|
||||
|
|
@ -747,7 +747,7 @@ Alle Wege fuehren zum selben, von Hand bestaetigten Optimum.
|
|||
<td>Modellaufbau wird sonst zum Engpass</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Nichtkonvexes NLP</td>
|
||||
<td>Nichtkonvexes <a href="anhang-glossar.md#gloss:nichtlineare-programmierung-nlp" class="glossar-link">NLP</a></td>
|
||||
<td><code>scipy.optimize.minimize</code></td>
|
||||
<td>Bewusst mit mehreren Startpunkten arbeiten</td>
|
||||
</tr>
|
||||
|
|
@ -1400,7 +1400,7 @@ Groesse Variante Aufbau Loesen Aufba
|
|||
<div class="card card-denkfehler">
|
||||
<blockquote>
|
||||
<p><strong>🐛 Finde den Denkfehler: Der Solver, der angeblich dreimal schneller ist</strong></p>
|
||||
<p>Ein Team vergleicht zwei Bibliotheken für sein Zuordnungsproblem und schreibt ins Protokoll: <em>„CVXPY braucht 1,9 s, SciPy nur 0,6 s — wir setzen auf SciPy.“</em> Gemessen wurde so:</p>
|
||||
<p>Ein Team vergleicht zwei Bibliotheken für sein <a href="anhang-glossar.md#gloss:zuordnungsproblem" class="glossar-link">Zuordnungsproblem</a> und schreibt ins Protokoll: <em>„CVXPY braucht 1,9 s, SciPy nur 0,6 s — wir setzen auf SciPy.“</em> Gemessen wurde so:</p>
|
||||
<div class="sourceCode" id="cb14"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> time</span>
|
||||
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>t0 <span class="op">=</span> time.perf_counter()</span>
|
||||
|
|
@ -1425,9 +1425,9 @@ Groesse Variante Aufbau Loesen Aufba
|
|||
<blockquote>
|
||||
<p><strong>❓ Micro-Quiz 3: Drei Fragen zum Selbstcheck</strong></p>
|
||||
<p>Genau eine Antwort ist jeweils richtig. Auflösung in <a href="anhang-loesungen.html#quiz-loesung-oekosystem">Anhang A</a>.</p>
|
||||
<p><strong>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?</strong> (a) CVXPY — es prüft die Konvexität automatisch. (b) OR-Tools CP-SAT — diskrete Zuweisung mit logischen Regeln ist genau sein Gebiet. (c) <code>scipy.optimize.minimize</code> — es kann beliebige Zielfunktionen.</p>
|
||||
<p><strong>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?</strong> (a) CVXPY — es prüft die <a href="anhang-glossar.md#gloss:konvexitaet" class="glossar-link">Konvexität</a> automatisch. (b) OR-Tools CP-SAT — diskrete Zuweisung mit logischen Regeln ist genau sein Gebiet. (c) <code>scipy.optimize.minimize</code> — es kann beliebige Zielfunktionen.</p>
|
||||
<p><strong>2. Ihr Modell mit 80 000 Variablen braucht 40 Sekunden, davon 32 Sekunden bis zum ersten Solver-Aufruf. Was ist die wirksamste Maßnahme?</strong> (a) Einen kommerziellen Solver lizenzieren. (b) Das Zeitlimit des Solvers heraufsetzen. (c) Den Modellaufbau vektorisieren — der Solver ist mit 8 Sekunden gar nicht der Engpass.</p>
|
||||
<p><strong>3. Was haben <code>scipy.optimize.linprog</code>, <code>highspy</code>, CVXPY (mit Standardeinstellung) und Pyomo (mit <code>appsi_highs</code>) gemeinsam?</strong> (a) Sie implementieren jeweils einen eigenen 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.</p>
|
||||
<p><strong>3. Was haben <code>scipy.optimize.linprog</code>, <code>highspy</code>, CVXPY (mit Standardeinstellung) und Pyomo (mit <code>appsi_highs</code>) gemeinsam?</strong> (a) Sie implementieren jeweils einen eigenen <a href="anhang-glossar.md#gloss:simplex-algorithmus" class="glossar-link">Simplex-Algorithmus</a> 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.</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
<hr />
|
||||
|
|
|
|||
78
OR_HTML_04/praxisfallen.html
generated
78
OR_HTML_04/praxisfallen.html
generated
|
|
@ -126,7 +126,7 @@
|
|||
<blockquote>
|
||||
<p><strong>🚀 In 5 Minuten gelöst: Die Abnahmeprüfung, die in jedes Modell gehört</strong></p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> pruefe_loesung(x, A, b, kosten, zielwert, ganzzahlig<span class="op">=</span>(), toleranz<span class="op">=</span><span class="fl">1e-6</span>):</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Prueft eine Loesung gegen die Anforderungen - OHNE den Solver zu fragen."""</span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Prueft eine Loesung gegen die Anforderungen - OHNE den [Solver](anhang-glossar.md#gloss:solver){.glossar-link} zu fragen."""</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> beanstandungen <span class="op">=</span> []</span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> verbrauch <span class="op">=</span> A <span class="op">@</span> x <span class="co"># 1. Werden Grenzen eingehalten?</span></span>
|
||||
|
|
@ -193,13 +193,13 @@
|
|||
<ol type="1">
|
||||
<li>… die fünf typischen Praxisfallen benennen und je ein Gegenmittel nennen.</li>
|
||||
<li>… ein unlösbares Modell in einen „am wenigsten schlechten“ Plan verwandeln.</li>
|
||||
<li>… Solver-Ergebnisse erklärbar machen (<em>Explainable OR</em>).</li>
|
||||
<li>… für jede Nebenbedingung beziffern, was sie den Plan kostet — und begründen, warum der Schattenpreis diese Frage nur für die <em>nächste</em> Einheit beantwortet.</li>
|
||||
<li>… Solver-Ergebnisse erklärbar machen (<em><a href="anhang-glossar.md#gloss:explainable-or" class="glossar-link">Explainable OR</a></em>).</li>
|
||||
<li>… für jede Nebenbedingung beziffern, was sie den Plan kostet — und begründen, warum der <a href="anhang-glossar.md#gloss:schattenpreis" class="glossar-link">Schattenpreis</a> diese Frage nur für die <em>nächste</em> Einheit beantwortet.</li>
|
||||
<li>… Zeitlimits und Optimalitätslücken sinnvoll setzen.</li>
|
||||
<li>… die Architektur einer produktionsreifen OR-Plattform skizzieren.</li>
|
||||
<li>… eine <strong>modellunabhängige Abnahmeprüfung</strong> schreiben, die eine Lösung gegen die Anforderungen prüft statt gegen das Modell.</li>
|
||||
<li>… Status, Gap und Zeitausschöpfung protokollieren und begründen, warum eine konstante Laufzeit bei Zeitlimit ein Warnsignal ist.</li>
|
||||
<li>… ein Modell in Domänenschicht, Modellbauer und Lösungs-DTO trennen — und begründen, warum sich das nicht wegen des Solverwechsels lohnt, sondern wegen der Prüfbarkeit.</li>
|
||||
<li>… ein Modell in Domänenschicht, Modellbauer und Lösungs-<a href="anhang-glossar.md#gloss:dto-data-transfer-object" class="glossar-link">DTO</a> trennen — und begründen, warum sich das nicht wegen des Solverwechsels lohnt, sondern wegen der Prüfbarkeit.</li>
|
||||
<li>… die Statuswerte verschiedener Solverbibliotheken auf eine gemeinsame Sprache abbilden.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
|
|
@ -209,10 +209,10 @@
|
|||
<figcaption aria-hidden="true">Abb. 22.1: Die fünf typischen Praxisfallen</figcaption>
|
||||
</figure>
|
||||
<h3 id="falle-1-infeasibility">Falle 1 — Infeasibility</h3>
|
||||
<p>Wenn Parameter unglücklich zusammentreffen — drei Mitarbeitende gleichzeitig krank, kein qualifizierter Ersatz —, meldet der Solver schlicht <code>INFEASIBLE</code>.</p>
|
||||
<p>Wenn <a href="anhang-glossar.md#gloss:parameter" class="glossar-link">Parameter</a> unglücklich zusammentreffen — drei Mitarbeitende gleichzeitig krank, kein qualifizierter Ersatz —, meldet der Solver schlicht <code>INFEASIBLE</code>.</p>
|
||||
<ul>
|
||||
<li><strong>Falsch:</strong> Das System stürzt ab oder zeigt „Fehler“. Der Disponent steht ohne Plan da.</li>
|
||||
<li><strong>Richtig:</strong> <strong>Hierarchische Relaxation.</strong> Jede harte Bedingung, die im Notfall gebrochen werden darf, erhält eine teure Schlupfvariable. So liefert der Solver immer einen Plan — und zeigt zugleich präzise, <strong>wo</strong> es klemmt.</li>
|
||||
<li><strong>Richtig:</strong> <strong><a href="anhang-glossar.md#gloss:hierarchische-relaxation" class="glossar-link">Hierarchische Relaxation</a>.</strong> Jede harte Bedingung, die im Notfall gebrochen werden darf, erhält eine teure Schlupfvariable. So liefert der Solver immer einen Plan — und zeigt zugleich präzise, <strong>wo</strong> es klemmt.</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||||
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
|
|
@ -328,11 +328,11 @@
|
|||
<span id="cb2-112"><a href="#cb2-112" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">78</span>)</span></code></pre></div>
|
||||
<h3 id="falle-2-der-black-box-effekt">Falle 2 — Der Black-Box-Effekt</h3>
|
||||
<p>Ein Planer oder Trader lehnt ein System ab, wenn er die Zuweisungen nicht nachvollziehen kann. <strong>Akzeptanz ist keine Nebensache, sondern Voraussetzung für den Betrieb.</strong></p>
|
||||
<p>Jede Entscheidung braucht einen <strong>Constraint-Trace</strong>:</p>
|
||||
<p>Jede Entscheidung braucht einen <strong><a href="anhang-glossar.md#gloss:constraint-trace" class="glossar-link">Constraint-Trace</a></strong>:</p>
|
||||
<blockquote>
|
||||
<p><em>„Warum bekommt Person A die Stunde und nicht Person B?“</em> → <em>„Weil B heute bereits zwei Vertretungsstunden hat und bei einer dritten die gesetzliche Ruhezeit von 11 Stunden unterschritten würde. A hat 80 Strafpunkte weniger.“</em></p>
|
||||
</blockquote>
|
||||
<p>Bei Portfolioentscheidungen: <strong>Kostenzerlegung</strong> ausweisen — Alpha-Ertrag, Risikoprämie, Transaktionskostenstrafe (siehe das Muster in <a href="cpsat.html#kap-cpsat">Kapitel 7</a> und <a href="cvar.html#kap-cvar">Kapitel 20</a>).</p>
|
||||
<p>Bei Portfolioentscheidungen: <strong><a href="anhang-glossar.md#gloss:kostenzerlegung" class="glossar-link">Kostenzerlegung</a></strong> ausweisen — Alpha-Ertrag, Risikoprämie, Transaktionskostenstrafe (siehe das Muster in <a href="cpsat.html#kap-cpsat">Kapitel 7</a> und <a href="cvar.html#kap-cvar">Kapitel 20</a>).</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Die Faustregel für Erklärbarkeit</strong> Für jede Entscheidung sollten Sie drei Fragen beantworten können: 1. <strong>Warum diese Lösung?</strong> — Zielfunktionswert und seine Bestandteile. 2. <strong>Warum nicht die naheliegende Alternative?</strong> — Welche Bedingung verhindert sie? 3. <strong>Was würde die Lösung verbessern?</strong> — Schattenpreise: welcher Engpass, welcher Wert.</p>
|
||||
<p><a href="lp.html#kap-lp">Kapitel 5</a> liefert für Frage 3 das Werkzeug. Nutzen Sie es — Schattenpreise sind in Managementgesprächen oft wertvoller als die Lösung selbst.</p>
|
||||
|
|
@ -446,14 +446,14 @@
|
|||
<h3 id="falle-3-regimewechsel-und-schätzfehler">Falle 3 — Regimewechsel und Schätzfehler</h3>
|
||||
<p>Ein Modell, das auf einer mehrjährigen Aufwärtsphase kalibriert wurde, kennt keine Liquiditätskrise und keine Zinswende.</p>
|
||||
<ul>
|
||||
<li><strong>Robuste Schätzung</strong> statt roher Historie: Ledoit-Wolf-Shrinkage (<a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a>), Szenarien (<a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a>).</li>
|
||||
<li><strong>Robuste Schätzung</strong> statt roher Historie: <a href="anhang-glossar.md#gloss:ledoit-wolf-shrinkage" class="glossar-link">Ledoit-Wolf-Shrinkage</a> (<a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a>), Szenarien (<a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a>).</li>
|
||||
<li><strong>Harte Obergrenzen</strong> für Einzelpositionen und Sektoren — auch dann, wenn der Solver rechnerisch alles in einen Titel legen möchte. Die Grenze kostet Ertrag im Normalfall und rettet im Ernstfall.</li>
|
||||
<li><strong>Rollierende Neuschätzung</strong> statt einmaliger Kalibrierung.</li>
|
||||
</ul>
|
||||
<h3 id="falle-4-lookahead--und-survivorship-bias">Falle 4 — Lookahead- und Survivorship-Bias</h3>
|
||||
<p>Ausführlich in <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a> behandelt. Die Kurzfassung: Beide Fehler machen Backtests systematisch zu gut, ohne eine Fehlermeldung zu erzeugen. Der Lookahead-Selbsttest aus <a href="handelsmaschine.html#sec:handelsmaschine-die-engine">Abschnitt 21.5</a> findet den ersten automatisch.</p>
|
||||
<h3 id="falle-5-laufzeitexplosion">Falle 5 — Laufzeitexplosion</h3>
|
||||
<p>Exakte Optimalität kann bei MILP oder CP-SAT Minuten bis Stunden dauern — und die Laufzeit wächst nicht linear mit der Problemgröße.</p>
|
||||
<p>Exakte Optimalität kann bei <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> oder <a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a> Minuten bis Stunden dauern — und die Laufzeit wächst nicht linear mit der Problemgröße.</p>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 33%" />
|
||||
|
|
@ -464,7 +464,7 @@
|
|||
<tr class="header">
|
||||
<th>Einsatzszenario</th>
|
||||
<th>Empfohlenes Zeitlimit</th>
|
||||
<th>Akzeptabler MIP-Gap</th>
|
||||
<th>Akzeptabler <a href="anhang-glossar.md#gloss:mip-gap" class="glossar-link">MIP-Gap</a></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -496,11 +496,11 @@
|
|||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:praxisfallen-attribution">22.4 Constraint Attribution: welche Bedingung kostet wie viel?</h2>
|
||||
<p>Der Constraint-Trace beantwortet „warum <strong>diese</strong> Zuweisung?“. Der Deletion Filter in <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a> beantwortet „warum geht es <strong>gar nicht</strong>?“. Der häufigste Fall in der Praxis liegt dazwischen, und für ihn hat bisher niemand ein Werkzeug bekommen:</p>
|
||||
<p>Der Constraint-Trace beantwortet „warum <strong>diese</strong> Zuweisung?“. Der <a href="anhang-glossar.md#gloss:deletion-filter" class="glossar-link">Deletion Filter</a> in <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a> beantwortet „warum geht es <strong>gar nicht</strong>?“. Der häufigste Fall in der Praxis liegt dazwischen, und für ihn hat bisher niemand ein Werkzeug bekommen:</p>
|
||||
<blockquote>
|
||||
<p><em>Das Modell rechnet. Der Plan ist zulässig. Und trotzdem ist er enttäuschend — nur weiß niemand, woran es liegt.</em></p>
|
||||
</blockquote>
|
||||
<p>Die Antwort heißt <strong>Constraint Attribution</strong>: Jede Bedingungsgruppe wird einzeln gelockert, und gemessen wird, was sich am Zielwert ändert. Das ist dasselbe Verfahren wie der Deletion Filter — nur mit <strong>Kosten</strong> statt Zulässigkeit als Kriterium.</p>
|
||||
<p>Die Antwort heißt <strong><a href="anhang-glossar.md#gloss:constraint-attribution" class="glossar-link">Constraint Attribution</a></strong>: Jede Bedingungsgruppe wird einzeln gelockert, und gemessen wird, was sich am Zielwert ändert. Das ist dasselbe Verfahren wie der Deletion Filter — nur mit <strong>Kosten</strong> statt Zulässigkeit als Kriterium.</p>
|
||||
<p>Gerechnet wird auf derselben Fabrik wie die Konfliktsuche in <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a>, aber <strong>nach der Reparatur</strong>: Dort war die Lackierkapazität von 150 Stunden der Kern des Widerspruchs (<span class="math inline">2 \cdot 40 + 3 \cdot 30 = 170 > 150</span>). Eine zweite Schicht hat sie auf 210 gebracht, der Mindestumsatz wurde auf 10 000 € gesenkt. Jetzt ist das Modell lösbar — und die Frage lautet nicht mehr „warum nicht?“, sondern „was kostet uns was?“.</p>
|
||||
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||||
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
|
|
@ -908,7 +908,7 @@ aus.
|
|||
|
||||
==============================================================================</code></pre>
|
||||
<h3 id="drei-befunde-und-keiner-steht-im-solverergebnis">Drei Befunde, und keiner steht im Solverergebnis</h3>
|
||||
<p><strong>Erstens: bindend heißt nicht teuer.</strong> Fünf Bedingungen binden, aber „Lackierbudget Schicht 2“ tut es mit einem Schattenpreis von <strong>0,00 €</strong>. Sie berührt den Plan, ohne ihn zu verteuern — wer sie nachverhandelt, gewinnt nichts. Das ist derselbe Unterschied, den <code>Erklaerbarkeit.py</code> oben an einer einzelnen Zuweisung zeigt, hier im Dualwert eines LP.</p>
|
||||
<p><strong>Erstens: bindend heißt nicht teuer.</strong> Fünf Bedingungen binden, aber „Lackierbudget Schicht 2“ tut es mit einem Schattenpreis von <strong>0,00 €</strong>. Sie berührt den Plan, ohne ihn zu verteuern — wer sie nachverhandelt, gewinnt nichts. Das ist derselbe Unterschied, den <code>Erklaerbarkeit.py</code> oben an einer einzelnen Zuweisung zeigt, hier im Dualwert eines <a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a>.</p>
|
||||
<p><strong>Zweitens: Der Schattenpreis ist eine Momentaufnahme.</strong> Er gilt für die <strong>nächste</strong> Einheit. Ein Planer kauft aber keine Einheit, sondern eine Schicht. Für die Lackiererei verspricht die Hochrechnung <span class="math inline">4{,}00 \cdot 30 = 120</span> €; gemessen kommen <strong>60 €</strong>. Der Preis von 4,00 € gilt exakt bis <strong>+15 Stunden</strong>, danach begrenzt etwas anderes — <strong>die zweite Hälfte der Sonderschicht wäre bezahlt und wirkungslos.</strong></p>
|
||||
<p>Und die Ranglisten drehen sich dabei um: Nach Schattenpreis führt der Trägervertrag mit 18,00 € je Stück, nach tatsächlicher Wirkung die Montage-Sonderschicht mit 450 €. Der Schattenpreis sagt, was <strong>eine</strong> Einheit wert ist — nicht, wie viele Einheiten zu haben sind. Für die Frage „welchen Hebel ziehen wir?“ ist das der entscheidende Unterschied.</p>
|
||||
<p><strong>Drittens: Ein Wunsch kann unmöglich statt teuer sein.</strong> Der Vertrieb hätte gern 55 Rahmen statt 47,5. Das Modell antwortet nicht mit einem Preis, sondern mit <code>INFEASIBLE</code> — und drei Bedingungen blockieren den Wunsch <strong>gemeinsam</strong>: Fällt eine davon weg, ist er erfüllbar, keine allein ist „der“ Grund. Genau die Struktur, die <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a> für den unlösbaren Fall beschreibt, hier auf einen Wunsch angewandt.</p>
|
||||
|
|
@ -959,7 +959,7 @@ aus.
|
|||
<tr class="odd">
|
||||
<td><strong>Optimierungs-Worker</strong></td>
|
||||
<td>Modell bauen, lösen, Timeout, Fallback</td>
|
||||
<td>Celery/Redis, OR-Tools, HiGHS, CVXPY</td>
|
||||
<td>Celery/Redis, <a href="anhang-glossar.md#gloss:or-tools" class="glossar-link">OR-Tools</a>, <a href="anhang-glossar.md#gloss:highs" class="glossar-link">HiGHS</a>, <a href="anhang-glossar.md#gloss:cvxpy" class="glossar-link">CVXPY</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>Disposition</strong></td>
|
||||
|
|
@ -981,10 +981,10 @@ aus.
|
|||
<p><strong>Was Sie in der Abbildung sehen.</strong> Fünf der sechs Schichten bilden einen Weg: Daten gehen oben hinein und unten als Handlung wieder hinaus. Die sechste steht daneben, und das ist keine zeichnerische Verlegenheit — Monitoring und Audit-Trail sind keine Station, die man durchläuft, sondern eine Anforderung an jede. Wer sie als sechsten Kasten unten anhängt, baut sie am Ende auch so: als etwas, das man hinterher noch macht.</p>
|
||||
<p><strong>Fünf Prinzipien, die sich in der Praxis bewährt haben:</strong></p>
|
||||
<ol type="1">
|
||||
<li><strong>Snapshot-Prinzip.</strong> Jeder Optimierungslauf arbeitet auf einem unveränderlichen Datenschnappschuss mit eigener ID. Nur so ist ein Ergebnis später reproduzierbar — und im Streitfall belegbar.</li>
|
||||
<li><strong>Zustandslosigkeit.</strong> Der Worker hält keinen Zustand; Eingabe und Ausgabe sind Daten. Das macht Skalierung und Wiederholung trivial.</li>
|
||||
<li><strong>Mensch in der Schleife.</strong> Der Optimierer <strong>schlägt vor</strong>, ein Mensch <strong>entscheidet</strong> — zumindest in der Einführungsphase. Das baut Vertrauen auf und fängt Modellfehler ab.</li>
|
||||
<li><strong>Fallback-Strategie.</strong> Was passiert, wenn der Solver kein Ergebnis liefert? Antwort: letzter gültiger Plan, regelbasierte Notlösung, Alarm. Nie: nichts.</li>
|
||||
<li><strong><a href="anhang-glossar.md#gloss:snapshot-prinzip" class="glossar-link">Snapshot-Prinzip</a>.</strong> Jeder Optimierungslauf arbeitet auf einem unveränderlichen Datenschnappschuss mit eigener ID. Nur so ist ein Ergebnis später reproduzierbar — und im Streitfall belegbar.</li>
|
||||
<li><strong><a href="anhang-glossar.md#gloss:zustandslosigkeit" class="glossar-link">Zustandslosigkeit</a>.</strong> Der Worker hält keinen Zustand; Eingabe und Ausgabe sind Daten. Das macht Skalierung und Wiederholung trivial.</li>
|
||||
<li><strong><a href="anhang-glossar.md#gloss:mensch-in-der-schleife" class="glossar-link">Mensch in der Schleife</a>.</strong> Der Optimierer <strong>schlägt vor</strong>, ein Mensch <strong>entscheidet</strong> — zumindest in der Einführungsphase. Das baut Vertrauen auf und fängt Modellfehler ab.</li>
|
||||
<li><strong><a href="anhang-glossar.md#gloss:fallback-strategie" class="glossar-link">Fallback-Strategie</a>.</strong> Was passiert, wenn der Solver kein Ergebnis liefert? Antwort: letzter gültiger Plan, regelbasierte Notlösung, Alarm. Nie: nichts.</li>
|
||||
<li><strong>Versionierung.</strong> Modellversion, Parametersatz und Solver-Version gehören ins Protokoll jedes Laufs. Ohne das lässt sich nicht klären, warum das Ergebnis von letzter Woche anders aussah.</li>
|
||||
</ol>
|
||||
<blockquote>
|
||||
|
|
@ -1062,9 +1062,9 @@ aus.
|
|||
<tr class="header">
|
||||
<th>Bedeutung</th>
|
||||
<th>pywraplp</th>
|
||||
<th>CP-SAT</th>
|
||||
<th><a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a></th>
|
||||
<th>HiGHS</th>
|
||||
<th>SciPy</th>
|
||||
<th><a href="anhang-glossar.md#gloss:scipy" class="glossar-link">SciPy</a></th>
|
||||
<th>CVXPY</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -1694,7 +1694,7 @@ Domaenenschicht.
|
|||
<tr class="even">
|
||||
<td><code>import pandas</code> <strong>in</strong> der Funktion</td>
|
||||
<td>Excel-Schicht als optionale Abhängigkeit</td>
|
||||
<td>Wer <code>or_kern</code> nur für Statusauswertung und Prüfung benutzt, soll pandas nicht installieren müssen.</td>
|
||||
<td>Wer <code>or_kern</code> nur für Statusauswertung und Prüfung benutzt, soll <a href="anhang-glossar.md#gloss:pandas" class="glossar-link">pandas</a> nicht installieren müssen.</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>schattenpreise</code> im DTO</td>
|
||||
|
|
@ -1710,7 +1710,7 @@ Domaenenschicht.
|
|||
<hr />
|
||||
<h2 id="sec:praxisfallen-solverwechsel">22.7 Der Solverwechsel in der Praxis</h2>
|
||||
<p>Der vorige Abschnitt endet mit einer Behauptung: Ein Solverwechsel betreffe genau <strong>einen</strong> Baustein. Das ist die Art Satz, die in jedem Architekturvortrag vorkommt und die man deshalb nicht glauben sollte, bevor sie jemand vorgeführt hat.</p>
|
||||
<p>Also führen wir sie vor — und zwar am unbequemsten Paar, das dieses Buch zu bieten hat: <strong>CP-SAT gegen HiGHS</strong>. Die beiden sind grundverschieden. CP-SAT ist ein Constraint-Programming-Solver, der ausschließlich ganzzahlig rechnet und Restriktionen als Ausdrücke entgegennimmt. HiGHS ist ein klassischer Branch-and-Bound-Löser, der eine Koeffizientenmatrix erwartet. Und sie lassen sich nicht einmal gemeinsam importieren (<a href="oekosystem.html#kap-oekosystem">Kapitel 3</a>).</p>
|
||||
<p>Also führen wir sie vor — und zwar am unbequemsten Paar, das dieses Buch zu bieten hat: <strong>CP-SAT gegen HiGHS</strong>. Die beiden sind grundverschieden. CP-SAT ist ein Constraint-Programming-Solver, der ausschließlich ganzzahlig rechnet und Restriktionen als Ausdrücke entgegennimmt. HiGHS ist ein klassischer <a href="anhang-glossar.md#gloss:branch-and-bound" class="glossar-link">Branch-and-Bound</a>-Löser, der eine Koeffizientenmatrix erwartet. Und sie lassen sich nicht einmal gemeinsam importieren (<a href="oekosystem.html#kap-oekosystem">Kapitel 3</a>).</p>
|
||||
<p><strong>Die Aufgabe</strong> ist eine kapazitierte Standortplanung: Aus sechs möglichen Lagern sind diejenigen zu eröffnen, mit denen zwölf Kunden am günstigsten beliefert werden. Jeder Kunde wird von genau einem Lager bedient, jedes eröffnete Lager kostet eine Fixgebühr, und die Kapazität reicht je Lager für 174 der insgesamt 387 Paletten — es müssen also mindestens drei Lager öffnen.</p>
|
||||
<p><strong>Der Aufbau folgt dem Muster aus <code>or_kern.py</code>:</strong></p>
|
||||
<table>
|
||||
|
|
@ -2141,16 +2141,16 @@ ein unzuverlaessiger Test (siehe JobShop_Intervalle.py).
|
|||
<hr />
|
||||
<h2 id="sec:praxisfallen-eine-checkliste-vor-dem-produktivgang">22.8 Eine Checkliste vor dem Produktivgang</h2>
|
||||
<p>Arbeiten Sie diese Liste ab, bevor ein OR-System in Betrieb geht:</p>
|
||||
<p><strong>Modell</strong> - [ ] Alle Nebenbedingungen sind dokumentiert — mit fachlicher Begründung, nicht nur als Code. - [ ] Für jede harte Bedingung ist geprüft: Muss sie wirklich hart sein? - [ ] Es gibt eine Relaxationsstrategie für den Infeasible-Fall. - [ ] Big-M-Werte sind so klein wie möglich gewählt. - [ ] Die Zielfunktion ist in konsistenten Einheiten formuliert.</p>
|
||||
<p><strong>Modell</strong> - [ ] Alle Nebenbedingungen sind dokumentiert — mit fachlicher Begründung, nicht nur als Code. - [ ] Für jede harte Bedingung ist geprüft: Muss sie wirklich hart sein? - [ ] Es gibt eine Relaxationsstrategie für den Infeasible-Fall. - [ ] Big-M-Werte sind so klein wie möglich gewählt. - [ ] Die <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a> ist in konsistenten Einheiten formuliert.</p>
|
||||
<p><strong>Daten</strong> - [ ] Spaltenreihenfolge und Datentypen werden nach jedem Import geprüft. - [ ] Fehlende Werte und Ausreißer haben eine definierte Behandlung. - [ ] Kovarianzmatrizen werden auf positive Definitheit geprüft. - [ ] Datenstände sind versioniert und reproduzierbar.</p>
|
||||
<p><strong>Validierung</strong> - [ ] Das Ergebnis wurde gegen eine unabhängige Rechnung geprüft (Handrechnung, zweiter Solver, Simulation). - [ ] Alle Nebenbedingungen werden nach dem Lösen per <code>assert</code> verifiziert. - [ ] Es gibt einen Vergleich gegen eine naive Referenzstrategie. - [ ] Bei Backtests: Lookahead-Selbsttest bestanden, Zahl der Versuche protokolliert.</p>
|
||||
<p><strong>Betrieb</strong> - [ ] Zeitlimit und akzeptierter Gap sind festgelegt und begründet. - [ ] Es gibt eine Fallback-Strategie und Alarmierung. - [ ] Jedes Ergebnis ist mit Snapshot-ID, Modellversion und Solver-Version protokolliert. - [ ] Die Ergebnisse sind erklärbar (Kostenzerlegung, Schattenpreise, Constraint-Trace).</p>
|
||||
<hr />
|
||||
<h2 id="sec:praxisfallen-weiterfuehrende-literatur-und-roadmap">22.9 Weiterführende Literatur und Roadmap</h2>
|
||||
<p><strong>Grundlagen und lineare/ganzzahlige Optimierung</strong> * Bertsimas & Tsitsiklis: <em>Introduction to Linear Optimization</em> — Standardwerk zu Simplex, Dualität, Polyedertheorie. * Wolsey: <em>Integer Programming</em> — Branch-and-Cut, Schnittebenen, Formulierungsstärke.</p>
|
||||
<p><strong>Grundlagen und lineare/ganzzahlige Optimierung</strong> * Bertsimas & Tsitsiklis: <em>Introduction to Linear Optimization</em> — Standardwerk zu Simplex, Dualität, Polyedertheorie. * Wolsey: <em>Integer Programming</em> — <a href="anhang-glossar.md#gloss:branch-and-cut" class="glossar-link">Branch-and-Cut</a>, Schnittebenen, Formulierungsstärke.</p>
|
||||
<p><strong>Konvexe Optimierung</strong> * Boyd & Vandenberghe: <em>Convex Optimization</em> — Pflichtlektüre; frei verfügbar. Die theoretische Basis von CVXPY.</p>
|
||||
<p><strong>Constraint Programming und Scheduling</strong> * Google OR-Tools Dokumentation und das CP-SAT-Primer von Laurent Perron.</p>
|
||||
<p><strong>Quantitative Finanzmathematik</strong> * López de Prado: <em>Advances in Financial Machine Learning</em> — Backtest-Overfitting, Denoising, Deflated Sharpe Ratio. * Cornuéjols, Peña & Tütüncü: <em>Optimization Methods in Finance</em>.</p>
|
||||
<p><strong>Constraint Programming und <a href="anhang-glossar.md#gloss:scheduling" class="glossar-link">Scheduling</a></strong> * Google OR-Tools Dokumentation und das CP-SAT-Primer von Laurent Perron.</p>
|
||||
<p><strong>Quantitative Finanzmathematik</strong> * López de Prado: <em>Advances in Financial Machine Learning</em> — <a href="anhang-glossar.md#gloss:backtest" class="glossar-link">Backtest</a>-<a href="anhang-glossar.md#gloss:overfitting" class="glossar-link">Overfitting</a>, Denoising, Deflated <a href="anhang-glossar.md#gloss:sharpe-ratio" class="glossar-link">Sharpe Ratio</a>. * Cornuéjols, Peña & Tütüncü: <em>Optimization Methods in Finance</em>.</p>
|
||||
<p><strong>Wie es weitergeht</strong></p>
|
||||
<p>Der nächste Schritt nach diesem Kurs ist selten ein weiteres Verfahren, sondern die <strong>Verankerung im Betrieb</strong>: reproduzierbare Datenpipelines, versionierte Modelle, Monitoring der Lösungsqualität, bewusster Umgang mit Zeitlimits.</p>
|
||||
<p>Wenn Sie doch tiefer in die Methodik wollen, sind das die lohnendsten Richtungen:</p>
|
||||
|
|
@ -2169,27 +2169,27 @@ ein unzuverlaessiger Test (siehe JobShop_Intervalle.py).
|
|||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><strong>Column Generation / Branch-and-Price</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:column-generation" class="glossar-link">Column Generation</a> / Branch-and-Price</strong></td>
|
||||
<td>sehr große Zuschnitt- und Dienstplanprobleme</td>
|
||||
<td><a href="dekomposition.html#kap-dekomposition">Kapitel 10</a>, Wolsey</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>Benders-Zerlegung</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:benders-zerlegung" class="glossar-link">Benders-Zerlegung</a></strong></td>
|
||||
<td>zweistufige stochastische Modelle mit vielen Szenarien</td>
|
||||
<td>Birge & Louveaux</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>Approximate Dynamic Programming / RL</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:approximate-dynamic-programming" class="glossar-link">Approximate Dynamic Programming</a> / RL</strong></td>
|
||||
<td>hochdimensionale Zustandsräume</td>
|
||||
<td>Powell: <em>Reinforcement Learning and Stochastic Optimization</em></td>
|
||||
<td>Powell: <em><a href="anhang-glossar.md#gloss:reinforcement-learning" class="glossar-link">Reinforcement Learning</a> and Stochastic Optimization</em></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>Konische Optimierung (SOCP, SDP)</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:konische-optimierung" class="glossar-link">Konische Optimierung</a> (SOCP, SDP)</strong></td>
|
||||
<td>robuste Portfolios, Ellipsoid-Unsicherheit</td>
|
||||
<td>Boyd & Vandenberghe, <a href="lp.html#kap-lp">Kapitel 5</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>Multi-Objective Optimization</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:multi-objective-optimization" class="glossar-link">Multi-Objective Optimization</a></strong></td>
|
||||
<td>echte Zielkonflikte ohne Gewichtung</td>
|
||||
<td>Ehrgott: <em>Multicriteria Optimization</em></td>
|
||||
</tr>
|
||||
|
|
@ -2201,15 +2201,15 @@ ein unzuverlaessiger Test (siehe JobShop_Intervalle.py).
|
|||
<p>Lösungen: <a href="anhang-loesungen.html#sec:loesungen-praxisfallen">Abschnitt A.22</a>.</p>
|
||||
</blockquote>
|
||||
<p><strong>Aufgabe 22.1 ⭐ — Hart oder weich, revisited.</strong> Nennen Sie für ein Vertretungsplanungssystem je zwei Bedingungen, die (a) zwingend hart bleiben müssen, (b) unbedingt weich sein sollten, (c) diskutabel sind. Begründen Sie.</p>
|
||||
<p><strong>Aufgabe 22.2 ⭐ — Zeitlimit wählen.</strong> Für welche Szenarien setzen Sie welches Zeitlimit und welchen Gap? (a) Taxi-Disposition in Echtzeit, (b) Wochendienstplan, freitags erstellt, (c) Jahresproduktionsplanung, (d) Portfolio-Rebalancing monatlich.</p>
|
||||
<p><strong>Aufgabe 22.3 ⭐⭐ — Relaxation einbauen.</strong> Nehmen Sie Ihr Modell aus der Aufgabe <em>Eigener Dienstplan</em> (<a href="cpsat.html#sec:cpsat-uebungsaufgaben">Abschnitt 7.9</a>) und machen Sie es <code>INFEASIBLE</code>-sicher: Schlupfvariablen für unbesetzte Schichten, gestaffelte Strafen. Testen Sie mit einem bewusst überlasteten Szenario.</p>
|
||||
<p><strong>Aufgabe 22.2 ⭐ — Zeitlimit wählen.</strong> Für welche Szenarien setzen Sie welches Zeitlimit und welchen Gap? (a) Taxi-Disposition in Echtzeit, (b) Wochendienstplan, freitags erstellt, (c) Jahresproduktionsplanung, (d) Portfolio-<a href="anhang-glossar.md#gloss:rebalancing" class="glossar-link">Rebalancing</a> monatlich.</p>
|
||||
<p><strong>Aufgabe 22.3 ⭐⭐ — <a href="anhang-glossar.md#gloss:relaxation" class="glossar-link">Relaxation</a> einbauen.</strong> Nehmen Sie Ihr Modell aus der Aufgabe <em>Eigener Dienstplan</em> (<a href="cpsat.html#sec:cpsat-uebungsaufgaben">Abschnitt 7.9</a>) und machen Sie es <code>INFEASIBLE</code>-sicher: Schlupfvariablen für unbesetzte Schichten, gestaffelte Strafen. Testen Sie mit einem bewusst überlasteten Szenario.</p>
|
||||
<p><strong>Aufgabe 22.4 ⭐⭐ — Erklärbarkeit implementieren.</strong> Erweitern Sie ein beliebiges Modell aus dem Kurs um einen <code>erklaere(loesung)</code>-Report, der die drei Fragen aus <a href="#sec:praxisfallen-die-fuenf-typischen-praxisfallen">Abschnitt 22.3</a> beantwortet.</p>
|
||||
<p><strong>Aufgabe 22.5 ⭐⭐ — Den Bericht in die Irre führen.</strong> <code>Constraint_Attribution.py</code> erzeugt seinen Bericht aus gerechneten Zahlen — richtig ist er deshalb noch nicht. (a) Setzen Sie den Deckungsbeitrag von <em>Deckel</em> von 9 € auf 20 €. Wie ändern sich Plan, Rangliste und Bericht? Welche Sätze bleiben wörtlich stehen, obwohl sie jetzt etwas anderes bedeuten? (b) Der Bericht nennt „Liefervertrag Träger” als teuerste Bindung. Formulieren Sie den Satz so um, dass ein Leser erkennt, <strong>worauf</strong> die Aussage beruht. (c) Welche Angabe müsste das Programm zusätzlich ausgeben, damit ein Empfänger die Belastbarkeit selbst einschätzen kann?</p>
|
||||
<p><strong>Aufgabe 22.6 ⭐⭐⭐ — Gap gegen Laufzeit.</strong> Nehmen Sie das MILP-Portfolio aus <a href="milp.html#kap-milp">Kapitel 6</a> und vergrößern Sie es auf 50 Anlagen. Messen Sie Laufzeit und Zielwert bei Gap-Vorgaben von 10 %, 5 %, 2 %, 1 %, 0,1 % und 0 %. Stellen Sie den Zusammenhang grafisch dar und leiten Sie eine Empfehlung ab.</p>
|
||||
<p><strong>Aufgabe 22.7 ⭐⭐⭐ — Post-Mortem schreiben.</strong> Suchen Sie sich einen der im Buch besprochenen Fehler aus (z. B. die Vorzeichenfalle in <a href="lp.html#sec:lp-die-vorzeichenfalle-bei-schattenpreisen">Abschnitt 5.7</a>, die ungültige Kovarianzmatrix in <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a>, die Sektor-Positionsindizes in <a href="markowitz.html#kap-markowitz">Kapitel 19</a>, die vermischten Einheiten in <a href="cvar.html#sec:cvar-implementierung-cvar-portfolio-mit-reibung">Abschnitt 20.6</a> oder die Rebalancing-Termine in <a href="handelsmaschine.html#sec:handelsmaschine-rebalancing-termine-richtig-bestimmen">Abschnitt 21.4</a>) und schreiben Sie ein einseitiges Post-Mortem: Was war der Fehler? Warum fiel er nicht auf? Welche Prüfung hätte ihn gefunden? Welche Regel leiten Sie daraus für eigene Projekte ab?</p>
|
||||
<p><strong>Aufgabe 22.7 ⭐⭐⭐ — Post-Mortem schreiben.</strong> Suchen Sie sich einen der im Buch besprochenen Fehler aus (z. B. die Vorzeichenfalle in <a href="lp.html#sec:lp-die-vorzeichenfalle-bei-schattenpreisen">Abschnitt 5.7</a>, die ungültige <a href="anhang-glossar.md#gloss:kovarianzmatrix" class="glossar-link">Kovarianzmatrix</a> in <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a>, die Sektor-Positionsindizes in <a href="markowitz.html#kap-markowitz">Kapitel 19</a>, die vermischten Einheiten in <a href="cvar.html#sec:cvar-implementierung-cvar-portfolio-mit-reibung">Abschnitt 20.6</a> oder die Rebalancing-Termine in <a href="handelsmaschine.html#sec:handelsmaschine-rebalancing-termine-richtig-bestimmen">Abschnitt 21.4</a>) und schreiben Sie ein einseitiges Post-Mortem: Was war der Fehler? Warum fiel er nicht auf? Welche Prüfung hätte ihn gefunden? Welche Regel leiten Sie daraus für eigene Projekte ab?</p>
|
||||
<hr />
|
||||
<h2 id="sec:praxisfallen-denkfehler">22.11 Finde den Denkfehler</h2>
|
||||
<p>Falle 5 — die Laufzeitexplosion — zeigt sich im Betrieb selten als Absturz. Sie zeigt sich als <strong>gar nichts</strong>.</p>
|
||||
<p>Falle 5 — die <a href="anhang-glossar.md#gloss:laufzeitexplosion" class="glossar-link">Laufzeitexplosion</a> — zeigt sich im Betrieb selten als Absturz. Sie zeigt sich als <strong>gar nichts</strong>.</p>
|
||||
<div class="card card-denkfehler">
|
||||
<blockquote>
|
||||
<p><strong>🐛 Finde den Denkfehler: Das Modell, das seit einem Jahr nicht mehr optimiert</strong></p>
|
||||
|
|
@ -2501,7 +2501,7 @@ sichtbar wird, und gibt Zeit zum Handeln.
|
|||
<p>Genau eine Antwort ist jeweils richtig. Auflösung in <a href="anhang-loesungen.html#quiz-loesung-praxisfallen">Anhang A</a>.</p>
|
||||
<p><strong>1. Ihr Nachtjob läuft seit Monaten konstant 3,0 Sekunden bei einem Zeitlimit von 3 Sekunden. Was schließen Sie daraus?</strong> (a) Das System ist bemerkenswert stabil. (b) Das Zeitlimit greift jedes Mal. Der Solver bricht ab, statt fertig zu werden — die konstante Laufzeit ist das Symptom, nicht die Beruhigung. (c) Der Rechner ist ausgelastet und sollte aufgerüstet werden.</p>
|
||||
<p><strong>2. Eine Prüffunktion soll kontrollieren, ob ein Tourenplan die Fahrzeugkapazitäten einhält. Woher nimmt sie die geladenen Mengen?</strong> (a) Aus der Ladungsdimension des Routing-Modells — dort stehen sie ja bereits. (b) Sie summiert die Bedarfe der Kunden aus dem <strong>ausgegebenen Tourenplan</strong> auf. Alles andere fragt das Modell, ob es sich an sich selbst hält. (c) Aus der Zielfunktion, sofern die Kapazität dort bepreist ist.</p>
|
||||
<p><strong>3. Ein Modell meldet <code>INFEASIBLE</code>, nachdem eine neue Regel aufgenommen wurde. Was ist der produktivste erste Schritt?</strong> (a) Das Zeitlimit erhöhen. (b) Die neue Regel wieder entfernen und in Ruhe abwarten. (c) Die harten Regeln hierarchisch lockern — mit teuren Strafkosten statt Verboten —, damit der Solver benennt, <strong>welche</strong> Regel den Widerspruch erzeugt, statt nur zu sagen, dass es einen gibt.</p>
|
||||
<p><strong>3. Ein Modell meldet <code>INFEASIBLE</code>, nachdem eine neue Regel aufgenommen wurde. Was ist der produktivste erste Schritt?</strong> (a) Das Zeitlimit erhöhen. (b) Die neue Regel wieder entfernen und in Ruhe abwarten. (c) Die harten Regeln hierarchisch lockern — mit teuren <a href="anhang-glossar.md#gloss:strafkosten" class="glossar-link">Strafkosten</a> statt Verboten —, damit der Solver benennt, <strong>welche</strong> Regel den Widerspruch erzeugt, statt nur zu sagen, dass es einen gibt.</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
<hr />
|
||||
|
|
@ -2521,7 +2521,7 @@ sichtbar wird, und gibt Zeit zum Handeln.
|
|||
<hr />
|
||||
<h2 id="sec:praxisfallen-zusammenfassung">22.14 Zusammenfassung</h2>
|
||||
<ul>
|
||||
<li><strong>Infeasibility ist ein Entwurfsproblem, kein Solverproblem.</strong> Wer alles hart formuliert, erhält irgendwann eine Fehlermeldung statt eines Plans.</li>
|
||||
<li><strong><a href="anhang-glossar.md#gloss:infeasibility" class="glossar-link">Infeasibility</a> ist ein Entwurfsproblem, kein Solverproblem.</strong> Wer alles hart formuliert, erhält irgendwann eine Fehlermeldung statt eines Plans.</li>
|
||||
<li><strong>Erklärbarkeit entscheidet über Akzeptanz.</strong> Schattenpreise, Kostenzerlegung und Constraint-Traces sind keine Kür.</li>
|
||||
<li><strong>Bindend heißt nicht teuer.</strong> Eine Bedingung kann den Plan berühren und trotzdem 0,00 € kosten. Nur die kostenrelevanten lohnen eine Nachverhandlung.</li>
|
||||
<li><strong>Der Schattenpreis gilt für die nächste Einheit, nicht für die nächste Schicht.</strong> Hochgerechnet auf einen realistischen Schritt überschätzt er den Nutzen — im Beispiel um das Doppelte. Wer wissen will, was ein Hebel bringt, <strong>misst</strong> die Lockerung, statt zu multiplizieren; die beiden Ranglisten können sich dabei umdrehen.</li>
|
||||
|
|
|
|||
12
OR_HTML_04/prognose.html
generated
12
OR_HTML_04/prognose.html
generated
|
|
@ -104,8 +104,8 @@
|
|||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Um die Naht zwischen zwei Welten, die in getrennten Abteilungen sitzen: Ein Modell <strong>prognostiziert</strong>, ein anderes <strong>entscheidet</strong>. Beide arbeiten sauber — und genau an der Naht entsteht ein Fehler, den keine der beiden Seiten sieht.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a>, insbesondere das Newsvendor-Problem und das kritische Verhältnis. Etwas Regression hilft, ist aber nicht nötig.</p>
|
||||
<p><strong>Danach können Sie:</strong> begründen, warum ein Prognosemodell mit kleinerem MSE teurere Entscheidungen erzeugen kann; die richtige <strong>Zielgröße</strong> einer Prognose bestimmen; und Prognosemodelle an Entscheidungskosten statt an Fehlermaßen bewerten.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a>, insbesondere das <a href="anhang-glossar.md#gloss:newsvendor-problem" class="glossar-link">Newsvendor-Problem</a> und das kritische Verhältnis. Etwas Regression hilft, ist aber nicht nötig.</p>
|
||||
<p><strong>Danach können Sie:</strong> begründen, warum ein Prognosemodell mit kleinerem <a href="anhang-glossar.md#gloss:mse" class="glossar-link">MSE</a> teurere Entscheidungen erzeugen kann; die richtige <strong>Zielgröße</strong> einer Prognose bestimmen; und Prognosemodelle an Entscheidungskosten statt an Fehlermaßen bewerten.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 3,5 Stunden.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>Predict_then_Optimize.py</code></p>
|
||||
|
|
@ -163,10 +163,10 @@ bestmoegliche feste Menge: 138 Stueck -> 62.10 EUR/Tag</code></pre>
|
|||
<p>In fast jedem Unternehmen sieht der Ablauf so aus:</p>
|
||||
<pre><code> Verkaufsdaten -> [ PROGNOSE ] -> Nachfrageschätzung -> [ PLANUNG ] -> Bestellung
|
||||
Data Science Disposition</code></pre>
|
||||
<p>Beide Seiten arbeiten sorgfältig. Die Prognoseabteilung optimiert ihr Modell auf ein <strong>Fehlermaß</strong> — meist den mittleren quadratischen Fehler (MSE) oder MAPE — und berichtet stolz eine Verbesserung von 12 %. Die Disposition nimmt die Zahl entgegen und rechnet ihre Bestellmenge aus.</p>
|
||||
<p>Beide Seiten arbeiten sorgfältig. Die Prognoseabteilung optimiert ihr Modell auf ein <strong>Fehlermaß</strong> — meist den mittleren quadratischen Fehler (MSE) oder <a href="anhang-glossar.md#gloss:mape" class="glossar-link">MAPE</a> — und berichtet stolz eine Verbesserung von 12 %. Die Disposition nimmt die Zahl entgegen und rechnet ihre Bestellmenge aus.</p>
|
||||
<p>Der Fehler steckt nicht in einer der beiden Hälften, sondern in der Naht:</p>
|
||||
<blockquote>
|
||||
<p><strong>📖 Definition: Predict-then-Optimize</strong></p>
|
||||
<p><strong>📖 Definition: <a href="anhang-glossar.md#gloss:predict-then-optimize" class="glossar-link">Predict-then-Optimize</a></strong></p>
|
||||
<p>Das übliche zweistufige Vorgehen: erst eine unbekannte Größe schätzen, dann mit der Schätzung optimieren, als wäre sie die Wahrheit.</p>
|
||||
<p>Das Problem: Die erste Stufe wird auf ein <strong>statistisches</strong> Maß trainiert, die zweite erzeugt <strong>ökonomische</strong> Kosten. Niemand garantiert, dass ein besseres statistisches Maß zu geringeren Kosten führt — und in diesem Kapitel ist es nachweislich umgekehrt.</p>
|
||||
</blockquote>
|
||||
|
|
@ -654,7 +654,7 @@ Kosten statt auf Fehler trainiert.
|
|||
<hr />
|
||||
<h2 id="sec:prognose-ausblick">15.7 Wie weit das Verfahren reicht</h2>
|
||||
<p>Die dritte Zeile der Ergebnistabelle — „Zuschlag auf Kosten trainiert” — ist die einfachste denkbare Form einer Idee, die derzeit erforscht wird: <strong>das Prognosemodell direkt auf die Entscheidungskosten zu trainieren</strong> statt auf ein Fehlermaß.</p>
|
||||
<p>Hier war es ein einziger Parameter, 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 <strong>durch das Optimierungsproblem hindurch ableiten</strong>.</p>
|
||||
<p>Hier war es ein einziger <a href="anhang-glossar.md#gloss:parameter" class="glossar-link">Parameter</a>, 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 <strong>durch das Optimierungsproblem hindurch ableiten</strong>.</p>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 33%" />
|
||||
|
|
@ -707,7 +707,7 @@ Kosten statt auf Fehler trainiert.
|
|||
<p><strong>🐛 „Wir haben die Prognose um 18 % verbessert”</strong></p>
|
||||
<p>Ein Data-Science-Team stellt sein Quartalsergebnis vor:</p>
|
||||
<blockquote>
|
||||
<p><em>„Wir haben das alte lineare Modell durch ein 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.”</em></p>
|
||||
<p><em>„Wir haben das alte lineare Modell durch ein <a href="anhang-glossar.md#gloss:gradient" class="glossar-link">Gradient</a>-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.”</em></p>
|
||||
</blockquote>
|
||||
<p>Sechs Wochen später meldet die Disposition, die Retouren seien gestiegen.</p>
|
||||
<p>Das Team prüft alles nach: Die Modellgüte stimmt, die Testdaten waren sauber getrennt, es gibt kein Leck. Das neue Modell prognostiziert die Nachfrage tatsächlich deutlich besser als das alte.</p>
|
||||
|
|
|
|||
30
OR_HTML_04/projektwerkstatt.html
generated
30
OR_HTML_04/projektwerkstatt.html
generated
|
|
@ -175,8 +175,8 @@
|
|||
</blockquote>
|
||||
<p><strong>Ausgangslage.</strong> Morgens um 7:15 Uhr meldet sich die dritte Lehrkraft krank. Die stellvertretende Schulleitung hat 20 Minuten, um einen Vertretungsplan zu erstellen, der Qualifikationen, Arbeitszeiten, bereits geleistete Vertretungen und persönliche Wünsche berücksichtigt.</p>
|
||||
<p><strong>Daten.</strong> Stundenplan (CSV: Klasse, Tag, Stunde, Fach, Lehrkraft, Raum) — in diesem Projektordner erzeugen die Skripte <code>stundenplan*.py</code> genau solche Dateien und eignen sich als Datenquelle. Zusätzlich: Qualifikationsmatrix, Deputate, Abwesenheitsmeldungen.</p>
|
||||
<p><strong>Modellskizze.</strong> * Variablen: <span class="math inline">x_{p,s} \in \{0,1\}</span> — Person <span class="math inline">p</span> übernimmt Slot <span class="math inline">s</span>. * Hart: genau eine Person je Slot; Qualifikation; keine Doppelbelegung; Höchstzahl Vertretungsstunden; Ruhezeiten. * Weich: Vorbelastung, Freistundenlöcher, Fachnähe, Wünsche, Fairness über die Woche. * Solver: CP-SAT.</p>
|
||||
<p><strong>Abnahmekriterien.</strong> - [ ] Läuft in unter 10 Sekunden für eine ganze Schule (60 Lehrkräfte, 30 Slots). - [ ] Liefert <strong>immer</strong> einen Plan — auch wenn nicht alle Slots besetzbar sind (Relaxation). - [ ] Weist je Zuweisung eine Begründung aus. - [ ] Ausgabe als CSV <strong>und</strong> als lesbare Tagestabelle. - [ ] Vergleich gegen die manuelle Lösung: Wie viele Wünsche werden erfüllt?</p>
|
||||
<p><strong>Modellskizze.</strong> * Variablen: <span class="math inline">x_{p,s} \in \{0,1\}</span> — Person <span class="math inline">p</span> übernimmt Slot <span class="math inline">s</span>. * Hart: genau eine Person je Slot; Qualifikation; keine Doppelbelegung; Höchstzahl Vertretungsstunden; Ruhezeiten. * Weich: Vorbelastung, Freistundenlöcher, Fachnähe, Wünsche, Fairness über die Woche. * <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a>: <a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a>.</p>
|
||||
<p><strong>Abnahmekriterien.</strong> - [ ] Läuft in unter 10 Sekunden für eine ganze Schule (60 Lehrkräfte, 30 Slots). - [ ] Liefert <strong>immer</strong> einen Plan — auch wenn nicht alle Slots besetzbar sind (<a href="anhang-glossar.md#gloss:relaxation" class="glossar-link">Relaxation</a>). - [ ] Weist je Zuweisung eine Begründung aus. - [ ] Ausgabe als CSV <strong>und</strong> als lesbare Tagestabelle. - [ ] Vergleich gegen die manuelle Lösung: Wie viele Wünsche werden erfüllt?</p>
|
||||
<p><strong>Stolperfallen.</strong> * Zu viele harte Regeln → <code>INFEASIBLE</code> an genau dem Tag, an dem man das System braucht. * Fairness nur über einen Tag statt über die Woche → dieselbe Person trifft es ständig. * Akzeptanz: Ohne Begründungsanzeige wird der Plan überschrieben.</p>
|
||||
<p><strong>Erweiterungen.</strong> Mehrtagesplanung; Raumkonflikte; Springerstunden; Schnittstelle zum Schulverwaltungsprogramm.</p>
|
||||
<hr />
|
||||
|
|
@ -185,9 +185,9 @@
|
|||
<p><strong>Schwierigkeit:</strong> ⭐⭐⭐ · <strong>Kapitel:</strong> <a href="milp.html#kap-milp">Kapitel 6</a>, <a href="cpsat.html#kap-cpsat">Kapitel 7</a>, <a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a> · <strong>Zeit:</strong> ca. 20 Stunden</p>
|
||||
</blockquote>
|
||||
<p><strong>Ausgangslage.</strong> 25 Pflegekräfte, drei Schichten täglich, 28-Tage-Zyklus. Es gelten Arbeitszeitgesetz, Tarifvertrag, Qualifikationsmix und individuelle Wünsche.</p>
|
||||
<p><strong>Modellskizze.</strong> * Variablen: <span class="math inline">x_{p,t,s} \in \{0,1\}</span> — Person, Tag, Schicht. * Hart: Mindestbesetzung je Schicht <strong>und</strong> Qualifikationsmix (mindestens eine examinierte Kraft); nach Nachtschicht ≥ 2 freie Tage; höchstens 6 Arbeitstage in Folge; monatliche Sollstunden ± 10 %. * Weich: Wunschfrei, gleichmäßige Wochenendverteilung, ungeteilte Dienste, stabile Schichtfolgen (nicht Früh–Nacht–Früh). * Solver: CP-SAT mit Intervall- und Cumulative-Constraints.</p>
|
||||
<p><strong>Abnahmekriterien.</strong> - [ ] Alle gesetzlichen Regeln nachweislich eingehalten (per <code>assert</code> geprüft). - [ ] Wunscherfüllungsquote wird ausgewiesen und ist fair verteilt (Gini-Koeffizient). - [ ] Läuft in unter 60 Sekunden. - [ ] Bei Unlösbarkeit: Notfallplan plus benannte Ursache.</p>
|
||||
<p><strong>Stolperfallen.</strong> Der 28-Tage-Zyklus erzeugt viele Variablen (25 × 28 × 3 = 2100) — Symmetriebrechung und gute Suchheuristiken werden wichtig. Fairness über einen Monat ist etwas anderes als Fairness über eine Woche.</p>
|
||||
<p><strong>Modellskizze.</strong> * Variablen: <span class="math inline">x_{p,t,s} \in \{0,1\}</span> — Person, Tag, Schicht. * Hart: Mindestbesetzung je Schicht <strong>und</strong> Qualifikationsmix (mindestens eine examinierte Kraft); nach Nachtschicht ≥ 2 freie Tage; höchstens 6 Arbeitstage in Folge; monatliche Sollstunden ± 10 %. * Weich: Wunschfrei, gleichmäßige Wochenendverteilung, ungeteilte Dienste, stabile Schichtfolgen (nicht Früh–Nacht–Früh). * Solver: <a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a> mit Intervall- und Cumulative-Constraints.</p>
|
||||
<p><strong>Abnahmekriterien.</strong> - [ ] Alle gesetzlichen Regeln nachweislich eingehalten (per <code>assert</code> geprüft). - [ ] Wunscherfüllungsquote wird ausgewiesen und ist fair verteilt (<a href="anhang-glossar.md#gloss:gini-koeffizient" class="glossar-link">Gini-Koeffizient</a>). - [ ] Läuft in unter 60 Sekunden. - [ ] Bei Unlösbarkeit: Notfallplan plus benannte Ursache.</p>
|
||||
<p><strong>Stolperfallen.</strong> Der 28-Tage-Zyklus erzeugt viele Variablen (25 × 28 × 3 = 2100) — <a href="anhang-glossar.md#gloss:symmetriebrechung" class="glossar-link">Symmetriebrechung</a> und gute Suchheuristiken werden wichtig. Fairness über einen Monat ist etwas anderes als Fairness über eine Woche.</p>
|
||||
<hr />
|
||||
<h2 id="p3-tourenplanung-für-einen-lieferdienst">P3 — Tourenplanung für einen Lieferdienst</h2>
|
||||
<blockquote>
|
||||
|
|
@ -195,7 +195,7 @@
|
|||
</blockquote>
|
||||
<p><strong>Ausgangslage.</strong> Ein regionaler Lieferdienst fährt täglich 40–80 Adressen mit 4 Fahrzeugen an. Kunden haben Zeitfenster, Fahrzeuge Kapazitäten, Fahrer Arbeitszeiten.</p>
|
||||
<p><strong>Daten.</strong> Adressen aus einer CSV; Entfernungen über OpenStreetMap (<code>osmnx</code>, <code>openrouteservice</code>) oder als Luftlinie mit Umwegfaktor 1,3 als Näherung.</p>
|
||||
<p><strong>Modellskizze.</strong> OR-Tools Routing-Bibliothek mit Kapazitäts- und Zeitdimension; Metaheuristik <code>GUIDED_LOCAL_SEARCH</code>, Zeitlimit 30 Sekunden.</p>
|
||||
<p><strong>Modellskizze.</strong> <a href="anhang-glossar.md#gloss:or-tools" class="glossar-link">OR-Tools</a> <a href="anhang-glossar.md#gloss:routing-bibliothek" class="glossar-link">Routing-Bibliothek</a> mit Kapazitäts- und Zeitdimension; <a href="anhang-glossar.md#gloss:metaheuristik" class="glossar-link">Metaheuristik</a> <code>GUIDED_LOCAL_SEARCH</code>, Zeitlimit 30 Sekunden.</p>
|
||||
<p><strong>Abnahmekriterien.</strong> - [ ] Alle Kunden werden innerhalb ihrer Zeitfenster beliefert. - [ ] Vergleich gegen die bisherige manuelle Tourenplanung: Ersparnis in km und Minuten. - [ ] Kartendarstellung der Touren (<code>folium</code>). - [ ] Robust gegen Ausfall eines Fahrzeugs (Neuplanung in unter 30 s).</p>
|
||||
<p><strong>Stolperfallen.</strong> Luftlinie unterschätzt Fahrzeiten systematisch — mit realistischem Umwegfaktor arbeiten oder echte Routing-Distanzen holen. Zeitfenster, die physisch nicht erreichbar sind, führen zu „keine Lösung“ ohne Erklärung: Vorabprüfung einbauen (siehe <a href="graphen.html#kap-graphen">Kapitel 8</a>).</p>
|
||||
<hr />
|
||||
|
|
@ -205,14 +205,14 @@
|
|||
</blockquote>
|
||||
<p><strong>Ausgangslage.</strong> Ein Handelsunternehmen prüft, welche von 12 möglichen Lagerstandorten eröffnet werden sollen, um 60 Filialen zu versorgen.</p>
|
||||
<p><strong>Modellskizze.</strong> Kombiniertes Standort- und Transportproblem: * <span class="math inline">y_j \in \{0,1\}</span> — Lager <span class="math inline">j</span> eröffnen (Fixkosten). * <span class="math inline">x_{ij} \ge 0</span> — Menge von Lager <span class="math inline">j</span> zu Filiale <span class="math inline">i</span>. * Kopplung: <span class="math inline">x_{ij} \le M\,y_j</span>; Kapazität je Lager; Bedarfsdeckung je Filiale. * Ziel: Fixkosten + Transportkosten minimieren.</p>
|
||||
<p><strong>Abnahmekriterien.</strong> - [ ] Sensitivitätsanalyse: Wie verändert sich die Lösung bei ±20 % Transportkosten? - [ ] Was-wäre-wenn: Standort X wird politisch vorgegeben — was kostet das? - [ ] Kartendarstellung mit Zuordnungslinien. - [ ] Amortisationsrechnung über 10 Jahre.</p>
|
||||
<p><strong>Abnahmekriterien.</strong> - [ ] <a href="anhang-glossar.md#gloss:sensitivitaetsanalyse" class="glossar-link">Sensitivitätsanalyse</a>: Wie verändert sich die Lösung bei ±20 % Transportkosten? - [ ] Was-wäre-wenn: Standort X wird politisch vorgegeben — was kostet das? - [ ] Kartendarstellung mit Zuordnungslinien. - [ ] Amortisationsrechnung über 10 Jahre.</p>
|
||||
<p><strong>Stolperfallen.</strong> Big-M zu groß wählen (<a href="milp.html#kap-milp">Kapitel 6</a>) — hier ist die Lagerkapazität die natürliche Wahl. Fixkosten sind einmalig, Transportkosten laufend: <strong>Barwerte rechnen</strong>, nicht einfach addieren.</p>
|
||||
<hr />
|
||||
<h2 id="p5-produktionsplanung-mit-rüstkosten">P5 — Produktionsplanung mit Rüstkosten</h2>
|
||||
<blockquote>
|
||||
<p><strong>Schwierigkeit:</strong> ⭐⭐⭐ · <strong>Kapitel:</strong> <a href="lp.html#kap-lp">Kapitel 5</a>, <a href="milp.html#kap-milp">Kapitel 6</a>, <a href="cpsat.html#kap-cpsat">Kapitel 7</a> · <strong>Zeit:</strong> ca. 18 Stunden</p>
|
||||
</blockquote>
|
||||
<p><strong>Ausgangslage.</strong> Eine Fertigung produziert 15 Varianten auf 4 Maschinen. Jeder Produktwechsel kostet Rüstzeit; die Rüstzeit hängt von der Reihenfolge ab.</p>
|
||||
<p><strong>Ausgangslage.</strong> Eine Fertigung produziert 15 Varianten auf 4 Maschinen. Jeder Produktwechsel kostet <a href="anhang-glossar.md#gloss:ruestzeit" class="glossar-link">Rüstzeit</a>; die Rüstzeit hängt von der Reihenfolge ab.</p>
|
||||
<p><strong>Modellskizze.</strong> Los- und Reihenfolgeplanung: * Variablen: Produktionsmengen, Rüstentscheidungen, Reihenfolge (Intervallvariablen). * Hart: Bedarfsdeckung je Periode, Maschinenkapazität, Mindestlosgrößen. * Ziel: Rüst- + Lager- + Fehlmengenkosten minimieren. * Solver: CP-SAT mit <code>AddNoOverlap</code> und reihenfolgeabhängigen Übergangszeiten.</p>
|
||||
<p><strong>Abnahmekriterien.</strong> - [ ] Gantt-Diagramm der Maschinenbelegung. - [ ] Vergleich gegen die aktuelle Praxis (Ersparnis in Rüststunden). - [ ] Schattenpreise: Welche Maschine ist der Engpass, was wäre eine zusätzliche Schicht wert?</p>
|
||||
<hr />
|
||||
|
|
@ -222,8 +222,8 @@
|
|||
<p>⚠️ <strong>Keine Anlageberatung.</strong> Dieses Projekt dient dem Methodenverständnis. Setzen Sie kein echtes Geld auf ein selbstgebautes Modell, dessen Grenzen Sie nicht vollständig verstehen.</p>
|
||||
</blockquote>
|
||||
<p><strong>Ausgangslage.</strong> Ein Privatdepot aus 10–15 ETFs und Einzeltiteln soll quartalsweise zurückgeführt werden — unter Berücksichtigung von Ordergebühren, Mindestordergrößen und der Steuerfreibetragsnutzung.</p>
|
||||
<p><strong>Modellskizze.</strong> * Variablen: Zielgewichte <span class="math inline">w_i</span>; Binärvariablen für „Position wird gehandelt“. * Hart: Vollinvestition, keine Leerverkäufe, Positionsobergrenzen, Mindestordergröße (semikontinuierlich, <a href="milp.html#kap-milp">Kapitel 6</a>), höchstens <span class="math inline">K</span> Transaktionen je Rebalancing. * Ziel: erwartete Rendite − Risikoterm − Transaktionskosten − Steuerwirkung. * Solver: CVXPY (konvexer Teil) oder MIQP für die Kardinalität.</p>
|
||||
<p><strong>Abnahmekriterien.</strong> - [ ] Toleranzband: Es wird nur gehandelt, wenn die Abweichung > 5 Prozentpunkte beträgt. - [ ] Alle Kosten (Ordergebühr, Spread, Steuer) sind explizit ausgewiesen. - [ ] Backtest über 5 Jahre mit Lookahead-Selbsttest. - [ ] Vergleich gegen: nie rebalancen, jährlich rebalancen, Gleichgewichtung. - [ ] Bericht, den ein Nicht-Fachmann versteht.</p>
|
||||
<p><strong>Modellskizze.</strong> * Variablen: Zielgewichte <span class="math inline">w_i</span>; Binärvariablen für „Position wird gehandelt“. * Hart: Vollinvestition, keine Leerverkäufe, Positionsobergrenzen, Mindestordergröße (semikontinuierlich, <a href="milp.html#kap-milp">Kapitel 6</a>), höchstens <span class="math inline">K</span> Transaktionen je <a href="anhang-glossar.md#gloss:rebalancing" class="glossar-link">Rebalancing</a>. * Ziel: erwartete Rendite − Risikoterm − <a href="anhang-glossar.md#gloss:transaktionskosten" class="glossar-link">Transaktionskosten</a> − Steuerwirkung. * Solver: <a href="anhang-glossar.md#gloss:cvxpy" class="glossar-link">CVXPY</a> (konvexer Teil) oder <a href="anhang-glossar.md#gloss:miqp" class="glossar-link">MIQP</a> für die Kardinalität.</p>
|
||||
<p><strong>Abnahmekriterien.</strong> - [ ] Toleranzband: Es wird nur gehandelt, wenn die Abweichung > 5 Prozentpunkte beträgt. - [ ] Alle Kosten (Ordergebühr, Spread, Steuer) sind explizit ausgewiesen. - [ ] <a href="anhang-glossar.md#gloss:backtest" class="glossar-link">Backtest</a> über 5 Jahre mit Lookahead-Selbsttest. - [ ] Vergleich gegen: nie rebalancen, jährlich rebalancen, Gleichgewichtung. - [ ] Bericht, den ein Nicht-Fachmann versteht.</p>
|
||||
<p><strong>Stolperfallen.</strong> Steuern sind pfadabhängig (FIFO, Freibetrag) und passen nicht sauber in ein einperiodiges Modell — Näherung wählen und die Näherung <strong>dokumentieren</strong>. Und: Wenn Ihre Strategie die Gleichgewichtung nicht schlägt, ist das ein Ergebnis, kein Misserfolg.</p>
|
||||
<hr />
|
||||
<h2 id="p7-risikoreport-mit-cvar-und-stresstests">P7 — Risikoreport mit CVaR und Stresstests</h2>
|
||||
|
|
@ -231,16 +231,16 @@
|
|||
<p><strong>Schwierigkeit:</strong> ⭐⭐ · <strong>Kapitel:</strong> <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a>, <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a>, <a href="cvar.html#kap-cvar">Kapitel 20</a> · <strong>Zeit:</strong> ca. 12 Stunden</p>
|
||||
</blockquote>
|
||||
<p><strong>Ausgangslage.</strong> Für ein bestehendes Portfolio soll ein monatlicher Risikobericht entstehen.</p>
|
||||
<p><strong>Inhalte des Berichts.</strong> * VaR und CVaR auf 95 % und 99 %, historisch <strong>und</strong> Monte-Carlo-simuliert. * Risikobeiträge je Position (<em>marginal CVaR</em>): Wer treibt das Risiko? * Stresstests: Was passiert bei −20 % Aktienmarkt, +200 Basispunkten Zins, Korrelationsanstieg auf 0,9? * Historische Szenarien nachspielen (2008, März 2020). * Konzentrationskennzahlen (Herfindahl-Index, effektive Titelzahl).</p>
|
||||
<p><strong>Inhalte des Berichts.</strong> * <a href="anhang-glossar.md#gloss:value-at-risk-var" class="glossar-link">VaR</a> und <a href="anhang-glossar.md#gloss:conditional-value-at-risk-cvar" class="glossar-link">CVaR</a> auf 95 % und 99 %, historisch <strong>und</strong> Monte-Carlo-simuliert. * Risikobeiträge je Position (<em>marginal CVaR</em>): Wer treibt das Risiko? * Stresstests: Was passiert bei −20 % Aktienmarkt, +200 Basispunkten Zins, Korrelationsanstieg auf 0,9? * Historische Szenarien nachspielen (2008, März 2020). * Konzentrationskennzahlen (<a href="anhang-glossar.md#gloss:herfindahl-index" class="glossar-link">Herfindahl-Index</a>, effektive Titelzahl).</p>
|
||||
<p><strong>Abnahmekriterien.</strong> - [ ] Bericht als PDF, automatisch erzeugt. - [ ] Alle Kennzahlen mit zwei unabhängigen Methoden berechnet und verglichen. - [ ] Klartext-Zusammenfassung: „Im schlechtesten Prozent der Monate verlieren Sie typischerweise X €.“</p>
|
||||
<p><strong>Stolperfallen.</strong> Die Wurzel-Zeit-Regel bei CVaR (<a href="cvar.html#kap-cvar">Kapitel 20</a>) — nicht blind anwenden. Korrelationen sind in Krisen andere als im Mittel: Stresstest mit erhöhten Korrelationen rechnen.</p>
|
||||
<p><strong>Stolperfallen.</strong> Die <a href="anhang-glossar.md#gloss:wurzel-zeit-regel" class="glossar-link">Wurzel-Zeit-Regel</a> bei CVaR (<a href="cvar.html#kap-cvar">Kapitel 20</a>) — nicht blind anwenden. Korrelationen sind in Krisen andere als im Mittel: Stresstest mit erhöhten Korrelationen rechnen.</p>
|
||||
<hr />
|
||||
<h2 id="p9-wenn-der-solver-aussteigt-tourenplanung-in-echtgröße">P9 — Wenn der Solver aussteigt: Tourenplanung in Echtgröße</h2>
|
||||
<blockquote>
|
||||
<p><strong>Schwierigkeit:</strong> ⭐⭐⭐ · <strong>Kapitel:</strong> <a href="graphen.html#kap-graphen">Kapitel 8</a>, <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a> · <strong>Zeit:</strong> ca. 18 Stunden</p>
|
||||
</blockquote>
|
||||
<p><strong>Ausgangslage.</strong> P3 hat funktioniert — mit 30 Kunden. Der Auftraggeber kommt mit 400 zurück, und derselbe Code liefert nach zwanzig Minuten noch keine Lösung. Das ist keine Panne, sondern der erwartbare Umschlagpunkt.</p>
|
||||
<p><strong>Modellskizze.</strong> Zwei Verfahren am <strong>selben</strong> Problem, verglichen unter <strong>gleichem Zeitbudget</strong>: * Exakt: MILP oder CP-SAT wie in P3, mit Zeitlimit und protokolliertem Gap. * Heuristisch: Startlösung mit einer Faustregel, dann Verbesserung durch Simulated Annealing oder Large Neighborhood Search (<a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a>). * Messgröße ist nicht „wer gewinnt”, sondern <strong>ab welcher Instanzgröße</strong> sich das Blatt wendet.</p>
|
||||
<p><strong>Modellskizze.</strong> Zwei Verfahren am <strong>selben</strong> Problem, verglichen unter <strong>gleichem Zeitbudget</strong>: * Exakt: <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> oder CP-SAT wie in P3, mit Zeitlimit und protokolliertem Gap. * Heuristisch: Startlösung mit einer Faustregel, dann Verbesserung durch <a href="anhang-glossar.md#gloss:simulated-annealing" class="glossar-link">Simulated Annealing</a> oder Large Neighborhood Search (<a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a>). * Messgröße ist nicht „wer gewinnt”, sondern <strong>ab welcher Instanzgröße</strong> sich das Blatt wendet.</p>
|
||||
<p><strong>Abnahmekriterien.</strong> - [ ] Eine Tabelle über mindestens vier Instanzgrößen: exakt gegen heuristisch, jeweils Zielwert und Laufzeit. - [ ] Der Umschlagpunkt ist auf ±50 Kunden eingegrenzt und <strong>benannt</strong>. - [ ] Bei kleinen Instanzen wird gegen die bewiesen optimale Lösung geprüft — sonst weiß niemand, wie gut die Heuristik wirklich ist. - [ ] Fester Seed, reproduzierbarer Lauf; das Zugbudget ist fix, nicht die Uhrzeit.</p>
|
||||
<blockquote>
|
||||
<p>⚠️ <strong>Die Falle, in die hier fast jeder tappt:</strong> die Heuristik nur auf großen Instanzen zu testen, wo man das Optimum nicht kennt. Dann sieht jede Lösung gut aus.</p>
|
||||
|
|
@ -252,7 +252,7 @@
|
|||
</blockquote>
|
||||
<p><strong>Ausgangslage.</strong> Die Geschäftsführung will „günstiger <strong>und</strong> grüner”. Beides zugleich gibt es nicht — und die übliche Antwort, beide Ziele mit Gewichten zu verrechnen, verdeckt genau die Frage, um die es geht.</p>
|
||||
<p><strong>Modellskizze.</strong> Ein Transport-, Beschaffungs- oder Produktionsmodell mit zwei Zielen: * Erst beide Ziele <strong>einzeln</strong> optimieren — das gibt die Eckpunkte und damit den Rahmen. * Dann die Front über das <span class="math inline">\varepsilon</span>-Constraint-Verfahren abfahren (<a href="mehrziel.html#kap-mehrziel">Kapitel 14</a>): ein Ziel minimieren, das andere als Nebenbedingung schrittweise verschärfen. * Ergebnis ist <strong>keine Lösung, sondern eine Kurve</strong> — plus die Angabe, was jeder eingesparte Kilogramm CO₂ an Mehrkosten bedeutet.</p>
|
||||
<p><strong>Abnahmekriterien.</strong> - [ ] Die Pareto-Front ist berechnet und gezeichnet, nicht nur beschrieben. - [ ] Für mindestens zwei Punkte ist der Aufpreis je eingesparter Einheit ausgerechnet. - [ ] Es ist geprüft und dokumentiert, welche Punkte der Front eine <strong>gewichtete Summe niemals</strong> finden würde — und warum. - [ ] Die Entscheidungsvorlage nennt drei Punkte zur Auswahl, nicht dreißig.</p>
|
||||
<p><strong>Abnahmekriterien.</strong> - [ ] Die <a href="anhang-glossar.md#gloss:pareto-front" class="glossar-link">Pareto-Front</a> ist berechnet und gezeichnet, nicht nur beschrieben. - [ ] Für mindestens zwei Punkte ist der Aufpreis je eingesparter Einheit ausgerechnet. - [ ] Es ist geprüft und dokumentiert, welche Punkte der Front eine <strong>gewichtete Summe niemals</strong> finden würde — und warum. - [ ] Die Entscheidungsvorlage nennt drei Punkte zur Auswahl, nicht dreißig.</p>
|
||||
<hr />
|
||||
<h2 id="p11-vom-skript-zum-dienst-das-modell-übergeben">P11 — Vom Skript zum Dienst: das Modell übergeben</h2>
|
||||
<blockquote>
|
||||
|
|
@ -307,7 +307,7 @@
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Speiseplan unter Nährwert- und Budgetgrenzen</td>
|
||||
<td>LP</td>
|
||||
<td><a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a></td>
|
||||
<td><a href="lp.html#kap-lp">Kapitel 5</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
|
|||
40
OR_HTML_04/qp-nlp.html
generated
40
OR_HTML_04/qp-nlp.html
generated
|
|
@ -107,7 +107,7 @@
|
|||
<figcaption aria-hidden="true">Entscheidungsdiagramm: Welches Werkzeug passt zu meinem Problem? (Teil III)</figcaption>
|
||||
</figure>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Merksatz zum Diagramm</strong> Die erste Frage trennt zwei Welten, die man nicht vermischen darf. Ist die <strong>Nichtlinearität</strong> das Problem, geht es um Konvexität — und damit darum, ob Sie eine Optimalitätsgarantie bekommen oder nur ein lokales Optimum. Ist die <strong>Unsicherheit</strong> 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.</p>
|
||||
<p><strong>🎯 Merksatz zum Diagramm</strong> Die erste Frage trennt zwei Welten, die man nicht vermischen darf. Ist die <strong>Nichtlinearität</strong> das Problem, geht es um <a href="anhang-glossar.md#gloss:konvexitaet" class="glossar-link">Konvexität</a> — und damit darum, ob Sie eine Optimalitätsgarantie bekommen oder nur ein lokales Optimum. Ist die <strong>Unsicherheit</strong> das Problem, geht es um etwas ganz anderes: Nicht der <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> ist die Schwierigkeit, sondern die Frage, was „optimal“ überhaupt heißen soll, wenn man die Daten nicht kennt.</p>
|
||||
<p>Der häufigste Fehler an dieser Stelle ist, Unsicherheit durch <strong>Mittelwerte</strong> zu ersetzen und dann deterministisch zu rechnen. Warum das systematisch danebengeht, zeigt <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a> unter dem Namen <em>Fluch des Durchschnitts</em>.</p>
|
||||
</blockquote>
|
||||
<p>Zwei weitere Kapitel schließen sich an, weil sie dieselbe Voraussetzung aufgeben, nur an einer anderen Stelle: <a href="mehrziel.html#kap-mehrziel">Kapitel 14</a> gibt das <strong>eine Ziel</strong> auf, <a href="prognose.html#kap-prognose">Kapitel 15</a> die Annahme, die <strong>Eingabedaten</strong> seien gegeben statt selbst geschätzt. Was dieser Teil insgesamt leistet, fasst die Synthese an seinem Ende zusammen.</p>
|
||||
|
|
@ -116,9 +116,9 @@
|
|||
<div class="card card-blick">
|
||||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> 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 Portfoliooptimierung in <a href="bruecke.html#teil-anwendungen">Teil IV</a>.</p>
|
||||
<p><strong>Worum geht es?</strong> Risiko ist quadratisch. Sobald Varianz ins Spiel kommt, verlässt man die Welt der <a href="anhang-glossar.md#gloss:polyeder" class="glossar-link">Polyeder</a>. Dieses Kapitel liefert das mathematische Fundament für die gesamte Portfoliooptimierung in <a href="bruecke.html#teil-anwendungen">Teil IV</a>.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="fundament.html#kap-fundament">Kapitel 2</a> (Konvexität, Eigenwerte), <a href="lp.html#kap-lp">Kapitel 5</a> (Dualität, Schattenpreise). Gradienten werden in <a href="#sec:qp-nlp-lernziele">Abschnitt 11.2</a> wiederholt.</p>
|
||||
<p><strong>Danach können Sie:</strong> 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, ohne ein lokales Optimum für das Optimum zu halten.</p>
|
||||
<p><strong>Danach können Sie:</strong> Ein quadratisches Programm aufstellen, die <a href="anhang-glossar.md#gloss:karush-kuhn-tucker-bedingungen-kkt" class="glossar-link">KKT</a>-Bedingungen anwenden, den Zusammenhang zwischen <a href="anhang-glossar.md#gloss:lagrange-multiplikator" class="glossar-link">Lagrange-Multiplikator</a> und <a href="anhang-glossar.md#gloss:schattenpreis" class="glossar-link">Schattenpreis</a> erklären, eine gültige <a href="anhang-glossar.md#gloss:kovarianzmatrix" class="glossar-link">Kovarianzmatrix</a> konstruieren — und mit nicht-konvexen Problemen umgehen, ohne ein lokales Optimum für das Optimum zu halten.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 6,5 Stunden.</p>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>QP_Grundlagen.py</code><br />
|
||||
|
|
@ -209,7 +209,7 @@ Risiko der Mischung: 8.90 %</code></pre>
|
|||
<p><span class="math display">
|
||||
\sigma_p^2 = w_A^2\sigma_A^2 + w_B^2\sigma_B^2 + 2\,w_A w_B \rho\,\sigma_A\sigma_B
|
||||
</span></p>
|
||||
<p>Der letzte Term ist der entscheidende: Bei negativer Korrelation ist er <strong>negativ</strong> und zieht das Gesamtrisiko herunter. Deshalb verlässt man mit Risiko die Welt der Polyeder aus <a href="lp.html#teil-kernverfahren">Teil II</a> — die Zielfunktion ist kein Skalarprodukt mehr, sondern eine quadratische Form. Was das für die Lösbarkeit bedeutet und warum CVXPY das trotzdem mit Optimalitätsgarantie löst, klärt der Rest des Kapitels.</p>
|
||||
<p>Der letzte Term ist der entscheidende: Bei negativer Korrelation ist er <strong>negativ</strong> und zieht das Gesamtrisiko herunter. Deshalb verlässt man mit Risiko die Welt der Polyeder aus <a href="lp.html#teil-kernverfahren">Teil II</a> — die <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a> ist kein <a href="anhang-glossar.md#gloss:skalarprodukt" class="glossar-link">Skalarprodukt</a> mehr, sondern eine quadratische Form. Was das für die Lösbarkeit bedeutet und warum <a href="anhang-glossar.md#gloss:cvxpy" class="glossar-link">CVXPY</a> das trotzdem mit Optimalitätsgarantie löst, klärt der Rest des Kapitels.</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> <code>cp.quad_form(w, S)</code> ist die Zeile, um die es im ganzen Kapitel geht. Sie ist genau dann harmlos, wenn <span class="math inline">\mathbf{S}</span> <strong>positiv semidefinit</strong> ist — und genau dann ein Problem, wenn nicht. CVXPY prüft das für Sie und verweigert die Arbeit im Zweifelsfall. Diese Verweigerung ist ein Schutzmechanismus, keine Schikane.</p>
|
||||
</blockquote>
|
||||
|
|
@ -217,13 +217,13 @@ Risiko der Mischung: 8.90 %</code></pre>
|
|||
<h2 id="sec:qp-nlp-lernziele">11.2 Lernziele</h2>
|
||||
<p>Nach diesem Kapitel können Sie …</p>
|
||||
<ol type="1">
|
||||
<li>… ein <strong>quadratisches Programm (QP)</strong> aufstellen und von einem allgemeinen nichtlinearen Programm abgrenzen.</li>
|
||||
<li>… ein <strong>quadratisches Programm (<a href="anhang-glossar.md#gloss:quadratische-programmierung-qp" class="glossar-link">QP</a>)</strong> aufstellen und von einem allgemeinen nichtlinearen Programm abgrenzen.</li>
|
||||
<li>… die <strong>KKT-Bedingungen</strong> herleiten und auf ein Optimierungsproblem anwenden.</li>
|
||||
<li>… den Zusammenhang zwischen <strong>Lagrange-Multiplikator</strong> und <strong>Schattenpreis</strong> erklären.</li>
|
||||
<li>… zwischen <strong>konvex</strong> und <strong>streng konvex</strong> unterscheiden und eine gültige, positiv semidefinite <strong>Kovarianzmatrix</strong> konstruieren.</li>
|
||||
</ol>
|
||||
<h3 id="auffrischung-gradient-in-einer-minute">Auffrischung: Gradient in einer Minute</h3>
|
||||
<p>Der <strong>Gradient</strong> <span class="math inline">\nabla f(\mathbf{x})</span> ist der Vektor aller partiellen Ableitungen:</p>
|
||||
<p>Der <strong><a href="anhang-glossar.md#gloss:gradient" class="glossar-link">Gradient</a></strong> <span class="math inline">\nabla f(\mathbf{x})</span> ist der Vektor aller partiellen Ableitungen:</p>
|
||||
<p><span class="math display">
|
||||
\nabla f(\mathbf{x}) = \left(\frac{\partial f}{\partial x_1},\ \frac{\partial f}{\partial x_2},\ \dots,\ \frac{\partial f}{\partial x_n}\right)^\top
|
||||
</span></p>
|
||||
|
|
@ -303,7 +303,7 @@ Risiko der Mischung: 8.90 %</code></pre>
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><strong>Warum das praktisch zählt:</strong> Eine Stichproben-Kovarianzmatrix mit mehr Titeln als Beobachtungen (<span class="math inline">N > T</span>) ist <strong>singulär</strong> — 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 dieses Problem behebt die Shrinkage aus <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a>.</p>
|
||||
<p><strong>Warum das praktisch zählt:</strong> Eine <a href="anhang-glossar.md#gloss:stichproben-kovarianzmatrix" class="glossar-link">Stichproben-Kovarianzmatrix</a> mit mehr Titeln als Beobachtungen (<span class="math inline">N > T</span>) ist <strong>singulär</strong> — 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 dieses Problem behebt die Shrinkage aus <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a>.</p>
|
||||
<p>Alle drei Zeilen der Tabelle lassen sich an einem winzigen Zwei-Variablen-QP direkt beobachten — inklusive der Stelle, an der CVXPY ein nicht konvexes Problem <strong>verweigert</strong>, bevor überhaupt ein Solver aufgerufen wird:</p>
|
||||
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
|
|
@ -389,7 +389,7 @@ DCP-konvex (CVXPY-Pruefung)? False
|
|||
<p><strong>⚠️ Prüfen Sie jede Matrix, bevor Sie sie verwenden</strong></p>
|
||||
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>eigenwerte <span class="op">=</span> np.linalg.eigvalsh(Sigma) <span class="co"># 'h' = fuer symmetrische Matrizen</span></span>
|
||||
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="cf">assert</span> np.<span class="bu">all</span>(eigenwerte <span class="op">>=</span> <span class="op">-</span><span class="fl">1e-10</span>), <span class="st">"Sigma ist nicht positiv semidefinit!"</span></span>
|
||||
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"Konditionszahl: </span><span class="sc">{</span>eigenwerte<span class="sc">.</span><span class="bu">max</span>() <span class="op">/</span> eigenwerte<span class="sc">.</span><span class="bu">min</span>()<span class="sc">:.1f}</span><span class="ss">"</span>)</span></code></pre></div>
|
||||
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"[Konditionszahl](anhang-glossar.md#gloss:konditionszahl)</span><span class="sc">{.</span>glossar<span class="op">-</span>link<span class="sc">}</span><span class="ss">: </span><span class="sc">{</span>eigenwerte<span class="sc">.</span><span class="bu">max</span>() <span class="op">/</span> eigenwerte<span class="sc">.</span><span class="bu">min</span>()<span class="sc">:.1f}</span><span class="ss">"</span>)</span></code></pre></div>
|
||||
<p>Eine einzige Zeile — und sie deckt eine ungültige Kovarianzmatrix sofort auf.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
|
|
@ -399,7 +399,7 @@ DCP-konvex (CVXPY-Pruefung)? False
|
|||
<p><span class="math display">
|
||||
\min f(\mathbf{x}) \quad\text{u. d. N.}\quad g_i(\mathbf{x})\le0\ (i=1..m),\qquad h_j(\mathbf{x})=0\ (j=1..p)
|
||||
</span></p>
|
||||
<p>lautet die <strong>Lagrange-Funktion</strong>:</p>
|
||||
<p>lautet die <strong><a href="anhang-glossar.md#gloss:lagrange-funktion" class="glossar-link">Lagrange-Funktion</a></strong>:</p>
|
||||
<p><span class="math display">
|
||||
\mathcal{L}(\mathbf{x},\boldsymbol{\lambda},\boldsymbol{\nu})
|
||||
= f(\mathbf{x}) + \sum_{i=1}^m \lambda_i g_i(\mathbf{x}) + \sum_{j=1}^p \nu_j h_j(\mathbf{x})
|
||||
|
|
@ -418,7 +418,7 @@ DCP-konvex (CVXPY-Pruefung)? False
|
|||
<p><strong>2. Primale Zulässigkeit</strong> — die ursprünglichen Bedingungen gelten: <span class="math inline">g_i(\mathbf{x}^*)\le0</span>, <span class="math inline">h_j(\mathbf{x}^*)=0</span>.</p>
|
||||
<p><strong>3. Duale Zulässigkeit</strong> — die Multiplikatoren der Ungleichungen sind nichtnegativ: <span class="math inline">\lambda_i^*\ge0</span>.</p>
|
||||
<p><em>Warum?</em> Eine Wand kann nur <strong>drücken</strong>, nicht ziehen. Ein negatives <span class="math inline">\lambda</span> hieße, die Bedingung würde die Lösung von sich weg<strong>ziehen</strong> — dann wäre sie nicht bindend.</p>
|
||||
<p><strong>4. Komplementärer Schlupf</strong> — <span class="math inline">\lambda_i^*\cdot g_i(\mathbf{x}^*)=0</span> für alle <span class="math inline">i</span>.</p>
|
||||
<p><strong>4. <a href="anhang-glossar.md#gloss:komplementaerer-schlupf" class="glossar-link">Komplementärer Schlupf</a></strong> — <span class="math inline">\lambda_i^*\cdot g_i(\mathbf{x}^*)=0</span> für alle <span class="math inline">i</span>.</p>
|
||||
<p><em>Bedeutung:</em> Entweder ist die Bedingung nicht bindend (<span class="math inline">g_i<0</span>), <strong>dann muss</strong> <span class="math inline">\lambda_i=0</span> sein. Oder der Multiplikator ist positiv, <strong>dann muss</strong> die Bedingung mit Gleichheit binden. Das ist derselbe Satz wie in <a href="lp.html#kap-lp">Kapitel 5</a> — nur allgemeiner formuliert.</p>
|
||||
<figure>
|
||||
<img src="bilder_04/kap_qp_kkt.svg" alt="Abb. 11.1: Links die Handrechnung dieses Abschnitts: Das freie Minimum liegt bei x=5, die Grenze lässt nur x \le 3 zu, und \lambda^* = 4 ist genau die Steigung von f am Rand — der Preis dafür, dass es nicht weitergeht. Rechts dieselbe Aussage in zwei Dimensionen: \nabla f und \lambda^*\nabla g zeigen gegeneinander und heben sich auf. Das Skript bilder_04/erzeuge_kkt.py prüft alle vier KKT-Bedingungen numerisch, bevor es zeichnet." />
|
||||
|
|
@ -458,7 +458,7 @@ DCP-konvex (CVXPY-Pruefung)? False
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><span class="math inline">\lambda_i^*</span> selbst</td>
|
||||
<td>Der <strong>Schattenpreis</strong> von Bedingung <span class="math inline">i</span> — dieselbe Größe wie im LP (<a href="lp.html#kap-lp">Kapitel 5</a>), nur für krumme Ränder.</td>
|
||||
<td>Der <strong>Schattenpreis</strong> von Bedingung <span class="math inline">i</span> — dieselbe Größe wie im <a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a> (<a href="lp.html#kap-lp">Kapitel 5</a>), nur für krumme Ränder.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
@ -589,12 +589,12 @@ DCP-konvex (CVXPY-Pruefung)? False
|
|||
<span id="cb6-110"><a href="#cb6-110" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">74</span>)</span></code></pre></div>
|
||||
<hr />
|
||||
<h2 id="sec:qp-nlp-nichtlineare-optimierung-mit-scipy-optimize-minimize">11.5 Nichtlineare Optimierung mit <code>scipy.optimize.minimize</code></h2>
|
||||
<p>Wenn Zielfunktion oder Nebenbedingungen weder linear noch quadratisch sind — Logarithmen, Wurzeln, Exponentialfunktionen — nutzt man gradientenbasierte Verfahren wie <strong>SLSQP</strong> (<em>Sequential Least Squares Programming</em>).</p>
|
||||
<p>Wenn Zielfunktion oder Nebenbedingungen weder linear noch quadratisch sind — Logarithmen, Wurzeln, Exponentialfunktionen — nutzt man gradientenbasierte Verfahren wie <strong><a href="anhang-glossar.md#gloss:slsqp" class="glossar-link">SLSQP</a></strong> (<em>Sequential Least Squares Programming</em>).</p>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Der entscheidende Unterschied zu CVXPY</strong> CVXPY <strong>prüft</strong> die Konvexität und garantiert bei Erfolg das globale Optimum. <code>scipy.optimize.minimize</code> prüft nichts und liefert ein <strong>lokales</strong> Optimum, das vom Startpunkt abhängt (siehe die Demonstration in <a href="fundament.html#sec:fundament-konvexitaet-die-grenze-zwischen-leicht-und">Abschnitt 2.5</a>). Wer SLSQP einsetzt, sollte <strong>immer mit mehreren Startpunkten rechnen</strong> und die Ergebnisse vergleichen.</p>
|
||||
</blockquote>
|
||||
<h3 id="praxisfall-entropie-maximierte-kapitalallokation">Praxisfall: Entropie-maximierte Kapitalallokation</h3>
|
||||
<p>Wir optimieren ein Portfolio nicht nur nach Varianz, sondern maximieren zusätzlich die <strong>Shannon-Entropie</strong> der Gewichte, um Klumpenrisiken glatt zu bestrafen:</p>
|
||||
<p>Wir optimieren ein Portfolio nicht nur nach Varianz, sondern maximieren zusätzlich die <strong><a href="anhang-glossar.md#gloss:shannon-entropie" class="glossar-link">Shannon-Entropie</a></strong> der Gewichte, um Klumpenrisiken glatt zu bestrafen:</p>
|
||||
<p><span class="math display">
|
||||
\min_{\mathbf{w}}\quad \underbrace{\tfrac12\mathbf{w}^\top\boldsymbol{\Sigma}\mathbf{w}}_{\text{Risiko}}
|
||||
\;-\;\underbrace{\alpha\,\boldsymbol{\mu}^\top\mathbf{w}}_{\text{Ertrag}}
|
||||
|
|
@ -823,7 +823,7 @@ US-Treasuries 3.0 % 7.0 % 0.45 %
|
|||
<tr class="even">
|
||||
<td><strong>Ja/Nein mal Menge</strong></td>
|
||||
<td>Anlage läuft <em>und</em> wie stark</td>
|
||||
<td>ganzzahlig + nichtlinear = MINLP</td>
|
||||
<td>ganzzahlig + nichtlinear = <a href="anhang-glossar.md#gloss:minlp" class="glossar-link">MINLP</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>Verhältnisse</strong></td>
|
||||
|
|
@ -1163,8 +1163,8 @@ Drei Konsequenzen fuer die Praxis:
|
|||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><strong>Ipopt</strong> (über <code>cyipopt</code> oder Pyomo)</td>
|
||||
<td>lokaler NLP-Solver</td>
|
||||
<td><strong>Ipopt</strong> (über <code>cyipopt</code> oder <a href="anhang-glossar.md#gloss:pyomo" class="glossar-link">Pyomo</a>)</td>
|
||||
<td>lokaler <a href="anhang-glossar.md#gloss:nichtlineare-programmierung-nlp" class="glossar-link">NLP</a>-Solver</td>
|
||||
<td>Innere-Punkte-Verfahren für große, glatte NLPs mit tausenden Variablen — deutlich leistungsfähiger als <code>scipy</code>, aber ebenfalls <strong>nur lokal</strong></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -1173,7 +1173,7 @@ Drei Konsequenzen fuer die Praxis:
|
|||
<td>Bonmin lokal, Couenne mit globaler Garantie für viele Klassen</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>SCIP</strong>, <strong>BARON</strong>, <strong>Gurobi</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:scip" class="glossar-link">SCIP</a></strong>, <strong>BARON</strong>, <strong><a href="anhang-glossar.md#gloss:gurobi" class="glossar-link">Gurobi</a></strong></td>
|
||||
<td>global</td>
|
||||
<td>Beweisbar globales Optimum, mit entsprechendem Rechenaufwand</td>
|
||||
</tr>
|
||||
|
|
@ -1219,7 +1219,7 @@ Drei Konsequenzen fuer die Praxis:
|
|||
<p><strong>Aufgabe 11.2 ⭐ — Komplementärer Schlupf.</strong> Ein QP liefert <span class="math inline">w = (0{,}4;\ 0{,}0;\ 0{,}6)</span> mit Bedingung <span class="math inline">w \ge 0</span> und Multiplikatoren <span class="math inline">\lambda = (0{,}0;\ 0{,}03;\ 0{,}0)</span>. Ist das mit KKT verträglich? Was sagt <span class="math inline">\lambda_2 = 0{,}03</span> wirtschaftlich?</p>
|
||||
<p><strong>Aufgabe 11.3 ⭐⭐ — KKT von Hand.</strong> Lösen Sie mit KKT vollständig von Hand: <span class="math display">\min\ x_1^2 + x_2^2 \qquad\text{u. d. N.}\qquad x_1 + x_2 \ge 4</span> Geben Sie <span class="math inline">x^*</span>, <span class="math inline">\lambda^*</span> und die Interpretation von <span class="math inline">\lambda^*</span> an. Prüfen Sie mit CVXPY.</p>
|
||||
<p><strong>Aufgabe 11.4 ⭐⭐ — Ungültige Kovarianzmatrix erkennen.</strong> Prüfen Sie, ob folgende Korrelationsmatrix möglich ist, und begründen Sie: <span class="math display">\mathbf{C} = \begin{pmatrix}1{,}0&0{,}9&-0{,}9\\0{,}9&1{,}0&0{,}9\\-0{,}9&0{,}9&1{,}0\end{pmatrix}</span> (Tipp: Wenn A stark mit B korreliert und B stark mit C, kann A dann stark <strong>negativ</strong> mit C korrelieren?)</p>
|
||||
<p><strong>Aufgabe 11.5 ⭐⭐⭐ — Effekt der Gewichtung untersuchen.</strong> Variieren Sie in <code>Entropie_Maximierte_Allokation.py</code> systematisch <span class="math inline">\alpha \in \{0{,}1;\ 0{,}5;\ 1;\ 5\}</span> und <span class="math inline">\beta \in \{0;\ 0{,}005;\ 0{,}015;\ 0{,}05\}</span>. Stellen Sie für jede Kombination Rendite, Volatilität und Entropie in einer Tabelle dar. (a) Wie verändert <span class="math inline">\beta</span> die Konzentration im Krypto-Titel? (b) Ab welchem <span class="math inline">\beta</span> nähert sich die Lösung der Gleichgewichtung? (c) Was ist Ihre Empfehlung — und mit welcher Begründung würden Sie sie einem Anlageausschuss vorlegen?</p>
|
||||
<p><strong>Aufgabe 11.5 ⭐⭐⭐ — Effekt der Gewichtung untersuchen.</strong> Variieren Sie in <code>Entropie_Maximierte_Allokation.py</code> systematisch <span class="math inline">\alpha \in \{0{,}1;\ 0{,}5;\ 1;\ 5\}</span> und <span class="math inline">\beta \in \{0;\ 0{,}005;\ 0{,}015;\ 0{,}05\}</span>. Stellen Sie für jede Kombination Rendite, <a href="anhang-glossar.md#gloss:volatilitaet" class="glossar-link">Volatilität</a> und Entropie in einer Tabelle dar. (a) Wie verändert <span class="math inline">\beta</span> die Konzentration im Krypto-Titel? (b) Ab welchem <span class="math inline">\beta</span> nähert sich die Lösung der Gleichgewichtung? (c) Was ist Ihre Empfehlung — und mit welcher Begründung würden Sie sie einem Anlageausschuss vorlegen?</p>
|
||||
<p><strong>Aufgabe 11.6 ⭐⭐⭐ — Nicht-Konvexität demonstrieren.</strong> Bauen Sie bewusst eine ungültige „Kovarianzmatrix“ (per <a href="mailto:A@A.T" class="email">A@A.T</a> mit anschließend überschriebener Diagonale) und lösen Sie das Modell mit 20 Startpunkten. Dokumentieren Sie: Wie viele verschiedene Optima entstehen? Wie groß ist der Unterschied zwischen bestem und schlechtestem Ergebnis? Kann die „Portfoliovarianz“ negativ werden?</p>
|
||||
<hr />
|
||||
<h2 id="sec:qp-nlp-denkfehler">11.8 Finde den Denkfehler</h2>
|
||||
|
|
@ -1234,7 +1234,7 @@ Drei Konsequenzen fuer die Praxis:
|
|||
</ul>
|
||||
<p>Alle drei schwanken mit 20 %. Leerverkäufe sind in seinem Mandat erlaubt, die Gewichte dürfen also negativ werden; sie müssen sich nur zu 100 % summieren.</p>
|
||||
<p>Sein erster Versuch mit CVXPY bricht ab:</p>
|
||||
<pre><code>DCPError: Problem does not follow DCP rules.
|
||||
<pre><code>[DCPError](anhang-glossar.md#gloss:dcperror){.glossar-link}: Problem does not follow [DCP](anhang-glossar.md#gloss:dcp-disciplined-convex-programming){.glossar-link} rules.
|
||||
The objective is not DCP. Its following subexpressions are not: QuadForm(...)</code></pre>
|
||||
<p>Er hält das für eine Einschränkung der Bibliothek und weicht auf <code>scipy</code> aus:</p>
|
||||
<div class="sourceCode" id="cb13"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||||
|
|
@ -1295,7 +1295,7 @@ The objective is not DCP. Its following subexpressions are not: QuadForm(...)</c
|
|||
<li><strong>Nicht-Konvexität kommt aus dem Alltag</strong>, nicht aus der Theorie: Mengenrabatte, Skaleneffekte, Produkte zweier Entscheidungen. Wo eines davon im Modell steht, ist die Optimalitätsgarantie weg.</li>
|
||||
<li><strong>Berichten Sie bei nicht-konvexen Problemen die Streuung mit</strong>, nicht die letzte Nachkommastelle. „Bester Wert aus 200 Startpunkten, Spanne bis …“ ist belastbar, ein einzelner Wert ist es nicht.</li>
|
||||
</ul>
|
||||
<p><strong>Ausblick.</strong> <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a> gibt die Annahme auf, dass die Parameter überhaupt bekannt sind. Wir lernen, mit Szenarien, Erwartungswerten und Worst Cases umzugehen.</p>
|
||||
<p><strong>Ausblick.</strong> <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a> gibt die Annahme auf, dass die <a href="anhang-glossar.md#gloss:parameter" class="glossar-link">Parameter</a> überhaupt bekannt sind. Wir lernen, mit Szenarien, Erwartungswerten und Worst Cases umzugehen.</p>
|
||||
|
||||
</article>
|
||||
<button type="button" class="fortschritt-knopf" data-kapitel="qp-nlp.html"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg> <span>Als gelesen markieren</span></button>
|
||||
|
|
|
|||
2
OR_HTML_04/stichwortverzeichnis.html
generated
2
OR_HTML_04/stichwortverzeichnis.html
generated
File diff suppressed because one or more lines are too long
6
OR_HTML_04/supplychain.html
generated
6
OR_HTML_04/supplychain.html
generated
|
|
@ -152,7 +152,7 @@ Umschlagpunkt: 3.9 Stunden</code></pre>
|
|||
<p><strong>Und jetzt der Punkt.</strong> Bis knapp vier Stunden ist die <em>fünfmal teurere</em> Gasturbine die günstigere Wahl. Erst danach hat der Kernblock seine Anfahrkosten wieder eingespielt.</p>
|
||||
<p>Die Merit-Order — Kraftwerke nach Grenzkosten sortieren und von unten auffüllen — ist damit nur für einen <strong>einzelnen</strong> Zeitpunkt richtig. Sobald ein Tag geplant wird, hängt jede Stunde an allen anderen: Ein Block, der um 8 Uhr angefahren wird, muss bis mindestens 16 Uhr laufen, und diese Entscheidung fällt am Vorabend.</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Anfahrkosten und Mindestlaufzeiten machen aus 24 unabhängigen Stundenentscheidungen <strong>ein</strong> Problem. Genau deshalb ist die Kraftwerkseinsatzplanung ein MILP und keine Sortierung.</p>
|
||||
<p><strong>🎯 Merksatz</strong> Anfahrkosten und Mindestlaufzeiten machen aus 24 unabhängigen Stundenentscheidungen <strong>ein</strong> Problem. Genau deshalb ist die Kraftwerkseinsatzplanung ein <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> und keine Sortierung.</p>
|
||||
</blockquote>
|
||||
<p><strong>Warum funktioniert das?</strong> Der Umschlagpunkt ist eine einfache Rechnung: Die Anfahrkostendifferenz (38 500 €) geteilt durch die Grenzkostendifferenz je Stunde (83 €/MWh × 120 MW = 9 960 €/h) ergibt 3,9 Stunden. Bei zwei Kraftwerken kann man das im Kopf ausrechnen — bei fünf Blöcken und 24 Stunden nicht mehr.</p>
|
||||
<hr />
|
||||
|
|
@ -162,7 +162,7 @@ Umschlagpunkt: 3.9 Stunden</code></pre>
|
|||
<li>… ein Unit-Commitment-Modell mit Anfahrkosten und Mindestlaufzeiten aufstellen.</li>
|
||||
<li>… erklären, warum eine <strong>binäre erste Stufe</strong> das zweistufige Modell aus <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a> verschärft.</li>
|
||||
<li>… zeigen, dass eine Planung auf den Erwartungswert nicht nur ungenau, sondern <strong>systematisch zu knapp</strong> ist.</li>
|
||||
<li>… eine CVaR-Schranke auf eine physikalische Größe (nicht gedeckte Energie) legen.</li>
|
||||
<li>… eine <a href="anhang-glossar.md#gloss:conditional-value-at-risk-cvar" class="glossar-link">CVaR</a>-Schranke auf eine physikalische Größe (nicht gedeckte Energie) legen.</li>
|
||||
<li>… begründen, wann eine Risikoschranke etwas ändert — und wann sie überflüssig ist.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
|
|
@ -848,7 +848,7 @@ zweistufig 111111222222222222222111 (39 Blockstunden)</code></pre>
|
|||
<p><strong>Aufgabe 17.2 ⭐ — Die fehlende Nebenbedingung.</strong> Das Modell kennt Mindestlaufzeiten, aber keine <strong>Mindeststillstandszeiten</strong>. Formulieren Sie die entsprechende Bedingung. Welchen realen Sachverhalt bildet sie ab?</p>
|
||||
<p><strong>Aufgabe 17.3 ⭐⭐ — Wie viele Szenarien?</strong> Rechnen Sie mit 10, 20, 40 und 80 Szenarien. Ab wann ändert sich der Commitment-Plan nicht mehr? Was folgt daraus für die Praxis — und was hat das mit <a href="prognose.html#sec:prognose-messfalle">Abschnitt 15.6</a> zu tun?</p>
|
||||
<p><strong>Aufgabe 17.4 ⭐⭐ — Der Wert eines Speichers.</strong> Ergänzen Sie einen Batteriespeicher (100 MW, 400 MWh, Wirkungsgrad 90 %). Um wie viel sinken die erwarteten Kosten — und was ist der Speicher damit je MWh Kapazität wert?</p>
|
||||
<p><strong>Aufgabe 17.5 ⭐⭐⭐ — Wenn es größer wird.</strong> Erhöhen Sie auf 20 Blöcke und 168 Stunden (eine Woche). Beobachten Sie MIP-Gap und Rechenzeit (<a href="milp.html#sec:milp-gap">Abschnitt 6.8</a>). Ab wann wird das Problem für den exakten Solver zu groß — und welches Verfahren aus <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a> würden Sie einsetzen?</p>
|
||||
<p><strong>Aufgabe 17.5 ⭐⭐⭐ — Wenn es größer wird.</strong> Erhöhen Sie auf 20 Blöcke und 168 Stunden (eine Woche). Beobachten Sie <a href="anhang-glossar.md#gloss:mip-gap" class="glossar-link">MIP-Gap</a> und Rechenzeit (<a href="milp.html#sec:milp-gap">Abschnitt 6.8</a>). Ab wann wird das Problem für den exakten <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> zu groß — und welches Verfahren aus <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a> würden Sie einsetzen?</p>
|
||||
<hr />
|
||||
<h2 id="sec:supplychain-denkfehler">17.8 Finde den Denkfehler</h2>
|
||||
<div class="card card-denkfehler">
|
||||
|
|
|
|||
10
OR_HTML_04/synthese-anwendungen.html
generated
10
OR_HTML_04/synthese-anwendungen.html
generated
|
|
@ -133,7 +133,7 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td>Rüstkosten, Anfahrkosten</td>
|
||||
<td>Transaktionskosten</td>
|
||||
<td><a href="anhang-glossar.md#gloss:transaktionskosten" class="glossar-link">Transaktionskosten</a></td>
|
||||
<td>Fixkosten mit Binärvariable (B1)</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
|
|
@ -175,12 +175,12 @@
|
|||
<td><a href="supplychain.html#kap-supplychain">Kapitel 17</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>„Der VaR sagt, wie riskant es ist.”</td>
|
||||
<td>VaR <strong>1,86 %</strong>, CVaR <strong>2,99 %</strong> — und der schlechteste Tag der Stichprobe (<strong>−23,0 %</strong>) ändert am VaR <strong>nichts</strong></td>
|
||||
<td>„Der <a href="anhang-glossar.md#gloss:value-at-risk-var" class="glossar-link">VaR</a> sagt, wie riskant es ist.”</td>
|
||||
<td>VaR <strong>1,86 %</strong>, <a href="anhang-glossar.md#gloss:conditional-value-at-risk-cvar" class="glossar-link">CVaR</a> <strong>2,99 %</strong> — und der schlechteste Tag der Stichprobe (<strong>−23,0 %</strong>) ändert am VaR <strong>nichts</strong></td>
|
||||
<td><a href="cvar.html#kap-cvar">Kapitel 20</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>„Die Kovarianzmatrix ist eine Eingabe wie jede andere.”</td>
|
||||
<td>„Die <a href="anhang-glossar.md#gloss:kovarianzmatrix" class="glossar-link">Kovarianzmatrix</a> ist eine Eingabe wie jede andere.”</td>
|
||||
<td>Aus kurzen Reihen geschätzt ist sie schlecht konditioniert; die Optimierung setzt dann auf Schätzrauschen</td>
|
||||
<td><a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a></td>
|
||||
</tr>
|
||||
|
|
@ -188,7 +188,7 @@
|
|||
</table>
|
||||
<h2 id="drei-fehler-die-dieser-teil-verhindert">Drei Fehler, die dieser Teil verhindert</h2>
|
||||
<ol type="1">
|
||||
<li><strong>Bei Markowitz einsteigen.</strong> Wer <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> überspringt, optimiert seine eigenen Schätzfehler und wundert sich über Gewichte, die niemand halten würde.</li>
|
||||
<li><strong>Bei Markowitz einsteigen.</strong> Wer <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> überspringt, optimiert seine eigenen <a href="anhang-glossar.md#gloss:schaetzfehler" class="glossar-link">Schätzfehler</a> und wundert sich über Gewichte, die niemand halten würde.</li>
|
||||
<li><strong>Den VaR für ein Risikomaß halten.</strong> Er sagt, <strong>ob</strong> die Schwelle gerissen wird, nicht <strong>wie schlimm</strong> es dahinter aussieht — und er ist nicht kohärent. Optimiert wird der CVaR.</li>
|
||||
<li><strong>Trägheit unterschätzen.</strong> Im Kraftwerkspark ist nicht die Prognosegüte das Problem, sondern dass sich ein Block mit acht Stunden Mindestlaufzeit um 18 Uhr nicht mehr herbeirufen lässt. Dieselbe Trägheit heißt im Depot Transaktionskosten.</li>
|
||||
</ol>
|
||||
|
|
|
|||
8
OR_HTML_04/synthese-grundlagen.html
generated
8
OR_HTML_04/synthese-grundlagen.html
generated
|
|
@ -100,7 +100,7 @@
|
|||
<nav class="prev-next"><a class="prev-next-knopf prev-next-prev" href="modellierung.html"><svg class="icon" aria-hidden="true"><use href="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 4: Vom Management-Wunsch zum Modell</span></a><a class="prev-next-knopf prev-next-next" href="lp.html"><span><small>Weiter</small>Kapitel 5: Lineare Programmierung — Simplex, Dualität und Schattenpreise</span><svg class="icon" aria-hidden="true"><use href="#icon-chevron-right"></use></svg></a></nav>
|
||||
<article>
|
||||
<h1 id="synthese-teil-i-grundlagen-auf-einen-blick">Synthese Teil I — Grundlagen auf einen Blick</h1>
|
||||
<p>Vier Kapitel, eine Frage: <strong>Was muss vorliegen, bevor ein Solver überhaupt sinnvoll gestartet werden kann?</strong> Die Antwort ist unbequem, weil das meiste davon nichts mit Programmieren zu tun hat.</p>
|
||||
<p>Vier Kapitel, eine Frage: <strong>Was muss vorliegen, bevor ein <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> überhaupt sinnvoll gestartet werden kann?</strong> Die Antwort ist unbequem, weil das meiste davon nichts mit Programmieren zu tun hat.</p>
|
||||
<h2 id="was-welches-kapitel-klärt">Was welches Kapitel klärt</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
|
|
@ -119,17 +119,17 @@
|
|||
<tr class="odd">
|
||||
<td>Was ist überhaupt ein Optimierungsmodell?</td>
|
||||
<td><a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a></td>
|
||||
<td>Die vier Bausteine benennen — Variablen, Zielfunktion, Nebenbedingungen, Daten — und sie in einem fremden Problem wiedererkennen</td>
|
||||
<td>Die vier Bausteine benennen — Variablen, <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a>, Nebenbedingungen, Daten — und sie in einem fremden Problem wiedererkennen</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>Warum rechnet der Solver falsch, obwohl das Modell stimmt?</td>
|
||||
<td><a href="fundament.html#kap-fundament">Kapitel 2</a></td>
|
||||
<td>Konvexität beurteilen, den zulässigen Bereich als Polyeder sehen, schlechte Konditionierung erkennen und beheben</td>
|
||||
<td><a href="anhang-glossar.md#gloss:konvexitaet" class="glossar-link">Konvexität</a> beurteilen, den zulässigen Bereich als <a href="anhang-glossar.md#gloss:polyeder" class="glossar-link">Polyeder</a> sehen, schlechte Konditionierung erkennen und beheben</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Welche Bibliothek, und warum vertragen sie sich nicht?</td>
|
||||
<td><a href="oekosystem.html#kap-oekosystem">Kapitel 3</a></td>
|
||||
<td>Solver, Bindings und Modellierungsschichten unterscheiden — und den HiGHS-Symbolkonflikt zwischen <code>ortools</code> und <code>highspy</code> umgehen</td>
|
||||
<td>Solver, Bindings und Modellierungsschichten unterscheiden — und den <a href="anhang-glossar.md#gloss:highs" class="glossar-link">HiGHS</a>-Symbolkonflikt zwischen <code>ortools</code> und <code>highspy</code> umgehen</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>Wie wird aus einem Satz ein Modell?</td>
|
||||
|
|
|
|||
14
OR_HTML_04/synthese-kernverfahren.html
generated
14
OR_HTML_04/synthese-kernverfahren.html
generated
|
|
@ -121,21 +121,21 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><strong>LP</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a></strong></td>
|
||||
<td>teilbare Mengen, lineare Zusammenhänge</td>
|
||||
<td>beweisbares Optimum <strong>plus Schattenpreise</strong></td>
|
||||
<td>sobald etwas ganzzahlig sein muss</td>
|
||||
<td><a href="lp.html#kap-lp">Kapitel 5</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>MILP</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a></strong></td>
|
||||
<td>Ja/Nein-Entscheidungen, Fixkosten, Logik</td>
|
||||
<td>beweisbares Optimum, Gap als Fortschrittsmaß</td>
|
||||
<td>Laufzeit wächst mit der Zahl der Binärvariablen</td>
|
||||
<td><a href="milp.html#kap-milp">Kapitel 6</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>CP-SAT</strong></td>
|
||||
<td><strong><a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a></strong></td>
|
||||
<td>Zuweisung, Reihenfolge, Kalender, harte Logik</td>
|
||||
<td>beweisbares Optimum, sehr ausdrucksstarke Bedingungen</td>
|
||||
<td>keine Schattenpreise, keine stetigen Größen</td>
|
||||
|
|
@ -150,7 +150,7 @@
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>Metaheuristiken</strong></td>
|
||||
<td>wenn der exakte Solver aussteigt</td>
|
||||
<td>wenn der exakte <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> aussteigt</td>
|
||||
<td>eine gute Lösung in <strong>fester Zeit</strong></td>
|
||||
<td>keine Garantie, kein Beweis, keine Schranke</td>
|
||||
<td><a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a></td>
|
||||
|
|
@ -182,12 +182,12 @@
|
|||
<tbody>
|
||||
<tr class="odd">
|
||||
<td>„Der exakte Solver ist immer besser.”</td>
|
||||
<td>Bei 500 Aufträgen liefert CP-SAT eine Lösung, die <strong>5,2 % schlechter</strong> ist als die Faustregel eines Meisters</td>
|
||||
<td>Bei 500 Aufträgen liefert <a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a> eine Lösung, die <strong>5,2 % schlechter</strong> ist als die Faustregel eines Meisters</td>
|
||||
<td><a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>„Metaheuristiken sind ungenau.”</td>
|
||||
<td>Faustregel 2 497 → Annealing 2 343 → Annealing plus LNS <strong>2 289</strong> Minuten Rüstzeit; untere Schranke 1 768</td>
|
||||
<td>Faustregel 2 497 → Annealing 2 343 → Annealing plus <a href="anhang-glossar.md#gloss:large-neighborhood-search-lns" class="glossar-link">LNS</a> <strong>2 289</strong> Minuten <a href="anhang-glossar.md#gloss:ruestzeit" class="glossar-link">Rüstzeit</a>; untere Schranke 1 768</td>
|
||||
<td><a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
|
|
@ -211,7 +211,7 @@
|
|||
<ol type="1">
|
||||
<li><strong>Runden.</strong> Die LP-Lösung ist keine Näherung der ganzzahligen Lösung — sie kann beliebig weit danebenliegen, und gerundet sogar unzulässig werden.</li>
|
||||
<li><strong>Ein zu großes Big-M.</strong> Es macht das Modell nicht falsch, sondern die Suche langsam und die Schranken wertlos. So klein wie zulässig, nie „sicherheitshalber groß”.</li>
|
||||
<li><strong>Zu früh heuristisch werden.</strong> Der Umschlagpunkt, ab dem eine Metaheuristik den exakten Solver schlägt, ist eine Eigenschaft <strong>des Problems</strong> und lässt sich messen. Wer ihn nicht misst, verzichtet auf Optimalitätsgarantien, die er hätte haben können.</li>
|
||||
<li><strong>Zu früh heuristisch werden.</strong> Der Umschlagpunkt, ab dem eine <a href="anhang-glossar.md#gloss:metaheuristik" class="glossar-link">Metaheuristik</a> den exakten Solver schlägt, ist eine Eigenschaft <strong>des Problems</strong> und lässt sich messen. Wer ihn nicht misst, verzichtet auf Optimalitätsgarantien, die er hätte haben können.</li>
|
||||
</ol>
|
||||
<h2 id="wenn-sie-nur-eines-mitnehmen">Wenn Sie nur eines mitnehmen</h2>
|
||||
<blockquote>
|
||||
|
|
|
|||
14
OR_HTML_04/synthese-nichtlinear.html
generated
14
OR_HTML_04/synthese-nichtlinear.html
generated
|
|
@ -121,7 +121,7 @@
|
|||
<tr class="odd">
|
||||
<td><strong>Linearität</strong></td>
|
||||
<td>Risiko wächst quadratisch, Kosten degressiv, Sättigung</td>
|
||||
<td>QP, konvexe Optimierung, KKT</td>
|
||||
<td><a href="anhang-glossar.md#gloss:quadratische-programmierung-qp" class="glossar-link">QP</a>, konvexe Optimierung, <a href="anhang-glossar.md#gloss:karush-kuhn-tucker-bedingungen-kkt" class="glossar-link">KKT</a></td>
|
||||
<td><a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -133,19 +133,19 @@
|
|||
<tr class="odd">
|
||||
<td><strong>Eine Periode</strong></td>
|
||||
<td>die Entscheidung heute verändert, was übermorgen möglich ist</td>
|
||||
<td>Bellman-Gleichung, Rückwärtsinduktion</td>
|
||||
<td><a href="anhang-glossar.md#gloss:bellman-gleichung" class="glossar-link">Bellman-Gleichung</a>, <a href="anhang-glossar.md#gloss:rueckwaertsinduktion" class="glossar-link">Rückwärtsinduktion</a></td>
|
||||
<td><a href="dynamische-programmierung.html#kap-dynamische-programmierung">Kapitel 13</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>Ein Ziel</strong></td>
|
||||
<td>zwei Kennzahlen sollen gleichzeitig stimmen</td>
|
||||
<td>Pareto-Front, ε-Constraint</td>
|
||||
<td><a href="anhang-glossar.md#gloss:pareto-front" class="glossar-link">Pareto-Front</a>, ε-Constraint</td>
|
||||
<td><a href="mehrziel.html#kap-mehrziel">Kapitel 14</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><strong>Daten sind gegeben</strong></td>
|
||||
<td>die Eingabe ist selbst eine Prognose</td>
|
||||
<td>Predict-then-Optimize, entscheidungsorientiertes Lernen</td>
|
||||
<td><a href="anhang-glossar.md#gloss:predict-then-optimize" class="glossar-link">Predict-then-Optimize</a>, entscheidungsorientiertes Lernen</td>
|
||||
<td><a href="prognose.html#kap-prognose">Kapitel 15</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
@ -183,7 +183,7 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td>„Die bessere Prognose führt zur besseren Entscheidung.”</td>
|
||||
<td>Das Modell mit dem <strong>schlechteren</strong> MSE trifft die günstigere Entscheidung</td>
|
||||
<td>Das Modell mit dem <strong>schlechteren</strong> <a href="anhang-glossar.md#gloss:mse" class="glossar-link">MSE</a> trifft die günstigere Entscheidung</td>
|
||||
<td><a href="prognose.html#kap-prognose">Kapitel 15</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
@ -191,12 +191,12 @@
|
|||
<h2 id="drei-fehler-die-dieser-teil-verhindert">Drei Fehler, die dieser Teil verhindert</h2>
|
||||
<ol type="1">
|
||||
<li><strong>Unsicherheit durch Mittelwerte ersetzen.</strong> Der Durchschnittskunde kauft nie. Bei asymmetrischen Kosten liegt das Optimum systematisch neben dem Mittelwert, und eine Terminzusage ist ein <strong>Quantil</strong>, kein Erwartungswert.</li>
|
||||
<li><strong>Konvexität voraussetzen, ohne sie zu prüfen.</strong> Ohne sie gibt es keine Optimalitätsgarantie, sondern nur ein lokales Ergebnis — und der Solver sagt das nicht von selbst.</li>
|
||||
<li><strong><a href="anhang-glossar.md#gloss:konvexitaet" class="glossar-link">Konvexität</a> voraussetzen, ohne sie zu prüfen.</strong> Ohne sie gibt es keine Optimalitätsgarantie, sondern nur ein lokales Ergebnis — und der <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> sagt das nicht von selbst.</li>
|
||||
<li><strong>Zwei Ziele mit einem Gewicht verrechnen, bevor die Front bekannt ist.</strong> Ein Gewicht ist eine Antwort auf eine Frage, die noch niemand gestellt hat. Die Pareto-Front stellt sie zuerst.</li>
|
||||
</ol>
|
||||
<h2 id="wenn-sie-nur-eines-mitnehmen">Wenn Sie nur eines mitnehmen</h2>
|
||||
<blockquote>
|
||||
<p><strong>🎯</strong> Jede der vier Annahmen lässt sich einzeln aufgeben — aber jede kostet etwas Bestimmtes: Linearität kostet die Optimalitätsgarantie, feste Daten kosten Rechenzeit oder Vorsicht, eine Periode kostet Zustandsraum, ein Ziel kostet eine Entscheidung, die nicht der Modellierer treffen darf. Wer weiß, <strong>welche</strong> Annahme bei ihm fällt, weiß auch, welchen Preis er zahlt.</p>
|
||||
<p><strong>🎯</strong> Jede der vier Annahmen lässt sich einzeln aufgeben — aber jede kostet etwas Bestimmtes: Linearität kostet die Optimalitätsgarantie, feste Daten kosten Rechenzeit oder Vorsicht, eine Periode kostet <a href="anhang-glossar.md#gloss:zustandsraum" class="glossar-link">Zustandsraum</a>, ein Ziel kostet eine Entscheidung, die nicht der Modellierer treffen darf. Wer weiß, <strong>welche</strong> Annahme bei ihm fällt, weiß auch, welchen Preis er zahlt.</p>
|
||||
</blockquote>
|
||||
|
||||
</article>
|
||||
|
|
|
|||
10
OR_HTML_04/synthese-praxis.html
generated
10
OR_HTML_04/synthese-praxis.html
generated
|
|
@ -118,16 +118,16 @@
|
|||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><code>INFEASIBLE</code> um 3 Uhr nachts, niemand weiß warum</td>
|
||||
<td>Relaxation mit gestaffelten Strafkosten (B18); Deletion Filter für die Diagnose</td>
|
||||
<td><a href="anhang-glossar.md#gloss:relaxation" class="glossar-link">Relaxation</a> mit gestaffelten <a href="anhang-glossar.md#gloss:strafkosten" class="glossar-link">Strafkosten</a> (B18); <a href="anhang-glossar.md#gloss:deletion-filter" class="glossar-link">Deletion Filter</a> für die Diagnose</td>
|
||||
<td><a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a>, <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>Der Disponent lehnt den Plan ab, weil er ihn nicht versteht</td>
|
||||
<td>Constraint-Trace für die einzelne Zuweisung; Kostenzurechnung für den ganzen Plan</td>
|
||||
<td><a href="anhang-glossar.md#gloss:constraint-trace" class="glossar-link">Constraint-Trace</a> für die einzelne Zuweisung; Kostenzurechnung für den ganzen Plan</td>
|
||||
<td><a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a>, <a href="praxisfallen.html#sec:praxisfallen-attribution">Abschnitt 22.4</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Der Solver läuft ins Zeitlimit und keiner merkt es</td>
|
||||
<td>Der <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> läuft ins Zeitlimit und keiner merkt es</td>
|
||||
<td>Status, Gap und Zeitausschöpfung protokollieren — konstante Laufzeit ist ein Warnsignal</td>
|
||||
<td><a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a></td>
|
||||
</tr>
|
||||
|
|
@ -138,7 +138,7 @@
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Ein Ergebnis lässt sich später nicht mehr nachvollziehen</td>
|
||||
<td>Snapshot-Prinzip: unveränderlicher Datenstand mit ID je Lauf</td>
|
||||
<td><a href="anhang-glossar.md#gloss:snapshot-prinzip" class="glossar-link">Snapshot-Prinzip</a>: unveränderlicher Datenstand mit ID je Lauf</td>
|
||||
<td><a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -174,7 +174,7 @@
|
|||
<td><a href="praxisfallen.html#sec:praxisfallen-attribution">Abschnitt 22.4</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>„Der Schattenpreis sagt, was der Hebel bringt.”</td>
|
||||
<td>„Der <a href="anhang-glossar.md#gloss:schattenpreis" class="glossar-link">Schattenpreis</a> sagt, was der Hebel bringt.”</td>
|
||||
<td>Hochgerechnet 120 €, gemessen <strong>60 €</strong> — er gilt nur bis +15 Stunden. Die Ranglisten nach Preis und nach Wirkung drehen sich um</td>
|
||||
<td><a href="praxisfallen.html#sec:praxisfallen-attribution">Abschnitt 22.4</a></td>
|
||||
</tr>
|
||||
|
|
|
|||
20
OR_HTML_04/testing.html
generated
20
OR_HTML_04/testing.html
generated
|
|
@ -120,9 +120,9 @@
|
|||
<div class="card card-schnellstart">
|
||||
<blockquote>
|
||||
<p><strong>🚀 In 5 Minuten gelöst: drei Zeilen, die einen echten Fehler fangen</strong></p>
|
||||
<p>Die Schreinerei aus <a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a>, nur mit etwas knapperen Kapazitäten. Der Solver liefert einen Plan, halbe Tische gibt es nicht — also wird gerundet.</p>
|
||||
<p>Die Schreinerei aus <a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a>, nur mit etwas knapperen Kapazitäten. Der <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> liefert einen Plan, halbe Tische gibt es nicht — also wird gerundet.</p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> linprog</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> [linprog](anhang<span class="op">-</span>glossar.md<span class="co">#gloss:linprog){.glossar-link}</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>verbrauch_je_stueck <span class="op">=</span> np.array([[<span class="fl">3.0</span>, <span class="fl">1.0</span>], <span class="co"># Montagestunden je Tisch/Stuhl</span></span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> [<span class="fl">6.0</span>, <span class="fl">1.0</span>]]) <span class="co"># Plattenmaterial je Tisch/Stuhl</span></span>
|
||||
|
|
@ -145,7 +145,7 @@
|
|||
AssertionError: Plan [31. 48.] braucht [141. 234.], verfuegbar sind [140. 232.]</code></pre>
|
||||
</blockquote>
|
||||
</div>
|
||||
<p><strong>Und jetzt der Punkt.</strong> Der Solver hat richtig gerechnet: 30,67 Tische und 48 Stühle sind das Optimum des LP. Das Runden hat den Plan kaputt gemacht — 31 Tische brauchen eine Montagestunde mehr, als es gibt. Ohne die drei Zeilen wäre dieser Plan in die Fertigung gegangen, und dort hätte am Monatsende eine Stunde gefehlt, die niemand einer Zeile Python zugeordnet hätte.</p>
|
||||
<p><strong>Und jetzt der Punkt.</strong> Der Solver hat richtig gerechnet: 30,67 Tische und 48 Stühle sind das Optimum des <a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a>. Das Runden hat den Plan kaputt gemacht — 31 Tische brauchen eine Montagestunde mehr, als es gibt. Ohne die drei Zeilen wäre dieser Plan in die Fertigung gegangen, und dort hätte am Monatsende eine Stunde gefehlt, die niemand einer Zeile Python zugeordnet hätte.</p>
|
||||
<p>Bemerkenswert ist, <strong>was</strong> der Test prüft. Er prüft nicht, ob 30,67 das Optimum ist — das könnte er gar nicht, dafür bräuchte er einen zweiten Solver. Er prüft die Eigenschaft, die jede brauchbare Lösung haben muss: <em>Sie hält die Kapazität ein.</em> Diese Verschiebung — <strong>von der Frage nach dem richtigen Wert zur Frage nach den notwendigen Eigenschaften</strong> — ist der Schlüssel zum ganzen Kapitel.</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Ein Optimierungsmodell lässt sich fast nie gegen den richtigen Wert testen. Gegen seine Eigenschaften lässt es sich immer testen.</p>
|
||||
|
|
@ -536,7 +536,7 @@ AssertionError: Plan [31. 48.] braucht [141. 234.], verfuegbar sind [140. 232.]<
|
|||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><code>@pytest.fixture(params=MODELLBAUER, ids=NAMEN)</code></td>
|
||||
<td>Jeder Test läuft <strong>zweimal</strong> — einmal mit GLOP, einmal mit SciPy. Ein Test, der nur einen Solver sieht, prüft die Bibliothek mit statt das Modell</td>
|
||||
<td>Jeder Test läuft <strong>zweimal</strong> — einmal mit <a href="anhang-glossar.md#gloss:glop" class="glossar-link">GLOP</a>, einmal mit <a href="anhang-glossar.md#gloss:scipy" class="glossar-link">SciPy</a>. Ein Test, der nur einen Solver sieht, prüft die Bibliothek mit statt das Modell</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>test_beide_solver_liefern_dasselbe</code></td>
|
||||
|
|
@ -1127,11 +1127,11 @@ NICHT ablesen darf man:
|
|||
</tbody>
|
||||
</table>
|
||||
<p><em>(Die genauen Prozentwerte schwanken von Lauf zu Lauf — es sind Verhältnisse zweier Zeitmessungen. Die Größenordnungen sind stabil.)</em></p>
|
||||
<p>Bei OR-Tools gehen drei von vier Sekunden dafür drauf, in Python 10 000 Variablenobjekte anzulegen und Nebenbedingungen daraus zusammenzusetzen. Wer an dieser Stelle einen schnelleren <em>Solver</em> sucht, sucht in der falschen Hälfte — die Antwort ist ein vektorisierter Modellaufbau (<a href="oekosystem.html#kap-oekosystem">Kapitel 3</a>).</p>
|
||||
<p>Die zweite unbequeme Zahl steht ganz rechts: <strong>CVXPY braucht rund 240 MB</strong>, unabhängig von der Problemgröße — das ist der Preis seiner Modellierungsschicht. Auf einem Rechner mit knappem Speicher entscheidet diese Spalte und nicht die Laufzeit darüber, was überhaupt läuft.</p>
|
||||
<p>Bei <a href="anhang-glossar.md#gloss:or-tools" class="glossar-link">OR-Tools</a> gehen drei von vier Sekunden dafür drauf, in Python 10 000 Variablenobjekte anzulegen und Nebenbedingungen daraus zusammenzusetzen. Wer an dieser Stelle einen schnelleren <em>Solver</em> sucht, sucht in der falschen Hälfte — die Antwort ist ein vektorisierter Modellaufbau (<a href="oekosystem.html#kap-oekosystem">Kapitel 3</a>).</p>
|
||||
<p>Die zweite unbequeme Zahl steht ganz rechts: <strong><a href="anhang-glossar.md#gloss:cvxpy" class="glossar-link">CVXPY</a> braucht rund 240 MB</strong>, unabhängig von der Problemgröße — das ist der Preis seiner Modellierungsschicht. Auf einem Rechner mit knappem Speicher entscheidet diese Spalte und nicht die Laufzeit darüber, was überhaupt läuft.</p>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Was diese Tabelle nicht sagt</strong></p>
|
||||
<p>Sie sagt <strong>nicht</strong> „ortools ist langsamer als scipy”. Gemessen wurde <em>ein</em> Problemtyp in <em>einer</em> Formulierung auf <em>einer</em> Maschine. Ein MILP statt eines LP, eine andere Modellierung desselben Problems oder ein anderer Rechner können die Reihenfolge umdrehen — und bei MILPs tun sie es regelmäßig.</p>
|
||||
<p>Sie sagt <strong>nicht</strong> „ortools ist langsamer als scipy”. Gemessen wurde <em>ein</em> Problemtyp in <em>einer</em> Formulierung auf <em>einer</em> Maschine. Ein <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> statt eines LP, eine andere Modellierung desselben Problems oder ein anderer Rechner können die Reihenfolge umdrehen — und bei MILPs tun sie es regelmäßig.</p>
|
||||
<p>Übertragbar ist der <strong>Trend</strong>, nicht der Absolutwert: dass der Aufbauanteil mit der Größe wächst, dass CVXPY einen konstanten Speichersockel hat. Der Zweck des Programms ist, dass Sie es auf Ihrer Maschine mit Ihrem Problem laufen lassen.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
|
|
@ -1560,12 +1560,12 @@ Das zugehoerige Dockerfile ist kurz genug, um es ganz zu zeigen:
|
|||
================================================================================</code></pre>
|
||||
<blockquote>
|
||||
<p><strong>💻 Code-Durchgang: drei Entscheidungen</strong></p>
|
||||
<p><strong>1. Das Domänenmodell ist das API-Schema.</strong> Der Parameter heißt <code>problem: Produktionsproblem</code> — mehr steht nicht da. FastAPI validiert die Anfrage damit gegen dieselben Pydantic-Regeln wie der Excel-Import aus <a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> und antwortet bei Unsinn mit <code>422</code>, <strong>bevor</strong> ein Solver startet. Die drei abgewiesenen Anfragen im Selbsttest sind genau die drei Fälle, die <code>or_kern.py</code> schon beim Einlesen abfängt.</p>
|
||||
<p><strong>2. Die Antwort enthält Status und Gap, nicht nur Zahlen.</strong> Ein Aufrufer, der nur die Mengen bekommt, kann nicht unterscheiden, ob er ein bewiesenes Optimum oder einen Zeitlimit-Abbruch in der Hand hält. Das <code>Loesung</code>-Objekt geht deshalb vollständig durch die Schnittstelle — dasselbe DTO, das in <a href="praxisfallen.html#sec:praxisfallen-solverwechsel">Abschnitt 22.7</a> schon eine Prozessgrenze überlebt hat.</p>
|
||||
<p><strong>1. Das Domänenmodell ist das API-Schema.</strong> Der <a href="anhang-glossar.md#gloss:parameter" class="glossar-link">Parameter</a> heißt <code>problem: Produktionsproblem</code> — mehr steht nicht da. FastAPI validiert die Anfrage damit gegen dieselben Pydantic-Regeln wie der Excel-Import aus <a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> und antwortet bei Unsinn mit <code>422</code>, <strong>bevor</strong> ein Solver startet. Die drei abgewiesenen Anfragen im Selbsttest sind genau die drei Fälle, die <code>or_kern.py</code> schon beim Einlesen abfängt.</p>
|
||||
<p><strong>2. Die Antwort enthält Status und Gap, nicht nur Zahlen.</strong> Ein Aufrufer, der nur die Mengen bekommt, kann nicht unterscheiden, ob er ein bewiesenes Optimum oder einen Zeitlimit-Abbruch in der Hand hält. Das <code>Loesung</code>-Objekt geht deshalb vollständig durch die Schnittstelle — dasselbe <a href="anhang-glossar.md#gloss:dto-data-transfer-object" class="glossar-link">DTO</a>, das in <a href="praxisfallen.html#sec:praxisfallen-solverwechsel">Abschnitt 22.7</a> schon eine Prozessgrenze überlebt hat.</p>
|
||||
<p><strong>3. Die Abnahmeprüfung läuft auch hier.</strong> <code>pruefe_loesung()</code> steht im Arbeiter, nicht nur im Skript. Ein Dienst ohne sie liefert Fehler schneller aus, als ein Mensch sie finden könnte.</p>
|
||||
</blockquote>
|
||||
<h3 id="threads-oder-prozesse-eine-messung-keine-meinung">Threads oder Prozesse? Eine Messung, keine Meinung</h3>
|
||||
<p>Punkt 6 des Selbsttests misst, ob vier Solverläufe in Threads sich überlappen. Das Ergebnis ist ein Faktor von rund 3,5 bei vier Threads: <strong>OR-Tools rechnet in C++ und gibt den GIL während <code>Solve()</code> frei.</strong> Ein Threadpool genügt also, es braucht keine eigenen Prozesse.</p>
|
||||
<p>Punkt 6 des Selbsttests misst, ob vier Solverläufe in Threads sich überlappen. Das Ergebnis ist ein Faktor von rund 3,5 bei vier Threads: <strong>OR-Tools rechnet in C++ und gibt den <a href="anhang-glossar.md#gloss:gil-global-interpreter-lock" class="glossar-link">GIL</a> während <code>Solve()</code> frei.</strong> Ein Threadpool genügt also, es braucht keine eigenen Prozesse.</p>
|
||||
<p>Das gilt aber nicht allgemein. Eine in reinem Python geschriebene Heuristik (<a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a>) hält den GIL die ganze Zeit — für sie braucht derselbe Dienst einen <code>ProcessPoolExecutor</code>. Die Entscheidung gehört gemessen, nicht angenommen.</p>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Der erste Entwurf dieser Messung war falsch</strong></p>
|
||||
|
|
|
|||
36
OR_HTML_04/unsicherheit.html
generated
36
OR_HTML_04/unsicherheit.html
generated
|
|
@ -103,7 +103,7 @@
|
|||
<div class="card card-blick">
|
||||
<blockquote>
|
||||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||||
<p><strong>Worum geht es?</strong> Bisher waren alle Parameter bekannt. In der Realität sind Nachfrage, Rendite und Fahrzeit <strong>Zufallsgrößen</strong>. Dieses Kapitel zeigt vier Wege, damit umzugehen — und warum „einfach den Mittelwert einsetzen“ der schlechteste davon ist.</p>
|
||||
<p><strong>Worum geht es?</strong> Bisher waren alle <a href="anhang-glossar.md#gloss:parameter" class="glossar-link">Parameter</a> bekannt. In der Realität sind Nachfrage, Rendite und Fahrzeit <strong>Zufallsgrößen</strong>. Dieses Kapitel zeigt vier Wege, damit umzugehen — und warum „einfach den Mittelwert einsetzen“ der schlechteste davon ist.</p>
|
||||
<p><strong>Voraussetzungen:</strong> <a href="lp.html#kap-lp">Kapitel 5</a>, <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a>. Grundbegriffe der Statistik (Erwartungswert, Quantil).</p>
|
||||
<p><strong>Danach können Sie:</strong> Ein zweistufiges stochastisches Modell aufstellen, Monte-Carlo zur Risikomessung einsetzen, ein robustes Modell für den Worst Case formulieren, eine Wahrscheinlichkeitszusage („mit 95 % Sicherheit“) als lösbare Nebenbedingung schreiben — und erkennen, wann Rechnen mit Mittelwerten zulässig ist und wann es systematisch danebengeht.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 6,5 Stunden.</p>
|
||||
|
|
@ -211,7 +211,7 @@ q^{*} = \frac{c_{\text{zu wenig}}}{c_{\text{zu wenig}} + c_{\text{zu viel}}}
|
|||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Die optimale Entscheidung unter Unsicherheit ist fast nie die Entscheidung, die für den Mittelwert optimal wäre. Sie hängt davon ab, <strong>welcher der beiden Fehler teurer ist</strong> — und verschiebt sich zu der Seite, auf der Irren billiger ist. Wer mit dem Mittelwert plant, hat diese Frage nie gestellt.</p>
|
||||
</blockquote>
|
||||
<p>Dieses Muster heißt <strong>Newsvendor-Problem</strong> (deutsch: Zeitungsjungen-Problem) und taucht überall dort auf, wo einmal entschieden und danach beobachtet wird: Ersatzteile, Frischwaren, Saisonware, Personalreserve, Kraftwerksvorhaltung. Der Rest dieses Kapitels verallgemeinert es — von einer Zahl auf ganze Modelle, und von einer bekannten Verteilung auf den Fall, dass man nicht einmal die kennt.</p>
|
||||
<p>Dieses Muster heißt <strong><a href="anhang-glossar.md#gloss:newsvendor-problem" class="glossar-link">Newsvendor-Problem</a></strong> (deutsch: Zeitungsjungen-Problem) und taucht überall dort auf, wo einmal entschieden und danach beobachtet wird: Ersatzteile, Frischwaren, Saisonware, Personalreserve, Kraftwerksvorhaltung. Der Rest dieses Kapitels verallgemeinert es — von einer Zahl auf ganze Modelle, und von einer bekannten Verteilung auf den Fall, dass man nicht einmal die kennt.</p>
|
||||
<hr />
|
||||
<h2 id="sec:unsicherheit-lernziele">12.2 Lernziele</h2>
|
||||
<p>Nach diesem Kapitel können Sie …</p>
|
||||
|
|
@ -219,8 +219,8 @@ q^{*} = \frac{c_{\text{zu wenig}}}{c_{\text{zu wenig}} + c_{\text{zu viel}}}
|
|||
<li>… den <strong>Fluch des Durchschnitts</strong> (<em>Flaw of Averages</em>) an einem Beispiel erklären.</li>
|
||||
<li>… ein <strong>zweistufiges stochastisches Programm</strong> mit Recourse formulieren.</li>
|
||||
<li>… Monte-Carlo einsetzen, um Verteilungen statt Punktschätzungen zu bewerten.</li>
|
||||
<li>… ein <strong>robustes</strong> Modell mit Unsicherheitsmenge aufstellen und seinen Preis beziffern.</li>
|
||||
<li>… eine <strong>Wahrscheinlichkeitszusage</strong> („mit 95 % Sicherheit“) als Chance Constraint schreiben — analytisch als Kegelbedingung oder szenariobasiert mit Big-M — und den Preis eines Prozentpunkts Sicherheit beziffern.</li>
|
||||
<li>… ein <strong>robustes</strong> Modell mit <a href="anhang-glossar.md#gloss:unsicherheitsmenge" class="glossar-link">Unsicherheitsmenge</a> aufstellen und seinen Preis beziffern.</li>
|
||||
<li>… eine <strong>Wahrscheinlichkeitszusage</strong> („mit 95 % Sicherheit“) als <a href="anhang-glossar.md#gloss:chance-constraint" class="glossar-link">Chance Constraint</a> schreiben — analytisch als Kegelbedingung oder szenariobasiert mit Big-M — und den Preis eines Prozentpunkts Sicherheit beziffern.</li>
|
||||
<li>… begründen, welcher der vier Ansätze für ein gegebenes Problem passt.</li>
|
||||
<li>… das <strong>kritische Verhältnis</strong> eines Newsvendor-Problems aufstellen und daraus die optimale Bestellmenge als Quantil ablesen.</li>
|
||||
<li>… eine Terminzusage als Quantil formulieren statt als Mittelwert.</li>
|
||||
|
|
@ -343,7 +343,7 @@ Kosten fuer ausgewaehlte x zum Vergleich:
|
|||
Das Optimum liegt exakt auf einem Szenariowert (250 = 'Volatil'),
|
||||
nicht beim Mittelwert 225 - typisch fuer asymmetrische Kostenfunktionen.</code></pre>
|
||||
<p>Kein Rechentrick, sondern brute-force über alle ganzzahligen <span class="math inline">x</span> von 0 bis 500 — das Optimum landet exakt dort, wo es die Handrechnung vorhersagt.</p>
|
||||
<p><strong>Warum?</strong> Die Kostenfunktion ist <strong>asymmetrisch</strong>: Unterdeckung kostet 120, Überdeckung nur 5. Bei asymmetrischen Kosten liegt das Optimum nie beim Mittelwert, sondern verschoben in die „billigere“ Richtung. Formal ist das die <strong>Jensensche Ungleichung</strong>: Für konvexe Kostenfunktionen gilt <span class="math inline">\mathbb{E}[f(X)] \ge f(\mathbb{E}[X])</span> — der Erwartungswert der Kosten ist größer als die Kosten des Erwartungswerts.</p>
|
||||
<p><strong>Warum?</strong> Die Kostenfunktion ist <strong>asymmetrisch</strong>: Unterdeckung kostet 120, Überdeckung nur 5. Bei asymmetrischen Kosten liegt das Optimum nie beim Mittelwert, sondern verschoben in die „billigere“ Richtung. Formal ist das die <strong><a href="anhang-glossar.md#gloss:jensensche-ungleichung" class="glossar-link">Jensensche Ungleichung</a></strong>: Für konvexe Kostenfunktionen gilt <span class="math inline">\mathbb{E}[f(X)] \ge f(\mathbb{E}[X])</span> — der Erwartungswert der Kosten ist größer als die Kosten des Erwartungswerts.</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Der Durchschnittskunde kauft nie. Das Durchschnittsszenario tritt nie ein. Wer mit Mittelwerten plant, optimiert eine Welt, die es nicht gibt.</p>
|
||||
</blockquote>
|
||||
|
|
@ -364,8 +364,8 @@ nicht beim Mittelwert 225 - typisch fuer asymmetrische Kostenfunktionen.</code><
|
|||
<tr class="header">
|
||||
<th></th>
|
||||
<th><strong>Monte-Carlo</strong></th>
|
||||
<th><strong>Stochastische Programmierung</strong></th>
|
||||
<th><strong>Robuste Optimierung</strong></th>
|
||||
<th><strong><a href="anhang-glossar.md#gloss:stochastische-programmierung" class="glossar-link">Stochastische Programmierung</a></strong></th>
|
||||
<th><strong><a href="anhang-glossar.md#gloss:robuste-optimierung" class="glossar-link">Robuste Optimierung</a></strong></th>
|
||||
<th><strong>Chance Constraints</strong></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -719,7 +719,7 @@ den Mittelwert (225), weil Unterdeckung (120 EUR)
|
|||
deutlich teurer ist als Leerlauf (5 EUR).
|
||||
==================================================================================</code></pre>
|
||||
<p><strong>Lesen Sie die Vergleichstabelle von unten nach oben.</strong> Die beiden extremen Haltungen sind die teuersten: Wer den Worst Case abdeckt (500 Einheiten), zahlt 5 000 € zu viel für Kapazität, die in 80 % der Fälle brachliegt. Wer optimistisch plant (100), zahlt 2 625 € Strafe für ständige Notzukäufe. Die naive Mittelwertplanung liegt dazwischen — aber eben auch nicht optimal.</p>
|
||||
<p>Der <strong>EVPI von 7 375 €</strong> ist bemerkenswert hoch: 45 % der Gesamtkosten entstehen allein daraus, dass man die Zukunft nicht kennt. In so einem Fall lohnt sich Investition in bessere Prognosen tatsächlich — anders als in dem Beispiel aus der Aufgabe <em>EVPI interpretieren</em> (<a href="#sec:unsicherheit-uebungsaufgaben">Abschnitt 12.8</a>).</p>
|
||||
<p>Der <strong><a href="anhang-glossar.md#gloss:evpi-expected-value-of-perfect-information" class="glossar-link">EVPI</a> von 7 375 €</strong> ist bemerkenswert hoch: 45 % der Gesamtkosten entstehen allein daraus, dass man die Zukunft nicht kennt. In so einem Fall lohnt sich Investition in bessere Prognosen tatsächlich — anders als in dem Beispiel aus der Aufgabe <em>EVPI interpretieren</em> (<a href="#sec:unsicherheit-uebungsaufgaben">Abschnitt 12.8</a>).</p>
|
||||
<blockquote>
|
||||
<p><strong>💡 Was ist der EVPI?</strong> Der <strong>Expected Value of Perfect Information</strong> beziffert, wie viel eine perfekte Prognose wert wäre: die Differenz zwischen den Kosten unter Unsicherheit und den Kosten bei vollständigem Wissen. Er ist eine <strong>Obergrenze für jedes Prognoseprojekt</strong>. Wenn der EVPI bei 12 000 € pro Jahr liegt, lohnt sich keine Prognosesoftware für 50 000 € — selbst wenn sie perfekt wäre. Diese Zahl bewahrt Projekte vor teuren Fehlinvestitionen.</p>
|
||||
</blockquote>
|
||||
|
|
@ -840,7 +840,7 @@ deutlich teurer ist als Leerlauf (5 EUR).
|
|||
<span id="cb9-98"><a href="#cb9-98" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" als sie im Normalfall kostet."</span>)</span>
|
||||
<span id="cb9-99"><a href="#cb9-99" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">88</span>)</span></code></pre></div>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Der Preis der Robustheit</strong> Robuste Modelle sind <strong>konservativ</strong>. Wer gegen den absoluten Worst Case absichert, zahlt im Normalfall drauf — oft erheblich. Drei Gegenmittel: 1. <strong>Unsicherheitsmenge realistisch wählen.</strong> Nicht „alles kann passieren“, sondern „Abweichungen bis zu einer Standardabweichung“. 2. <strong>Budgeted Uncertainty (Bertsimas/Sim)</strong>: Man nimmt an, dass höchstens <span class="math inline">\Gamma</span> von <span class="math inline">n</span> Parametern gleichzeitig ihren Worst Case annehmen. <span class="math inline">\Gamma</span> steuert die Vorsicht stufenlos. 3. <strong>Nutzen und Preis immer beziffern</strong> — genau wie im Programm oben. Ohne diese zwei Zahlen ist die Diskussion „robust oder nicht“ Glaubenssache.</p>
|
||||
<p><strong>⚠️ Der Preis der Robustheit</strong> Robuste Modelle sind <strong>konservativ</strong>. Wer gegen den absoluten Worst Case absichert, zahlt im Normalfall drauf — oft erheblich. Drei Gegenmittel: 1. <strong>Unsicherheitsmenge realistisch wählen.</strong> Nicht „alles kann passieren“, sondern „Abweichungen bis zu einer Standardabweichung“. 2. <strong><a href="anhang-glossar.md#gloss:budgeted-uncertainty" class="glossar-link">Budgeted Uncertainty</a> (Bertsimas/Sim)</strong>: Man nimmt an, dass höchstens <span class="math inline">\Gamma</span> von <span class="math inline">n</span> Parametern gleichzeitig ihren Worst Case annehmen. <span class="math inline">\Gamma</span> steuert die Vorsicht stufenlos. 3. <strong>Nutzen und Preis immer beziffern</strong> — genau wie im Programm oben. Ohne diese zwei Zahlen ist die Diskussion „robust oder nicht“ Glaubenssache.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:unsicherheit-chance-constraints">12.7 Wahrscheinlichkeitsbeschränkungen: „mit 95 % Sicherheit“</h2>
|
||||
|
|
@ -853,7 +853,7 @@ deutlich teurer ist als Leerlauf (5 EUR).
|
|||
<p><strong>📐 Formel-Lesehilfe</strong> * <span class="math inline">\mathbf{a}</span> — der <strong>unsichere</strong> Vektor: Verfügbarkeiten, Erträge, Fahrzeiten. Er ist keine Zahl, sondern eine Zufallsgröße. * <span class="math inline">\mathbf{x}</span> — Ihre Entscheidung. Sie fällt, <strong>bevor</strong> <span class="math inline">\mathbf{a}</span> sich zeigt. * <span class="math inline">\alpha</span> — die Ausfallwahrscheinlichkeit, die Sie akzeptieren. <span class="math inline">\alpha = 0{,}05</span> heißt „in höchstens 5 % der Fälle darf es schiefgehen“.</p>
|
||||
<p><strong>Ohne Formel gesagt:</strong> „Plane so, dass die Zusage in 95 von 100 Fällen hält — und sag mir, was das kostet.“</p>
|
||||
</blockquote>
|
||||
<p><strong>Das Problem daran.</strong> So aufgeschrieben ist die Bedingung nicht lösbar: Ein Solver kann nichts mit einem Wahrscheinlichkeitsoperator anfangen. Es braucht einen Weg, sie in etwas zu übersetzen, das ein Optimierer versteht. Es gibt zwei, und sie unterscheiden sich in dem, was sie über die Verteilung voraussetzen.</p>
|
||||
<p><strong>Das Problem daran.</strong> So aufgeschrieben ist die Bedingung nicht lösbar: Ein <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a> kann nichts mit einem Wahrscheinlichkeitsoperator anfangen. Es braucht einen Weg, sie in etwas zu übersetzen, das ein Optimierer versteht. Es gibt zwei, und sie unterscheiden sich in dem, was sie über die Verteilung voraussetzen.</p>
|
||||
<h3 id="weg-1-normalverteilung-die-bedingung-wird-ein-kegel">Weg 1: Normalverteilung — die Bedingung wird ein Kegel</h3>
|
||||
<p>Ist <span class="math inline">\mathbf{a} \sim \mathcal{N}(\hat{\mathbf{a}}, \boldsymbol{\Sigma})</span>, dann ist <span class="math inline">\mathbf{a}^\top\mathbf{x}</span> für festes <span class="math inline">\mathbf{x}</span> selbst normalverteilt, mit Erwartungswert <span class="math inline">\hat{\mathbf{a}}^\top\mathbf{x}</span> und Standardabweichung <span class="math inline">\sqrt{\mathbf{x}^\top\boldsymbol{\Sigma}\mathbf{x}}</span>. Damit lässt sich die Wahrscheinlichkeit durch ein Quantil ersetzen:</p>
|
||||
<p><span class="math display">
|
||||
|
|
@ -863,9 +863,9 @@ deutlich teurer ist als Leerlauf (5 EUR).
|
|||
\boldsymbol{\Sigma} = \mathbf{L}\mathbf{L}^\top,\quad
|
||||
z_{1-\alpha} = \Phi^{-1}(1-\alpha)
|
||||
</span></p>
|
||||
<p>Das ist eine <strong>Second-Order-Cone-Bedingung</strong> — dieselbe Bauform, die <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a> eingeführt hat, und CVXPY löst sie ohne Umstände.</p>
|
||||
<p>Das ist eine <strong>Second-Order-Cone-Bedingung</strong> — dieselbe Bauform, die <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a> eingeführt hat, und <a href="anhang-glossar.md#gloss:cvxpy" class="glossar-link">CVXPY</a> löst sie ohne Umstände.</p>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Warum eine Norm und keine Summe</strong> Der Sicherheitszuschlag <span class="math inline">\lVert\mathbf{L}^\top\mathbf{x}\rVert_2</span> ist <strong>keine</strong> Summe von Einzelzuschlägen je Anlage. Genau darin steckt der Nutzen der Mischung: Zwei gegenläufige Quellen schwanken <strong>gemeinsam</strong> 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.</p>
|
||||
<p><strong>🎯 Warum eine Norm und keine Summe</strong> Der Sicherheitszuschlag <span class="math inline">\lVert\mathbf{L}^\top\mathbf{x}\rVert_2</span> ist <strong>keine</strong> Summe von Einzelzuschlägen je Anlage. Genau darin steckt der Nutzen der Mischung: Zwei gegenläufige Quellen schwanken <strong>gemeinsam</strong> 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 <a href="anhang-glossar.md#gloss:diversifikation" class="glossar-link">Diversifikation</a> nicht belohnen.</p>
|
||||
</blockquote>
|
||||
<h3 id="weg-2-szenarien-big-m-ohne-verteilungsannahme">Weg 2: Szenarien — Big-M ohne Verteilungsannahme</h3>
|
||||
<p>Liegen statt einer Verteilung nur <span class="math inline">S</span> beobachtete Szenarien vor, bekommt jedes eine Binärvariable <span class="math inline">z_s</span>, die sagt, ob es verletzt werden <strong>darf</strong>:</p>
|
||||
|
|
@ -876,7 +876,7 @@ z_{1-\alpha} = \Phi^{-1}(1-\alpha)
|
|||
z_s &\in \{0,1\}
|
||||
\end{aligned}
|
||||
</span></p>
|
||||
<p>Aus dem Kegelproblem wird ein MILP mit <span class="math inline">S</span> Binärvariablen. Für <span class="math inline">M</span> gilt, was <a href="milp.html#kap-milp">Kapitel 6</a> über die Big-M-Falle sagt: <strong>so klein wie möglich</strong>. Hier ist <span class="math inline">M = b</span> die kleinste gültige Schranke, denn <span class="math inline">\mathbf{a}_s^\top\mathbf{x} \ge 0</span> — größer kann eine Verletzung gar nicht ausfallen.</p>
|
||||
<p>Aus dem Kegelproblem wird ein <a href="anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class="glossar-link">MILP</a> mit <span class="math inline">S</span> Binärvariablen. Für <span class="math inline">M</span> gilt, was <a href="milp.html#kap-milp">Kapitel 6</a> über die Big-M-Falle sagt: <strong>so klein wie möglich</strong>. Hier ist <span class="math inline">M = b</span> die kleinste gültige Schranke, denn <span class="math inline">\mathbf{a}_s^\top\mathbf{x} \ge 0</span> — größer kann eine Verletzung gar nicht ausfallen.</p>
|
||||
<h3 id="der-fall-ein-kraftwerkspark-mit-500-mw-zusage">Der Fall: ein Kraftwerkspark mit 500 MW Zusage</h3>
|
||||
<div class="sourceCode" id="cb10"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||||
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
|
|
@ -1172,12 +1172,12 @@ Szenarien, 95 % 43,760,709 350 0 0 350 100.00 % 94.84 %
|
|||
<p><strong>Drei Befunde, die man dem Plan nicht ansieht.</strong></p>
|
||||
<p><strong>Erstens: Der Mittelwertplan fällt in der Hälfte aller Fälle aus.</strong> Das ist kein Fehler, sondern die Definition des Erwartungswerts — und dieselbe Falle wie in <a href="#sec:unsicherheit-der-fluch-des-durchschnitts">Abschnitt 12.3</a>, nur teurer. Er kauft die billigsten Quellen je <em>erwarteter</em> Megawattstunde und maximiert Wind und Sonne bis an die Ausbaugrenze. Sobald die Zusage im Modell steht, dreht sich das Bild: Gas und Biomasse tragen den Plan, Wind und Sonne schrumpfen auf einen Rest.</p>
|
||||
<p><strong>Zweitens: Sicherheit ist konvex bepreist.</strong> Die ersten dreißig Prozentpunkte kosten rund 56 000 € pro Punkt, die letzten vier rund 254 000 € — das <strong>4,5-fache</strong>. Das ist die Zahl, die in die Vorlage gehört: Nicht „was kostet Versorgungssicherheit“, sondern „was kostet der <em>nächste</em> Prozentpunkt“. Wer 99,9 % fordert, ohne diese Kurve gesehen zu haben, fordert ins Blaue.</p>
|
||||
<p><strong>Drittens — und das ist der unangenehme Befund: Die Zusage gilt nur für die unterstellte Verteilung.</strong> Der Plan verspricht 95 % und hält <strong>87,4 %</strong>. Nicht weil das Verfahren falsch 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 <strong>alles zugleich</strong> ein — auch das Gaskraftwerk, weil bei Frost der Netzdruck fällt. Eine Kovarianzmatrix mit Korrelationen um null kann so etwas nicht ausdrücken.</p>
|
||||
<p><strong>Drittens — und das ist der unangenehme Befund: Die Zusage gilt nur für die unterstellte Verteilung.</strong> Der Plan verspricht 95 % und hält <strong>87,4 %</strong>. Nicht weil das Verfahren falsch 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 <strong>alles zugleich</strong> ein — auch das Gaskraftwerk, weil bei Frost der Netzdruck fällt. Eine <a href="anhang-glossar.md#gloss:kovarianzmatrix" class="glossar-link">Kovarianzmatrix</a> mit Korrelationen um null kann so etwas nicht ausdrücken.</p>
|
||||
<p>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 <strong>keine Windkraft mehr</strong>. Die Logik dahinter ist hart und richtig: Was im Ernstfall ausfällt, hilft der Zusage nicht.</p>
|
||||
<blockquote>
|
||||
<p><strong>⚠️ Die Szenariomethode überanpasst — und mehr Szenarien helfen nicht verlässlich</strong> Bei <span class="math inline">S</span> Szenarien und <span class="math inline">\alpha = 5\,\%</span> darf das Modell genau <span class="math inline">0{,}05 \cdot S</span> davon ignorieren — und es sucht sich die <strong>teuersten</strong> aus. In der Stichprobe trifft es seine Quote dadurch immer; außerhalb streut sie.</p>
|
||||
<p>Gemessen an zwölf Läufen dieses Modells (je vier Ziehungen bei <span class="math inline">S = 200</span>, <span class="math inline">400</span>, <span class="math inline">800</span>, geprüft an 200 000 unabhängigen Szenarien): Die tatsächliche Quote lag zwischen <strong>93,1 % und 96,7 %</strong>. Die Spanne wurde von <span class="math inline">S = 200</span> auf <span class="math inline">400</span> enger (3,5 → 1,2 Prozentpunkte), bei <span class="math inline">S = 800</span> aber wieder breiter (3,1) — die Zahl der Szenarien allein schließt die Lücke also nicht.</p>
|
||||
<p><strong>Konsequenz für die Praxis:</strong> Eine mit Szenarien erkaufte Zusage immer an einer <strong>zurückgehaltenen</strong> Stichprobe nachmessen, so wie es das Programm oben tut. Wer nur die Trefferquote in den Baudaten berichtet, berichtet eine Tautologie — dieselbe Falle wie beim Backtest in <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a>.</p>
|
||||
<p><strong>Konsequenz für die Praxis:</strong> Eine mit Szenarien erkaufte Zusage immer an einer <strong>zurückgehaltenen</strong> Stichprobe nachmessen, so wie es das Programm oben tut. Wer nur die Trefferquote in den Baudaten berichtet, berichtet eine Tautologie — dieselbe Falle wie beim <a href="anhang-glossar.md#gloss:backtest" class="glossar-link">Backtest</a> in <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a>.</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p><strong>🎯 Merksatz</strong> Die robuste Optimierung fragt „was, wenn alles schiefgeht?“, die Chance Constraint „wie oft darf es schiefgehen?“. Nur die zweite Frage hat eine Antwort, über die man verhandeln kann — und nur sie zwingt dazu, den Preis eines Prozentpunkts Sicherheit zu beziffern.</p>
|
||||
|
|
@ -1191,7 +1191,7 @@ Szenarien, 95 % 43,760,709 350 0 0 350 100.00 % 94.84 %
|
|||
<p><strong>Aufgabe 12.2 ⭐ — Ansatz wählen.</strong> Welcher der vier Ansätze passt? Begründen Sie: (a) Wie viele Notstromaggregate für ein Krankenhaus? (b) Wie viel Weizen einkaufen bei bekannter Preisverteilung? (c) Wie hoch ein Deich gebaut werden muss? (d) Wie viele Saisonkräfte einstellen bei bekannten Nachfrageszenarien? (e) Wie viel Speicherkapazität, damit ein Gasnetz an 99 % aller Wintertage hält?</p>
|
||||
<p><strong>Aufgabe 12.3 ⭐⭐ — Zweistufiges Modell rechnen.</strong> Wiederholen Sie die Handrechnung <em>Warum der Mittelwert in die Irre führt</em> mit geänderten Kosten: Spot 60 € statt 120 €. (a) Wie ändert sich die optimale Kapazität? (b) Erklären Sie die Richtung der Änderung. (c) Bei welchem Spot-Preis wäre die Mittelwert-Planung optimal?</p>
|
||||
<p><strong>Aufgabe 12.4 ⭐⭐ — EVPI interpretieren.</strong> Ihr Modell liefert EVPI = 8 400 € pro Jahr. Ein Anbieter verlangt 15 000 € jährlich für eine Prognoselösung, die „80 % Treffsicherheit“ verspricht. Wie argumentieren Sie?</p>
|
||||
<p><strong>Aufgabe 12.5 ⭐⭐⭐ — Monte-Carlo erweitern.</strong> Erweitern Sie <code>Monte_Carlo.py</code>: (a) Fügen Sie ein Servicelevel-Kriterium hinzu: „Die Unterdeckung darf höchstens in 5 % der Fälle auftreten.“ Welche Kapazität ist dafür nötig, und was kostet sie zusätzlich? (b) Berechnen Sie den CVaR der Kosten (Mittelwert der schlechtesten 5 %). (c) Zeichnen Sie ein Histogramm der Kosten für drei Kapazitäten.</p>
|
||||
<p><strong>Aufgabe 12.5 ⭐⭐⭐ — Monte-Carlo erweitern.</strong> Erweitern Sie <code>Monte_Carlo.py</code>: (a) Fügen Sie ein Servicelevel-Kriterium hinzu: „Die Unterdeckung darf höchstens in 5 % der Fälle auftreten.“ Welche Kapazität ist dafür nötig, und was kostet sie zusätzlich? (b) Berechnen Sie den <a href="anhang-glossar.md#gloss:conditional-value-at-risk-cvar" class="glossar-link">CVaR</a> der Kosten (Mittelwert der schlechtesten 5 %). (c) Zeichnen Sie ein Histogramm der Kosten für drei Kapazitäten.</p>
|
||||
<p><strong>Aufgabe 12.6 ⭐⭐ — Den Preis der Zusage selbst bestimmen.</strong> <code>Chance_Constraints.py</code> beziffert die Kosten für 80, 90, 95 und 99 %. (a) Ergänzen Sie die Stufen 99,5 % und 99,9 % und setzen Sie die Kosten je Prozentpunkt fort. Was passiert mit dem Anlagenmix? (b) Drosseln Sie die Ausbaugrenze der Biomasse von 350 auf 200 MW. Das <strong>szenariobasierte</strong> Modell meldet dann bei 95 % <code>infeasible</code>, das <strong>analytische</strong> dagegen <code>optimal</code>. Erklären Sie den Unterschied. Welchem der beiden würden Sie glauben? (c) Ein Vorstand fordert „99,99 % Versorgungssicherheit“. Formulieren Sie in drei Sätzen, was Sie ihm mit dieser Kurve antworten.</p>
|
||||
<p><strong>Aufgabe 12.7 ⭐⭐⭐ — Budgeted Uncertainty.</strong> Erweitern Sie <code>Robuste_Optimierung.py</code> um den Ansatz von Bertsimas/Sim: Höchstens <span class="math inline">\Gamma</span> Titel nehmen gleichzeitig ihren Worst Case an. Variieren Sie <span class="math inline">\Gamma \in \{0, 1, 2, 3, 4\}</span> und stellen Sie den Verlauf von Ertrag und Absicherung dar. (Hinweis: Bei <span class="math inline">\Gamma</span> ganzzahlig genügt es, die <span class="math inline">\Gamma</span> größten <span class="math inline">\delta_i w_i</span> abzuziehen — das lässt sich in CVXPY mit <code>cp.sum_largest</code> formulieren.)</p>
|
||||
<hr />
|
||||
|
|
@ -1232,7 +1232,7 @@ Anteil ueber 11,34 Tage: 95.5 %</code></pre>
|
|||
<p>Genau eine Antwort ist jeweils richtig. Auflösung in <a href="anhang-loesungen.html#quiz-loesung-unsicherheit">Anhang A</a>.</p>
|
||||
<p><strong>1. Bei einem Ersatzteil kostet ein Stück zu wenig 1 400 €, ein Stück zu viel 120 €. Der Bedarf beträgt im Mittel 30 Stück. Wie viel bestellen Sie?</strong> (a) 30 — das ist der Erwartungswert des Bedarfs. (b) Deutlich mehr als 30, nämlich das 92,1-%-Quantil des Bedarfs. Das kritische Verhältnis <span class="math inline">1400/(1400+120)</span> sagt, wie weit man sich auf die günstigere Fehlerseite stellen soll. (c) Weniger als 30, weil Lagerhaltung Kapital bindet.</p>
|
||||
<p><strong>2. Was unterscheidet </strong>stochastische** von <strong>robuster</strong> Optimierung?** (a) Stochastische Optimierung ist genauer, robuste ist eine Näherung für schnelle Rechnungen. (b) Stochastische Optimierung braucht <strong>Wahrscheinlichkeiten</strong> und optimiert den Erwartungswert; robuste Optimierung braucht nur <strong>Bandbreiten</strong> und sichert den schlechtesten Fall darin ab. (c) Robuste Optimierung berücksichtigt mehr Szenarien.</p>
|
||||
<p><strong>3. Ein Kollege ersetzt in seinem Modell alle unsicheren Größen durch ihre Mittelwerte und rechnet deterministisch. Wann ist das unproblematisch?</strong> (a) Immer — der Erwartungswert ist die beste Einzelschätzung. (b) Nie. (c) Wenn Zielfunktion und Nebenbedingungen in den unsicheren Größen <strong>linear</strong> sind und keine Entscheidung erst nach Beobachtung fällt. Sobald Minimum, Maximum, Betrag oder eine Nachbesserungsentscheidung im Spiel ist, gilt es nicht mehr.</p>
|
||||
<p><strong>3. Ein Kollege ersetzt in seinem Modell alle unsicheren Größen durch ihre Mittelwerte und rechnet deterministisch. Wann ist das unproblematisch?</strong> (a) Immer — der Erwartungswert ist die beste Einzelschätzung. (b) Nie. (c) Wenn <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a> und Nebenbedingungen in den unsicheren Größen <strong>linear</strong> sind und keine Entscheidung erst nach Beobachtung fällt. Sobald Minimum, Maximum, Betrag oder eine Nachbesserungsentscheidung im Spiel ist, gilt es nicht mehr.</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
<hr />
|
||||
|
|
@ -1263,7 +1263,7 @@ Anteil ueber 11,34 Tage: 95.5 %</code></pre>
|
|||
<li><strong>Eine Zusage gilt nur für die unterstellte Verteilung.</strong> Ein Plan, der unter Normalverteilung 95 % verspricht, hielt gemessen 87 %, weil das Modell die Kältewelle nicht kannte, in der <em>alles</em> zugleich ausfällt. Szenariobasierte Zusagen wiederum überanpassen — beide müssen an zurückgehaltenen Daten nachgemessen werden.</li>
|
||||
<li><strong>Beziffern Sie immer Preis und Nutzen der Absicherung.</strong> Ohne beide Zahlen ist die Entscheidung nicht begründbar.</li>
|
||||
</ul>
|
||||
<p><strong>Ausblick.</strong> <a href="dynamische-programmierung.html#kap-dynamische-programmierung">Kapitel 13</a> fügt die Zeitdimension hinzu: Entscheidungen, die über viele Perioden aufeinander aufbauen — gelöst mit der Bellman-Gleichung.</p>
|
||||
<p><strong>Ausblick.</strong> <a href="dynamische-programmierung.html#kap-dynamische-programmierung">Kapitel 13</a> fügt die Zeitdimension hinzu: Entscheidungen, die über viele Perioden aufeinander aufbauen — gelöst mit der <a href="anhang-glossar.md#gloss:bellman-gleichung" class="glossar-link">Bellman-Gleichung</a>.</p>
|
||||
|
||||
</article>
|
||||
<button type="button" class="fortschritt-knopf" data-kapitel="unsicherheit.html"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg> <span>Als gelesen markieren</span></button>
|
||||
|
|
|
|||
70
OR_HTML_04/vorwort.html
generated
70
OR_HTML_04/vorwort.html
generated
|
|
@ -106,11 +106,11 @@
|
|||
<hr />
|
||||
<h1 class="unlisted unnumbered" id="optimierte-entscheidungsfindung-mit-python">Optimierte Entscheidungsfindung mit Python</h1>
|
||||
<h2 class="unlisted unnumbered" id="von-der-mathematischen-modellierung-zu-praktischen-intelligenten-lösungen-für-betrieb-technik-und-finanzmärkte">Von der mathematischen Modellierung zu praktischen intelligenten Lösungen für Betrieb, Technik und Finanzmärkte</h2>
|
||||
<p><strong>Ein praxisorientiertes Kompendium für Entscheider</strong> mit Constraint Programming, Vektor- und Matrixmethoden sowie HiGHS, SciPy, Google OR-Tools und CVXPY.</p>
|
||||
<p><strong>Ein praxisorientiertes Kompendium für Entscheider</strong> mit Constraint Programming, Vektor- und Matrixmethoden sowie <a href="anhang-glossar.md#gloss:highs" class="glossar-link">HiGHS</a>, <a href="anhang-glossar.md#gloss:scipy" class="glossar-link">SciPy</a>, Google <a href="anhang-glossar.md#gloss:or-tools" class="glossar-link">OR-Tools</a> und <a href="anhang-glossar.md#gloss:cvxpy" class="glossar-link">CVXPY</a>.</p>
|
||||
<p>Mit Python planen, optimieren und entscheiden: von <strong>Personal, Schichten und Logistik</strong> über <strong>Energie, Ressourcen und Netzwerke</strong> bis zur <strong>Portfoliooptimierung an den Finanzmärkten</strong>.</p>
|
||||
<p>Autor / Herausgeber: Dieter Schlüter</p>
|
||||
<p><dieter(dot)schlueter(atsign)linix(dot)de></p>
|
||||
<p>Stand: 10. September 2026 v16.11</p>
|
||||
<p>Stand: 10. September 2026 v17.39</p>
|
||||
<hr />
|
||||
<h1 class="unnumbered" id="über-den-kurs">Über den Kurs</h1>
|
||||
<h2 class="unnumbered" id="vorwort">Vorwort</h2>
|
||||
|
|
@ -125,9 +125,9 @@
|
|||
<p>Die Programme des Kurses laufen unter Linux, MacOS und Windows (WSL) gleichermaßen, entweder im Terminal, in Jupyter Notebook oder nach dem Hochladen in Google Colab. Entwickelt und ausgiebig getestet wurden sie in der Linux-Umgebung.</p>
|
||||
<hr />
|
||||
<h2 class="unnumbered" id="ziel-der-masterclass">Ziel der Masterclass</h2>
|
||||
<p>Ein umfassendes, didaktisch von Grund auf aufgebautes Lehrbuch zur mathematischen Entscheidungsoptimierung (<strong>Operations Research, OR</strong>) mit praktischer Umsetzung in <strong>Python</strong>. Dieser Kurs der <strong>mathematischen Optimierung</strong> setzt kein Vorwissen in OR voraus und führt schrittweise von den algebraischen und kombinatorischen Grundlagen über Scheduling- und Constraint-Modelle bis hin zur professionellen Anwendung im quantitativen Aktienhandel, Portfoliomanagement und Risikocontrolling.</p>
|
||||
<p>Ein umfassendes, didaktisch von Grund auf aufgebautes Lehrbuch zur mathematischen Entscheidungsoptimierung (<strong>Operations Research, OR</strong>) mit praktischer Umsetzung in <strong>Python</strong>. Dieser Kurs der <strong>mathematischen Optimierung</strong> setzt kein Vorwissen in OR voraus und führt schrittweise von den algebraischen und kombinatorischen Grundlagen über <a href="anhang-glossar.md#gloss:scheduling" class="glossar-link">Scheduling</a>- und Constraint-Modelle bis hin zur professionellen Anwendung im quantitativen Aktienhandel, Portfoliomanagement und Risikocontrolling.</p>
|
||||
<h3 class="unnumbered" id="vorausgesetzte-kenntnisse">Vorausgesetzte Kenntnisse</h3>
|
||||
<p>Vorausgesetzt werden <strong>sichere Python-Kenntnisse</strong> (Funktionen, Klassen, NumPy, pandas) sowie Mathematik auf Grundstudiumsniveau:</p>
|
||||
<p>Vorausgesetzt werden <strong>sichere Python-Kenntnisse</strong> (Funktionen, Klassen, <a href="anhang-glossar.md#gloss:numpy" class="glossar-link">NumPy</a>, <a href="anhang-glossar.md#gloss:pandas" class="glossar-link">pandas</a>) sowie Mathematik auf Grundstudiumsniveau:</p>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 33%" />
|
||||
|
|
@ -149,7 +149,7 @@
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><strong>Analysis</strong></td>
|
||||
<td>Ableitung, Gradient, notwendige Bedingung erster Ordnung</td>
|
||||
<td>Ableitung, <a href="anhang-glossar.md#gloss:gradient" class="glossar-link">Gradient</a>, notwendige Bedingung erster Ordnung</td>
|
||||
<td><a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
|
|
@ -181,7 +181,7 @@
|
|||
<div class="sourceCode" id="cb2"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ex">pip</span> install <span class="at">-r</span> Operations_Research_mit_Python_Version_04_Programme/requirements.txt</span></code></pre></div>
|
||||
<h3 class="unnumbered" id="installationstest">Installationstest</h3>
|
||||
<p>Prüfen Sie mit diesem Skript, ob alles bereitsteht, <strong>bevor</strong> Sie mit <a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> beginnen. Es meldet für jedes Paket Version und Status und löst ein Mini-Optimierungsproblem.</p>
|
||||
<p>Eine Besonderheit dabei — die Import-Reihenfolge ist bewusst gewählt: <code>highspy</code> und <code>cvxpy</code> werden in der Paketübersicht nur auf Anwesenheit geprüft, und <code>ortools</code> lädt seine native Bibliothek zuerst. Der Grund: <code>ortools</code> und <code>highspy</code> bringen jeweils eine eigene HiGHS-Kopie mit, die sich nicht im selben Python-Prozess verträgt — und <code>cvxpy</code> importiert ein installiertes <code>highspy</code> bei der Solver-Erkennung selbst mit. Lädt deren HiGHS-Kopie zuerst, bricht der Test beim CP-SAT-Funktionstest mit einem kryptischen <code>ImportError: undefined symbol</code> ab; so gewinnt die Kopie von <code>ortools</code>, und CVXPY verzichtet lediglich auf sein HIGHS-Interface (für alle Buchprogramme folgenlos). Details und Abhilfen: <a href="oekosystem.html#sec:oekosystem-ein-system-vier-programmieransaetze">Abschnitt 3.5</a> und <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a>.</p>
|
||||
<p>Eine Besonderheit dabei — die Import-Reihenfolge ist bewusst gewählt: <code>highspy</code> und <code>cvxpy</code> werden in der Paketübersicht nur auf Anwesenheit geprüft, und <code>ortools</code> lädt seine native Bibliothek zuerst. Der Grund: <code>ortools</code> und <code>highspy</code> bringen jeweils eine eigene HiGHS-Kopie mit, die sich nicht im selben Python-Prozess verträgt — und <code>cvxpy</code> importiert ein installiertes <code>highspy</code> bei der <a href="anhang-glossar.md#gloss:solver" class="glossar-link">Solver</a>-Erkennung selbst mit. Lädt deren HiGHS-Kopie zuerst, bricht der Test beim <a href="anhang-glossar.md#gloss:cp-sat" class="glossar-link">CP-SAT</a>-Funktionstest mit einem kryptischen <code>ImportError: undefined symbol</code> ab; so gewinnt die Kopie von <code>ortools</code>, und CVXPY verzichtet lediglich auf sein HIGHS-Interface (für alle Buchprogramme folgenlos). Details und Abhilfen: <a href="oekosystem.html#sec:oekosystem-ein-system-vier-programmieransaetze">Abschnitt 3.5</a> und <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a>.</p>
|
||||
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Installationstest.py</span></span>
|
||||
|
|
@ -364,20 +364,20 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
<ul>
|
||||
<li><strong>Was Planen mit Durchschnitten kostet, wird hier beziffert, nicht behauptet.</strong> Im Kraftwerkseinsatz aus <a href="supplychain.html#kap-supplychain">Kapitel 17</a> kostet ein Plan, der mit dem Wind-<strong>Erwartungswert</strong> rechnet, in der Wirklichkeit <strong>149 % mehr</strong> als einer, der 40 Szenarien berücksichtigt — 874 870 € statt 351 356 € — und führt in <strong>28 von 40 Szenarien</strong> zum Lastabwurf statt in keinem.</li>
|
||||
<li><strong>„Wie sicher soll es sein?“ wird eine Preisfrage.</strong> <a href="unsicherheit.html#sec:unsicherheit-chance-constraints">Abschnitt 12.7</a> rechnet aus, was ein Prozentpunkt Versorgungssicherheit kostet: rund 56 000 € auf dem Weg zu 80 %, rund 254 000 € zwischen 95 und 99 %. Das <strong>4,5-fache</strong>. Wer 99,9 % fordert, ohne diese Kurve gesehen zu haben, fordert ins Blaue.</li>
|
||||
<li><strong>Für die Sitzung gibt es einen Bericht, keine Tabelle.</strong> <a href="praxisfallen.html#sec:praxisfallen-attribution">Abschnitt 22.4</a> beziffert je Nebenbedingung, was sie den Plan kostet, und formuliert daraus Sätze in Alltagssprache. Für die Frage des Betriebsrats — <em>„warum ausgerechnet ich?“</em> — liefert <a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a> den Constraint-Trace, der die einzelne Zuweisung begründet.</li>
|
||||
<li><strong>Für die Sitzung gibt es einen Bericht, keine Tabelle.</strong> <a href="praxisfallen.html#sec:praxisfallen-attribution">Abschnitt 22.4</a> beziffert je Nebenbedingung, was sie den Plan kostet, und formuliert daraus Sätze in Alltagssprache. Für die Frage des Betriebsrats — <em>„warum ausgerechnet ich?“</em> — liefert <a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a> den <a href="anhang-glossar.md#gloss:constraint-trace" class="glossar-link">Constraint-Trace</a>, der die einzelne Zuweisung begründet.</li>
|
||||
</ul>
|
||||
<p><strong>Ihr Weg.</strong> Zuerst Pfad E (2–4 Stunden): <a href="einfuehrung.html#sec:einfuehrung-historischer-kontext-und-evolution">Abschnitt 1.5</a> und <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a>. Wenn Sie danach wissen wollen, was in Ihrem Betrieb geht, Pfad B und Projekt <strong>P1</strong> oder <strong>P2</strong>.</p>
|
||||
<p><strong>Woran es scheitert.</strong> Nicht am Modell, sondern an der Einführung — das ist der meistgenannte Befund in <a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a>. Und an einer Verwechslung, die dieses Buch Ihnen nicht abnehmen kann: Ein Bericht erklärt das <strong>Modell</strong>, nicht die <strong>Wirklichkeit</strong>. Ist ein Deckungsbeitrag falsch geschätzt, ist er überzeugend <strong>und</strong> falsch. Fragen Sie deshalb jedes Mal, worauf eine Zahl beruht.</p>
|
||||
<blockquote>
|
||||
<p><strong>Eine Erwartung, die dieses Buch enttäuscht:</strong> Es nennt keine ROI-Kennzahl und keine Amortisationsdauer. Beide hängen an Ihrem Betrieb, und jede Zahl hier wäre erfunden. Was es stattdessen liefert, ist das Werkzeug, Ihre eigene auszurechnen: den <strong>EVPI</strong> in <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a> (was eine perfekte Prognose überhaupt wert wäre — eine Obergrenze für jedes Prognoseprojekt) und die Kostenzurechnung aus <a href="praxisfallen.html#sec:praxisfallen-attribution">Abschnitt 22.4</a>.</p>
|
||||
<p><strong>Eine Erwartung, die dieses Buch enttäuscht:</strong> Es nennt keine ROI-Kennzahl und keine Amortisationsdauer. Beide hängen an Ihrem Betrieb, und jede Zahl hier wäre erfunden. Was es stattdessen liefert, ist das Werkzeug, Ihre eigene auszurechnen: den <strong><a href="anhang-glossar.md#gloss:evpi-expected-value-of-perfect-information" class="glossar-link">EVPI</a></strong> in <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a> (was eine perfekte Prognose überhaupt wert wäre — eine Obergrenze für jedes Prognoseprojekt) und die Kostenzurechnung aus <a href="praxisfallen.html#sec:praxisfallen-attribution">Abschnitt 22.4</a>.</p>
|
||||
</blockquote>
|
||||
<h3 class="unnumbered" id="für-ingenieure-und-produktionsplaner-die-physik-des-systems">Für Ingenieure und Produktionsplaner — die Physik des Systems</h3>
|
||||
<blockquote>
|
||||
<p><em>„Der Engpass wandert. Kaum ist eine Maschine entlastet, steht die nächste — und niemand kann mir vorher sagen, welche.“</em></p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li><strong>Der Engpass lässt sich benennen und bepreisen.</strong> <a href="praxisfallen.html#sec:praxisfallen-attribution">Abschnitt 22.4</a> 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 Lackiererei exakt bis <strong>+15 Stunden</strong>; eine ganze Sonderschicht von 30 Stunden bringt deshalb 60 € statt der rechnerischen 120 €. <strong>Die zweite Hälfte wäre bezahlt und wirkungslos.</strong></li>
|
||||
<li><strong>Rüstzeiten, Reihenfolgen, Taktzeiten sind der Kern, nicht die Ausnahme.</strong> <a href="cpsat.html#kap-cpsat">Kapitel 7</a> modelliert Maschinenbelegung mit Intervallvariablen, <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a> zeigt am selben Fall das Gesamtbild: Faustregel 2 497 Minuten Rüstzeit, CP-SAT allein 2 628, Simulated Annealing 2 343, Annealing plus LNS <strong>2 289</strong> — und die untere Schranke bei 1 768, damit sichtbar bleibt, wie viel Luft noch da ist.</li>
|
||||
<li><strong>Der Engpass lässt sich benennen und bepreisen.</strong> <a href="praxisfallen.html#sec:praxisfallen-attribution">Abschnitt 22.4</a> 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 <a href="anhang-glossar.md#gloss:schattenpreis" class="glossar-link">Schattenpreis</a> der Lackiererei exakt bis <strong>+15 Stunden</strong>; eine ganze Sonderschicht von 30 Stunden bringt deshalb 60 € statt der rechnerischen 120 €. <strong>Die zweite Hälfte wäre bezahlt und wirkungslos.</strong></li>
|
||||
<li><strong>Rüstzeiten, Reihenfolgen, Taktzeiten sind der Kern, nicht die Ausnahme.</strong> <a href="cpsat.html#kap-cpsat">Kapitel 7</a> modelliert Maschinenbelegung mit Intervallvariablen, <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a> zeigt am selben Fall das Gesamtbild: Faustregel 2 497 Minuten <a href="anhang-glossar.md#gloss:ruestzeit" class="glossar-link">Rüstzeit</a>, <a href="anhang-glossar.md#gloss:constraint-programming-cp" class="glossar-link">CP</a>-<a href="anhang-glossar.md#gloss:sat-boolean-satisfiability" class="glossar-link">SAT</a> allein 2 628, <a href="anhang-glossar.md#gloss:simulated-annealing" class="glossar-link">Simulated Annealing</a> 2 343, Annealing plus <a href="anhang-glossar.md#gloss:large-neighborhood-search-lns" class="glossar-link">LNS</a> <strong>2 289</strong> — und die untere Schranke bei 1 768, damit sichtbar bleibt, wie viel Luft noch da ist.</li>
|
||||
<li><strong>Wenn der Solver zu lange braucht, gibt es Zahlen statt Ratschläge.</strong> <a href="cpsat.html#sec:cpsat-parallele-suche">Abschnitt 7.7</a> misst, was mehrere Suchstränge bringen (hier Faktor 12,3) — und ab wo mehr Arbeiter wieder schaden.</li>
|
||||
</ul>
|
||||
<p><strong>Ihr Weg.</strong> Pfad B bis <a href="cpsat.html#kap-cpsat">Kapitel 7</a>, dann Projekt <strong>P5</strong> (Produktionsplanung mit Rüstkosten). Wenn Ihre echten Instanzen den Solver stehen lassen: <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a> und Projekt <strong>P9</strong>.</p>
|
||||
|
|
@ -387,18 +387,18 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
<p><em>„Die Optimierung liefert mir Gewichte, die kein Mensch halten würde: 60 % in einem Titel, null in fünf anderen. Und im nächsten Quartal sieht sie völlig anders aus.“</em></p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li><strong>Der Grund dafür steht in <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a>, nicht in <a href="markowitz.html#kap-markowitz">Kapitel 19</a>.</strong> Eine aus kurzen Zeitreihen geschätzte Kovarianzmatrix ist schlecht konditioniert; der Optimierer setzt dann auf Schätzrauschen. Shrinkage nach Ledoit-Wolf ist das Gegenmittel; ihre Wirkung wird an <strong>Eigenwertspektrum und Konditionszahl</strong> gemessen, nicht behauptet.</li>
|
||||
<li><strong>Der VaR verschweigt genau das, worauf es ankommt.</strong> In der Stichprobe aus <a href="cvar.html#kap-cvar">Kapitel 20</a> sagt der VaR: „an 95 % der Tage höchstens <strong>1,86 %</strong> Verlust“. Der CVaR sagt: „und wenn doch, dann im Mittel <strong>2,99 %</strong>“. Der schlechteste Tag der Stichprobe liegt bei <strong>−23,0 %</strong> — am VaR ändert dieser eine Tag <strong>nichts</strong>, am CVaR sehr wohl. Deshalb ist der CVaR die Größe, die man optimiert.</li>
|
||||
<li><strong>Transaktionskosten und Rebalancing sind Teil des Modells, nicht ein Abzug danach.</strong> <a href="cvar.html#kap-cvar">Kapitel 20</a> nimmt sie in die Zielfunktion, <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a> setzt den Backtest daneben — samt der Fallen, die einen guten Backtest wertlos machen.</li>
|
||||
<li><strong>Der Grund dafür steht in <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a>, nicht in <a href="markowitz.html#kap-markowitz">Kapitel 19</a>.</strong> Eine aus kurzen Zeitreihen geschätzte <a href="anhang-glossar.md#gloss:kovarianzmatrix" class="glossar-link">Kovarianzmatrix</a> ist schlecht konditioniert; der Optimierer setzt dann auf Schätzrauschen. Shrinkage nach Ledoit-Wolf ist das Gegenmittel; ihre Wirkung wird an <strong>Eigenwertspektrum und <a href="anhang-glossar.md#gloss:konditionszahl" class="glossar-link">Konditionszahl</a></strong> gemessen, nicht behauptet.</li>
|
||||
<li><strong>Der <a href="anhang-glossar.md#gloss:value-at-risk-var" class="glossar-link">VaR</a> verschweigt genau das, worauf es ankommt.</strong> In der Stichprobe aus <a href="cvar.html#kap-cvar">Kapitel 20</a> sagt der VaR: „an 95 % der Tage höchstens <strong>1,86 %</strong> Verlust“. Der <a href="anhang-glossar.md#gloss:conditional-value-at-risk-cvar" class="glossar-link">CVaR</a> sagt: „und wenn doch, dann im Mittel <strong>2,99 %</strong>“. Der schlechteste Tag der Stichprobe liegt bei <strong>−23,0 %</strong> — am VaR ändert dieser eine Tag <strong>nichts</strong>, am CVaR sehr wohl. Deshalb ist der CVaR die Größe, die man optimiert.</li>
|
||||
<li><strong><a href="anhang-glossar.md#gloss:transaktionskosten" class="glossar-link">Transaktionskosten</a> und <a href="anhang-glossar.md#gloss:rebalancing" class="glossar-link">Rebalancing</a> sind Teil des Modells, nicht ein Abzug danach.</strong> <a href="cvar.html#kap-cvar">Kapitel 20</a> nimmt sie in die <a href="anhang-glossar.md#gloss:zielfunktion" class="glossar-link">Zielfunktion</a>, <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a> setzt den <a href="anhang-glossar.md#gloss:backtest" class="glossar-link">Backtest</a> daneben — samt der Fallen, die einen guten Backtest wertlos machen.</li>
|
||||
</ul>
|
||||
<p><strong>Ihr Weg.</strong> Pfad D, und zwar <strong>mit</strong> <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a>. Danach Projekt <strong>P6</strong> (Portfolio-Rebalancer) oder <strong>P7</strong> (Risikoreport mit CVaR und Stresstests).</p>
|
||||
<p><strong>Woran es scheitert.</strong> An der Reihenfolge. Wer bei Markowitz einsteigt und die Datenkapitel überspringt, bekommt ein Modell, das seine eigenen Schätzfehler maximiert — und merkt es erst im Echtgeldbetrieb.</p>
|
||||
<p><strong>Woran es scheitert.</strong> An der Reihenfolge. Wer bei Markowitz einsteigt und die Datenkapitel überspringt, bekommt ein Modell, das seine eigenen <a href="anhang-glossar.md#gloss:schaetzfehler" class="glossar-link">Schätzfehler</a> maximiert — und merkt es erst im Echtgeldbetrieb.</p>
|
||||
<h3 class="unnumbered" id="für-studierende-und-data-scientists-die-methodik">Für Studierende und Data Scientists — die Methodik</h3>
|
||||
<blockquote>
|
||||
<p><em>„Ich kann ein Modell trainieren und den Fehler senken. Aber wie wird aus einer Prognose eine Entscheidung — und woher weiß ich, dass sie gut ist?“</em></p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li><strong>Die unbequemste Erkenntnis zuerst.</strong> <a href="prognose.html#kap-prognose">Kapitel 15</a> zeigt an einem gerechneten Fall, dass das Modell mit dem <strong>schlechteren</strong> MSE die <strong>günstigere</strong> Entscheidung trifft. Prognosegüte und Entscheidungsqualität sind zwei verschiedene Größen; wer die eine optimiert, bekommt die andere nicht geschenkt.</li>
|
||||
<li><strong>Die unbequemste Erkenntnis zuerst.</strong> <a href="prognose.html#kap-prognose">Kapitel 15</a> zeigt an einem gerechneten Fall, dass das Modell mit dem <strong>schlechteren</strong> <a href="anhang-glossar.md#gloss:mse" class="glossar-link">MSE</a> die <strong>günstigere</strong> Entscheidung trifft. Prognosegüte und Entscheidungsqualität sind zwei verschiedene Größen; wer die eine optimiert, bekommt die andere nicht geschenkt.</li>
|
||||
<li><strong>Dieselbe Mathematik, zwei Welten.</strong> <a href="bruecke.html#kap-bruecke">Kapitel 16</a> lässt <strong>denselben Code</strong> einmal über eine Werkstatt und einmal über ein Depot laufen — und benennt die drei Stellen, an denen die Analogie endet. Struktur zu erkennen ist die eigentliche Fähigkeit, nicht Bibliothekskenntnis; zu wissen, wo eine Analogie aufhört, gehört dazu.</li>
|
||||
<li><strong>Es wird gerechnet, nicht nacherzählt.</strong> Zu jedem Kapitel gehören Aufgaben mit vollständigen Lösungen, Handrechnungen und ein „Finde den Denkfehler“ — und jedes abgedruckte Ergebnis stammt aus einem echten Lauf des danebenstehenden Programms.</li>
|
||||
</ul>
|
||||
|
|
@ -410,13 +410,13 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
<h3 class="unnumbered" id="pfad-a-vollständiger-lehrgang-100140-stunden">Pfad A — Vollständiger Lehrgang (100–140 Stunden)</h3>
|
||||
<p><a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> bis <a href="testing.html#kap-testing">Kapitel 23</a> in Reihenfolge, danach ein Projekt aus der Projektwerkstatt. Empfohlen, wenn Sie OR systematisch lernen wollen. Rechnen Sie mit 4–6 Stunden je Kapitel inklusive Übungen.</p>
|
||||
<h3 class="unnumbered" id="pfad-b-planung-disposition-personaleinsatz-ca.-25-stunden">Pfad B — Planung, Disposition, Personaleinsatz (ca. 25 Stunden)</h3>
|
||||
<p><a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> (Bausteine) → <a href="fundament.html#kap-fundament">Kapitel 2</a> (bis <a href="fundament.html#sec:fundament-konvexitaet-die-grenze-zwischen-leicht-und">Abschnitt 2.5</a>) → <a href="modellierung.html#kap-modellierung">Kapitel 4</a> (vom Wunsch zum Modell) → <a href="lp.html#kap-lp">Kapitel 5</a> (LP, Schattenpreise) → <a href="milp.html#kap-milp">Kapitel 6</a> (Ja/Nein-Entscheidungen) → <a href="cpsat.html#kap-cpsat">Kapitel 7</a> (CP-SAT, Scheduling) → Projekt <strong>P1</strong> (Vertretungsplaner) oder <strong>P2</strong> (Schichtplanung). Das ist der kürzeste Weg zu einem einsetzbaren Dienstplan-Optimierer.</p>
|
||||
<p><a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> (Bausteine) → <a href="fundament.html#kap-fundament">Kapitel 2</a> (bis <a href="fundament.html#sec:fundament-konvexitaet-die-grenze-zwischen-leicht-und">Abschnitt 2.5</a>) → <a href="modellierung.html#kap-modellierung">Kapitel 4</a> (vom Wunsch zum Modell) → <a href="lp.html#kap-lp">Kapitel 5</a> (<a href="anhang-glossar.md#gloss:lineare-programmierung-lp" class="glossar-link">LP</a>, Schattenpreise) → <a href="milp.html#kap-milp">Kapitel 6</a> (Ja/Nein-Entscheidungen) → <a href="cpsat.html#kap-cpsat">Kapitel 7</a> (CP-SAT, Scheduling) → Projekt <strong>P1</strong> (Vertretungsplaner) oder <strong>P2</strong> (Schichtplanung). Das ist der kürzeste Weg zu einem einsetzbaren Dienstplan-Optimierer.</p>
|
||||
<p><em>Wenn der Solver bei Ihrer echten Instanz stehen bleibt:</em> <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a> und Projekt <strong>P9</strong>.</p>
|
||||
<h3 class="unnumbered" id="pfad-c-logistik-und-tourenplanung-ca.-25-stunden">Pfad C — Logistik und Tourenplanung (ca. 25 Stunden)</h3>
|
||||
<p><a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> → <a href="fundament.html#kap-fundament">Kapitel 2</a> (bis <a href="fundament.html#sec:fundament-der-zulaessige-loesungsraum-und-das-polyeder">Abschnitt 2.4</a>) → <a href="lp.html#kap-lp">Kapitel 5</a> → <a href="milp.html#kap-milp">Kapitel 6</a> → <a href="graphen.html#kap-graphen">Kapitel 8</a> (Graphen, VRP) → Projekt <strong>P3</strong> (Liefertouren) oder <strong>P4</strong> (Lagernetzwerk).</p>
|
||||
<p><a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> → <a href="fundament.html#kap-fundament">Kapitel 2</a> (bis <a href="fundament.html#sec:fundament-der-zulaessige-loesungsraum-und-das-polyeder">Abschnitt 2.4</a>) → <a href="lp.html#kap-lp">Kapitel 5</a> → <a href="milp.html#kap-milp">Kapitel 6</a> → <a href="graphen.html#kap-graphen">Kapitel 8</a> (<a href="anhang-glossar.md#gloss:graphen" class="glossar-link">Graphen</a>, <a href="anhang-glossar.md#gloss:vehicle-routing-problem-vrp" class="glossar-link">VRP</a>) → Projekt <strong>P3</strong> (Liefertouren) oder <strong>P4</strong> (Lagernetzwerk).</p>
|
||||
<p><em>Wenn die Instanzen zu groß werden:</em> <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a> (gute Lösung in fester Zeit) und <a href="dekomposition.html#kap-dekomposition">Kapitel 10</a> (das Modell umbauen statt die Lösung raten) — dazu Projekt <strong>P9</strong>, das beide Wege am selben Problem vergleicht.</p>
|
||||
<h3 class="unnumbered" id="pfad-d-quantitative-finance-ca.-30-stunden">Pfad D — Quantitative Finance (ca. 30 Stunden)</h3>
|
||||
<p><a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> → <a href="fundament.html#kap-fundament">Kapitel 2</a> → <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a> (QP, KKT) → <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> (Daten, Shrinkage) → <a href="markowitz.html#kap-markowitz">Kapitel 19</a> (Markowitz) → <a href="cvar.html#kap-cvar">Kapitel 20</a> (CVaR) → <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a> (Backtest) → Projekt <strong>P6</strong> (Portfolio-Rebalancer) oder <strong>P7</strong> (Risikoreport). <strong>Wichtig:</strong> Überspringen Sie <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> nicht. Wer direkt bei Markowitz einsteigt, optimiert Schätzrauschen und wundert sich über absurde Gewichte.</p>
|
||||
<p><a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a> → <a href="fundament.html#kap-fundament">Kapitel 2</a> → <a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a> (<a href="anhang-glossar.md#gloss:quadratische-programmierung-qp" class="glossar-link">QP</a>, <a href="anhang-glossar.md#gloss:karush-kuhn-tucker-bedingungen-kkt" class="glossar-link">KKT</a>) → <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> (Daten, Shrinkage) → <a href="markowitz.html#kap-markowitz">Kapitel 19</a> (Markowitz) → <a href="cvar.html#kap-cvar">Kapitel 20</a> (CVaR) → <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a> (Backtest) → Projekt <strong>P6</strong> (Portfolio-Rebalancer) oder <strong>P7</strong> (Risikoreport). <strong>Wichtig:</strong> Überspringen Sie <a href="finanzdaten.html#kap-finanzdaten">Kapitel 18</a> nicht. Wer direkt bei Markowitz einsteigt, optimiert Schätzrauschen und wundert sich über absurde Gewichte.</p>
|
||||
<h3 class="unnumbered" id="pfad-e-ich-habe-morgen-ein-konkretes-problem-24-stunden">Pfad E — Ich habe morgen ein konkretes Problem (2–4 Stunden)</h3>
|
||||
<p>Lesen Sie <a href="einfuehrung.html#sec:einfuehrung-historischer-kontext-und-evolution">Abschnitt 1.5</a> (die vier Bausteine) und <a href="modellierung.html#sec:modellierung-glossar">Abschnitt 4.6</a> (welcher Satz welcher Baustein ist), dann <a href="anhang-modellierungsmuster.html#anhang-modellierungsmuster">Anhang B</a> (<a href="anhang-modellierungsmuster.html">Modellierungsmuster</a>) und suchen Sie dort das Muster, das zu Ihrem Problem passt. Von jedem Muster führt ein Verweis in das zuständige Kapitel. Wie die gewählte Bibliothek es schreibt, steht in <a href="anhang-spickzettel.html#anhang-spickzettel">Anhang D</a> (<a href="anhang-spickzettel.html">Spickzettel</a>); wenn etwas nicht läuft, in <a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a> (<a href="anhang-fehlerdiagnose.html">Fehlerdiagnose</a>).</p>
|
||||
<h3 class="unnumbered" id="pfad-f-vom-prototyp-in-den-betrieb-ca.-15-stunden">Pfad F — Vom Prototyp in den Betrieb (ca. 15 Stunden)</h3>
|
||||
|
|
@ -451,7 +451,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>Brute_Force_Vergleich.py</code></td>
|
||||
<td>Kombinatorische Explosion</td>
|
||||
<td><a href="anhang-glossar.md#gloss:kombinatorische-explosion" class="glossar-link">Kombinatorische Explosion</a></td>
|
||||
<td><a href="einfuehrung.html#kap-einfuehrung">Kapitel 1</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -476,7 +476,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>Visualisierung_Loesungsraum.py</code></td>
|
||||
<td>Polyeder mit Ecken</td>
|
||||
<td><a href="anhang-glossar.md#gloss:polyeder" class="glossar-link">Polyeder</a> mit Ecken</td>
|
||||
<td><a href="fundament.html#kap-fundament">Kapitel 2</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
|
|
@ -496,7 +496,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>Modellierungsschichten.py</code></td>
|
||||
<td>Pyomo und Linopy</td>
|
||||
<td><a href="anhang-glossar.md#gloss:pyomo" class="glossar-link">Pyomo</a> und <a href="anhang-glossar.md#gloss:linopy" class="glossar-link">Linopy</a></td>
|
||||
<td><a href="oekosystem.html#kap-oekosystem">Kapitel 3</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
|
|
@ -526,7 +526,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>Toleranzen_und_Entartung.py</code></td>
|
||||
<td>Entartung, Toleranzen, Dualspannen</td>
|
||||
<td><a href="anhang-glossar.md#gloss:entartung" class="glossar-link">Entartung</a>, Toleranzen, Dualspannen</td>
|
||||
<td><a href="lp.html#kap-lp">Kapitel 5</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
|
|
@ -546,7 +546,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>Solverstatus_und_Gap.py</code></td>
|
||||
<td>MIP-Gap, Zeitlimit, Statusfälle</td>
|
||||
<td><a href="anhang-glossar.md#gloss:mip-gap" class="glossar-link">MIP-Gap</a>, Zeitlimit, Statusfälle</td>
|
||||
<td><a href="milp.html#kap-milp">Kapitel 6</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
|
|
@ -556,7 +556,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>Big_M_Falle.py</code></td>
|
||||
<td>Trickle Flow bei zu großem M</td>
|
||||
<td><a href="anhang-glossar.md#gloss:trickle-flow" class="glossar-link">Trickle Flow</a> bei zu großem M</td>
|
||||
<td><a href="milp.html#kap-milp">Kapitel 6</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
|
|
@ -571,7 +571,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>JobShop_Intervalle.py</code></td>
|
||||
<td>Job-Shop-Scheduling</td>
|
||||
<td><a href="anhang-glossar.md#gloss:job-shop-scheduling" class="glossar-link">Job-Shop-Scheduling</a></td>
|
||||
<td><a href="cpsat.html#kap-cpsat">Kapitel 7</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -601,7 +601,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>VRP_Flotten_Routing.py</code></td>
|
||||
<td>CVRPTW</td>
|
||||
<td><a href="anhang-glossar.md#gloss:cvrptw" class="glossar-link">CVRPTW</a></td>
|
||||
<td><a href="graphen.html#kap-graphen">Kapitel 8</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -631,7 +631,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>QP_Grundlagen.py</code></td>
|
||||
<td>Konvexität, DCP-Check</td>
|
||||
<td><a href="anhang-glossar.md#gloss:konvexitaet" class="glossar-link">Konvexität</a>, <a href="anhang-glossar.md#gloss:dcp-disciplined-convex-programming" class="glossar-link">DCP</a>-Check</td>
|
||||
<td><a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -641,7 +641,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>Entropie_Maximierte_Allokation.py</code></td>
|
||||
<td>NLP mit Entropie</td>
|
||||
<td><a href="anhang-glossar.md#gloss:nichtlineare-programmierung-nlp" class="glossar-link">NLP</a> mit Entropie</td>
|
||||
<td><a href="qp-nlp.html#kap-qp-nlp">Kapitel 11</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -676,12 +676,12 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>Bellman_Minimalbeispiel.py</code></td>
|
||||
<td>Rückwärtsinduktion</td>
|
||||
<td><a href="anhang-glossar.md#gloss:rueckwaertsinduktion" class="glossar-link">Rückwärtsinduktion</a></td>
|
||||
<td><a href="dynamische-programmierung.html#kap-dynamische-programmierung">Kapitel 13</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>Mehrziel_Pareto.py</code></td>
|
||||
<td>Pareto-Front, ε-Constraint, Gewichtslücke</td>
|
||||
<td><a href="anhang-glossar.md#gloss:pareto-front" class="glossar-link">Pareto-Front</a>, ε-Constraint, Gewichtslücke</td>
|
||||
<td><a href="mehrziel.html#kap-mehrziel">Kapitel 14</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -726,7 +726,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>Markowitz_CVXPY.py</code></td>
|
||||
<td>GMV, Max Sharpe, Frontier</td>
|
||||
<td><a href="anhang-glossar.md#gloss:global-minimum-variance-portfolio-gmv" class="glossar-link">GMV</a>, Max Sharpe, Frontier</td>
|
||||
<td><a href="markowitz.html#kap-markowitz">Kapitel 19</a></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
|
|
@ -741,7 +741,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>VaR_CVaR_Demo.py</code></td>
|
||||
<td>Fat Tails, Subadditivität</td>
|
||||
<td><a href="anhang-glossar.md#gloss:fat-tails" class="glossar-link">Fat Tails</a>, <a href="anhang-glossar.md#gloss:subadditivitaet" class="glossar-link">Subadditivität</a></td>
|
||||
<td><a href="cvar.html#kap-cvar">Kapitel 20</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -751,7 +751,7 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="odd">
|
||||
<td><code>QuantitativeTradingEngine.py</code></td>
|
||||
<td>Walk-Forward-Backtest</td>
|
||||
<td><a href="anhang-glossar.md#gloss:walk-forward-backtest" class="glossar-link">Walk-Forward-Backtest</a></td>
|
||||
<td><a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
|
|
@ -816,14 +816,14 @@ Alles bereit — Sie können mit dem ersten Kapitel beginnen.</code></pre>
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td><code>Konfliktsuche.py</code></td>
|
||||
<td>Deletion Filter: den Widerspruch einkreisen</td>
|
||||
<td><a href="anhang-glossar.md#gloss:deletion-filter" class="glossar-link">Deletion Filter</a>: den Widerspruch einkreisen</td>
|
||||
<td><a href="anhang-fehlerdiagnose.html#anhang-fehlerdiagnose">Anhang C</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 class="unnumbered" id="was-dieses-buch-nicht-ist">Was dieses Buch nicht ist</h2>
|
||||
<p>Es ist <strong>keine Anleitung zum Bau eigener Solver</strong> — wir nutzen ausgereifte Implementierungen und investieren die Zeit stattdessen in die Modellierung. Die einzige Ausnahme ist der Simplex-Algorithmus in <a href="lp.html#kap-lp">Kapitel 5</a>, den wir von Grund auf programmieren, weil man ihn verstanden haben muss, um Dualität und Schattenpreise zu begreifen.</p>
|
||||
<p>Es ist <strong>keine Anleitung zum Bau eigener Solver</strong> — wir nutzen ausgereifte Implementierungen und investieren die Zeit stattdessen in die Modellierung. Die einzige Ausnahme ist der <a href="anhang-glossar.md#gloss:simplex-algorithmus" class="glossar-link">Simplex-Algorithmus</a> in <a href="lp.html#kap-lp">Kapitel 5</a>, den wir von Grund auf programmieren, weil man ihn verstanden haben muss, um Dualität und Schattenpreise zu begreifen.</p>
|
||||
<p>Es ist <strong>kein Buch über maschinelles Lernen</strong>. Prognosen kommen nur so weit vor, wie sie als Eingangsdaten einer Optimierung nötig sind.</p>
|
||||
<p>Und der vierte Teil ist <strong>ausdrücklich keine Anlageberatung</strong>. Die Finanzbeispiele demonstrieren Methodik an realen Daten, nicht handelbare Strategien. <a href="praxisfallen.html#kap-praxisfallen">Kapitel 22</a> erklärt ausführlich, warum ein gut aussehender Backtest noch keine funktionierende Strategie ist.</p>
|
||||
<hr />
|
||||
|
|
|
|||
1706
Operations_Research_mit_Python_Version_04.md
generated
1706
Operations_Research_mit_Python_Version_04.md
generated
File diff suppressed because it is too large
Load diff
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
|
@ -157,4 +157,4 @@ Details zu den Lernpfaden stehen in [`00_Vorwort_und_Lesehilfe.md`](00_Vorwort_u
|
|||
|
||||
---
|
||||
|
||||
*Autor / Herausgeber: Dieter Schlüter · Stand: 10. September 2026 v16.09*
|
||||
*Autor / Herausgeber: Dieter Schlüter · Stand: 10. September 2026 v17.38*
|
||||
|
|
|
|||
|
|
@ -711,6 +711,17 @@ def reflow_markdown(text: str) -> str:
|
|||
i += 1
|
||||
continue
|
||||
|
||||
# Fenced-Div-Grenzen (::: {#...} / :::): wie Ueberschriften als
|
||||
# Blockgrenze behandeln, sonst wuerde reflow die ::: mit dem
|
||||
# folgenden Absatz zu einer Zeile verbinden — und Pandoc wuerde den
|
||||
# div nicht mehr erkennen. Genutzt im Glossar (Anhang E): jeder
|
||||
# Eintrag steht in einem ::: {#gloss:<slug>} ... :::-Block.
|
||||
if content_stripped.startswith(":::"):
|
||||
flush()
|
||||
out.append(raw)
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if _HR_RE.match(content_stripped):
|
||||
flush()
|
||||
out.append(raw)
|
||||
|
|
@ -1070,6 +1081,162 @@ def resolve_index(text: str) -> str:
|
|||
return text
|
||||
|
||||
|
||||
# --- Glossar-Links: Fachbegriffe im Fließtext automatisch verlinken -------
|
||||
#
|
||||
# resolve_glossar() sucht im Fließtext nach Begriffen aus LINK_TEXTE (siehe
|
||||
# glossar_eintraege_04.py) und ersetzt das ERSTE Vorkommen je Begriff im
|
||||
# aktuellen Text durch einen Markdown-Link auf den Glossar-Eintrag. "Erste
|
||||
# Nennung" statt jedes Vorkommen: ein Begriff, der 576-mal vorkommt ('Solver'),
|
||||
# wuerde sonst jeden Absatz mit Links pflastern.
|
||||
#
|
||||
# Ausgeschlossen vom Link sind Code-Bloecke (```...```), Inline-Code (`...`),
|
||||
# Marken ({idx:...}, {ref:...}, {#...}), Markdown-Links [...](...) und
|
||||
# Ueberschriften — dort wuerde der Link stoen oder kaputtgehen.
|
||||
#
|
||||
# fuer_seite=False: Link als [Begriff](#gloss:slug) — fuer das Gesamtdokument.
|
||||
# fuer_seite=True: Link als [Begriff](anhang-glossar.md#gloss:slug) — fuer
|
||||
# Einzelseiten (seitenuebergreifend).
|
||||
#
|
||||
# Die manuelle Marke {gl:Begriff} wird ebenfalls aufgeloest — sie erzwingt
|
||||
# einen Link auch fuer Begriffe, die nicht in LINK_TEXTE stehen (z.B. weil
|
||||
# sie zu mehrdeutig fuer Auto-Linking sind, aber an dieser Stelle als
|
||||
# Fachbegriff gemeint sind).
|
||||
|
||||
_GLOSSAR_TOKEN_RE = re.compile(
|
||||
r'`[^`]*`' # Inline-Code `...`
|
||||
r'|\{[^}]*\}' # Marken {...}
|
||||
r'|\[[^\]]*\]\([^)]*\)' # Markdown-Links [text](url)
|
||||
)
|
||||
|
||||
_GLOSSAR_GL_RE = re.compile(r'\{gl:([^}]+)\}')
|
||||
|
||||
|
||||
def resolve_glossar(text: str, fuer_seite: bool = False) -> str:
|
||||
"""Verlinkt Glossar-Begriffe im Fließtext automatisch (erste Nennung je
|
||||
Begriff im uebergebenen Text) und loest {gl:}-Marken auf."""
|
||||
from glossar_eintraege_04 import LINK_TEXTE
|
||||
|
||||
# {gl:Begriff}-Marken zuerst: erzwingen einen Link auch fuer Begriffe,
|
||||
# die nicht auto-linkbar sind. 'Begriff' ist der Anzeigetext im Link;
|
||||
# das Ziel ist der Glossar-Eintrag mit diesem Namen als Indexmarke (oder
|
||||
# falls vorhanden, der Slug aus LINK_TEXTE).
|
||||
gl_treffer = 0
|
||||
def _gl_repl(m: re.Match) -> str:
|
||||
nonlocal gl_treffer
|
||||
begriff = m.group(1)
|
||||
slug = LINK_TEXTE.get(begriff) or _glossar_slug_fuer(begriff)
|
||||
ziel = (f'anhang-glossar.md#gloss:{slug}' if fuer_seite
|
||||
else f'#gloss:{slug}')
|
||||
gl_treffer += 1
|
||||
return f'[{begriff}]({ziel}){{.glossar-link}}'
|
||||
text = _GLOSSAR_GL_RE.sub(_gl_repl, text)
|
||||
if gl_treffer:
|
||||
print(f"Glossar-Links (manuell): {gl_treffer} Marke(n) aufgeloest.")
|
||||
|
||||
# Auto-Linking: laengste Link-Texte zuerst (damit 'Value at Risk' vor
|
||||
# 'VaR' gematcht wird, falls beide im Text stuenden).
|
||||
texte = sorted(LINK_TEXTE.items(), key=lambda x: -len(x[0]))
|
||||
|
||||
lines = text.split('\n')
|
||||
in_code_block = False
|
||||
code_fence = None
|
||||
seen: set[str] = set()
|
||||
treffer = 0
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
stripped = line.lstrip()
|
||||
# Code-Block: nicht verlinken, nur Fence-Ende erkennen.
|
||||
if in_code_block:
|
||||
if stripped.startswith(code_fence):
|
||||
in_code_block = False
|
||||
continue
|
||||
fence_m = re.match(r'^(```+|~~~+)', stripped)
|
||||
if fence_m:
|
||||
code_fence = fence_m.group(1)
|
||||
in_code_block = True
|
||||
continue
|
||||
# Ueberschriften: nicht verlinken (wuerde Inhaltsverzeichnis stoen).
|
||||
if _HEADING_RE.match(stripped):
|
||||
continue
|
||||
|
||||
# Zeile in Token-Segmente (Code/Marke/Link) und Fließtext splitten;
|
||||
# nur in Fließtext-Segmenten wird gesucht.
|
||||
new_parts: list[str] = []
|
||||
last = 0
|
||||
for m in _GLOSSAR_TOKEN_RE.finditer(line):
|
||||
seg = line[last:m.start()]
|
||||
seg, t = _glossar_in_segment(seg, texte, seen, fuer_seite)
|
||||
treffer += t
|
||||
new_parts.append(seg)
|
||||
new_parts.append(m.group(0)) # Token unverändert
|
||||
last = m.end()
|
||||
rest = line[last:]
|
||||
rest, t = _glossar_in_segment(rest, texte, seen, fuer_seite)
|
||||
treffer += t
|
||||
new_parts.append(rest)
|
||||
lines[i] = ''.join(new_parts)
|
||||
|
||||
if treffer:
|
||||
print(f"Glossar-Links (auto): {treffer} Begriff(e) verlinkt.")
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def _glossar_slug_fuer(begriff: str) -> str:
|
||||
"""Slug fuer einen Begriff, der nicht in LINK_TEXTE steht (fuer {gl:}."""
|
||||
from glossar_eintraege_04 import glossar_slug
|
||||
return glossar_slug(begriff)
|
||||
|
||||
|
||||
def _glossar_in_segment(segment: str, texte: list[tuple[str, str]],
|
||||
seen: set[str], fuer_seite: bool) -> tuple[str, int]:
|
||||
"""Sucht im Fließtext-Segment nach Glossar-Begriffen und ersetzt das
|
||||
erste Vorkommen je Begriff durch einen Link.
|
||||
|
||||
Alle Link-Texte werden im Original-Segment gesucht (mit finditer, also
|
||||
alle Vorkommen), dann nach Position sortiert und nicht-ueberlappend
|
||||
ersetzt — laengste zuerst bei gleicher Position. So wird 'CP-SAT' als
|
||||
Ganzes erkannt, bevor 'CP' (als Teilstring darin) ein eigenes Match
|
||||
erzeugt. Wird ein Match wegen Ueberlappung übersprungen, wird das
|
||||
naechste Vorkommen desselben Begriffs genommen (falls nicht ueberlappend).
|
||||
"""
|
||||
matches: list[tuple[int, int, str, str]] = []
|
||||
for link_text, slug in texte:
|
||||
if link_text in seen:
|
||||
continue
|
||||
pat = re.compile(r'\b' + re.escape(link_text) + r'\b')
|
||||
for m in pat.finditer(segment):
|
||||
matches.append((m.start(), m.end(), link_text, slug))
|
||||
# Alle Vorkommen sammeln — falls das erste wegen Ueberlappung
|
||||
# mit einem laengeren Begriff (z.B. 'CP-SAT-Solver' blockiert
|
||||
# 'Solver') uebersprungen wird, greift das naechste.
|
||||
if not matches:
|
||||
return segment, 0
|
||||
# Nach Position aufsteigend, bei gleicher Position laengste zuerst —
|
||||
# damit 'CP-SAT-Solver' (start=X, len=13) vor 'CP-SAT' (start=X, len=6)
|
||||
# und 'CP' (start=X, len=2) kommt.
|
||||
matches.sort(key=lambda x: (x[0], -(x[1] - x[0])))
|
||||
result: list[str] = []
|
||||
last_end = 0
|
||||
treffer = 0
|
||||
for start, end, link_text, slug in matches:
|
||||
if start < last_end:
|
||||
continue # ueberlappt mit einem bereits gesetzten laengeren Match
|
||||
if link_text in seen:
|
||||
continue # dieser Begriff wurde schon weiter oben im Segment
|
||||
# verlinkt (zweiter nicht-ueberlappender Treffer waere moeglich,
|
||||
# aber 'erste Nennung je Begriff' gilt global pro Datei, nicht pro
|
||||
# Segment)
|
||||
result.append(segment[last_end:start])
|
||||
ziel = (f'anhang-glossar.md#gloss:{slug}' if fuer_seite
|
||||
else f'#gloss:{slug}')
|
||||
result.append(f'[{link_text}]({ziel}){{.glossar-link}}')
|
||||
seen.add(link_text)
|
||||
treffer += 1
|
||||
last_end = end
|
||||
result.append(segment[last_end:])
|
||||
return ''.join(result), treffer
|
||||
|
||||
|
||||
# Wird als letzter Textbaustein angehaengt - landet damit unmittelbar vor dem
|
||||
# von Pandoc automatisch erzeugten \end{document}. \phantomsection sorgt
|
||||
# dafuer, dass hyperref einen Sprunganker fuer den (mit \section* erzeugten,
|
||||
|
|
@ -1150,6 +1317,11 @@ def baue_markdown() -> str:
|
|||
inhalt = inhalt.replace("Stand: {datum}", f"Stand: {datum}")
|
||||
# Vorwort-Signatur 'Köln, im {vorwort_datum}' dynamisch setzen.
|
||||
inhalt = inhalt.replace("{vorwort_datum}", aktuelles_monat_jahr())
|
||||
# Glossar-Links pro Datei (erste Nennung je Begriff je Datei) —
|
||||
# aber nicht im Glossar selbst: dort wuerde jeder Eintrag auf sich
|
||||
# selbst verlinken.
|
||||
if name != "94_Anhang_Glossar.md":
|
||||
inhalt = resolve_glossar(inhalt, fuer_seite=False)
|
||||
|
||||
# Inhaltsverzeichnis vor dem Vorwort einfuegen (LaTeX-Rohblock)
|
||||
if TOC_MARKE in inhalt and i == 0:
|
||||
|
|
@ -2293,6 +2465,9 @@ def baue_kapitel_seiten(html_verz: str, datei_seite: dict, labels: dict,
|
|||
text = text.replace("{vorwort_datum}", aktuelles_monat_jahr())
|
||||
text = reflow_markdown(text)
|
||||
text = resolve_numbering_seite(text, eintrag["seite"], labels, label_seite)
|
||||
# Glossar-Links — aber nicht im Glossar selbst (sonst Self-Links).
|
||||
if name != "94_Anhang_Glossar.md":
|
||||
text = resolve_glossar(text, fuer_seite=True)
|
||||
text = resolve_index(text)
|
||||
text, mit_plotly = resolve_plotly(text, fuer_html=True)
|
||||
text = resolve_karte(text, fuer_html=True)
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ HIER = os.path.dirname(os.path.abspath(__file__))
|
|||
BASIS = os.path.dirname(HIER)
|
||||
sys.path.insert(0, HIER)
|
||||
|
||||
from glossar_eintraege_04 import EINTRAEGE # noqa: E402
|
||||
from glossar_eintraege_04 import EINTRAEGE, glossar_slug # noqa: E402
|
||||
|
||||
ZIEL = os.path.join(HIER, "94_Anhang_Glossar.md")
|
||||
|
||||
|
|
@ -70,11 +70,14 @@ BREITE = 96 # Zeilenbreite wie in den uebrigen Kapiteldateien
|
|||
# hier eintragen.
|
||||
NUR_IM_GLOSSAR = frozenset({
|
||||
"Alternativoptima",
|
||||
"Backtest",
|
||||
"Binärvariable",
|
||||
"CP-SAT",
|
||||
"Calmar Ratio",
|
||||
"DCP",
|
||||
"Dualitätstheorie",
|
||||
"Explainable OR",
|
||||
"Graphen",
|
||||
"Kanonische Standardform",
|
||||
"Kohärentes Risikomaß",
|
||||
"Lagrange-Multiplikator",
|
||||
|
|
@ -86,7 +89,9 @@ NUR_IM_GLOSSAR = frozenset({
|
|||
"Rebalancing",
|
||||
"Regime-Shift",
|
||||
"Relaxation",
|
||||
"Scheduling",
|
||||
"Schätzfehler",
|
||||
"Solver",
|
||||
"Solver-Status",
|
||||
"Transaktionskosten",
|
||||
"Unsicherheitsmenge",
|
||||
|
|
@ -184,7 +189,13 @@ def baue() -> str:
|
|||
zeilen += [f"## {buchstabe}", ""]
|
||||
letzter = buchstabe
|
||||
marke = "{idx:" + idx + "}" if idx else ""
|
||||
zeilen += [absatz(f"**{name}**{marke} — {text} → {ziel}"), ""]
|
||||
slug = glossar_slug(name)
|
||||
# ::: {#gloss:<slug>} ... ::: erzeugt im HTML einen <div id="gloss-slug">-
|
||||
# Anker und im PDF eine \hypertarget-Marke; beide sind das Ziel der
|
||||
# Auto-Links aus dem Fließtext.
|
||||
zeilen += [f"::: {{#gloss:{slug}}}",
|
||||
absatz(f"**{name}**{marke} — {text} → {ziel}"),
|
||||
":::", ""]
|
||||
zeilen += ["---", "", SCHLUSS, ""]
|
||||
return "\n".join(zeilen)
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,41 @@ ueberschreibt sie und bricht ab, wenn er eine Handaenderung bemerkt.
|
|||
|
||||
EINTRAEGE = [
|
||||
|
||||
("Backtest", "Backtest",
|
||||
"Rückblickender Test einer Strategie auf historischen Daten. Ein Backtest "
|
||||
"ist nur so glaubwürdig wie seine Daten, seine Kostenannahme und seine "
|
||||
"Trennung von Trainings- und Testzeitraum — "
|
||||
"{ref:kap:handelsmaschine} zeigt die fünf Selbsttäuschungen, die ihn wertlos "
|
||||
"machen.",
|
||||
"{ref:kap:handelsmaschine}"),
|
||||
|
||||
("DCP (Disciplined Convex Programming)", "DCP",
|
||||
"Regelwerk von CVXPY, das jede Variable als konkav, konvex oder affin "
|
||||
"ausweist und aus der Kombination der Bausteine die Konkavität/Konvexität "
|
||||
"der Zielfunktion und der Nebenbedingungen erschließt. {ref:kap:qp-nlp} "
|
||||
"erklärt es; ein `DCPError` meldet eine Verletzung.",
|
||||
"{ref:kap:qp-nlp}"),
|
||||
|
||||
("Graphen", "Graphen",
|
||||
"Mathematische Struktur aus Knoten und Kanten; das Modellierungsmittel für "
|
||||
"Netzwerke, Touren und Flüsse. {ref:kap:graphen} behandelt Min-Cost-Flow, "
|
||||
"Matching und das Vehicle Routing Problem als Graphanwendungen.",
|
||||
"{ref:kap:graphen}"),
|
||||
|
||||
("Scheduling", "Scheduling",
|
||||
"Zuweisung von Tätigkeiten an Maschinen oder Personen unter "
|
||||
"Ressourcen- und Reihenfolgebedingungen. {ref:kap:cpsat} behandelt es mit "
|
||||
"CP-SAT (Intervallvariablen), {ref:kap:metaheuristiken} mit Simulated "
|
||||
"Annealing und LNS.",
|
||||
"{ref:kap:cpsat}"),
|
||||
|
||||
("Solver", "Solver",
|
||||
"Softwarekomponente, die ein mathematisches Modell löst — also das "
|
||||
"Optimierungsproblem in eine Lösung übersetzt. {ref:kap:oekosystem} "
|
||||
"vergleicht die in diesem Buch verwendeten Solver (HiGHS, OR-Tools/CP-SAT, "
|
||||
"CVXPY) und ihre Stärken.",
|
||||
"{ref:kap:oekosystem}"),
|
||||
|
||||
("Absolutbetrag", "Absolutbetrag (Modellierungsmuster)",
|
||||
"Modellierungsmuster für $|x-z|$: Der Betrag selbst ist nicht linear, lässt sich aber "
|
||||
"durch eine Hilfsvariable $d$ mit den beiden Bedingungen $x-z \\le d$ und $z-x \\le d$ "
|
||||
|
|
@ -1418,3 +1453,96 @@ EINTRAEGE = [
|
|||
"{ref:anhang:fehlerdiagnose}"),
|
||||
|
||||
]
|
||||
|
||||
|
||||
# --- Auto-Link-Infrastruktur ---------------------------------------------
|
||||
# Der Build verlinkt Glossar-Begriffe im Fließtext automatisch — die
|
||||
# {gl:}-Marke von Hand ist nur Ausnahme, nicht Regelfall. Diese beiden
|
||||
# Werte liefern die dazu noetigen Daten:
|
||||
#
|
||||
# glossar_slug(name) Eine stabile HTML-ID je Eintrag ('cp-sat', 'var'…).
|
||||
# Die Glossar-Datei traegt denselben Slug als
|
||||
# {#gloss:<slug>}-Anchor; der Link im Fließtext
|
||||
# zeigt dorthin.
|
||||
# LINK_TEXTE {Text_im_Buch: slug} — alles, was der Build durch
|
||||
# einen Link ersetzt. Generiert aus den EINTRAEGEN:
|
||||
# der Anzeigename je Eintrag, plus die Abkürzung,
|
||||
# falls der Name eine enthaelt (z.B. 'VaR' neben
|
||||
# 'Value at Risk').
|
||||
#
|
||||
# Einträge, die NICHT auto-verlinkt werden sollen, fehlen hier einfach.
|
||||
# 'Variable', 'Lösung', 'Matrix' etc. sind zu mehrdeutig als Fließtext und
|
||||
# werden nicht auto-verlinkt — wer sie verlinkt haben will, setzt {gl:}.
|
||||
|
||||
import re as _re
|
||||
|
||||
_UMLAUT = str.maketrans({"ä": "ae", "ö": "oe", "ü": "ue", "Ä": "Ae",
|
||||
"Ö": "Oe", "Ü": "Ue", "ß": "ss"})
|
||||
|
||||
|
||||
def glossar_slug(name: str) -> str:
|
||||
"""ASCII-sicherer Slug fuer den Glossar-Anchor (wie die sec:-Labels)."""
|
||||
s = name.translate(_UMLAUT).lower()
|
||||
s = _re.sub(r"[^a-z0-9]+", "-", s).strip("-")
|
||||
return s or "glossar"
|
||||
|
||||
|
||||
def _abkuerzung_aus_name(name: str) -> str | None:
|
||||
"""Extrahiert die Abkürzung aus einem Glossar-Namen.
|
||||
|
||||
Zwei Fälle:
|
||||
* 'Value at Risk (VaR)' — Abkürzung im Klammerinhalt (kurz, überwiegend
|
||||
Großbuchstaben, z.B. VaR, CVaR, KKT, MILP).
|
||||
* 'EVPI (Expected Value ...)' — Abkürzung VOR der Klammer, wenn der
|
||||
Teil vor der Klammer durchgehend Großbuchstaben ist (z.B. EVPI, IIS,
|
||||
TSP, DTO, GIL, SAT).
|
||||
"""
|
||||
m = _re.search(r"\(([^)]+)\)\s*$", name)
|
||||
if not m:
|
||||
return None
|
||||
k = m.group(1).strip()
|
||||
if len(k) <= 15 and sum(1 for c in k if c.isupper()) >= len(k) * 0.5:
|
||||
return k
|
||||
# Fall 2: Teil vor der Klammer ist die Abkürzung (z.B. 'EVPI (... )').
|
||||
vor = name[: m.start()].strip()
|
||||
if vor and len(vor) <= 8 and vor.isupper() and vor.isalpha():
|
||||
return vor
|
||||
return None
|
||||
|
||||
|
||||
# Begriffe, die zwar im Glossar stehen, aber im Fließtext NICHT
|
||||
# auto-verlinkt werden (zu mehrdeutig — 'Lösung' als Lösung eines
|
||||
# Gleichungssystems vs. Lösung einer Aufgabe vs. Optimallösung).
|
||||
# Wer sie verlinkt haben will, setzt {gl:Lösung} — das ist die Ausnahme.
|
||||
_NICHT_AUTO_LINKEN = frozenset({
|
||||
"Binärvariable", "Entscheidungsvariable", "Intervallvariable",
|
||||
"Schlupfvariable", "Semikontinuierliche Variable",
|
||||
"Lösung", "Lösung (Modellierungsmuster)", "Instabile Lösung",
|
||||
"Unsinniges Ergebnis", "Verdächtig guter Backtest",
|
||||
"Matrix", "Matrixform", "Matrix-Vektor-Produkt",
|
||||
"Nebenbedingung (Constraint)",
|
||||
"Widersprüchliche Solver",
|
||||
# Fehlerbilder: werden im Glossar geführt, aber im Fließtext nicht
|
||||
# jedes Vorkommen verlinkt (sonst wird aus jedem 'Tippfehler' ein Link).
|
||||
})
|
||||
|
||||
|
||||
# Abkürzungen, die nicht auto-verlinkt werden — 'OR' ist 2 Zeichen und
|
||||
# taucht als Teilstring in 'OR-Tools' auf (Produktname, nicht die
|
||||
# Abkürzung für Operations Research). Wer 'OR' als Fachbegriff verlinken
|
||||
# will, setzt {gl:OR}. Die anderen 2-Zeichen-Abkürzungen (LP, QP, DP, CP)
|
||||
# kommen im Text nur als Fachbegriff vor und bleiben auto-verlinkt.
|
||||
_ZU_KURZ_ABK = frozenset({"OR"})
|
||||
|
||||
|
||||
LINK_TEXTE: dict[str, str] = {}
|
||||
for _name, _idx, _text, _ziel in EINTRAEGE:
|
||||
if _name in _NICHT_AUTO_LINKEN:
|
||||
continue
|
||||
_slug = glossar_slug(_name)
|
||||
# Anzeigename immer (z.B. 'Schattenpreis' -> 'schattenpreis').
|
||||
LINK_TEXTE[_name] = _slug
|
||||
# Abkürzung falls vorhanden (z.B. 'VaR' -> 'value-at-risk-var').
|
||||
_abk = _abkuerzung_aus_name(_name)
|
||||
if _abk and _abk not in _ZU_KURZ_ABK:
|
||||
LINK_TEXTE[_abk] = _slug
|
||||
|
|
|
|||
|
|
@ -2444,7 +2444,7 @@ z
|
|||
</g>
|
||||
</g>
|
||||
<g id="text_14">
|
||||
<!-- Stand: 10. September 2026 v16.09 -->
|
||||
<!-- Stand: 10. September 2026 v17.38 -->
|
||||
<g style="fill: #c7d2fe" transform="translate(71.4528 818.05749) scale(0.12 -0.12)">
|
||||
<defs>
|
||||
<path id="DejaVuSans-31" d="M 794 531
|
||||
|
|
@ -2536,34 +2536,85 @@ Q 2619 4750 2861 4703
|
|||
Q 3103 4656 3366 4563
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-39" d="M 703 97
|
||||
L 703 672
|
||||
Q 941 559 1184 500
|
||||
Q 1428 441 1663 441
|
||||
Q 2288 441 2617 861
|
||||
Q 2947 1281 2994 2138
|
||||
Q 2813 1869 2534 1725
|
||||
Q 2256 1581 1919 1581
|
||||
Q 1219 1581 811 2004
|
||||
Q 403 2428 403 3163
|
||||
Q 403 3881 828 4315
|
||||
Q 1253 4750 1959 4750
|
||||
Q 2769 4750 3195 4129
|
||||
Q 3622 3509 3622 2328
|
||||
Q 3622 1225 3098 567
|
||||
Q 2575 -91 1691 -91
|
||||
Q 1453 -91 1209 -44
|
||||
Q 966 3 703 97
|
||||
<path id="DejaVuSans-37" d="M 525 4666
|
||||
L 3525 4666
|
||||
L 3525 4397
|
||||
L 1831 0
|
||||
L 1172 0
|
||||
L 2766 4134
|
||||
L 525 4134
|
||||
L 525 4666
|
||||
z
|
||||
M 1959 2075
|
||||
Q 2384 2075 2632 2365
|
||||
Q 2881 2656 2881 3163
|
||||
Q 2881 3666 2632 3958
|
||||
Q 2384 4250 1959 4250
|
||||
Q 1534 4250 1286 3958
|
||||
Q 1038 3666 1038 3163
|
||||
Q 1038 2656 1286 2365
|
||||
Q 1534 2075 1959 2075
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-33" d="M 2597 2516
|
||||
Q 3050 2419 3304 2112
|
||||
Q 3559 1806 3559 1356
|
||||
Q 3559 666 3084 287
|
||||
Q 2609 -91 1734 -91
|
||||
Q 1441 -91 1130 -33
|
||||
Q 819 25 488 141
|
||||
L 488 750
|
||||
Q 750 597 1062 519
|
||||
Q 1375 441 1716 441
|
||||
Q 2309 441 2620 675
|
||||
Q 2931 909 2931 1356
|
||||
Q 2931 1769 2642 2001
|
||||
Q 2353 2234 1838 2234
|
||||
L 1294 2234
|
||||
L 1294 2753
|
||||
L 1863 2753
|
||||
Q 2328 2753 2575 2939
|
||||
Q 2822 3125 2822 3475
|
||||
Q 2822 3834 2567 4026
|
||||
Q 2313 4219 1838 4219
|
||||
Q 1578 4219 1281 4162
|
||||
Q 984 4106 628 3988
|
||||
L 628 4550
|
||||
Q 988 4650 1302 4700
|
||||
Q 1616 4750 1894 4750
|
||||
Q 2613 4750 3031 4423
|
||||
Q 3450 4097 3450 3541
|
||||
Q 3450 3153 3228 2886
|
||||
Q 3006 2619 2597 2516
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
<path id="DejaVuSans-38" d="M 2034 2216
|
||||
Q 1584 2216 1326 1975
|
||||
Q 1069 1734 1069 1313
|
||||
Q 1069 891 1326 650
|
||||
Q 1584 409 2034 409
|
||||
Q 2484 409 2743 651
|
||||
Q 3003 894 3003 1313
|
||||
Q 3003 1734 2745 1975
|
||||
Q 2488 2216 2034 2216
|
||||
z
|
||||
M 1403 2484
|
||||
Q 997 2584 770 2862
|
||||
Q 544 3141 544 3541
|
||||
Q 544 4100 942 4425
|
||||
Q 1341 4750 2034 4750
|
||||
Q 2731 4750 3128 4425
|
||||
Q 3525 4100 3525 3541
|
||||
Q 3525 3141 3298 2862
|
||||
Q 3072 2584 2669 2484
|
||||
Q 3125 2378 3379 2068
|
||||
Q 3634 1759 3634 1313
|
||||
Q 3634 634 3220 271
|
||||
Q 2806 -91 2034 -91
|
||||
Q 1263 -91 848 271
|
||||
Q 434 634 434 1313
|
||||
Q 434 1759 690 2068
|
||||
Q 947 2378 1403 2484
|
||||
z
|
||||
M 1172 3481
|
||||
Q 1172 3119 1398 2916
|
||||
Q 1625 2713 2034 2713
|
||||
Q 2441 2713 2670 2916
|
||||
Q 2900 3119 2900 3481
|
||||
Q 2900 3844 2670 4047
|
||||
Q 2441 4250 2034 4250
|
||||
Q 1625 4250 1398 4047
|
||||
Q 1172 3844 1172 3481
|
||||
z
|
||||
" transform="scale(0.015625)"/>
|
||||
</defs>
|
||||
|
|
@ -2596,10 +2647,10 @@ z
|
|||
<use xlink:href="#DejaVuSans-20" transform="translate(1417.919922 0)"/>
|
||||
<use xlink:href="#DejaVuSans-76" transform="translate(1449.707031 0)"/>
|
||||
<use xlink:href="#DejaVuSans-31" transform="translate(1508.886719 0)"/>
|
||||
<use xlink:href="#DejaVuSans-36" transform="translate(1572.509766 0)"/>
|
||||
<use xlink:href="#DejaVuSans-37" transform="translate(1572.509766 0)"/>
|
||||
<use xlink:href="#DejaVuSans-2e" transform="translate(1636.132812 0)"/>
|
||||
<use xlink:href="#DejaVuSans-30" transform="translate(1667.919922 0)"/>
|
||||
<use xlink:href="#DejaVuSans-39" transform="translate(1731.542969 0)"/>
|
||||
<use xlink:href="#DejaVuSans-33" transform="translate(1667.919922 0)"/>
|
||||
<use xlink:href="#DejaVuSans-38" transform="translate(1731.542969 0)"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="text_15">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 89 KiB |
|
|
@ -209,6 +209,18 @@ article h2[id$="-zusammenfassung"]::before { content: "📌 "; }
|
|||
article a { color: var(--accent); text-decoration: none; }
|
||||
article a:hover { text-decoration: underline; }
|
||||
article a[target="_blank"]::after { content: " \2197"; font-size: .82em; color: var(--cyan); text-decoration: none; }
|
||||
/* Glossar-Links: dezent (gestrichelte Unterstreichung, nicht blau) —
|
||||
sie sollen auffindbar, aber nicht wie Navigationslinks aussehen. */
|
||||
article a.glossar-link {
|
||||
color: inherit;
|
||||
text-decoration: underline dotted var(--accent);
|
||||
text-decoration-thickness: 1px;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
article a.glossar-link:hover {
|
||||
color: var(--accent);
|
||||
text-decoration: underline solid var(--accent);
|
||||
}
|
||||
article p { margin: .75em 0; }
|
||||
article hr { border: 0; border-top: 1px solid var(--border); margin: 2.2em 0; }
|
||||
article figure { margin: 2em 0; text-align: center; }
|
||||
|
|
|
|||
Loading…
Reference in a new issue