Phase 6.1: Chance Constraints - die Zusage "mit 95 % Sicherheit"
Neuer Abschnitt im Kapitel Unsicherheit plus Chance_Constraints.py (74. Programm). Das Kapitel hatte Monte-Carlo, Zweistufigkeit und Worst-Case-Robustheit; die Wahrscheinlichkeitszusage war die fehlende vierte Antwort - und die, nach der das Management tatsaechlich fragt. Setzt Paket 4 aus Verbesserungen_02.md um. Beide Wege an DERSELBEN Instanz (Kraftwerkspark, 500 MW gesicherte Zusage): analytisch als Second-Order-Cone-Bedingung (CLARABEL) und szenariobasiert als Big-M-MILP (SciPy/HiGHS) - beides in einem Prozess, ohne ortools- oder highspy-Import. Drei gemessene Befunde: * Der Mittelwertplan haelt 50,08 %. Kein Fehler, sondern die Definition des Erwartungswerts. * Sicherheit ist konvex bepreist: 56.289 EUR je Prozentpunkt auf dem Weg zu 80 %, 253.848 EUR zwischen 95 und 99 % - das 4,5-fache. Das Programm rechnet die Tabelle selbst aus, statt sie zu behaupten. * Die Zusage gilt nur fuer die unterstellte Verteilung: Der 95-%-Plan haelt gemessen 87,44 %, sobald die Testverteilung eine Kaeltewelle mit Dunkelflaute enthaelt, in der alles zugleich einbricht - auch das Gaskraftwerk. In einer reinen Normalwelt liefert derselbe Plan 94,97 %. Zwei eigene Fehlgriffe, beide durch Messen aufgefallen und korrigiert: Die erste Kostentarierung ergab eine entartete Loesung (alles ins Gaskraftwerk), womit die Kovarianzmatrix wirkungslos war - und gerade sie begruendet die Kegelform. Und der erste Kaelteeinbruch traf nur Wind und Sonne; der SOC-Plan hatte die ohnehin herausgehalten und war zufaellig robust, das Argument trug nicht. Ehrlich berichtet statt geglaettet: Die Szenariomethode ueberanpasst. Ueber zwoelf Laeufe (S = 200, 400, 800) lag die tatsaechliche Quote zwischen 93,14 % und 96,71 %, und die Spanne wurde von S = 400 auf 800 wieder breiter. Beide Solver bestaetigen optimal bei identischen Kosten - echte Ueberanpassung, kein Solverartefakt. Steht als Warnkasten im Abschnitt. Die Laufzeitmessung ist aus der Ausgabe entfernt: Eine Wanduhrzeit ist nie byteidentisch reproduzierbar (2,2 s / 2,3 s zwischen zwei Laeufen) und haette Regel 4 dauerhaft gebrochen. Danach drei Laeufe zeichengleich, und die abgedruckte Ausgabe stimmt mit dem Lauf des extrahierten Programms ueberein. Mitgezogen: Kapitelkopf, Lernziele, Uebersichtstabelle (drei -> vier Ansaetze), Selbsttest, Zusammenfassung, Vorwort-Programmverzeichnis, eine neue Uebungsaufgabe und ihre Loesung in Anhang A. pyproject.toml korrigiert: cvxpy lag in [finance], wird aber von 13 Programmen gebraucht, darunter dreien in diesem Kapitel - jetzt in der Grundausstattung. Es zieht kein highspy nach, der Solverkonflikt bleibt auf [large-scale] beschraenkt. Stand: 293 Abschnitte, 712 Querverweise, 327 Indexmarken, 74 Programme (0 Fehler), 33 pytest-Tests, PDF 725 Seiten. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
62952ba066
commit
6c67e126dd
23 changed files with 9089 additions and 6419 deletions
|
|
@ -103,15 +103,16 @@
|
|||
<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 drei Wege, damit umzugehen — und warum „einfach den Mittelwert einsetzen“ der schlechteste davon ist.</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>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 — und erkennen, wann Rechnen mit Mittelwerten zulässig ist und wann es systematisch danebengeht.</p>
|
||||
<p><strong>Zeitbedarf:</strong> ca. 5,5 Stunden.</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>
|
||||
<p><strong>Programme:</strong><br />
|
||||
<code>Fluch_des_Durchschnitts.py</code><br />
|
||||
<code>Monte_Carlo.py</code><br />
|
||||
<code>Stochastische_Optimierung.py</code><br />
|
||||
<code>Robuste_Optimierung.py</code></p>
|
||||
<code>Robuste_Optimierung.py</code><br />
|
||||
<code>Chance_Constraints.py</code></p>
|
||||
<p><strong>Notebook:</strong> <a href="Notebooks_04/unsicherheit.ipynb">unsicherheit.ipynb</a><br />
|
||||
<a href="https://colab.research.google.com/github/dschlueter/or-mit-python/blob/main/Notebooks_04/unsicherheit.ipynb">In Google Colab öffnen</a></p>
|
||||
</blockquote>
|
||||
|
|
@ -220,7 +221,8 @@ q^{*} = \frac{c_{\text{zu wenig}}}{c_{\text{zu wenig}} + c_{\text{zu viel}}}
|
|||
<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>… begründen, welcher der drei Ansätze für ein gegebenes Problem passt.</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>… 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>
|
||||
</ol>
|
||||
|
|
@ -341,17 +343,18 @@ nicht beim Mittelwert 225 - typisch fuer asymmetrische Kostenfunktionen.</code><
|
|||
<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>
|
||||
<h3 id="die-drei-ansätze-im-überblick">Die drei Ansätze im Überblick</h3>
|
||||
<h3 id="die-vier-ansätze-im-überblick">Die vier Ansätze im Überblick</h3>
|
||||
<figure>
|
||||
<img src="bilder_04/kap09_unsicherheit_ansaetze.svg" alt="Abb. 12.1: Ansätze für Optimierung unter Unsicherheit" />
|
||||
<figcaption aria-hidden="true">Abb. 12.1: Ansätze für Optimierung unter Unsicherheit</figcaption>
|
||||
</figure>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 25%" />
|
||||
<col style="width: 25%" />
|
||||
<col style="width: 25%" />
|
||||
<col style="width: 25%" />
|
||||
<col style="width: 20%" />
|
||||
<col style="width: 20%" />
|
||||
<col style="width: 20%" />
|
||||
<col style="width: 20%" />
|
||||
<col style="width: 20%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="header">
|
||||
|
|
@ -359,6 +362,7 @@ nicht beim Mittelwert 225 - typisch fuer asymmetrische Kostenfunktionen.</code><
|
|||
<th><strong>Monte-Carlo</strong></th>
|
||||
<th><strong>Stochastische Programmierung</strong></th>
|
||||
<th><strong>Robuste Optimierung</strong></th>
|
||||
<th><strong>Chance Constraints</strong></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -367,39 +371,46 @@ nicht beim Mittelwert 225 - typisch fuer asymmetrische Kostenfunktionen.</code><
|
|||
<td>Verteilung</td>
|
||||
<td>Szenarien <strong>mit Wahrscheinlichkeiten</strong></td>
|
||||
<td>nur eine <strong>Menge</strong> möglicher Werte</td>
|
||||
<td>Verteilung <strong>oder</strong> Szenarien</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>Optimiert</td>
|
||||
<td>nichts (bewertet nur)</td>
|
||||
<td><strong>Erwartungswert</strong> über Szenarien</td>
|
||||
<td><strong>Worst Case</strong> in der Menge</td>
|
||||
<td>Kosten bei <strong>zugesicherter Quote</strong></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Typische Frage</td>
|
||||
<td>„Wie riskant ist dieser Plan?“</td>
|
||||
<td>„Was ist im Mittel am besten?“</td>
|
||||
<td>„Was hält auch im schlimmsten Fall?“</td>
|
||||
<td>„Was hält in 95 % der Fälle?“</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>Stärke</td>
|
||||
<td>beliebige Kennzahlen, sehr flexibel</td>
|
||||
<td>nutzt Wahrscheinlichkeiten voll aus</td>
|
||||
<td>keine Verteilungsannahme nötig</td>
|
||||
<td>die Zusage steht <strong>im Modell</strong></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>Schwäche</td>
|
||||
<td>keine Optimierung</td>
|
||||
<td>Wahrscheinlichkeiten müssen stimmen</td>
|
||||
<td>oft übervorsichtig, kostet Ertrag</td>
|
||||
<td>Zusage gilt nur für die unterstellte Verteilung</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>Kapitel</td>
|
||||
<td>9.2</td>
|
||||
<td>9.3</td>
|
||||
<td>9.4</td>
|
||||
<td>Nachzulesen in</td>
|
||||
<td><a href="#sec:unsicherheit-monte-carlo-simulation">Abschnitt 12.4</a></td>
|
||||
<td><a href="#sec:unsicherheit-zweistufige-stochastische-programmierung">Abschnitt 12.5</a></td>
|
||||
<td><a href="#sec:unsicherheit-robuste-optimierung-gegen-den-worst-case">Abschnitt 12.6</a></td>
|
||||
<td><a href="#sec:unsicherheit-chance-constraints">Abschnitt 12.7</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><strong>Der Unterschied zwischen den letzten beiden</strong> ist der, an dem die meisten Diskussionen hängenbleiben. Die robuste Optimierung sagt: <em>„Es darf <strong>nie</strong> schiefgehen“</em> — und zahlt dafür. Die Chance Constraint sagt: <em>„Es darf in höchstens 5 % der Fälle schiefgehen“</em> — und macht damit verhandelbar, was die Sicherheit kosten darf.</p>
|
||||
<hr />
|
||||
<h2 id="sec:unsicherheit-monte-carlo-simulation">12.4 Monte-Carlo-Simulation</h2>
|
||||
<p><strong>Monte-Carlo</strong> heißt schlicht: Ziehe sehr viele Zufallsszenarien, werte für jedes den Plan aus, und betrachte die <strong>Verteilung</strong> der Ergebnisse statt eines einzigen Werts.</p>
|
||||
|
|
@ -828,34 +839,375 @@ deutlich teurer ist als Leerlauf (5 EUR).
|
|||
<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>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:unsicherheit-uebungsaufgaben">12.7 Übungsaufgaben</h2>
|
||||
<h2 id="sec:unsicherheit-chance-constraints">12.7 Wahrscheinlichkeitsbeschränkungen: „mit 95 % Sicherheit“</h2>
|
||||
<p>Die drei bisherigen Ansätze beantworten Fragen, die im Sitzungssaal selten so gestellt werden. „Was ist im Mittel am besten?“ hört ein Vorstand als Ausflucht; „was hält auch im schlimmsten Fall?“ als Einladung, zu viel Geld auszugeben. Gefragt wird fast immer nach einer <strong>Wahrscheinlichkeit</strong>: <em>Mit welcher Sicherheit hält der Plan?</em></p>
|
||||
<p>Die <strong>Wahrscheinlichkeitsbeschränkung</strong> schreibt genau das ins Modell:</p>
|
||||
<p><span class="math display">
|
||||
\mathbb{P}\!\left(\mathbf{a}^\top\mathbf{x} \ge b\right) \ge 1 - \alpha
|
||||
</span></p>
|
||||
<blockquote>
|
||||
<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>
|
||||
<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">
|
||||
\hat{\mathbf{a}}^\top\mathbf{x} \;-\; z_{1-\alpha}\,\lVert \mathbf{L}^\top\mathbf{x}\rVert_2
|
||||
\;\ge\; b
|
||||
\qquad\text{mit}\qquad
|
||||
\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>
|
||||
<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>
|
||||
</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>
|
||||
<p><span class="math display">
|
||||
\begin{aligned}
|
||||
\mathbf{a}_s^\top\mathbf{x} &\ge b - M z_s && \forall s\\
|
||||
\sum_{s} z_s &\le \alpha S\\
|
||||
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>
|
||||
<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>
|
||||
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Chance_Constraints.py</span></span>
|
||||
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="co">"""</span></span>
|
||||
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="co">Kapitel Unsicherheit: Wahrscheinlichkeitsbeschraenkungen.</span></span>
|
||||
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="co">Das Management fragt selten "was ist im Mittel am besten?", sondern "mit</span></span>
|
||||
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="co">welcher Sicherheit haelt der Plan?". Genau das formuliert eine Chance</span></span>
|
||||
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="co">Constraint: P(Versorgung >= Bedarf) >= 1 - alpha.</span></span>
|
||||
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a><span class="co">Gezeigt werden beide Wege dorthin, an derselben Instanz:</span></span>
|
||||
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a><span class="co"> (a) analytisch - unter Normalverteilungsannahme wird daraus eine</span></span>
|
||||
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a><span class="co"> Second-Order-Cone-Bedingung, loesbar mit CVXPY</span></span>
|
||||
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a><span class="co"> (b) szenariobasiert - Big-M mit Binaervariablen, fuer beliebige</span></span>
|
||||
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a><span class="co"> empirische Verteilungen</span></span>
|
||||
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a><span class="co">Und die beiden Messungen, auf die es ankommt: Was kostet ein Prozentpunkt</span></span>
|
||||
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a><span class="co">Versorgungssicherheit - und haelt die Zusage auch dann, wenn die Verteilung</span></span>
|
||||
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a><span class="co">nicht normal ist?</span></span>
|
||||
<span id="cb10-20"><a href="#cb10-20" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-21"><a href="#cb10-21" aria-hidden="true" tabindex="-1"></a><span class="co">Solver: CLARABEL (Kegel) und SciPy/HiGHS (gemischt-ganzzahlig). Weder ortools</span></span>
|
||||
<span id="cb10-22"><a href="#cb10-22" aria-hidden="true" tabindex="-1"></a><span class="co">noch ein direkter highspy-Import, damit alles in einem Prozess laeuft.</span></span>
|
||||
<span id="cb10-23"><a href="#cb10-23" aria-hidden="true" tabindex="-1"></a><span class="co">"""</span></span>
|
||||
<span id="cb10-24"><a href="#cb10-24" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-25"><a href="#cb10-25" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> cvxpy <span class="im">as</span> cp</span>
|
||||
<span id="cb10-26"><a href="#cb10-26" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||||
<span id="cb10-27"><a href="#cb10-27" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.stats <span class="im">import</span> norm</span>
|
||||
<span id="cb10-28"><a href="#cb10-28" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-29"><a href="#cb10-29" aria-hidden="true" tabindex="-1"></a><span class="co"># --- Der Kraftwerkspark ----------------------------------------------------</span></span>
|
||||
<span id="cb10-30"><a href="#cb10-30" aria-hidden="true" tabindex="-1"></a><span class="co"># Die Verfuegbarkeit ist der Anteil, den eine installierte MW im Mittel</span></span>
|
||||
<span id="cb10-31"><a href="#cb10-31" aria-hidden="true" tabindex="-1"></a><span class="co"># wirklich liefert: bei Wind und Sonne klein und stark schwankend, bei Gas und</span></span>
|
||||
<span id="cb10-32"><a href="#cb10-32" aria-hidden="true" tabindex="-1"></a><span class="co"># Biomasse gross und stabil. Die Ausbaugrenze ist der Standort - Flaeche,</span></span>
|
||||
<span id="cb10-33"><a href="#cb10-33" aria-hidden="true" tabindex="-1"></a><span class="co"># Genehmigung, Brennstoffversorgung.</span></span>
|
||||
<span id="cb10-34"><a href="#cb10-34" aria-hidden="true" tabindex="-1"></a>TECHNIK <span class="op">=</span> [<span class="st">"Gaskraftwerk"</span>, <span class="st">"Windpark"</span>, <span class="st">"Solarpark"</span>, <span class="st">"Biomasse"</span>]</span>
|
||||
<span id="cb10-35"><a href="#cb10-35" aria-hidden="true" tabindex="-1"></a>KOSTEN <span class="op">=</span> np.array([<span class="fl">65_000.0</span>, <span class="fl">24_000.0</span>, <span class="fl">12_000.0</span>, <span class="fl">60_000.0</span>]) <span class="co"># EUR je MW und Jahr</span></span>
|
||||
<span id="cb10-36"><a href="#cb10-36" aria-hidden="true" tabindex="-1"></a>VERFUEGBAR <span class="op">=</span> np.array([<span class="fl">0.92</span>, <span class="fl">0.35</span>, <span class="fl">0.18</span>, <span class="fl">0.85</span>])</span>
|
||||
<span id="cb10-37"><a href="#cb10-37" aria-hidden="true" tabindex="-1"></a>STREUUNG <span class="op">=</span> np.array([<span class="fl">0.05</span>, <span class="fl">0.16</span>, <span class="fl">0.10</span>, <span class="fl">0.04</span>])</span>
|
||||
<span id="cb10-38"><a href="#cb10-38" aria-hidden="true" tabindex="-1"></a>GRENZE <span class="op">=</span> np.array([<span class="fl">400.0</span>, <span class="fl">250.0</span>, <span class="fl">600.0</span>, <span class="fl">350.0</span>]) <span class="co"># MW</span></span>
|
||||
<span id="cb10-39"><a href="#cb10-39" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-40"><a href="#cb10-40" aria-hidden="true" tabindex="-1"></a><span class="co"># Wind und Sonne sind leicht gegenlaeufig: Ein Tiefdruckgebiet bringt Wind und</span></span>
|
||||
<span id="cb10-41"><a href="#cb10-41" aria-hidden="true" tabindex="-1"></a><span class="co"># Wolken zugleich. Genau diese Korrelation macht die Bedingung zu einem Kegel</span></span>
|
||||
<span id="cb10-42"><a href="#cb10-42" aria-hidden="true" tabindex="-1"></a><span class="co"># und nicht zu einer Summe unabhaengiger Einzelzuschlaege.</span></span>
|
||||
<span id="cb10-43"><a href="#cb10-43" aria-hidden="true" tabindex="-1"></a>KORRELATION <span class="op">=</span> np.array([</span>
|
||||
<span id="cb10-44"><a href="#cb10-44" aria-hidden="true" tabindex="-1"></a> [<span class="fl">1.00</span>, <span class="fl">0.00</span>, <span class="fl">0.00</span>, <span class="fl">0.05</span>],</span>
|
||||
<span id="cb10-45"><a href="#cb10-45" aria-hidden="true" tabindex="-1"></a> [<span class="fl">0.00</span>, <span class="fl">1.00</span>, <span class="op">-</span><span class="fl">0.25</span>, <span class="fl">0.00</span>],</span>
|
||||
<span id="cb10-46"><a href="#cb10-46" aria-hidden="true" tabindex="-1"></a> [<span class="fl">0.00</span>, <span class="op">-</span><span class="fl">0.25</span>, <span class="fl">1.00</span>, <span class="fl">0.00</span>],</span>
|
||||
<span id="cb10-47"><a href="#cb10-47" aria-hidden="true" tabindex="-1"></a> [<span class="fl">0.05</span>, <span class="fl">0.00</span>, <span class="fl">0.00</span>, <span class="fl">1.00</span>],</span>
|
||||
<span id="cb10-48"><a href="#cb10-48" aria-hidden="true" tabindex="-1"></a>])</span>
|
||||
<span id="cb10-49"><a href="#cb10-49" aria-hidden="true" tabindex="-1"></a>SIGMA <span class="op">=</span> np.diag(STREUUNG) <span class="op">@</span> KORRELATION <span class="op">@</span> np.diag(STREUUNG)</span>
|
||||
<span id="cb10-50"><a href="#cb10-50" aria-hidden="true" tabindex="-1"></a>WURZEL <span class="op">=</span> np.linalg.cholesky(SIGMA) <span class="co"># L mit L @ L.T == SIGMA</span></span>
|
||||
<span id="cb10-51"><a href="#cb10-51" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-52"><a href="#cb10-52" aria-hidden="true" tabindex="-1"></a>BEDARF <span class="op">=</span> <span class="fl">500.0</span> <span class="co"># MW, die gesichert bereitstehen muessen</span></span>
|
||||
<span id="cb10-53"><a href="#cb10-53" aria-hidden="true" tabindex="-1"></a>N <span class="op">=</span> <span class="bu">len</span>(TECHNIK)</span>
|
||||
<span id="cb10-54"><a href="#cb10-54" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-55"><a href="#cb10-55" aria-hidden="true" tabindex="-1"></a><span class="co"># Die Kaeltewelle mit Dunkelflaute: selten, aber sie trifft alles zugleich.</span></span>
|
||||
<span id="cb10-56"><a href="#cb10-56" aria-hidden="true" tabindex="-1"></a><span class="co"># Wind und Sonne brechen fast vollstaendig weg - und, das ist der Punkt, das</span></span>
|
||||
<span id="cb10-57"><a href="#cb10-57" aria-hidden="true" tabindex="-1"></a><span class="co"># Gaskraftwerk liefert ebenfalls weniger, weil bei Frost der Netzdruck faellt.</span></span>
|
||||
<span id="cb10-58"><a href="#cb10-58" aria-hidden="true" tabindex="-1"></a><span class="co"># Eine Kovarianzmatrix mit Korrelationen um null kann das nicht ausdruecken.</span></span>
|
||||
<span id="cb10-59"><a href="#cb10-59" aria-hidden="true" tabindex="-1"></a>P_KAELTEWELLE <span class="op">=</span> <span class="fl">0.08</span></span>
|
||||
<span id="cb10-60"><a href="#cb10-60" aria-hidden="true" tabindex="-1"></a>EINBRUCH <span class="op">=</span> np.array([<span class="fl">0.72</span>, <span class="fl">0.10</span>, <span class="fl">0.15</span>, <span class="fl">0.88</span>])</span>
|
||||
<span id="cb10-61"><a href="#cb10-61" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-62"><a href="#cb10-62" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-63"><a href="#cb10-63" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> mittelwertplan():</span>
|
||||
<span id="cb10-64"><a href="#cb10-64" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Plant mit den Erwartungswerten - ignoriert die Streuung vollstaendig."""</span></span>
|
||||
<span id="cb10-65"><a href="#cb10-65" aria-hidden="true" tabindex="-1"></a> x <span class="op">=</span> cp.Variable(N, nonneg<span class="op">=</span><span class="va">True</span>)</span>
|
||||
<span id="cb10-66"><a href="#cb10-66" aria-hidden="true" tabindex="-1"></a> problem <span class="op">=</span> cp.Problem(cp.Minimize(KOSTEN <span class="op">@</span> x),</span>
|
||||
<span id="cb10-67"><a href="#cb10-67" aria-hidden="true" tabindex="-1"></a> [VERFUEGBAR <span class="op">@</span> x <span class="op">>=</span> BEDARF, x <span class="op"><=</span> GRENZE])</span>
|
||||
<span id="cb10-68"><a href="#cb10-68" aria-hidden="true" tabindex="-1"></a> problem.solve(solver<span class="op">=</span>cp.CLARABEL)</span>
|
||||
<span id="cb10-69"><a href="#cb10-69" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> problem.value, x.value</span>
|
||||
<span id="cb10-70"><a href="#cb10-70" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-71"><a href="#cb10-71" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-72"><a href="#cb10-72" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> chance_constraint_analytisch(alpha):</span>
|
||||
<span id="cb10-73"><a href="#cb10-73" aria-hidden="true" tabindex="-1"></a> <span class="co">"""</span></span>
|
||||
<span id="cb10-74"><a href="#cb10-74" aria-hidden="true" tabindex="-1"></a><span class="co"> P(a^T x >= BEDARF) >= 1 - alpha unter a ~ N(VERFUEGBAR, SIGMA).</span></span>
|
||||
<span id="cb10-75"><a href="#cb10-75" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-76"><a href="#cb10-76" aria-hidden="true" tabindex="-1"></a><span class="co"> Aequivalent zu: VERFUEGBAR^T x - z * ||L^T x||_2 >= BEDARF</span></span>
|
||||
<span id="cb10-77"><a href="#cb10-77" aria-hidden="true" tabindex="-1"></a><span class="co"> mit z = Phi^-1(1 - alpha). Das ist eine Second-Order-Cone-Bedingung: Der</span></span>
|
||||
<span id="cb10-78"><a href="#cb10-78" aria-hidden="true" tabindex="-1"></a><span class="co"> Sicherheitszuschlag ist eine Norm ueber x, kein fester Aufschlag je Anlage.</span></span>
|
||||
<span id="cb10-79"><a href="#cb10-79" aria-hidden="true" tabindex="-1"></a><span class="co"> Deshalb belohnt sie Mischung - zwei gegenlaeufige Quellen schwanken</span></span>
|
||||
<span id="cb10-80"><a href="#cb10-80" aria-hidden="true" tabindex="-1"></a><span class="co"> gemeinsam weniger als jede fuer sich.</span></span>
|
||||
<span id="cb10-81"><a href="#cb10-81" aria-hidden="true" tabindex="-1"></a><span class="co"> """</span></span>
|
||||
<span id="cb10-82"><a href="#cb10-82" aria-hidden="true" tabindex="-1"></a> x <span class="op">=</span> cp.Variable(N, nonneg<span class="op">=</span><span class="va">True</span>)</span>
|
||||
<span id="cb10-83"><a href="#cb10-83" aria-hidden="true" tabindex="-1"></a> z <span class="op">=</span> norm.ppf(<span class="dv">1</span> <span class="op">-</span> alpha)</span>
|
||||
<span id="cb10-84"><a href="#cb10-84" aria-hidden="true" tabindex="-1"></a> bedingung <span class="op">=</span> VERFUEGBAR <span class="op">@</span> x <span class="op">-</span> z <span class="op">*</span> cp.norm(WURZEL.T <span class="op">@</span> x, <span class="dv">2</span>) <span class="op">>=</span> BEDARF</span>
|
||||
<span id="cb10-85"><a href="#cb10-85" aria-hidden="true" tabindex="-1"></a> problem <span class="op">=</span> cp.Problem(cp.Minimize(KOSTEN <span class="op">@</span> x), [bedingung, x <span class="op"><=</span> GRENZE])</span>
|
||||
<span id="cb10-86"><a href="#cb10-86" aria-hidden="true" tabindex="-1"></a> problem.solve(solver<span class="op">=</span>cp.CLARABEL)</span>
|
||||
<span id="cb10-87"><a href="#cb10-87" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> problem.value, x.value</span>
|
||||
<span id="cb10-88"><a href="#cb10-88" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-89"><a href="#cb10-89" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-90"><a href="#cb10-90" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> chance_constraint_szenarien(a, alpha):</span>
|
||||
<span id="cb10-91"><a href="#cb10-91" aria-hidden="true" tabindex="-1"></a> <span class="co">"""</span></span>
|
||||
<span id="cb10-92"><a href="#cb10-92" aria-hidden="true" tabindex="-1"></a><span class="co"> Dieselbe Zusage ohne Verteilungsannahme: Fuer jedes Szenario s sagt eine</span></span>
|
||||
<span id="cb10-93"><a href="#cb10-93" aria-hidden="true" tabindex="-1"></a><span class="co"> Binaervariable z_s, ob es verletzt werden darf.</span></span>
|
||||
<span id="cb10-94"><a href="#cb10-94" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-95"><a href="#cb10-95" aria-hidden="true" tabindex="-1"></a><span class="co"> a_s^T x >= BEDARF - M * z_s fuer alle s</span></span>
|
||||
<span id="cb10-96"><a href="#cb10-96" aria-hidden="true" tabindex="-1"></a><span class="co"> sum_s z_s <= alpha * S</span></span>
|
||||
<span id="cb10-97"><a href="#cb10-97" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-98"><a href="#cb10-98" aria-hidden="true" tabindex="-1"></a><span class="co"> M = BEDARF ist die kleinstmoegliche gueltige Schranke, denn a_s^T x >= 0:</span></span>
|
||||
<span id="cb10-99"><a href="#cb10-99" aria-hidden="true" tabindex="-1"></a><span class="co"> Groesser kann eine Verletzung gar nicht ausfallen. Ein unnoetig grosses M</span></span>
|
||||
<span id="cb10-100"><a href="#cb10-100" aria-hidden="true" tabindex="-1"></a><span class="co"> wuerde die LP-Relaxierung aufweichen und die Suche verlangsamen - die</span></span>
|
||||
<span id="cb10-101"><a href="#cb10-101" aria-hidden="true" tabindex="-1"></a><span class="co"> Big-M-Falle aus dem Kapitel Gemischt-ganzzahlige Optimierung.</span></span>
|
||||
<span id="cb10-102"><a href="#cb10-102" aria-hidden="true" tabindex="-1"></a><span class="co"> """</span></span>
|
||||
<span id="cb10-103"><a href="#cb10-103" aria-hidden="true" tabindex="-1"></a> S <span class="op">=</span> <span class="bu">len</span>(a)</span>
|
||||
<span id="cb10-104"><a href="#cb10-104" aria-hidden="true" tabindex="-1"></a> x <span class="op">=</span> cp.Variable(N, nonneg<span class="op">=</span><span class="va">True</span>)</span>
|
||||
<span id="cb10-105"><a href="#cb10-105" aria-hidden="true" tabindex="-1"></a> z <span class="op">=</span> cp.Variable(S, boolean<span class="op">=</span><span class="va">True</span>)</span>
|
||||
<span id="cb10-106"><a href="#cb10-106" aria-hidden="true" tabindex="-1"></a> problem <span class="op">=</span> cp.Problem(</span>
|
||||
<span id="cb10-107"><a href="#cb10-107" aria-hidden="true" tabindex="-1"></a> cp.Minimize(KOSTEN <span class="op">@</span> x),</span>
|
||||
<span id="cb10-108"><a href="#cb10-108" aria-hidden="true" tabindex="-1"></a> [a <span class="op">@</span> x <span class="op">>=</span> BEDARF <span class="op">-</span> BEDARF <span class="op">*</span> z, cp.<span class="bu">sum</span>(z) <span class="op"><=</span> alpha <span class="op">*</span> S, x <span class="op"><=</span> GRENZE])</span>
|
||||
<span id="cb10-109"><a href="#cb10-109" aria-hidden="true" tabindex="-1"></a> problem.solve(solver<span class="op">=</span>cp.SCIPY)</span>
|
||||
<span id="cb10-110"><a href="#cb10-110" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> problem.value, x.value</span>
|
||||
<span id="cb10-111"><a href="#cb10-111" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-112"><a href="#cb10-112" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-113"><a href="#cb10-113" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> ziehe_wetter(anzahl, seed):</span>
|
||||
<span id="cb10-114"><a href="#cb10-114" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Mischverteilung: normales Wetter, mit P_KAELTEWELLE ein Einbruch."""</span></span>
|
||||
<span id="cb10-115"><a href="#cb10-115" aria-hidden="true" tabindex="-1"></a> rng <span class="op">=</span> np.random.default_rng(seed)</span>
|
||||
<span id="cb10-116"><a href="#cb10-116" aria-hidden="true" tabindex="-1"></a> a <span class="op">=</span> rng.multivariate_normal(VERFUEGBAR, SIGMA, size<span class="op">=</span>anzahl)</span>
|
||||
<span id="cb10-117"><a href="#cb10-117" aria-hidden="true" tabindex="-1"></a> getroffen <span class="op">=</span> rng.random(anzahl) <span class="op"><</span> P_KAELTEWELLE</span>
|
||||
<span id="cb10-118"><a href="#cb10-118" aria-hidden="true" tabindex="-1"></a> a[getroffen] <span class="op">*=</span> EINBRUCH</span>
|
||||
<span id="cb10-119"><a href="#cb10-119" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> np.clip(a, <span class="fl">0.0</span>, <span class="fl">1.0</span>)</span>
|
||||
<span id="cb10-120"><a href="#cb10-120" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-121"><a href="#cb10-121" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-122"><a href="#cb10-122" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> sicherheit(x, a):</span>
|
||||
<span id="cb10-123"><a href="#cb10-123" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Anteil der Szenarien, in denen der Plan den Bedarf deckt."""</span></span>
|
||||
<span id="cb10-124"><a href="#cb10-124" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="bu">float</span>(np.mean(a <span class="op">@</span> x <span class="op">>=</span> BEDARF))</span>
|
||||
<span id="cb10-125"><a href="#cb10-125" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-126"><a href="#cb10-126" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-127"><a href="#cb10-127" aria-hidden="true" tabindex="-1"></a>KOPF <span class="op">=</span> (<span class="ss">f"</span><span class="sc">{</span><span class="st">'Plan'</span><span class="sc">:<20}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Kosten (EUR)'</span><span class="sc">:>13}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Gas'</span><span class="sc">:>4}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Wind'</span><span class="sc">:>4}</span><span class="ss"> "</span></span>
|
||||
<span id="cb10-128"><a href="#cb10-128" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="st">'Sol'</span><span class="sc">:>4}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Bio'</span><span class="sc">:>4}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Normalwelt'</span><span class="sc">:>11}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'echte Welt'</span><span class="sc">:>11}</span><span class="ss">"</span>)</span>
|
||||
<span id="cb10-129"><a href="#cb10-129" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-130"><a href="#cb10-130" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-131"><a href="#cb10-131" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> zeile(name, kosten, x, in_normal, in_echt):</span>
|
||||
<span id="cb10-132"><a href="#cb10-132" aria-hidden="true" tabindex="-1"></a> mix <span class="op">=</span> <span class="st">" "</span>.join(<span class="ss">f"</span><span class="sc">{</span>w<span class="sc">:4.0f}</span><span class="ss">"</span> <span class="cf">for</span> w <span class="kw">in</span> x)</span>
|
||||
<span id="cb10-133"><a href="#cb10-133" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> (<span class="ss">f"</span><span class="sc">{</span>name<span class="sc">:<20}</span><span class="ss"> </span><span class="sc">{</span>kosten<span class="sc">:>13,.0f}</span><span class="ss"> </span><span class="sc">{</span>mix<span class="sc">}</span><span class="ss"> "</span></span>
|
||||
<span id="cb10-134"><a href="#cb10-134" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>in_normal <span class="op">*</span> <span class="dv">100</span><span class="sc">:>9.2f}</span><span class="ss"> % </span><span class="sc">{</span>in_echt <span class="op">*</span> <span class="dv">100</span><span class="sc">:>9.2f}</span><span class="ss"> %"</span>)</span>
|
||||
<span id="cb10-135"><a href="#cb10-135" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-136"><a href="#cb10-136" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-137"><a href="#cb10-137" 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="cb10-138"><a href="#cb10-138" 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>
|
||||
<span id="cb10-139"><a href="#cb10-139" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" WAHRSCHEINLICHKEITSBESCHRAENKUNGEN IM KRAFTWERKSPARK"</span>)</span>
|
||||
<span id="cb10-140"><a href="#cb10-140" 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>
|
||||
<span id="cb10-141"><a href="#cb10-141" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Gesichert bereitzustellen: </span><span class="sc">{</span>BEDARF<span class="sc">:.0f}</span><span class="ss"> MW</span><span class="ch">\n</span><span class="ss">"</span>)</span>
|
||||
<span id="cb10-142"><a href="#cb10-142" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="sc">{</span><span class="st">'Technologie'</span><span class="sc">:<14}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'EUR/MW'</span><span class="sc">:>8}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'verfuegbar'</span><span class="sc">:>11}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Streuung'</span><span class="sc">:>9}</span><span class="ss"> "</span></span>
|
||||
<span id="cb10-143"><a href="#cb10-143" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="st">'Grenze'</span><span class="sc">:>8}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'EUR je erw. MW'</span><span class="sc">:>15}</span><span class="ss">"</span>)</span>
|
||||
<span id="cb10-144"><a href="#cb10-144" 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>
|
||||
<span id="cb10-145"><a href="#cb10-145" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> i, name <span class="kw">in</span> <span class="bu">enumerate</span>(TECHNIK):</span>
|
||||
<span id="cb10-146"><a href="#cb10-146" 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>KOSTEN[i]<span class="sc">:>8,.0f}</span><span class="ss"> </span><span class="sc">{</span>VERFUEGBAR[i]<span class="sc">:>10.2f}</span><span class="ss"> "</span></span>
|
||||
<span id="cb10-147"><a href="#cb10-147" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>STREUUNG[i]<span class="sc">:>8.2f}</span><span class="ss"> </span><span class="sc">{</span>GRENZE[i]<span class="sc">:>7.0f}</span><span class="ss"> "</span></span>
|
||||
<span id="cb10-148"><a href="#cb10-148" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>KOSTEN[i] <span class="op">/</span> VERFUEGBAR[i]<span class="sc">:>15,.0f}</span><span class="ss">"</span>)</span>
|
||||
<span id="cb10-149"><a href="#cb10-149" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss">Vollausbau liefert im Mittel </span><span class="sc">{</span>VERFUEGBAR <span class="op">@</span> GRENZE<span class="sc">:.0f}</span><span class="ss"> MW, "</span></span>
|
||||
<span id="cb10-150"><a href="#cb10-150" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"in der Kaeltewelle </span><span class="sc">{</span>(VERFUEGBAR <span class="op">*</span> EINBRUCH) <span class="op">@</span> GRENZE<span class="sc">:.0f}</span><span class="ss"> MW."</span>)</span>
|
||||
<span id="cb10-151"><a href="#cb10-151" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-152"><a href="#cb10-152" aria-hidden="true" tabindex="-1"></a> <span class="co"># Zwei grosse, unabhaengige Testmengen. An ihnen wird JEDER Plan gemessen -</span></span>
|
||||
<span id="cb10-153"><a href="#cb10-153" aria-hidden="true" tabindex="-1"></a> <span class="co"># einmal in der unterstellten Normalwelt, einmal in der echten Verteilung.</span></span>
|
||||
<span id="cb10-154"><a href="#cb10-154" aria-hidden="true" tabindex="-1"></a> echt <span class="op">=</span> ziehe_wetter(<span class="dv">200_000</span>, seed<span class="op">=</span><span class="dv">771</span>)</span>
|
||||
<span id="cb10-155"><a href="#cb10-155" aria-hidden="true" tabindex="-1"></a> normalwelt <span class="op">=</span> np.random.default_rng(<span class="dv">4711</span>).multivariate_normal(</span>
|
||||
<span id="cb10-156"><a href="#cb10-156" aria-hidden="true" tabindex="-1"></a> VERFUEGBAR, SIGMA, size<span class="op">=</span><span class="dv">200_000</span>)</span>
|
||||
<span id="cb10-157"><a href="#cb10-157" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-158"><a href="#cb10-158" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">"</span> <span class="op">+</span> <span class="st">"="</span> <span class="op">*</span> <span class="dv">78</span>)</span>
|
||||
<span id="cb10-159"><a href="#cb10-159" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" (1) Mittelwertplan und Chance Constraints im Vergleich"</span>)</span>
|
||||
<span id="cb10-160"><a href="#cb10-160" 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>
|
||||
<span id="cb10-161"><a href="#cb10-161" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(KOPF)</span>
|
||||
<span id="cb10-162"><a href="#cb10-162" 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>
|
||||
<span id="cb10-163"><a href="#cb10-163" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-164"><a href="#cb10-164" aria-hidden="true" tabindex="-1"></a> k_mittel, x_mittel <span class="op">=</span> mittelwertplan()</span>
|
||||
<span id="cb10-165"><a href="#cb10-165" aria-hidden="true" tabindex="-1"></a> stufen <span class="op">=</span> [(<span class="st">"Mittelwert"</span>, k_mittel, sicherheit(x_mittel, normalwelt))]</span>
|
||||
<span id="cb10-166"><a href="#cb10-166" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(zeile(<span class="st">"Mittelwert"</span>, k_mittel, x_mittel,</span>
|
||||
<span id="cb10-167"><a href="#cb10-167" aria-hidden="true" tabindex="-1"></a> sicherheit(x_mittel, normalwelt), sicherheit(x_mittel, echt)))</span>
|
||||
<span id="cb10-168"><a href="#cb10-168" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-169"><a href="#cb10-169" aria-hidden="true" tabindex="-1"></a> plaene <span class="op">=</span> {}</span>
|
||||
<span id="cb10-170"><a href="#cb10-170" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> alpha <span class="kw">in</span> (<span class="fl">0.20</span>, <span class="fl">0.10</span>, <span class="fl">0.05</span>, <span class="fl">0.01</span>):</span>
|
||||
<span id="cb10-171"><a href="#cb10-171" aria-hidden="true" tabindex="-1"></a> kosten, x <span class="op">=</span> chance_constraint_analytisch(alpha)</span>
|
||||
<span id="cb10-172"><a href="#cb10-172" aria-hidden="true" tabindex="-1"></a> plaene[alpha] <span class="op">=</span> (kosten, x)</span>
|
||||
<span id="cb10-173"><a href="#cb10-173" aria-hidden="true" tabindex="-1"></a> quote_normal <span class="op">=</span> sicherheit(x, normalwelt)</span>
|
||||
<span id="cb10-174"><a href="#cb10-174" aria-hidden="true" tabindex="-1"></a> stufen.append((<span class="ss">f"Zusage </span><span class="sc">{</span>(<span class="dv">1</span> <span class="op">-</span> alpha) <span class="op">*</span> <span class="dv">100</span><span class="sc">:.0f}</span><span class="ss"> %"</span>, kosten, quote_normal))</span>
|
||||
<span id="cb10-175"><a href="#cb10-175" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(zeile(<span class="ss">f"Zusage </span><span class="sc">{</span>(<span class="dv">1</span> <span class="op">-</span> alpha) <span class="op">*</span> <span class="dv">100</span><span class="sc">:.0f}</span><span class="ss"> %"</span>, kosten, x,</span>
|
||||
<span id="cb10-176"><a href="#cb10-176" aria-hidden="true" tabindex="-1"></a> quote_normal, sicherheit(x, echt)))</span>
|
||||
<span id="cb10-177"><a href="#cb10-177" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-178"><a href="#cb10-178" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st"> In der Normalwelt trifft jede Zusage ihren Wert - das Verfahren"</span>)</span>
|
||||
<span id="cb10-179"><a href="#cb10-179" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" rechnet richtig. Die Spalte 'echte Welt' kommt in Teil (3)."</span>)</span>
|
||||
<span id="cb10-180"><a href="#cb10-180" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-181"><a href="#cb10-181" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">"</span> <span class="op">+</span> <span class="st">"="</span> <span class="op">*</span> <span class="dv">78</span>)</span>
|
||||
<span id="cb10-182"><a href="#cb10-182" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" (2) Was kostet ein Prozentpunkt Versorgungssicherheit?"</span>)</span>
|
||||
<span id="cb10-183"><a href="#cb10-183" 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>
|
||||
<span id="cb10-184"><a href="#cb10-184" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="sc">{</span><span class="st">'von -> nach'</span><span class="sc">:<26}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Prozentpunkte'</span><span class="sc">:>13}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Mehrkosten'</span><span class="sc">:>13}</span><span class="ss"> "</span></span>
|
||||
<span id="cb10-185"><a href="#cb10-185" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="st">'EUR je Punkt'</span><span class="sc">:>13}</span><span class="ss">"</span>)</span>
|
||||
<span id="cb10-186"><a href="#cb10-186" 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>
|
||||
<span id="cb10-187"><a href="#cb10-187" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> (n1, k1, q1), (n2, k2, q2) <span class="kw">in</span> <span class="bu">zip</span>(stufen, stufen[<span class="dv">1</span>:]):</span>
|
||||
<span id="cb10-188"><a href="#cb10-188" aria-hidden="true" tabindex="-1"></a> d_punkte <span class="op">=</span> (q2 <span class="op">-</span> q1) <span class="op">*</span> <span class="dv">100</span></span>
|
||||
<span id="cb10-189"><a href="#cb10-189" aria-hidden="true" tabindex="-1"></a> d_kosten <span class="op">=</span> k2 <span class="op">-</span> k1</span>
|
||||
<span id="cb10-190"><a href="#cb10-190" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="sc">{</span>n1 <span class="op">+</span> <span class="st">' -> '</span> <span class="op">+</span> n2<span class="sc">:<26}</span><span class="ss"> </span><span class="sc">{</span>d_punkte<span class="sc">:>13.2f}</span><span class="ss"> </span><span class="sc">{</span>d_kosten<span class="sc">:>13,.0f}</span><span class="ss"> "</span></span>
|
||||
<span id="cb10-191"><a href="#cb10-191" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>d_kosten <span class="op">/</span> d_punkte<span class="sc">:>13,.0f}</span><span class="ss">"</span>)</span>
|
||||
<span id="cb10-192"><a href="#cb10-192" aria-hidden="true" tabindex="-1"></a> erst <span class="op">=</span> (stufen[<span class="dv">1</span>][<span class="dv">1</span>] <span class="op">-</span> stufen[<span class="dv">0</span>][<span class="dv">1</span>]) <span class="op">/</span> ((stufen[<span class="dv">1</span>][<span class="dv">2</span>] <span class="op">-</span> stufen[<span class="dv">0</span>][<span class="dv">2</span>]) <span class="op">*</span> <span class="dv">100</span>)</span>
|
||||
<span id="cb10-193"><a href="#cb10-193" aria-hidden="true" tabindex="-1"></a> letzt <span class="op">=</span> (stufen[<span class="op">-</span><span class="dv">1</span>][<span class="dv">1</span>] <span class="op">-</span> stufen[<span class="op">-</span><span class="dv">2</span>][<span class="dv">1</span>]) <span class="op">/</span> ((stufen[<span class="op">-</span><span class="dv">1</span>][<span class="dv">2</span>] <span class="op">-</span> stufen[<span class="op">-</span><span class="dv">2</span>][<span class="dv">2</span>]) <span class="op">*</span> <span class="dv">100</span>)</span>
|
||||
<span id="cb10-194"><a href="#cb10-194" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss"> Der letzte Prozentpunkt kostet das </span><span class="sc">{</span>letzt <span class="op">/</span> erst<span class="sc">:.1f}</span><span class="ss">-fache des ersten."</span>)</span>
|
||||
<span id="cb10-195"><a href="#cb10-195" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Sicherheit ist konvex bepreist - genau deshalb muss jemand"</span>)</span>
|
||||
<span id="cb10-196"><a href="#cb10-196" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" entscheiden, wie viel davon das Unternehmen kaufen will."</span>)</span>
|
||||
<span id="cb10-197"><a href="#cb10-197" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-198"><a href="#cb10-198" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">"</span> <span class="op">+</span> <span class="st">"="</span> <span class="op">*</span> <span class="dv">78</span>)</span>
|
||||
<span id="cb10-199"><a href="#cb10-199" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" (3) Und wenn die Verteilung nicht normal ist?"</span>)</span>
|
||||
<span id="cb10-200"><a href="#cb10-200" 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>
|
||||
<span id="cb10-201"><a href="#cb10-201" aria-hidden="true" tabindex="-1"></a> k_soc, x_soc <span class="op">=</span> plaene[<span class="fl">0.05</span>]</span>
|
||||
<span id="cb10-202"><a href="#cb10-202" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Die echte Welt kennt die Kaeltewelle mit Dunkelflaute: in "</span></span>
|
||||
<span id="cb10-203"><a href="#cb10-203" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>P_KAELTEWELLE <span class="op">*</span> <span class="dv">100</span><span class="sc">:.0f}</span><span class="ss"> % der Faelle liefern"</span>)</span>
|
||||
<span id="cb10-204"><a href="#cb10-204" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Wind </span><span class="sc">{</span>EINBRUCH[<span class="dv">1</span>] <span class="op">*</span> <span class="dv">100</span><span class="sc">:.0f}</span><span class="ss"> %, Sonne </span><span class="sc">{</span>EINBRUCH[<span class="dv">2</span>] <span class="op">*</span> <span class="dv">100</span><span class="sc">:.0f}</span><span class="ss"> % "</span></span>
|
||||
<span id="cb10-205"><a href="#cb10-205" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"und - entscheidend - auch das Gaskraftwerk nur "</span></span>
|
||||
<span id="cb10-206"><a href="#cb10-206" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>EINBRUCH[<span class="dv">0</span>] <span class="op">*</span> <span class="dv">100</span><span class="sc">:.0f}</span><span class="ss"> %"</span>)</span>
|
||||
<span id="cb10-207"><a href="#cb10-207" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"des Ueblichen. Alles bricht gleichzeitig ein.</span><span class="ch">\n</span><span class="st">"</span>)</span>
|
||||
<span id="cb10-208"><a href="#cb10-208" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-209"><a href="#cb10-209" aria-hidden="true" tabindex="-1"></a> a_bau <span class="op">=</span> ziehe_wetter(<span class="dv">400</span>, seed<span class="op">=</span><span class="dv">20260908</span>)</span>
|
||||
<span id="cb10-210"><a href="#cb10-210" aria-hidden="true" tabindex="-1"></a> k_sz, x_sz <span class="op">=</span> chance_constraint_szenarien(a_bau, <span class="fl">0.05</span>)</span>
|
||||
<span id="cb10-211"><a href="#cb10-211" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-212"><a href="#cb10-212" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(KOPF)</span>
|
||||
<span id="cb10-213"><a href="#cb10-213" 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>
|
||||
<span id="cb10-214"><a href="#cb10-214" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(zeile(<span class="st">"SOC, Zusage 95 %"</span>, k_soc, x_soc,</span>
|
||||
<span id="cb10-215"><a href="#cb10-215" aria-hidden="true" tabindex="-1"></a> sicherheit(x_soc, normalwelt), sicherheit(x_soc, echt)))</span>
|
||||
<span id="cb10-216"><a href="#cb10-216" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(zeile(<span class="st">"Szenarien, 95 %"</span>, k_sz, x_sz,</span>
|
||||
<span id="cb10-217"><a href="#cb10-217" aria-hidden="true" tabindex="-1"></a> sicherheit(x_sz, normalwelt), sicherheit(x_sz, echt)))</span>
|
||||
<span id="cb10-218"><a href="#cb10-218" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-219"><a href="#cb10-219" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss"> Der SOC-Plan verspricht 95 % und haelt "</span></span>
|
||||
<span id="cb10-220"><a href="#cb10-220" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>sicherheit(x_soc, echt) <span class="op">*</span> <span class="dv">100</span><span class="sc">:.1f}</span><span class="ss"> %. Nicht das Verfahren ist"</span>)</span>
|
||||
<span id="cb10-221"><a href="#cb10-221" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" falsch, sondern die Annahme: In der Normalwelt liefert derselbe"</span>)</span>
|
||||
<span id="cb10-222"><a href="#cb10-222" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Plan </span><span class="sc">{</span>sicherheit(x_soc, normalwelt) <span class="op">*</span> <span class="dv">100</span><span class="sc">:.1f}</span><span class="ss"> %."</span>)</span>
|
||||
<span id="cb10-223"><a href="#cb10-223" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss"> Der Szenarioplan (</span><span class="sc">{</span><span class="bu">len</span>(a_bau)<span class="sc">}</span><span class="ss"> Szenarien, </span><span class="sc">{</span><span class="bu">len</span>(a_bau)<span class="sc">}</span><span class="ss"> "</span></span>
|
||||
<span id="cb10-224"><a href="#cb10-224" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"Binaervariablen) kommt auf"</span>)</span>
|
||||
<span id="cb10-225"><a href="#cb10-225" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span>sicherheit(x_sz, echt) <span class="op">*</span> <span class="dv">100</span><span class="sc">:.1f}</span><span class="ss"> % - und kostet dafuer "</span></span>
|
||||
<span id="cb10-226"><a href="#cb10-226" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>(k_sz <span class="op">/</span> k_soc <span class="op">-</span> <span class="dv">1</span>) <span class="op">*</span> <span class="dv">100</span><span class="sc">:+.1f}</span><span class="ss"> %. Er kauft keine Windkraft mehr:"</span>)</span>
|
||||
<span id="cb10-227"><a href="#cb10-227" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Was im Ernstfall ausfaellt, hilft der Zusage nicht."</span>)</span>
|
||||
<span id="cb10-228"><a href="#cb10-228" 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>
|
||||
<p><strong>Ausgabe:</strong></p>
|
||||
<pre><code>==============================================================================
|
||||
WAHRSCHEINLICHKEITSBESCHRAENKUNGEN IM KRAFTWERKSPARK
|
||||
==============================================================================
|
||||
Gesichert bereitzustellen: 500 MW
|
||||
|
||||
Technologie EUR/MW verfuegbar Streuung Grenze EUR je erw. MW
|
||||
------------------------------------------------------------------------------
|
||||
Gaskraftwerk 65,000 0.92 0.05 400 70,652
|
||||
Windpark 24,000 0.35 0.16 250 68,571
|
||||
Solarpark 12,000 0.18 0.10 600 66,667
|
||||
Biomasse 60,000 0.85 0.04 350 70,588
|
||||
|
||||
Vollausbau liefert im Mittel 861 MW, in der Kaeltewelle 552 MW.
|
||||
|
||||
==============================================================================
|
||||
(1) Mittelwertplan und Chance Constraints im Vergleich
|
||||
==============================================================================
|
||||
Plan Kosten (EUR) Gas Wind Sol Bio Normalwelt echte Welt
|
||||
------------------------------------------------------------------------------
|
||||
Mittelwert 34,694,565 8 250 600 350 50.08 % 46.18 %
|
||||
Zusage 80 % 36,382,277 226 25 44 343 80.06 % 73.61 %
|
||||
Zusage 90 % 36,994,777 233 20 35 349 89.99 % 82.82 %
|
||||
Zusage 95 % 37,514,307 241 19 31 350 94.97 % 87.44 %
|
||||
Zusage 99 % 38,529,698 258 18 28 350 98.97 % 91.05 %
|
||||
|
||||
In der Normalwelt trifft jede Zusage ihren Wert - das Verfahren
|
||||
rechnet richtig. Die Spalte 'echte Welt' kommt in Teil (3).
|
||||
|
||||
==============================================================================
|
||||
(2) Was kostet ein Prozentpunkt Versorgungssicherheit?
|
||||
==============================================================================
|
||||
von -> nach Prozentpunkte Mehrkosten EUR je Punkt
|
||||
------------------------------------------------------------------------------
|
||||
Mittelwert -> Zusage 80 % 29.98 1,687,712 56,289
|
||||
Zusage 80 % -> Zusage 90 % 9.93 612,500 61,685
|
||||
Zusage 90 % -> Zusage 95 % 4.98 519,530 104,365
|
||||
Zusage 95 % -> Zusage 99 % 4.00 1,015,390 253,848
|
||||
|
||||
Der letzte Prozentpunkt kostet das 4.5-fache des ersten.
|
||||
Sicherheit ist konvex bepreist - genau deshalb muss jemand
|
||||
entscheiden, wie viel davon das Unternehmen kaufen will.
|
||||
|
||||
==============================================================================
|
||||
(3) Und wenn die Verteilung nicht normal ist?
|
||||
==============================================================================
|
||||
Die echte Welt kennt die Kaeltewelle mit Dunkelflaute: in 8 % der Faelle liefern
|
||||
Wind 10 %, Sonne 15 % und - entscheidend - auch das Gaskraftwerk nur 72 %
|
||||
des Ueblichen. Alles bricht gleichzeitig ein.
|
||||
|
||||
Plan Kosten (EUR) Gas Wind Sol Bio Normalwelt echte Welt
|
||||
------------------------------------------------------------------------------
|
||||
SOC, Zusage 95 % 37,514,307 241 19 31 350 94.97 % 87.44 %
|
||||
Szenarien, 95 % 43,760,709 350 0 0 350 100.00 % 94.84 %
|
||||
|
||||
Der SOC-Plan verspricht 95 % und haelt 87.4 %. Nicht das Verfahren ist
|
||||
falsch, sondern die Annahme: In der Normalwelt liefert derselbe
|
||||
Plan 95.0 %.
|
||||
|
||||
Der Szenarioplan (400 Szenarien, 400 Binaervariablen) kommt auf
|
||||
94.8 % - und kostet dafuer +16.7 %. Er kauft keine Windkraft mehr:
|
||||
Was im Ernstfall ausfaellt, hilft der Zusage nicht.
|
||||
==============================================================================</code></pre>
|
||||
<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>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>
|
||||
</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>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:unsicherheit-uebungsaufgaben">12.8 Übungsaufgaben</h2>
|
||||
<blockquote>
|
||||
<p>Lösungen: <a href="anhang-loesungen.html#sec:loesungen-unsicherheit">Abschnitt A.12</a>.</p>
|
||||
</blockquote>
|
||||
<p><strong>Aufgabe 12.1 ⭐ — Fluch des Durchschnitts erkennen.</strong> Ein Bauunternehmer plant mit der <em>durchschnittlichen</em> Bauzeit von 8 Monaten. Warum ist die <em>erwartete</em> Fertigstellung trotzdem später als 8 Monate, wenn Verzögerungen wahrscheinlicher sind als Beschleunigungen? Nennen Sie zwei weitere Alltagsbeispiele.</p>
|
||||
<p><strong>Aufgabe 12.2 ⭐ — Ansatz wählen.</strong> Welcher der drei 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?</p>
|
||||
<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.6 ⭐⭐⭐ — 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>
|
||||
<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 />
|
||||
<h2 id="sec:unsicherheit-denkfehler">12.8 Finde den Denkfehler</h2>
|
||||
<h2 id="sec:unsicherheit-denkfehler">12.9 Finde den Denkfehler</h2>
|
||||
<div class="card card-denkfehler">
|
||||
<blockquote>
|
||||
<p><strong>🐛 Finde den Denkfehler 9.1: Warum jedes Projekt zu spät fertig wird</strong></p>
|
||||
<p>Ein Projektleiter plant eine Umbaumaßnahme. Fünf Gewerke arbeiten <strong>parallel</strong> und unabhängig voneinander; fertig ist der Umbau, wenn das letzte fertig ist. Für jedes Gewerk liegt eine Schätzung vor: mindestens 6 Tage, wahrscheinlich 10, im schlechtesten Fall 18.</p>
|
||||
<p>Er rechnet: <em>„Jedes Gewerk braucht im Mittel <span class="math inline">(6 + 10 + 18)/3 = 11{,}3</span> Tage. Alle laufen gleichzeitig. Also ist der Umbau nach 11,3 Tagen fertig — ich plane großzügig 12 ein.“</em></p>
|
||||
<p>Nachgerechnet mit 200 000 simulierten Umbauten:</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><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||||
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>rng <span class="op">=</span> np.random.default_rng(<span class="dv">3</span>)</span>
|
||||
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>dauer <span class="op">=</span> rng.triangular(<span class="dv">6</span>, <span class="dv">10</span>, <span class="dv">18</span>, size<span class="op">=</span>(<span class="dv">200_000</span>, <span class="dv">5</span>)) <span class="co"># 5 Gewerke, je eine Schaetzung</span></span>
|
||||
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>projekt <span class="op">=</span> dauer.<span class="bu">max</span>(axis<span class="op">=</span><span class="dv">1</span>) <span class="co"># fertig, wenn das LETZTE fertig ist</span></span>
|
||||
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"Mittelwert einer Einzeldauer: </span><span class="sc">{</span>dauer<span class="sc">.</span>mean()<span class="sc">:.2f}</span><span class="ss"> Tage"</span>)</span>
|
||||
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"Tatsaechliche Projektdauer: </span><span class="sc">{</span>projekt<span class="sc">.</span>mean()<span class="sc">:.2f}</span><span class="ss"> Tage"</span>)</span>
|
||||
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"90-%-Quantil: </span><span class="sc">{</span>np<span class="sc">.</span>quantile(projekt, <span class="fl">0.9</span>)<span class="sc">:.2f}</span><span class="ss"> Tage"</span>)</span>
|
||||
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"Anteil ueber 11,34 Tage: </span><span class="sc">{</span>(projekt <span class="op">></span> <span class="fl">11.34</span>)<span class="sc">.</span>mean() <span class="op">*</span> <span class="dv">100</span><span class="sc">:.1f}</span><span class="ss"> %"</span>)</span></code></pre></div>
|
||||
<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="im">import</span> numpy <span class="im">as</span> np</span>
|
||||
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>rng <span class="op">=</span> np.random.default_rng(<span class="dv">3</span>)</span>
|
||||
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>dauer <span class="op">=</span> rng.triangular(<span class="dv">6</span>, <span class="dv">10</span>, <span class="dv">18</span>, size<span class="op">=</span>(<span class="dv">200_000</span>, <span class="dv">5</span>)) <span class="co"># 5 Gewerke, je eine Schaetzung</span></span>
|
||||
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>projekt <span class="op">=</span> dauer.<span class="bu">max</span>(axis<span class="op">=</span><span class="dv">1</span>) <span class="co"># fertig, wenn das LETZTE fertig ist</span></span>
|
||||
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"Mittelwert einer Einzeldauer: </span><span class="sc">{</span>dauer<span class="sc">.</span>mean()<span class="sc">:.2f}</span><span class="ss"> Tage"</span>)</span>
|
||||
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"Tatsaechliche Projektdauer: </span><span class="sc">{</span>projekt<span class="sc">.</span>mean()<span class="sc">:.2f}</span><span class="ss"> Tage"</span>)</span>
|
||||
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"90-%-Quantil: </span><span class="sc">{</span>np<span class="sc">.</span>quantile(projekt, <span class="fl">0.9</span>)<span class="sc">:.2f}</span><span class="ss"> Tage"</span>)</span>
|
||||
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"Anteil ueber 11,34 Tage: </span><span class="sc">{</span>(projekt <span class="op">></span> <span class="fl">11.34</span>)<span class="sc">.</span>mean() <span class="op">*</span> <span class="dv">100</span><span class="sc">:.1f}</span><span class="ss"> %"</span>)</span></code></pre></div>
|
||||
<p><strong>Ausgabe:</strong></p>
|
||||
<pre><code>Mittelwert einer Einzeldauer: 11.34 Tage
|
||||
Tatsaechliche Projektdauer: 14.38 Tage
|
||||
|
|
@ -869,7 +1221,7 @@ Anteil ueber 11,34 Tage: 95.5 %</code></pre>
|
|||
<p><strong>🎯 Merksatz</strong> Der Fluch des Durchschnitts hat zwei Gesichter. Beim Ersatzteil aus <a href="#sec:unsicherheit-schnellstart">Abschnitt 12.1</a> führt der Mittelwert in die Irre, weil die <strong>Kosten</strong> asymmetrisch sind. Hier führt er in die Irre, weil die <strong>Verknüpfung</strong> asymmetrisch ist: Ein Gewerk, das früher fertig wird, hilft niemandem — ein Gewerk, das sich verspätet, verzögert alles. Beide Male gilt: <em>Der Mittelwert einer Funktion ist nicht die Funktion des Mittelwerts.</em></p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="sec:unsicherheit-quiz">12.9 Micro-Quiz</h2>
|
||||
<h2 id="sec:unsicherheit-quiz">12.10 Micro-Quiz</h2>
|
||||
<div class="card card-quiz">
|
||||
<blockquote>
|
||||
<p><strong>❓ Micro-Quiz 9: Drei Fragen zum Selbstcheck</strong></p>
|
||||
|
|
@ -880,7 +1232,7 @@ Anteil ueber 11,34 Tage: 95.5 %</code></pre>
|
|||
</blockquote>
|
||||
</div>
|
||||
<hr />
|
||||
<h2 id="sec:unsicherheit-selbsttest">12.10 Selbsttest</h2>
|
||||
<h2 id="sec:unsicherheit-selbsttest">12.11 Selbsttest</h2>
|
||||
<blockquote>
|
||||
<p>Antworten: <a href="anhang-loesungen.html#selbsttest-loesung-unsicherheit">Anhang A</a>.</p>
|
||||
</blockquote>
|
||||
|
|
@ -890,9 +1242,11 @@ Anteil ueber 11,34 Tage: 95.5 %</code></pre>
|
|||
<li>Was misst der EVPI, und wofür ist er praktisch nützlich?</li>
|
||||
<li>Warum braucht robuste Optimierung keine Wahrscheinlichkeiten?</li>
|
||||
<li>Wie macht man ein Min-Max-Problem mit Box-Unsicherheit lösbar?</li>
|
||||
<li>Warum wird aus <span class="math inline">\mathbb{P}(\mathbf{a}^\top\mathbf{x} \ge b) \ge 1-\alpha</span> unter Normalverteilung eine <strong>Norm</strong> und nicht ein fester Zuschlag je Variable?</li>
|
||||
<li>Ein Plan mit Chance Constraint verspricht 95 % und hält gemessen 87 %. Woran liegt das — und was ändert die szenariobasierte Formulierung daran?</li>
|
||||
</ol>
|
||||
<hr />
|
||||
<h2 id="sec:unsicherheit-zusammenfassung">12.11 Zusammenfassung</h2>
|
||||
<h2 id="sec:unsicherheit-zusammenfassung">12.12 Zusammenfassung</h2>
|
||||
<ul>
|
||||
<li><strong>Der Fluch des Durchschnitts</strong> ist kein Randphänomen und hat zwei Gesichter. Bei asymmetrischen <strong>Kosten</strong> liegt das Optimum systematisch neben dem Mittelwert — das Newsvendor-Verhältnis <span class="math inline">c_{-}/(c_{-}+c_{+})</span> sagt, wie weit. Bei asymmetrischer <strong>Verknüpfung</strong> (Maximum über parallele Vorgänge) ist der Erwartungswert des Ganzen größer als das Ganze der Erwartungswerte. Beide Male gilt: Der Mittelwert einer Funktion ist nicht die Funktion des Mittelwerts (Jensensche Ungleichung).</li>
|
||||
<li><strong>Eine Terminzusage ist ein Quantil, kein Mittelwert.</strong> Wer den Erwartungswert zusagt, reißt den Termin bei fünf parallelen Vorgängen in 95 % der Fälle.</li>
|
||||
|
|
@ -900,6 +1254,9 @@ Anteil ueber 11,34 Tage: 95.5 %</code></pre>
|
|||
<li><strong>Zweistufige stochastische Programme</strong> trennen die Festlegung von der Reaktion — ein <span class="math inline">\mathbf{x}</span>, aber je Szenario ein <span class="math inline">\mathbf{y}_s</span>.</li>
|
||||
<li><strong>Der EVPI</strong> begrenzt, was eine perfekte Prognose wert sein darf.</li>
|
||||
<li><strong>Robuste Optimierung</strong> braucht keine Wahrscheinlichkeiten, nur eine Unsicherheitsmenge — und wird für einfache Mengen zu einem gewöhnlichen Problem mit Abzugsterm.</li>
|
||||
<li><strong>Chance Constraints</strong> schreiben die Zusage selbst ins Modell. Unter Normalverteilung wird daraus eine <strong>Kegelbedingung</strong> (der Sicherheitszuschlag ist eine Norm, deshalb belohnt sie Mischung), szenariobasiert ein <strong>MILP mit Big-M</strong> ohne jede Verteilungsannahme.</li>
|
||||
<li><strong>Sicherheit ist konvex bepreist.</strong> Im Beispiel kostet der letzte Prozentpunkt das 4,5-fache des ersten. Die richtige Managementfrage lautet nicht „was kostet Sicherheit“, sondern „was kostet der <em>nächste</em> Prozentpunkt“.</li>
|
||||
<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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue