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:
dschlueter 2026-09-10 17:40:29 +02:00
commit e8abb66d75
52 changed files with 4316 additions and 1921 deletions

View file

@ -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 &quot;&lt;=&quot;. 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&quot;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 -&gt; </span><span class="sc">{</span>res<span class="sc">.</span>fun<span class="sc">:.4f}</span><span class="ss"> EUR/kg&quot;</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 -&gt; 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>&lt;=</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>&gt;=</code> einfach <code>&gt;=</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>&gt;=</code> einfach <code>&gt;=</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 -&gt; 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 -&gt; 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 -&gt; 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 -&gt; 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 -&gt; 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 />