Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
<!doctype html>
< html lang = "de" >
< head >
< meta charset = "utf-8" / >
< meta name = "viewport" content = "width=device-width, initial-scale=1" / >
< title > Anhang D: Spickzettel der Solver · Optimierte Entscheidungsfindung mit Python< / title >
< script >
(function () {
try {
var t = localStorage.getItem("or-theme");
if (t) document.documentElement.setAttribute("data-theme", t);
} catch (e) {}
})();
< / script >
< link rel = "stylesheet" href = "assets/highlight.css" / >
< link rel = "stylesheet" href = "katex/katex.min.css" / >
< script defer = "" src = "katex/katex.min.js" > < / script >
< script > d o c u m e n t . a d d E v e n t L i s t e n e r ( " D O M C o n t e n t L o a d e d " , f u n c t i o n ( ) {
var mathElements = document.getElementsByClassName("math");
var macros = [];
for (var i = 0; i < mathElements.length ; i + + ) {
var texText = mathElements[i].firstChild;
if (mathElements[i].tagName == "SPAN") {
katex.render(texText.data, mathElements[i], {
displayMode: mathElements[i].classList.contains('display'),
throwOnError: false,
macros: macros,
fleqn: false
});
}}
// Der Browser springt zu einem #anker in der URL schon beim ersten Rendern
// an, BEVOR die KaTeX-Formeln oben im Text ihre finale Hoehe bekommen -
// durch den Reflow landet der Anker danach zu weit unten. Nach dem
// Formel-Rendering hier erneut zum Anker springen, das behebt es.
if (location.hash) {
var ziel = document.getElementById(decodeURIComponent(location.hash.slice(1)));
if (ziel) ziel.scrollIntoView({behavior: "instant", block: "start"});
}
});
< / script >
< link rel = "stylesheet" href = "assets/site.css" / >
< / head >
< body >
< svg style = "display:none" aria-hidden = "true" > < symbol id = "icon-menu" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" >
< line x1 = "3" y1 = "6" x2 = "21" y2 = "6" / > < line x1 = "3" y1 = "12" x2 = "21" y2 = "12" / > < line x1 = "3" y1 = "18" x2 = "21" y2 = "18" / >
< / symbol >
< symbol id = "icon-search" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" >
< circle cx = "11" cy = "11" r = "7" / > < line x1 = "21" y1 = "21" x2 = "16.2" y2 = "16.2" / >
< / symbol >
< symbol id = "icon-sun" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" >
< circle cx = "12" cy = "12" r = "4.5" / >
< line x1 = "12" y1 = "1.5" x2 = "12" y2 = "4" / > < line x1 = "12" y1 = "20" x2 = "12" y2 = "22.5" / >
< line x1 = "1.5" y1 = "12" x2 = "4" y2 = "12" / > < line x1 = "20" y1 = "12" x2 = "22.5" y2 = "12" / >
< line x1 = "4.5" y1 = "4.5" x2 = "6.2" y2 = "6.2" / > < line x1 = "17.8" y1 = "17.8" x2 = "19.5" y2 = "19.5" / >
< line x1 = "19.5" y1 = "4.5" x2 = "17.8" y2 = "6.2" / > < line x1 = "6.2" y1 = "17.8" x2 = "4.5" y2 = "19.5" / >
< / symbol >
< symbol id = "icon-moon" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" >
< path d = "M20 14.5A8.5 8.5 0 1 1 9.5 4a6.8 6.8 0 0 0 10.5 10.5z" / >
< / symbol >
< symbol id = "icon-chevron-left" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" >
< polyline points = "15 4 7 12 15 20" / >
< / symbol >
< symbol id = "icon-chevron-right" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" >
< polyline points = "9 4 17 12 9 20" / >
< / symbol >
< symbol id = "icon-check" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" >
< polyline points = "4 13 9.5 18.5 20 6" / >
< / symbol >
< symbol id = "icon-external-link" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" >
< path d = "M18 13.5V19a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 19V7A1.5 1.5 0 0 1 5 5.5h5.5" / >
< polyline points = "14.5 3.5 20.5 3.5 20.5 9.5" / > < line x1 = "11" y1 = "13" x2 = "20" y2 = "4" / >
< / symbol >
< symbol id = "icon-book" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" >
< path d = "M4 5.5A2 2 0 0 1 6 4h6v16H6a2 2 0 0 0-2 1.5z" / >
< path d = "M20 5.5A2 2 0 0 0 18 4h-6v16h6a2 2 0 0 1 2 1.5z" / >
< / symbol >
< symbol id = "icon-copy" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" >
< rect x = "9" y = "9" width = "13" height = "13" rx = "2" / > < path d = "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" / >
< / symbol >
< symbol id = "icon-download" viewBox = "0 0 24 24" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" >
< path d = "M12 3v12" / > < polyline points = "7 10 12 15 17 10" / > < path d = "M4 19.5h16" / >
< / symbol > < / svg >
< header class = "site-header" >
< button type = "button" class = "icon-btn" id = "sidebar-toggle" aria-label = "Menü öffnen" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-menu" > < / use > < / svg > < / button >
< a class = "brand" href = "index.html" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-book" > < / use > < / svg > < span > Optimierte Entscheidungsfindung mit Python< / span > < / a >
< div class = "site-search" >
< input id = "suche-eingabe" type = "search" placeholder = "Suchen …" aria-label = "Suche" autocomplete = "off" / >
< svg class = "icon such-icon" aria-hidden = "true" > < use href = "#icon-search" > < / use > < / svg >
< div id = "suche-ergebnisse" class = "suche-ergebnisse" hidden > < / div >
< / div >
< button type = "button" class = "icon-btn" id = "theme-toggle" aria-label = "Darstellung umschalten" >
< svg class = "icon icon-sun" aria-hidden = "true" > < use href = "#icon-sun" > < / use > < / svg > < svg class = "icon icon-moon" aria-hidden = "true" > < use href = "#icon-moon" > < / use > < / svg >
< / button >
< / header >
< div class = "site-body" >
< div class = "sidebar-overlay" id = "sidebar-overlay" hidden > < / div >
2026-09-10 00:07:01 +02:00
< nav class = "sidebar" id = "sidebar" aria-label = "Kapitelnavigation" > < div class = "sidebar-inhalt" > < details class = "sidebar-gruppe" > < summary > Einstieg< / summary > < ul > < li data-kapitel = "vorwort.html" > < a href = "vorwort.html" > < span class = "fortschritt-haken" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < / span > < span > Vorwort & Lesehilfe< / span > < / a > < / li > < li data-kapitel = "notation.html" > < a href = "notation.html" > < span class = "fortschritt-haken" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < / span > < span > Notation & Abkürzungen< / span > < / a > < / li > < / ul > < / details > < details class = "sidebar-gruppe" > < summary > Teil I: Grundlagen des Operations Research< / summary > < ul > < li data-kapitel = "einfuehrung.html" > < a href = "einfuehrung.html" > < span class = "fortschritt-haken" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < / span > < span > Kapitel 1: Einführung in Operations Research — Vom Ursprung zur mathematischen Entscheidungsfindung< / span > < / a > < / li > < li data-kapitel = "fundament.html" > < a href = "fundament.html" > < span class = "fortschritt-haken" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < / span > < span > Kapitel 2: Das mathematische Fundament — Vektoren, Matrizen, Konvexität{idx:Konvexität}< / span > < / a > < / li > < li data-kapitel = "oekosystem.html" > < a href = "oekosystem.html" > < span class = "fortschritt-haken" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < / span > < span > Kapitel 3: Das Python-Ökosystem für OR — Solver, Bindings und Modellierungsschichten< / span > < / a > < / li > < li data-kapitel = "modellierung.html" > < a href = "modellierung.html" > < span class = "fortschritt-haken" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < / span > < span > Kapitel 4: Vom Management-Wunsch zum Modell< / span > < / a > < / li > < li data-kapitel = "synthese-grundlagen.html" > < a href = "synthese-grundlagen.html" > < span class = "fortschritt-haken" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < / span > < span > Synthese Teil I< / span > < / a > < / li > < / ul > < / details > < details class = "sidebar-gruppe" > < summary > Teil II: Die Kernverfahren der deterministischen Optimierung< / summary > < ul > < li data-kapitel = "lp.html" > < a href = "lp.html" > < span class = "fortschritt-haken" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < / span > < span > Kapitel 5: Lineare Programmierung — Simplex, Dualität und Schattenpreise< / span > < / a > < / li > < li data-kapitel = "milp.html" > < a href = "milp.html" > < span class = "fortschritt-haken" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < / span > < span > Kapitel 6: Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound{idx:Branch-and-Bound}< / span > < / a > < / li > < li data-kapitel = "cpsat.html" > < a href = "cpsat.html" > < span class = "fortschritt-haken" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < / span > < span > Kapitel 7: Constraint Programming mit CP-SAT{idx:CP-SAT} — Logik, Scheduling und Zuweisung< / span > < / a > < / li > < li data-kapitel = "graphen.html" > < a href = "graphen.html" > < span class = "fortschritt-haken" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < / span > < span > Kapitel 8: Graphen, Flüsse und Touren — Min-Cost-Flow, Matching und VRP< / span > < / a > < / li > < li data-kapitel = "metaheuristiken.html" > < a href = "metaheuristiken.html" > < span class = "fortschritt-haken" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < / span > < span > Kapitel 9: Metaheuristiken — wenn der exakte Solver aussteigt< / span > < / a > < / li > < li data-kapitel = "dekomposition.html" > < a href = "dekomposition.html" > < span class = "fortschritt-haken" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < / span > < span > Kapitel 10: Spaltengenerierung — das Modell umbauen statt die Lösung raten< / span > < / a > < / li > < li data-kapitel = "synthese-kernverfahren.html" > < a href = "synthese-kernverfahren.html" > < span class = "fortschritt-haken" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < / span > < span > Synthese Teil II< / span > < / a > < / li > < / ul > < / details > < details class = "sidebar-gruppe" > < summary > Teil III:
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
< main class = "content" >
< nav class = "breadcrumb" aria-label = "Breadcrumb" > < a href = "index.html" > Start< / a > › < span > Anhang D: Spickzettel der Solver< / span > < / nav >
Glossar und Literatur trennen, Menue um Glossar und ZIP-Download ergaenzen
94_Anhang_Glossar_und_Literatur.md enthielt zwei verschiedene Nachschlagewerke
in einer Datei. Jetzt sind es zwei Anhaenge: E = Glossar (92 Eintraege),
F = Literaturverzeichnis (6 Kategorien). Aus 5 Anhaengen werden 6, aus 36
Kapiteldateien 37.
Die Teilung war billig: Die Datei trug bereits zwei eigenstaendige
Ueberschriften mit nichts als einem --- dazwischen, und im ganzen Buch gab es
genau einen {ref:anhang:glossar-literatur} - die Weiter-mit-Zeile im
Spickzettel. Geprueft: keine Inhaltszeile verloren, alle 92 Glossareintraege
auf der neuen Seite, Indexmarken unveraendert bei 328.
Das Seitenleisten-Menue bekommt zwei Eintraege:
Beispielprogramme
Notebooks
Download Notebooks als ZIP <- neu, eingerueckt
Glossar <- neu
Stichwortverzeichnis
Gesamtdokument (eine Seite)
Download als PDF
Der ZIP-Link benutzt dieselbe Konstante wie baue_notebooks_seite() beim
Schreiben des Archivs, damit Link und Datei nicht auseinanderlaufen. Das
Glossar erscheint absichtlich doppelt: hier als Abkuerzung neben dem
Stichwortverzeichnis, und unten in der Gruppe "Anhaenge", weil es ein Anhang
ist.
Die verwaiste anhang-glossar-literatur.html von Hand entfernt - der Build
raeumt alte Seiten nicht ab.
Nebenbefund, in PROGRESS.md festgehalten: OR_HTML_04/assets/site.css ist eine
von Hand gepflegte Quelle, die im als "generiert" beschriebenen Verzeichnis
liegt. Der Build schreibt sie nie. Dasselbe gilt fuer site.js, icons.svg,
highlight.css und plotly.min.js.
--check: 5 Teile, 23 Kapitel, 6 Anhaenge, 296 Abschnitte, 825 Querverweise,
328 Indexmarken, 37 Dateien, 28.544 Zeilen, 305 Hauptueberschriften, keine
Warnung. PDF unveraendert 759 Seiten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 15:48:57 +02:00
< nav class = "prev-next" > < a class = "prev-next-knopf prev-next-prev" href = "anhang-fehlerdiagnose.html" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-chevron-left" > < / use > < / svg > < span > < small > Zurück< / small > Anhang C: Fehlerdiagnose-Handbuch< / span > < / a > < a class = "prev-next-knopf prev-next-next" href = "anhang-glossar.html" > < span > < small > Weiter< / small > Anhang E: Glossar< / span > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-chevron-right" > < / use > < / svg > < / a > < / nav >
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
< article >
< h1 id = "anhang-spickzettel" > Anhang D: Spickzettel der Solver< / h1 >
< blockquote >
< p > < strong > Wofür dieser Anhang gedacht ist:< / strong > Sie wissen, was Sie modellieren wollen, und suchen nur noch, wie die gewählte Bibliothek es schreibt. Jede Seite hat denselben Aufbau — Modell, Variablen, Nebenbedingungen, Lösen, < strong > alle< / strong > Statusfälle, Lösung auslesen, Stolpersteine. So lassen sich die Seiten nebeneinanderlegen.< / p >
< / blockquote >
< p > < strong > Alle Schnipsel lösen dasselbe Problem< / strong > — das Produktionsprogramm aus < a href = "oekosystem.html#sec:oekosystem-schnellstart" > Abschnitt 3.1< / a > mit dem bekannten Optimum < strong > 530< / strong > und den Schattenpreisen < strong > 12< / strong > und < strong > 1< / strong > :< / p >
< p > < span class = "math display" > \max\; 10x_1 + 15x_2 + 25x_3 \quad\text{u.d.N.}\quad x_1 + x_2 + 2x_3 \le 40,\;\; 2x_1 + 3x_2 + x_3 \le 50,\;\; x \ge 0< / span > < / p >
Glossar: Sprungleiste, Abkürzungen ausschreiben, CLAUDE.md-Regel
Sprungleiste (A B C ... Z) im Glossar — wie im Stichwortverzeichnis:
ein Klick je Buchstabe springt zur '## <Buchstabe>'-Überschrift.
Eingebaut in erzeuge_glossar_04.py als {=html}-Rohblock (nur HTML,
im PDF bedeutungslos).
Abkürzungen beim ersten Mal ausschreiben: 'VaR' → 'VaR (Value at Risk)',
'EVPI' → 'EVPI (Expected Value of Perfect Information)' als Link-Text
bei der ersten Nennung je Datei; danach nur die Abkürzung. 19 Abkürzungen
erfasst (VaR, CVaR, KKT, NLP, MILP, EVPI, LP, QP, ...).
CLAUDE.md: Regel 'Glossar-Links: Fachbegriffe im Fließtext automatisch
verlinkt' dokumentiert — resolve_glossar(), LINK_TEXTE,
ABBREV_ERSTE_NENNUNG, _NICHT_AUTO_LINKEN, _ZU_KURZ_ABK, .glossar-link,
{gl:}-Marke, Sprungleiste, {#gloss:<slug>}-Anchor.
2026-09-10 17:52:49 +02:00
< p > Damit ist jeder Schnipsel selbstprüfend: Kommt bei Ihnen etwas anderes als 530 heraus, liegt es an der Übertragung, nicht am Modell. (Die Ausnahme ist < a href = "anhang-glossar.md#gloss:cp-sat" class = "glossar-link" > CP-SAT< / a > — ein rein stetiges < a href = "anhang-glossar.md#gloss:lineare-programmierung-lp" class = "glossar-link" > LP (Lineare Programmierung)< / a > ist dort das falsche Werkzeug; die Seite zeigt stattdessen die < a href = "anhang-glossar.md#gloss:constraint-programming-cp" class = "glossar-link" > CP (Constraint Programming)< / a > -< a href = "anhang-glossar.md#gloss:sat-boolean-satisfiability" class = "glossar-link" > SAT (Boolean Satisfiability)< / a > -eigenen Bausteine.)< / p >
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
< blockquote >
< p > < strong > Was dieser Anhang < em > nicht< / em > ist.< / strong > Kein Vergleich und keine Empfehlung. Welche Bibliothek für welche Aufgabe taugt, steht in < a href = "oekosystem.html#sec:oekosystem-wann-lohnt-sich-welche-ebene" > Abschnitt 3.6< / a > ; denselben Fall in vier Bibliotheken < em > nebeneinander< / em > zeigt < code > Ein_System_Vier_Ansaetze.py< / code > , die beiden Modellierungssprachen < code > Modellierungsschichten.py< / code > . Hier geht es allein ums Nachschlagen.< / p >
< / blockquote >
< hr / >
< h2 id = "d1-scipy-linprog-und-milp" > D1 — SciPy: < code > linprog< / code > und < code > milp< / code > < / h2 >
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.
2026-09-10 17:40:29 +02:00
< p > < strong > Wofür.< / strong > Die Einstiegsschicht: keine zusätzliche Installation, < a href = "anhang-glossar.md#gloss:highs" class = "glossar-link" > HiGHS< / a > als Unterbau, ideal für lineare und gemischt-ganzzahlige Probleme in Matrixform. < strong > Wofür nicht:< / strong > alles, was sich nicht als Matrix schreiben lässt, und jede nichtlineare < a href = "anhang-glossar.md#gloss:zielfunktion" class = "glossar-link" > Zielfunktion< / a > .< / p >
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
< h3 id = "lineares-programm" > Lineares Programm< / h3 >
< div class = "sourceCode" id = "cb1" > < pre class = "sourceCode python" > < code class = "sourceCode python" > < span id = "cb1-1" > < a href = "#cb1-1" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > import< / span > numpy < span class = "im" > as< / span > np< / span >
< span id = "cb1-2" > < a href = "#cb1-2" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > from< / span > scipy.optimize < span class = "im" > import< / span > linprog< / span >
< span id = "cb1-3" > < a href = "#cb1-3" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb1-4" > < a href = "#cb1-4" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "co" > # linprog MINIMIERT immer -> zum Maximieren die Zielfunktion negieren< / span > < / span >
< span id = "cb1-5" > < a href = "#cb1-5" aria-hidden = "true" tabindex = "-1" > < / a > ergebnis < span class = "op" > =< / span > linprog(< / span >
< span id = "cb1-6" > < a href = "#cb1-6" aria-hidden = "true" tabindex = "-1" > < / a > c< span class = "op" > =< / span > [< span class = "op" > -< / span > < span class = "fl" > 10.0< / span > , < span class = "op" > -< / span > < span class = "fl" > 15.0< / span > , < span class = "op" > -< / span > < span class = "fl" > 25.0< / span > ], < span class = "co" > # Zielkoeffizienten< / span > < / span >
< span id = "cb1-7" > < a href = "#cb1-7" aria-hidden = "true" tabindex = "-1" > < / a > A_ub< span class = "op" > =< / span > [[< span class = "dv" > 1< / span > , < span class = "dv" > 1< / span > , < span class = "dv" > 2< / span > ], [< span class = "dv" > 2< / span > , < span class = "dv" > 3< / span > , < span class = "dv" > 1< / span > ]], b_ub< span class = "op" > =< / span > [< span class = "dv" > 40< / span > , < span class = "dv" > 50< / span > ], < span class = "co" > # A_ub @ x < = b_ub< / span > < / span >
< span id = "cb1-8" > < a href = "#cb1-8" aria-hidden = "true" tabindex = "-1" > < / a > A_eq< span class = "op" > =< / span > < span class = "va" > None< / span > , b_eq< span class = "op" > =< / span > < span class = "va" > None< / span > , < span class = "co" > # Gleichungen, falls vorhanden< / span > < / span >
< span id = "cb1-9" > < a href = "#cb1-9" aria-hidden = "true" tabindex = "-1" > < / a > bounds< span class = "op" > =< / span > [(< span class = "dv" > 0< / span > , < span class = "va" > None< / span > )] < span class = "op" > *< / span > < span class = "dv" > 3< / span > , < span class = "co" > # je Variable (unten, oben)< / span > < / span >
< span id = "cb1-10" > < a href = "#cb1-10" aria-hidden = "true" tabindex = "-1" > < / a > method< span class = "op" > =< / span > < span class = "st" > " highs" < / span > )< / span >
< span id = "cb1-11" > < a href = "#cb1-11" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb1-12" > < a href = "#cb1-12" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > if< / span > ergebnis.status < span class = "op" > ==< / span > < span class = "dv" > 0< / span > :< / span >
< span id = "cb1-13" > < a href = "#cb1-13" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" optimal: < / span > < span class = "sc" > {< / span > < span class = "op" > -< / span > ergebnis< span class = "sc" > .< / span > fun< span class = "sc" > :.2f}< / span > < span class = "ss" > " < / span > ) < span class = "co" > # Vorzeichen zuruecknehmen!< / span > < / span >
< span id = "cb1-14" > < a href = "#cb1-14" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" x = < / span > < span class = "sc" > {< / span > np< span class = "sc" > .< / span > < span class = "bu" > round< / span > (ergebnis.x, < span class = "dv" > 4< / span > )< span class = "sc" > }< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb1-15" > < a href = "#cb1-15" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" Schattenpreise: < / span > < span class = "sc" > {< / span > < span class = "op" > -< / span > ergebnis< span class = "sc" > .< / span > ineqlin< span class = "sc" > .< / span > marginals< span class = "sc" > }< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb1-16" > < a href = "#cb1-16" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > ergebnis.status < span class = "op" > ==< / span > < span class = "dv" > 2< / span > :< / span >
< span id = "cb1-17" > < a href = "#cb1-17" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " INFEASIBLE - kein zulaessiger Punkt" < / span > )< / span >
< span id = "cb1-18" > < a href = "#cb1-18" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > ergebnis.status < span class = "op" > ==< / span > < span class = "dv" > 3< / span > :< / span >
< span id = "cb1-19" > < a href = "#cb1-19" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " UNBOUNDED - Zielfunktion unbeschraenkt" < / span > )< / span >
< span id = "cb1-20" > < a href = "#cb1-20" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > ergebnis.status < span class = "op" > ==< / span > < span class = "dv" > 1< / span > :< / span >
< span id = "cb1-21" > < a href = "#cb1-21" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " Iterations- oder Zeitlimit erreicht" < / span > )< / span >
< span id = "cb1-22" > < a href = "#cb1-22" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > else< / span > :< / span >
< span id = "cb1-23" > < a href = "#cb1-23" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" numerisches Problem (status < / span > < span class = "sc" > {< / span > ergebnis< span class = "sc" > .< / span > status< span class = "sc" > }< / span > < span class = "ss" > ): < / span > < span class = "sc" > {< / span > ergebnis< span class = "sc" > .< / span > message< span class = "sc" > }< / span > < span class = "ss" > " < / span > )< / span > < / code > < / pre > < / div >
< h3 id = "ganzzahlig-milp" > Ganzzahlig: < code > milp< / code > < / h3 >
< div class = "sourceCode" id = "cb2" > < pre class = "sourceCode python" > < code class = "sourceCode python" > < span id = "cb2-1" > < a href = "#cb2-1" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > import< / span > numpy < span class = "im" > as< / span > np< / span >
< span id = "cb2-2" > < a href = "#cb2-2" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > from< / span > scipy.optimize < span class = "im" > import< / span > milp, LinearConstraint, Bounds< / span >
< span id = "cb2-3" > < a href = "#cb2-3" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb2-4" > < a href = "#cb2-4" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "co" > # Ganzzahlig: dasselbe Problem, aber x muss ganzzahlig sein< / span > < / span >
< span id = "cb2-5" > < a href = "#cb2-5" aria-hidden = "true" tabindex = "-1" > < / a > ergebnis < span class = "op" > =< / span > milp(< / span >
< span id = "cb2-6" > < a href = "#cb2-6" aria-hidden = "true" tabindex = "-1" > < / a > c< span class = "op" > =< / span > [< span class = "op" > -< / span > < span class = "fl" > 10.0< / span > , < span class = "op" > -< / span > < span class = "fl" > 15.0< / span > , < span class = "op" > -< / span > < span class = "fl" > 25.0< / span > ], < span class = "co" > # auch milp MINIMIERT< / span > < / span >
< span id = "cb2-7" > < a href = "#cb2-7" aria-hidden = "true" tabindex = "-1" > < / a > constraints< span class = "op" > =< / span > LinearConstraint([[< span class = "dv" > 1< / span > , < span class = "dv" > 1< / span > , < span class = "dv" > 2< / span > ], [< span class = "dv" > 2< / span > , < span class = "dv" > 3< / span > , < span class = "dv" > 1< / span > ]], < span class = "op" > -< / span > np.inf, [< span class = "dv" > 40< / span > , < span class = "dv" > 50< / span > ]),< / span >
< span id = "cb2-8" > < a href = "#cb2-8" aria-hidden = "true" tabindex = "-1" > < / a > integrality< span class = "op" > =< / span > [< span class = "dv" > 1< / span > , < span class = "dv" > 1< / span > , < span class = "dv" > 1< / span > ], < span class = "co" > # 0 = stetig, 1 = ganzzahlig< / span > < / span >
< span id = "cb2-9" > < a href = "#cb2-9" aria-hidden = "true" tabindex = "-1" > < / a > bounds< span class = "op" > =< / span > Bounds(< span class = "dv" > 0< / span > , np.inf))< / span >
< span id = "cb2-10" > < a href = "#cb2-10" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb2-11" > < a href = "#cb2-11" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > if< / span > ergebnis.status < span class = "op" > ==< / span > < span class = "dv" > 0< / span > :< / span >
< span id = "cb2-12" > < a href = "#cb2-12" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" optimal: < / span > < span class = "sc" > {< / span > < span class = "op" > -< / span > ergebnis< span class = "sc" > .< / span > fun< span class = "sc" > :.2f}< / span > < span class = "ss" > x = < / span > < span class = "sc" > {< / span > np< span class = "sc" > .< / span > < span class = "bu" > round< / span > (ergebnis.x)< span class = "sc" > .< / span > astype(< span class = "bu" > int< / span > )< span class = "sc" > }< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb2-13" > < a href = "#cb2-13" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" MIP-Gap: < / span > < span class = "sc" > {< / span > ergebnis< span class = "sc" > .< / span > mip_gap< span class = "sc" > :.4f}< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb2-14" > < a href = "#cb2-14" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > ergebnis.status < span class = "op" > ==< / span > < span class = "dv" > 1< / span > :< / span >
< span id = "cb2-15" > < a href = "#cb2-15" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " Zeitlimit - beste gefundene Loesung nutzen, Gap pruefen" < / span > )< / span >
< span id = "cb2-16" > < a href = "#cb2-16" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > ergebnis.status < span class = "op" > ==< / span > < span class = "dv" > 2< / span > :< / span >
< span id = "cb2-17" > < a href = "#cb2-17" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " INFEASIBLE" < / span > )< / span >
< span id = "cb2-18" > < a href = "#cb2-18" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > ergebnis.status < span class = "op" > ==< / span > < span class = "dv" > 3< / span > :< / span >
< span id = "cb2-19" > < a href = "#cb2-19" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " UNBOUNDED" < / span > )< / span >
< span id = "cb2-20" > < a href = "#cb2-20" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > else< / span > :< / span >
< span id = "cb2-21" > < a href = "#cb2-21" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" kein Ergebnis: < / span > < span class = "sc" > {< / span > ergebnis< span class = "sc" > .< / span > message< span class = "sc" > }< / span > < span class = "ss" > " < / span > )< / span > < / code > < / pre > < / div >
< h3 id = "die-drei-häufigsten-stolpersteine" > Die drei häufigsten Stolpersteine< / h3 >
< ol type = "1" >
< li > < strong > < code > linprog< / code > minimiert immer.< / strong > Zum Maximieren < code > c< / code > negieren — und beim Ausgeben des Zielwerts das Vorzeichen wieder zurücknehmen. Dieselbe Negation dreht auch die Schattenpreise (< a href = "lp.html#sec:lp-die-vorzeichenfalle-bei-schattenpreisen" > Abschnitt 5.7< / a > ).< / li >
< li > < strong > < code > status == 0< / code > prüfen, nicht < code > res.success< / code > allein.< / strong > < code > success< / code > ist bei < code > status == 1< / code > (Limit erreicht) < code > False< / code > , obwohl eine brauchbare Lösung vorliegen kann.< / li >
< li > < strong > < code > bounds< / code > gilt je Variable.< / strong > < code > bounds=(0, None)< / code > setzt alle Variablen gleich; < code > bounds=[(0, None), (0, 10), ...]< / code > einzeln. Wer die Liste vergisst, bekommt stillschweigend überall dieselbe Schranke.< / li >
< / ol >
< hr / >
< h2 id = "d2-highs-über-highspy" > D2 — HiGHS über < code > highspy< / code > < / h2 >
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.
2026-09-10 17:40:29 +02:00
< p > < strong > Wofür.< / strong > Derselbe < a href = "anhang-glossar.md#gloss:solver" class = "glossar-link" > Solver< / a > wie unter < a href = "anhang-glossar.md#gloss:scipy" class = "glossar-link" > SciPy< / a > , aber direkt gesteuert: Optionen, Warm-Starts, inkrementelles Ändern eines bestehenden Modells. < strong > Wofür nicht:< / strong > schnelles Hinschreiben — die CSR-Matrixübergabe ist fehleranfällig.< / p >
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
< div class = "sourceCode" id = "cb3" > < pre class = "sourceCode python" > < code class = "sourceCode python" > < span id = "cb3-1" > < a href = "#cb3-1" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > import< / span > numpy < span class = "im" > as< / span > np< / span >
< span id = "cb3-2" > < a href = "#cb3-2" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > import< / span > highspy< / span >
< span id = "cb3-3" > < a href = "#cb3-3" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb3-4" > < a href = "#cb3-4" aria-hidden = "true" tabindex = "-1" > < / a > h < span class = "op" > =< / span > highspy.Highs()< / span >
< span id = "cb3-5" > < a href = "#cb3-5" aria-hidden = "true" tabindex = "-1" > < / a > h.setOptionValue(< span class = "st" > " output_flag" < / span > , < span class = "va" > False< / span > ) < span class = "co" > # Solverprotokoll abschalten< / span > < / span >
< span id = "cb3-6" > < a href = "#cb3-6" aria-hidden = "true" tabindex = "-1" > < / a > h.setOptionValue(< span class = "st" > " time_limit" < / span > , < span class = "fl" > 60.0< / span > )< / span >
< span id = "cb3-7" > < a href = "#cb3-7" aria-hidden = "true" tabindex = "-1" > < / a > h.setOptionValue(< span class = "st" > " mip_rel_gap" < / span > , < span class = "fl" > 0.01< / span > ) < span class = "co" > # 1 % Gap genuegt< / span > < / span >
< span id = "cb3-8" > < a href = "#cb3-8" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb3-9" > < a href = "#cb3-9" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "co" > # Variablen: Anzahl, Untergrenzen, Obergrenzen< / span > < / span >
< span id = "cb3-10" > < a href = "#cb3-10" aria-hidden = "true" tabindex = "-1" > < / a > h.addVars(< span class = "dv" > 3< / span > , np.zeros(< span class = "dv" > 3< / span > ), np.full(< span class = "dv" > 3< / span > , highspy.kHighsInf))< / span >
< span id = "cb3-11" > < a href = "#cb3-11" aria-hidden = "true" tabindex = "-1" > < / a > h.changeObjectiveSense(highspy.ObjSense.kMaximize)< / span >
< span id = "cb3-12" > < a href = "#cb3-12" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > for< / span > spalte, wert < span class = "kw" > in< / span > < span class = "bu" > enumerate< / span > ([< span class = "fl" > 10.0< / span > , < span class = "fl" > 15.0< / span > , < span class = "fl" > 25.0< / span > ]):< / span >
< span id = "cb3-13" > < a href = "#cb3-13" aria-hidden = "true" tabindex = "-1" > < / a > h.changeColCost(spalte, wert)< / span >
< span id = "cb3-14" > < a href = "#cb3-14" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb3-15" > < a href = "#cb3-15" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "co" > # Zeilen im CSR-Format: starts[i] = Beginn von Zeile i in indices/values< / span > < / span >
< span id = "cb3-16" > < a href = "#cb3-16" aria-hidden = "true" tabindex = "-1" > < / a > h.addRows(< span class = "dv" > 2< / span > , np.full(< span class = "dv" > 2< / span > , < span class = "op" > -< / span > highspy.kHighsInf), np.array([< span class = "fl" > 40.0< / span > , < span class = "fl" > 50.0< / span > ]), < span class = "dv" > 6< / span > ,< / span >
< span id = "cb3-17" > < a href = "#cb3-17" aria-hidden = "true" tabindex = "-1" > < / a > np.array([< span class = "dv" > 0< / span > , < span class = "dv" > 3< / span > ], dtype< span class = "op" > =< / span > np.int32), < span class = "co" > # starts< / span > < / span >
< span id = "cb3-18" > < a href = "#cb3-18" aria-hidden = "true" tabindex = "-1" > < / a > np.array([< span class = "dv" > 0< / span > , < span class = "dv" > 1< / span > , < span class = "dv" > 2< / span > , < span class = "dv" > 0< / span > , < span class = "dv" > 1< / span > , < span class = "dv" > 2< / span > ], dtype< span class = "op" > =< / span > np.int32), < span class = "co" > # Spaltenindizes< / span > < / span >
< span id = "cb3-19" > < a href = "#cb3-19" aria-hidden = "true" tabindex = "-1" > < / a > np.array([< span class = "fl" > 1.0< / span > , < span class = "fl" > 1.0< / span > , < span class = "fl" > 2.0< / span > , < span class = "fl" > 2.0< / span > , < span class = "fl" > 3.0< / span > , < span class = "fl" > 1.0< / span > ])) < span class = "co" > # Koeffizienten< / span > < / span >
< span id = "cb3-20" > < a href = "#cb3-20" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "co" > # Ganzzahligkeit: h.changeColsIntegrality(...) mit highspy.HighsVarType.kInteger< / span > < / span >
< span id = "cb3-21" > < a href = "#cb3-21" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb3-22" > < a href = "#cb3-22" aria-hidden = "true" tabindex = "-1" > < / a > h.run()< / span >
< span id = "cb3-23" > < a href = "#cb3-23" aria-hidden = "true" tabindex = "-1" > < / a > status < span class = "op" > =< / span > h.getModelStatus()< / span >
< span id = "cb3-24" > < a href = "#cb3-24" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > if< / span > status < span class = "op" > ==< / span > highspy.HighsModelStatus.kOptimal:< / span >
< span id = "cb3-25" > < a href = "#cb3-25" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" optimal: < / span > < span class = "sc" > {< / span > h< span class = "sc" > .< / span > getInfo()< span class = "sc" > .< / span > objective_function_value< span class = "sc" > :.2f}< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb3-26" > < a href = "#cb3-26" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" x = < / span > < span class = "sc" > {< / span > np< span class = "sc" > .< / span > < span class = "bu" > round< / span > (h.getSolution().col_value[:< span class = "dv" > 3< / span > ], < span class = "dv" > 4< / span > )< span class = "sc" > }< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb3-27" > < a href = "#cb3-27" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" Schattenpreise: < / span > < span class = "sc" > {< / span > np< span class = "sc" > .< / span > < span class = "bu" > round< / span > (h.getSolution().row_dual[:< span class = "dv" > 2< / span > ], < span class = "dv" > 4< / span > )< span class = "sc" > }< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb3-28" > < a href = "#cb3-28" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > status < span class = "op" > ==< / span > highspy.HighsModelStatus.kInfeasible:< / span >
< span id = "cb3-29" > < a href = "#cb3-29" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " INFEASIBLE" < / span > )< / span >
< span id = "cb3-30" > < a href = "#cb3-30" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > status < span class = "op" > ==< / span > highspy.HighsModelStatus.kUnbounded:< / span >
< span id = "cb3-31" > < a href = "#cb3-31" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " UNBOUNDED" < / span > )< / span >
< span id = "cb3-32" > < a href = "#cb3-32" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > status < span class = "op" > ==< / span > highspy.HighsModelStatus.kTimeLimit:< / span >
< span id = "cb3-33" > < a href = "#cb3-33" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" Zeitlimit, Gap < / span > < span class = "sc" > {< / span > h< span class = "sc" > .< / span > getInfo()< span class = "sc" > .< / span > mip_gap< span class = "sc" > :.3f}< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb3-34" > < a href = "#cb3-34" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > else< / span > :< / span >
< span id = "cb3-35" > < a href = "#cb3-35" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " kein Optimum:" < / span > , h.modelStatusToString(status))< / span > < / code > < / pre > < / div >
< h3 id = "die-drei-häufigsten-stolpersteine-1" > Die drei häufigsten Stolpersteine< / h3 >
< ol type = "1" >
< li > < strong > Nicht zusammen mit < code > ortools< / code > importieren.< / strong > Beide bringen eine eigene HiGHS-Kopie mit; im selben Prozess endet das in < code > undefined symbol< / code > (< a href = "anhang-fehlerdiagnose.html#anhang-fehlerdiagnose" > Anhang C< / a > , C9). Auch < code > cvxpy< / code > zieht < code > highspy< / code > bei der Solver-Erkennung mit hinein.< / li >
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.
2026-09-10 17:40:29 +02:00
< li > < strong > Das < a href = "anhang-glossar.md#gloss:csr-format" class = "glossar-link" > CSR-Format< / a > stimmt oder es stimmt still nicht.< / strong > < code > starts< / code > hat so viele Einträge wie Zeilen, < code > indices< / code > und < code > values< / code > so viele wie Nichtnullen. Ein falscher < code > starts< / code > -Eintrag erzeugt ein < em > anderes< / em > , aber lösbares Modell — es fällt nur durch ein falsches Ergebnis auf.< / li >
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
< li > < strong > < code > output_flag< / code > abschalten< / strong > , sonst überschwemmt das Solverprotokoll jede Ausgabe.< / li >
< / ol >
< hr / >
< h2 id = "d3-or-tools-pywraplp" > D3 — OR-Tools: < code > pywraplp< / code > < / h2 >
Glossar: Sprungleiste, Abkürzungen ausschreiben, CLAUDE.md-Regel
Sprungleiste (A B C ... Z) im Glossar — wie im Stichwortverzeichnis:
ein Klick je Buchstabe springt zur '## <Buchstabe>'-Überschrift.
Eingebaut in erzeuge_glossar_04.py als {=html}-Rohblock (nur HTML,
im PDF bedeutungslos).
Abkürzungen beim ersten Mal ausschreiben: 'VaR' → 'VaR (Value at Risk)',
'EVPI' → 'EVPI (Expected Value of Perfect Information)' als Link-Text
bei der ersten Nennung je Datei; danach nur die Abkürzung. 19 Abkürzungen
erfasst (VaR, CVaR, KKT, NLP, MILP, EVPI, LP, QP, ...).
CLAUDE.md: Regel 'Glossar-Links: Fachbegriffe im Fließtext automatisch
verlinkt' dokumentiert — resolve_glossar(), LINK_TEXTE,
ABBREV_ERSTE_NENNUNG, _NICHT_AUTO_LINKEN, _ZU_KURZ_ABK, .glossar-link,
{gl:}-Marke, Sprungleiste, {#gloss:<slug>}-Anchor.
2026-09-10 17:52:49 +02:00
< p > < strong > Wofür.< / strong > Bequeme algebraische Schreibweise für LP und < a href = "anhang-glossar.md#gloss:gemischt-ganzzahlige-optimierung-milp" class = "glossar-link" > MILP (Gemischt-ganzzahlige Optimierung)< / a > mit umschaltbarem Backend (< code > GLOP< / code > , < code > SCIP< / code > , < code > CBC< / code > , < code > SAT< / code > ). < strong > Wofür nicht:< / strong > < a href = "anhang-glossar.md#gloss:scheduling" class = "glossar-link" > Scheduling< / a > und kombinatorische Bedingungen — dafür ist CP-SAT (D4) da.< / p >
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
< div class = "sourceCode" id = "cb4" > < pre class = "sourceCode python" > < code class = "sourceCode python" > < span id = "cb4-1" > < a href = "#cb4-1" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > from< / span > ortools.linear_solver < span class = "im" > import< / span > pywraplp< / span >
< span id = "cb4-2" > < a href = "#cb4-2" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb4-3" > < a href = "#cb4-3" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "co" > # " GLOP" = LP, " SCIP" oder " CBC" = MILP, " SAT" = CP-SAT als MILP-Backend< / span > < / span >
< span id = "cb4-4" > < a href = "#cb4-4" aria-hidden = "true" tabindex = "-1" > < / a > loeser < span class = "op" > =< / span > pywraplp.Solver.CreateSolver(< span class = "st" > " GLOP" < / span > )< / span >
< span id = "cb4-5" > < a href = "#cb4-5" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > if< / span > loeser < span class = "kw" > is< / span > < span class = "va" > None< / span > :< / span >
< span id = "cb4-6" > < a href = "#cb4-6" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > raise< / span > < span class = "pp" > SystemExit< / span > (< span class = "st" > " Solver nicht verfuegbar" < / span > )< / span >
< span id = "cb4-7" > < a href = "#cb4-7" aria-hidden = "true" tabindex = "-1" > < / a > loeser.SetTimeLimit(< span class = "dv" > 60_000< / span > ) < span class = "co" > # Millisekunden!< / span > < / span >
< span id = "cb4-8" > < a href = "#cb4-8" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb4-9" > < a href = "#cb4-9" aria-hidden = "true" tabindex = "-1" > < / a > unendlich < span class = "op" > =< / span > loeser.infinity()< / span >
< span id = "cb4-10" > < a href = "#cb4-10" aria-hidden = "true" tabindex = "-1" > < / a > x < span class = "op" > =< / span > [loeser.NumVar(< span class = "dv" > 0< / span > , unendlich, < span class = "ss" > f" x< / span > < span class = "sc" > {< / span > j< span class = "sc" > }< / span > < span class = "ss" > " < / span > ) < span class = "cf" > for< / span > j < span class = "kw" > in< / span > < span class = "bu" > range< / span > (< span class = "dv" > 3< / span > )]< / span >
< span id = "cb4-11" > < a href = "#cb4-11" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "co" > # ganzzahlig: loeser.IntVar(0, unendlich, " n" ) | binaer: loeser.BoolVar(" b" )< / span > < / span >
< span id = "cb4-12" > < a href = "#cb4-12" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb4-13" > < a href = "#cb4-13" aria-hidden = "true" tabindex = "-1" > < / a > loeser.Add(x[< span class = "dv" > 0< / span > ] < span class = "op" > +< / span > x[< span class = "dv" > 1< / span > ] < span class = "op" > +< / span > < span class = "dv" > 2< / span > < span class = "op" > *< / span > x[< span class = "dv" > 2< / span > ] < span class = "op" > < =< / span > < span class = "dv" > 40< / span > )< / span >
< span id = "cb4-14" > < a href = "#cb4-14" aria-hidden = "true" tabindex = "-1" > < / a > loeser.Add(< span class = "dv" > 2< / span > < span class = "op" > *< / span > x[< span class = "dv" > 0< / span > ] < span class = "op" > +< / span > < span class = "dv" > 3< / span > < span class = "op" > *< / span > x[< span class = "dv" > 1< / span > ] < span class = "op" > +< / span > x[< span class = "dv" > 2< / span > ] < span class = "op" > < =< / span > < span class = "dv" > 50< / span > )< / span >
< span id = "cb4-15" > < a href = "#cb4-15" aria-hidden = "true" tabindex = "-1" > < / a > loeser.Maximize(< span class = "dv" > 10< / span > < span class = "op" > *< / span > x[< span class = "dv" > 0< / span > ] < span class = "op" > +< / span > < span class = "dv" > 15< / span > < span class = "op" > *< / span > x[< span class = "dv" > 1< / span > ] < span class = "op" > +< / span > < span class = "dv" > 25< / span > < span class = "op" > *< / span > x[< span class = "dv" > 2< / span > ])< / span >
< span id = "cb4-16" > < a href = "#cb4-16" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb4-17" > < a href = "#cb4-17" aria-hidden = "true" tabindex = "-1" > < / a > status < span class = "op" > =< / span > loeser.Solve()< / span >
< span id = "cb4-18" > < a href = "#cb4-18" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > if< / span > status < span class = "op" > ==< / span > pywraplp.Solver.OPTIMAL:< / span >
< span id = "cb4-19" > < a href = "#cb4-19" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" optimal: < / span > < span class = "sc" > {< / span > loeser< span class = "sc" > .< / span > Objective()< span class = "sc" > .< / span > Value()< span class = "sc" > :.2f}< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb4-20" > < a href = "#cb4-20" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" x = < / span > < span class = "sc" > {< / span > [< span class = "bu" > round< / span > (v.solution_value(), < span class = "dv" > 4< / span > ) < span class = "cf" > for< / span > v < span class = "kw" > in< / span > x]< span class = "sc" > }< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb4-21" > < a href = "#cb4-21" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > status < span class = "op" > ==< / span > pywraplp.Solver.FEASIBLE:< / span >
< span id = "cb4-22" > < a href = "#cb4-22" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " zulaessig, nicht bewiesen optimal (Zeitlimit)" < / span > )< / span >
< span id = "cb4-23" > < a href = "#cb4-23" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > status < span class = "op" > ==< / span > pywraplp.Solver.INFEASIBLE:< / span >
< span id = "cb4-24" > < a href = "#cb4-24" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " INFEASIBLE" < / span > )< / span >
< span id = "cb4-25" > < a href = "#cb4-25" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > status < span class = "op" > ==< / span > pywraplp.Solver.UNBOUNDED:< / span >
< span id = "cb4-26" > < a href = "#cb4-26" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " UNBOUNDED" < / span > )< / span >
< span id = "cb4-27" > < a href = "#cb4-27" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > else< / span > :< / span >
< span id = "cb4-28" > < a href = "#cb4-28" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " ABNORMAL / NOT_SOLVED - Modell oder Solver pruefen" < / span > )< / span > < / code > < / pre > < / div >
< h3 id = "die-drei-häufigsten-stolpersteine-2" > Die drei häufigsten Stolpersteine< / h3 >
< ol type = "1" >
< li > < strong > < code > CreateSolver< / code > liefert < code > None< / code > < / strong > , wenn der Backend-Name unbekannt oder nicht gebaut ist — immer prüfen, statt am < code > None< / code > später zu scheitern.< / li >
< li > < strong > < code > SetTimeLimit< / code > erwartet Millisekunden< / strong > , nicht Sekunden. Ein < code > SetTimeLimit(60)< / code > bricht nach einer sechzigstel Sekunde ab.< / li >
< li > < strong > < code > FEASIBLE< / code > ist kein < code > OPTIMAL< / code > .< / strong > Bei Zeitlimit liefert der Solver eine gültige, aber möglicherweise schlechte Lösung — den Gap mitberichten, nicht die Zahl allein.< / li >
< / ol >
< hr / >
< h2 id = "d4-cp-sat-cp_model" > D4 — CP-SAT: < code > cp_model< / code > < / h2 >
< p > < strong > Wofür.< / strong > Scheduling, Zuordnung, Reihenfolgen, alles Kombinatorische mit globalen Bedingungen. < strong > Wofür nicht:< / strong > stetige Größen — CP-SAT rechnet ausschließlich ganzzahlig. Wer Nachkommastellen braucht, skaliert (Cent statt Euro, Promille statt Anteil).< / p >
< div class = "sourceCode" id = "cb5" > < pre class = "sourceCode python" > < code class = "sourceCode python" > < span id = "cb5-1" > < a href = "#cb5-1" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > from< / span > ortools.sat.python < span class = "im" > import< / span > cp_model< / span >
< span id = "cb5-2" > < a href = "#cb5-2" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb5-3" > < a href = "#cb5-3" aria-hidden = "true" tabindex = "-1" > < / a > modell < span class = "op" > =< / span > cp_model.CpModel()< / span >
< span id = "cb5-4" > < a href = "#cb5-4" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb5-5" > < a href = "#cb5-5" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "co" > # Variablen - CP-SAT rechnet ausschliesslich mit GANZEN Zahlen< / span > < / span >
< span id = "cb5-6" > < a href = "#cb5-6" aria-hidden = "true" tabindex = "-1" > < / a > x < span class = "op" > =< / span > modell.NewIntVar(< span class = "dv" > 0< / span > , < span class = "dv" > 100< / span > , < span class = "st" > " x" < / span > ) < span class = "co" > # untere, obere Schranke, Name< / span > < / span >
< span id = "cb5-7" > < a href = "#cb5-7" aria-hidden = "true" tabindex = "-1" > < / a > y < span class = "op" > =< / span > modell.NewIntVar(< span class = "dv" > 0< / span > , < span class = "dv" > 100< / span > , < span class = "st" > " y" < / span > )< / span >
< span id = "cb5-8" > < a href = "#cb5-8" aria-hidden = "true" tabindex = "-1" > < / a > b < span class = "op" > =< / span > modell.NewBoolVar(< span class = "st" > " b" < / span > ) < span class = "co" > # 0/1< / span > < / span >
< span id = "cb5-9" > < a href = "#cb5-9" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb5-10" > < a href = "#cb5-10" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "co" > # Nebenbedingungen< / span > < / span >
< span id = "cb5-11" > < a href = "#cb5-11" aria-hidden = "true" tabindex = "-1" > < / a > modell.Add(< span class = "dv" > 2< / span > < span class = "op" > *< / span > x < span class = "op" > +< / span > < span class = "dv" > 3< / span > < span class = "op" > *< / span > y < span class = "op" > < =< / span > < span class = "dv" > 50< / span > )< / span >
< span id = "cb5-12" > < a href = "#cb5-12" aria-hidden = "true" tabindex = "-1" > < / a > modell.Add(x < span class = "op" > > =< / span > < span class = "dv" > 5< / span > ).OnlyEnforceIf(b) < span class = "co" > # gilt nur, wenn b wahr ist< / span > < / span >
< span id = "cb5-13" > < a href = "#cb5-13" aria-hidden = "true" tabindex = "-1" > < / a > modell.AddAllDifferent([x, y]) < span class = "co" > # globale Bedingung< / span > < / span >
< span id = "cb5-14" > < a href = "#cb5-14" aria-hidden = "true" tabindex = "-1" > < / a > modell.AddMaxEquality(z < span class = "op" > :=< / span > modell.NewIntVar(< span class = "dv" > 0< / span > , < span class = "dv" > 100< / span > , < span class = "st" > " z" < / span > ), [x, y])< / span >
< span id = "cb5-15" > < a href = "#cb5-15" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb5-16" > < a href = "#cb5-16" aria-hidden = "true" tabindex = "-1" > < / a > modell.Maximize(< span class = "dv" > 10< / span > < span class = "op" > *< / span > x < span class = "op" > +< / span > < span class = "dv" > 15< / span > < span class = "op" > *< / span > y < span class = "op" > -< / span > < span class = "dv" > 3< / span > < span class = "op" > *< / span > z)< / span >
< span id = "cb5-17" > < a href = "#cb5-17" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb5-18" > < a href = "#cb5-18" aria-hidden = "true" tabindex = "-1" > < / a > loeser < span class = "op" > =< / span > cp_model.CpSolver()< / span >
< span id = "cb5-19" > < a href = "#cb5-19" aria-hidden = "true" tabindex = "-1" > < / a > loeser.parameters.max_time_in_seconds < span class = "op" > =< / span > < span class = "fl" > 10.0< / span > < / span >
< span id = "cb5-20" > < a href = "#cb5-20" aria-hidden = "true" tabindex = "-1" > < / a > loeser.parameters.num_workers < span class = "op" > =< / span > < span class = "dv" > 1< / span > < span class = "co" > # 1 = reproduzierbar< / span > < / span >
< span id = "cb5-21" > < a href = "#cb5-21" aria-hidden = "true" tabindex = "-1" > < / a > loeser.parameters.random_seed < span class = "op" > =< / span > < span class = "dv" > 1< / span > < / span >
< span id = "cb5-22" > < a href = "#cb5-22" aria-hidden = "true" tabindex = "-1" > < / a > status < span class = "op" > =< / span > loeser.Solve(modell)< / span >
< span id = "cb5-23" > < a href = "#cb5-23" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb5-24" > < a href = "#cb5-24" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > if< / span > status < span class = "op" > ==< / span > cp_model.OPTIMAL:< / span >
< span id = "cb5-25" > < a href = "#cb5-25" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" optimal: < / span > < span class = "sc" > {< / span > loeser< span class = "sc" > .< / span > ObjectiveValue()< span class = "sc" > :.0f}< / span > < span class = "ss" > x=< / span > < span class = "sc" > {< / span > loeser< span class = "sc" > .< / span > Value(x)< span class = "sc" > }< / span > < span class = "ss" > y=< / span > < span class = "sc" > {< / span > loeser< span class = "sc" > .< / span > Value(y)< span class = "sc" > }< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb5-26" > < a href = "#cb5-26" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > status < span class = "op" > ==< / span > cp_model.FEASIBLE:< / span >
< span id = "cb5-27" > < a href = "#cb5-27" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" zulaessig, nicht bewiesen optimal - Gap-Schranke: < / span > < span class = "sc" > {< / span > loeser< span class = "sc" > .< / span > BestObjectiveBound()< span class = "sc" > }< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb5-28" > < a href = "#cb5-28" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > status < span class = "op" > ==< / span > cp_model.INFEASIBLE:< / span >
< span id = "cb5-29" > < a href = "#cb5-29" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " INFEASIBLE - Bedingungen widersprechen sich" < / span > )< / span >
< span id = "cb5-30" > < a href = "#cb5-30" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > status < span class = "op" > ==< / span > cp_model.MODEL_INVALID:< / span >
< span id = "cb5-31" > < a href = "#cb5-31" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " Modellfehler:" < / span > , modell.Validate())< / span >
< span id = "cb5-32" > < a href = "#cb5-32" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > else< / span > :< / span >
< span id = "cb5-33" > < a href = "#cb5-33" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " UNKNOWN - Zeit abgelaufen, ohne eine Loesung zu finden" < / span > )< / span >
< span id = "cb5-34" > < a href = "#cb5-34" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" Laufzeit < / span > < span class = "sc" > {< / span > loeser< span class = "sc" > .< / span > WallTime()< span class = "sc" > :.3f}< / span > < span class = "ss" > s, < / span > < span class = "sc" > {< / span > loeser< span class = "sc" > .< / span > NumBranches()< span class = "sc" > }< / span > < span class = "ss" > Verzweigungen" < / span > )< / span > < / code > < / pre > < / div >
< h3 id = "die-drei-häufigsten-stolpersteine-3" > Die drei häufigsten Stolpersteine< / h3 >
< ol type = "1" >
< li > < strong > Alles ist ganzzahlig.< / strong > < code > 0.5 * x< / code > gibt es nicht. Skalieren Sie das ganze Modell auf eine feinere Einheit, statt zu runden.< / li >
< li > < strong > < code > UNKNOWN< / code > heißt nicht < code > INFEASIBLE< / code > .< / strong > Es heißt: Die Zeit war zu knapp, um überhaupt etwas zu finden. Die beiden zu verwechseln ist einer der teuersten Fehler in Produktion — das Modell wird für widersprüchlich erklärt, obwohl es lösbar ist.< / li >
< li > < strong > Ohne < code > num_workers = 1< / code > ist der Lauf nicht reproduzierbar.< / strong > Mehrere Suchstränge finden je nach Zeitverlauf verschiedene, gleich gute Lösungen. Für Tests und für abgedruckte Ausgaben Worker und Seed festnageln.< / li >
< / ol >
< hr / >
< h2 id = "d5-cvxpy" > D5 — CVXPY< / h2 >
Glossar: Sprungleiste, Abkürzungen ausschreiben, CLAUDE.md-Regel
Sprungleiste (A B C ... Z) im Glossar — wie im Stichwortverzeichnis:
ein Klick je Buchstabe springt zur '## <Buchstabe>'-Überschrift.
Eingebaut in erzeuge_glossar_04.py als {=html}-Rohblock (nur HTML,
im PDF bedeutungslos).
Abkürzungen beim ersten Mal ausschreiben: 'VaR' → 'VaR (Value at Risk)',
'EVPI' → 'EVPI (Expected Value of Perfect Information)' als Link-Text
bei der ersten Nennung je Datei; danach nur die Abkürzung. 19 Abkürzungen
erfasst (VaR, CVaR, KKT, NLP, MILP, EVPI, LP, QP, ...).
CLAUDE.md: Regel 'Glossar-Links: Fachbegriffe im Fließtext automatisch
verlinkt' dokumentiert — resolve_glossar(), LINK_TEXTE,
ABBREV_ERSTE_NENNUNG, _NICHT_AUTO_LINKEN, _ZU_KURZ_ABK, .glossar-link,
{gl:}-Marke, Sprungleiste, {#gloss:<slug>}-Anchor.
2026-09-10 17:52:49 +02:00
< p > < strong > Wofür.< / strong > Konvexe Probleme: quadratische Ziele, Normen, < a href = "anhang-glossar.md#gloss:conditional-value-at-risk-cvar" class = "glossar-link" > CVaR (Conditional Value at Risk)< / a > , alles mit Regularisierungstermen. < strong > Wofür nicht:< / strong > große kombinatorische Modelle — der Aufbau der Ausdrücke wird dann selbst zum Engpass.< / p >
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
< div class = "sourceCode" id = "cb6" > < pre class = "sourceCode python" > < code class = "sourceCode python" > < span id = "cb6-1" > < a href = "#cb6-1" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > import< / span > numpy < span class = "im" > as< / span > np< / span >
< span id = "cb6-2" > < a href = "#cb6-2" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > import< / span > cvxpy < span class = "im" > as< / span > cp< / span >
< span id = "cb6-3" > < a href = "#cb6-3" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb6-4" > < a href = "#cb6-4" aria-hidden = "true" tabindex = "-1" > < / a > x < span class = "op" > =< / span > cp.Variable(< span class = "dv" > 3< / span > , nonneg< span class = "op" > =< / span > < span class = "va" > True< / span > ) < span class = "co" > # nonneg=True statt x > = 0< / span > < / span >
< span id = "cb6-5" > < a href = "#cb6-5" aria-hidden = "true" tabindex = "-1" > < / a > gewichte < span class = "op" > =< / span > cp.Variable(< span class = "dv" > 3< / span > )< / span >
< span id = "cb6-6" > < a href = "#cb6-6" aria-hidden = "true" tabindex = "-1" > < / a > ganzzahlig < span class = "op" > =< / span > cp.Variable(< span class = "dv" > 3< / span > , integer< span class = "op" > =< / span > < span class = "va" > True< / span > ) < span class = "co" > # macht daraus ein MIP< / span > < / span >
< span id = "cb6-7" > < a href = "#cb6-7" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb6-8" > < a href = "#cb6-8" aria-hidden = "true" tabindex = "-1" > < / a > ziel < span class = "op" > =< / span > cp.Maximize(np.array([< span class = "fl" > 10.0< / span > , < span class = "fl" > 15.0< / span > , < span class = "fl" > 25.0< / span > ]) < span class = "op" > @< / span > x)< / span >
< span id = "cb6-9" > < a href = "#cb6-9" aria-hidden = "true" tabindex = "-1" > < / a > bedingungen < span class = "op" > =< / span > [np.array([[< span class = "dv" > 1< / span > , < span class = "dv" > 1< / span > , < span class = "dv" > 2< / span > ], [< span class = "dv" > 2< / span > , < span class = "dv" > 3< / span > , < span class = "dv" > 1< / span > ]]) < span class = "op" > @< / span > x < span class = "op" > < =< / span > np.array([< span class = "fl" > 40.0< / span > , < span class = "fl" > 50.0< / span > ])]< / span >
< span id = "cb6-10" > < a href = "#cb6-10" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb6-11" > < a href = "#cb6-11" aria-hidden = "true" tabindex = "-1" > < / a > problem < span class = "op" > =< / span > cp.Problem(ziel, bedingungen)< / span >
< span id = "cb6-12" > < a href = "#cb6-12" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > if< / span > < span class = "kw" > not< / span > problem.is_dcp(): < span class = "co" > # VOR dem Loesen pruefen< / span > < / span >
< span id = "cb6-13" > < a href = "#cb6-13" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " nicht DCP:" < / span > , [c < span class = "cf" > for< / span > c < span class = "kw" > in< / span > bedingungen < span class = "cf" > if< / span > < span class = "kw" > not< / span > c.is_dcp()])< / span >
< span id = "cb6-14" > < a href = "#cb6-14" aria-hidden = "true" tabindex = "-1" > < / a > problem.solve()< / span >
< span id = "cb6-15" > < a href = "#cb6-15" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb6-16" > < a href = "#cb6-16" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > if< / span > problem.status < span class = "op" > ==< / span > cp.OPTIMAL:< / span >
< span id = "cb6-17" > < a href = "#cb6-17" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" optimal: < / span > < span class = "sc" > {< / span > problem< span class = "sc" > .< / span > value< span class = "sc" > :.2f}< / span > < span class = "ss" > x = < / span > < span class = "sc" > {< / span > np< span class = "sc" > .< / span > < span class = "bu" > round< / span > (x.value, < span class = "dv" > 4< / span > )< span class = "sc" > }< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb6-18" > < a href = "#cb6-18" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" Schattenpreis: < / span > < span class = "sc" > {< / span > np< span class = "sc" > .< / span > < span class = "bu" > round< / span > (bedingungen[< span class = "dv" > 0< / span > ].dual_value, < span class = "dv" > 4< / span > )< span class = "sc" > }< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb6-19" > < a href = "#cb6-19" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > problem.status < span class = "op" > ==< / span > cp.OPTIMAL_INACCURATE:< / span >
< span id = "cb6-20" > < a href = "#cb6-20" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " Loesung numerisch unsicher - Skalierung pruefen, anderen Solver testen" < / span > )< / span >
< span id = "cb6-21" > < a href = "#cb6-21" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > problem.status < span class = "op" > ==< / span > cp.INFEASIBLE:< / span >
< span id = "cb6-22" > < a href = "#cb6-22" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " INFEASIBLE" < / span > )< / span >
< span id = "cb6-23" > < a href = "#cb6-23" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > problem.status < span class = "op" > ==< / span > cp.UNBOUNDED:< / span >
< span id = "cb6-24" > < a href = "#cb6-24" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " UNBOUNDED" < / span > )< / span >
< span id = "cb6-25" > < a href = "#cb6-25" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > else< / span > :< / span >
< span id = "cb6-26" > < a href = "#cb6-26" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " Solverfehler:" < / span > , problem.status)< / span > < / code > < / pre > < / div >
< h3 id = "die-drei-häufigsten-stolpersteine-4" > Die drei häufigsten Stolpersteine< / h3 >
< ol type = "1" >
Glossar: Sprungleiste, Abkürzungen ausschreiben, CLAUDE.md-Regel
Sprungleiste (A B C ... Z) im Glossar — wie im Stichwortverzeichnis:
ein Klick je Buchstabe springt zur '## <Buchstabe>'-Überschrift.
Eingebaut in erzeuge_glossar_04.py als {=html}-Rohblock (nur HTML,
im PDF bedeutungslos).
Abkürzungen beim ersten Mal ausschreiben: 'VaR' → 'VaR (Value at Risk)',
'EVPI' → 'EVPI (Expected Value of Perfect Information)' als Link-Text
bei der ersten Nennung je Datei; danach nur die Abkürzung. 19 Abkürzungen
erfasst (VaR, CVaR, KKT, NLP, MILP, EVPI, LP, QP, ...).
CLAUDE.md: Regel 'Glossar-Links: Fachbegriffe im Fließtext automatisch
verlinkt' dokumentiert — resolve_glossar(), LINK_TEXTE,
ABBREV_ERSTE_NENNUNG, _NICHT_AUTO_LINKEN, _ZU_KURZ_ABK, .glossar-link,
{gl:}-Marke, Sprungleiste, {#gloss:<slug>}-Anchor.
2026-09-10 17:52:49 +02:00
< li > < strong > < a href = "anhang-glossar.md#gloss:dcp-disciplined-convex-programming" class = "glossar-link" > DCP (Disciplined Convex Programming)< / a > -Regeln vor dem Lösen prüfen.< / strong > < code > problem.is_dcp()< / code > und dann die einzelnen Bedingungen — das nennt die Schuldige, statt einen < code > DCPError< / code > ohne Ort zu werfen (< a href = "anhang-fehlerdiagnose.html#anhang-fehlerdiagnose" > Anhang C< / a > , C8).< / li >
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
< li > < strong > < code > OPTIMAL_INACCURATE< / code > ist kein Erfolg.< / strong > Der Solver hat aufgegeben und meldet das leise. Diesen Fall immer eigens behandeln.< / li >
< li > < strong > Der Aufbau kann teurer sein als das Lösen.< / strong > Schleifen über Szenarien durch Vektorausdrücke ersetzen; < code > Parameter< / code > statt Neuaufbau, wenn sich nur Zahlen ändern.< / li >
< / ol >
< hr / >
< h2 id = "d6-modellierungssprachen-pyomo-und-linopy" > D6 — Modellierungssprachen: Pyomo und Linopy< / h2 >
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.
2026-09-10 17:40:29 +02:00
< p > < strong > Wofür.< / strong > Beide trennen < em > Modell< / em > von < em > Solver< / em > : dasselbe Modell läuft ohne Änderung unter HiGHS, CBC, < a href = "anhang-glossar.md#gloss:gurobi" class = "glossar-link" > Gurobi< / a > . < a href = "anhang-glossar.md#gloss:pyomo" class = "glossar-link" > Pyomo< / a > denkt in < strong > Mengen und Indizes< / strong > wie eine mathematische Formulierung; < a href = "anhang-glossar.md#gloss:linopy" class = "glossar-link" > Linopy< / a > denkt in < strong > beschrifteten Arrays< / strong > und baut Nebenbedingungen als Matrixoperation statt in Python-Schleifen. < strong > Wofür nicht:< / strong > ein Modell mit zehn Nebenbedingungen — dort ist der Aufwand höher als der Nutzen.< / p >
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
< h3 id = "pyomo" > Pyomo< / h3 >
< div class = "sourceCode" id = "cb7" > < pre class = "sourceCode python" > < code class = "sourceCode python" > < span id = "cb7-1" > < a href = "#cb7-1" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > import< / span > pyomo.environ < span class = "im" > as< / span > pyo< / span >
< span id = "cb7-2" > < a href = "#cb7-2" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb7-3" > < a href = "#cb7-3" aria-hidden = "true" tabindex = "-1" > < / a > modell < span class = "op" > =< / span > pyo.ConcreteModel()< / span >
< span id = "cb7-4" > < a href = "#cb7-4" aria-hidden = "true" tabindex = "-1" > < / a > modell.J < span class = "op" > =< / span > pyo.RangeSet(< span class = "dv" > 0< / span > , < span class = "dv" > 2< / span > ) < span class = "co" > # Indexmenge< / span > < / span >
< span id = "cb7-5" > < a href = "#cb7-5" aria-hidden = "true" tabindex = "-1" > < / a > modell.x < span class = "op" > =< / span > pyo.Var(modell.J, domain< span class = "op" > =< / span > pyo.NonNegativeReals)< / span >
< span id = "cb7-6" > < a href = "#cb7-6" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "co" > # ganzzahlig: domain=pyo.NonNegativeIntegers | binaer: domain=pyo.Binary< / span > < / span >
< span id = "cb7-7" > < a href = "#cb7-7" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb7-8" > < a href = "#cb7-8" aria-hidden = "true" tabindex = "-1" > < / a > ertrag < span class = "op" > =< / span > {< span class = "dv" > 0< / span > : < span class = "fl" > 10.0< / span > , < span class = "dv" > 1< / span > : < span class = "fl" > 15.0< / span > , < span class = "dv" > 2< / span > : < span class = "fl" > 25.0< / span > }< / span >
< span id = "cb7-9" > < a href = "#cb7-9" aria-hidden = "true" tabindex = "-1" > < / a > modell.ziel < span class = "op" > =< / span > pyo.Objective(expr< span class = "op" > =< / span > < span class = "bu" > sum< / span > (ertrag[j] < span class = "op" > *< / span > modell.x[j] < span class = "cf" > for< / span > j < span class = "kw" > in< / span > modell.J),< / span >
< span id = "cb7-10" > < a href = "#cb7-10" aria-hidden = "true" tabindex = "-1" > < / a > sense< span class = "op" > =< / span > pyo.maximize)< / span >
< span id = "cb7-11" > < a href = "#cb7-11" aria-hidden = "true" tabindex = "-1" > < / a > modell.montage < span class = "op" > =< / span > pyo.Constraint(< / span >
< span id = "cb7-12" > < a href = "#cb7-12" aria-hidden = "true" tabindex = "-1" > < / a > expr< span class = "op" > =< / span > modell.x[< span class = "dv" > 0< / span > ] < span class = "op" > +< / span > modell.x[< span class = "dv" > 1< / span > ] < span class = "op" > +< / span > < span class = "dv" > 2< / span > < span class = "op" > *< / span > modell.x[< span class = "dv" > 2< / span > ] < span class = "op" > < =< / span > < span class = "dv" > 40< / span > )< / span >
< span id = "cb7-13" > < a href = "#cb7-13" aria-hidden = "true" tabindex = "-1" > < / a > modell.pruefung < span class = "op" > =< / span > pyo.Constraint(< / span >
< span id = "cb7-14" > < a href = "#cb7-14" aria-hidden = "true" tabindex = "-1" > < / a > expr< span class = "op" > =< / span > < span class = "dv" > 2< / span > < span class = "op" > *< / span > modell.x[< span class = "dv" > 0< / span > ] < span class = "op" > +< / span > < span class = "dv" > 3< / span > < span class = "op" > *< / span > modell.x[< span class = "dv" > 1< / span > ] < span class = "op" > +< / span > modell.x[< span class = "dv" > 2< / span > ] < span class = "op" > < =< / span > < span class = "dv" > 50< / span > )< / span >
< span id = "cb7-15" > < a href = "#cb7-15" aria-hidden = "true" tabindex = "-1" > < / a > modell.dual < span class = "op" > =< / span > pyo.Suffix(direction< span class = "op" > =< / span > pyo.Suffix.IMPORT) < span class = "co" > # fuer Schattenpreise< / span > < / span >
< span id = "cb7-16" > < a href = "#cb7-16" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb7-17" > < a href = "#cb7-17" aria-hidden = "true" tabindex = "-1" > < / a > ergebnis < span class = "op" > =< / span > pyo.SolverFactory(< span class = "st" > " appsi_highs" < / span > ).solve(modell)< / span >
< span id = "cb7-18" > < a href = "#cb7-18" aria-hidden = "true" tabindex = "-1" > < / a > zustand < span class = "op" > =< / span > ergebnis.solver.termination_condition< / span >
< span id = "cb7-19" > < a href = "#cb7-19" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > if< / span > zustand < span class = "op" > ==< / span > pyo.TerminationCondition.optimal:< / span >
< span id = "cb7-20" > < a href = "#cb7-20" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" optimal: < / span > < span class = "sc" > {< / span > pyo< span class = "sc" > .< / span > value(modell.ziel)< span class = "sc" > :.2f}< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb7-21" > < a href = "#cb7-21" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" x = < / span > < span class = "sc" > {< / span > [< span class = "bu" > round< / span > (pyo.value(modell.x[j]), < span class = "dv" > 4< / span > ) < span class = "cf" > for< / span > j < span class = "kw" > in< / span > modell.J]< span class = "sc" > }< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb7-22" > < a href = "#cb7-22" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" Schattenpreis Montage: < / span > < span class = "sc" > {< / span > modell< span class = "sc" > .< / span > dual[modell.montage]< span class = "sc" > :.4f}< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb7-23" > < a href = "#cb7-23" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > zustand < span class = "op" > ==< / span > pyo.TerminationCondition.infeasible:< / span >
< span id = "cb7-24" > < a href = "#cb7-24" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " INFEASIBLE" < / span > )< / span >
< span id = "cb7-25" > < a href = "#cb7-25" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > zustand < span class = "op" > ==< / span > pyo.TerminationCondition.unbounded:< / span >
< span id = "cb7-26" > < a href = "#cb7-26" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " UNBOUNDED" < / span > )< / span >
< span id = "cb7-27" > < a href = "#cb7-27" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > zustand < span class = "op" > ==< / span > pyo.TerminationCondition.maxTimeLimit:< / span >
< span id = "cb7-28" > < a href = "#cb7-28" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " Zeitlimit" < / span > )< / span >
< span id = "cb7-29" > < a href = "#cb7-29" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > else< / span > :< / span >
< span id = "cb7-30" > < a href = "#cb7-30" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " kein Optimum:" < / span > , zustand)< / span > < / code > < / pre > < / div >
< h3 id = "linopy" > Linopy< / h3 >
< div class = "sourceCode" id = "cb8" > < pre class = "sourceCode python" > < code class = "sourceCode python" > < span id = "cb8-1" > < a href = "#cb8-1" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > import< / span > linopy< / span >
< span id = "cb8-2" > < a href = "#cb8-2" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > import< / span > numpy < span class = "im" > as< / span > np< / span >
< span id = "cb8-3" > < a href = "#cb8-3" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > import< / span > pandas < span class = "im" > as< / span > pd< / span >
< span id = "cb8-4" > < a href = "#cb8-4" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "im" > import< / span > xarray < span class = "im" > as< / span > xr< / span >
< span id = "cb8-5" > < a href = "#cb8-5" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb8-6" > < a href = "#cb8-6" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "co" > # Benannte Indizes statt blosser Listen - sonst heissen die Achsen " dim_0" < / span > < / span >
< span id = "cb8-7" > < a href = "#cb8-7" aria-hidden = "true" tabindex = "-1" > < / a > produkt < span class = "op" > =< / span > pd.Index([< span class = "st" > " Rahmen" < / span > , < span class = "st" > " Gehaeuse" < / span > , < span class = "st" > " Deckel" < / span > ], name< span class = "op" > =< / span > < span class = "st" > " produkt" < / span > )< / span >
< span id = "cb8-8" > < a href = "#cb8-8" aria-hidden = "true" tabindex = "-1" > < / a > ressource < span class = "op" > =< / span > pd.Index([< span class = "st" > " Montage" < / span > , < span class = "st" > " Pruefung" < / span > ], name< span class = "op" > =< / span > < span class = "st" > " ressource" < / span > )< / span >
< span id = "cb8-9" > < a href = "#cb8-9" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb8-10" > < a href = "#cb8-10" aria-hidden = "true" tabindex = "-1" > < / a > modell < span class = "op" > =< / span > linopy.Model()< / span >
< span id = "cb8-11" > < a href = "#cb8-11" aria-hidden = "true" tabindex = "-1" > < / a > modell.add_variables(lower< span class = "op" > =< / span > < span class = "dv" > 0< / span > , coords< span class = "op" > =< / span > [produkt], name< span class = "op" > =< / span > < span class = "st" > " menge" < / span > )< / span >
< span id = "cb8-12" > < a href = "#cb8-12" aria-hidden = "true" tabindex = "-1" > < / a > x < span class = "op" > =< / span > modell.variables[< span class = "st" > " menge" < / span > ]< / span >
< span id = "cb8-13" > < a href = "#cb8-13" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "co" > # ganzzahlig: integer=True | binaer: binary=True< / span > < / span >
< span id = "cb8-14" > < a href = "#cb8-14" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb8-15" > < a href = "#cb8-15" aria-hidden = "true" tabindex = "-1" > < / a > ertrag < span class = "op" > =< / span > xr.DataArray([< span class = "fl" > 10.0< / span > , < span class = "fl" > 15.0< / span > , < span class = "fl" > 25.0< / span > ], coords< span class = "op" > =< / span > [produkt])< / span >
< span id = "cb8-16" > < a href = "#cb8-16" aria-hidden = "true" tabindex = "-1" > < / a > verbrauch < span class = "op" > =< / span > xr.DataArray([[< span class = "fl" > 1.0< / span > , < span class = "fl" > 1.0< / span > , < span class = "fl" > 2.0< / span > ], [< span class = "fl" > 2.0< / span > , < span class = "fl" > 3.0< / span > , < span class = "fl" > 1.0< / span > ]],< / span >
< span id = "cb8-17" > < a href = "#cb8-17" aria-hidden = "true" tabindex = "-1" > < / a > coords< span class = "op" > =< / span > [ressource, produkt])< / span >
< span id = "cb8-18" > < a href = "#cb8-18" aria-hidden = "true" tabindex = "-1" > < / a > vorrat < span class = "op" > =< / span > xr.DataArray([< span class = "fl" > 40.0< / span > , < span class = "fl" > 50.0< / span > ], coords< span class = "op" > =< / span > [ressource])< / span >
< span id = "cb8-19" > < a href = "#cb8-19" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb8-20" > < a href = "#cb8-20" aria-hidden = "true" tabindex = "-1" > < / a > modell.add_objective((ertrag < span class = "op" > *< / span > x).< span class = "bu" > sum< / span > (), sense< span class = "op" > =< / span > < span class = "st" > " max" < / span > )< / span >
< span id = "cb8-21" > < a href = "#cb8-21" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "co" > # EINE Zeile, so viele Nebenbedingungen wie ' ressource' Eintraege hat:< / span > < / span >
< span id = "cb8-22" > < a href = "#cb8-22" aria-hidden = "true" tabindex = "-1" > < / a > modell.add_constraints((verbrauch < span class = "op" > *< / span > x).< span class = "bu" > sum< / span > (< span class = "st" > " produkt" < / span > ) < span class = "op" > < =< / span > vorrat, name< span class = "op" > =< / span > < span class = "st" > " kapazitaet" < / span > )< / span >
< span id = "cb8-23" > < a href = "#cb8-23" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb8-24" > < a href = "#cb8-24" aria-hidden = "true" tabindex = "-1" > < / a > modell.solve(solver_name< span class = "op" > =< / span > < span class = "st" > " highs" < / span > , output_flag< span class = "op" > =< / span > < span class = "va" > False< / span > )< / span >
< span id = "cb8-25" > < a href = "#cb8-25" aria-hidden = "true" tabindex = "-1" > < / a > < / span >
< span id = "cb8-26" > < a href = "#cb8-26" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > if< / span > modell.termination_condition < span class = "op" > ==< / span > < span class = "st" > " optimal" < / span > :< / span >
< span id = "cb8-27" > < a href = "#cb8-27" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "ss" > f" optimal: < / span > < span class = "sc" > {< / span > modell< span class = "sc" > .< / span > objective< span class = "sc" > .< / span > value< span class = "sc" > :.2f}< / span > < span class = "ss" > " < / span > )< / span >
< span id = "cb8-28" > < a href = "#cb8-28" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (x.solution.to_series().< span class = "bu" > round< / span > (< span class = "dv" > 4< / span > ).to_dict())< / span >
< span id = "cb8-29" > < a href = "#cb8-29" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " Schattenpreise:" < / span > ,< / span >
< span id = "cb8-30" > < a href = "#cb8-30" aria-hidden = "true" tabindex = "-1" > < / a > modell.constraints[< span class = "st" > " kapazitaet" < / span > ].dual.to_series().< span class = "bu" > round< / span > (< span class = "dv" > 4< / span > ).to_dict())< / span >
< span id = "cb8-31" > < a href = "#cb8-31" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > modell.termination_condition < span class = "op" > ==< / span > < span class = "st" > " infeasible" < / span > :< / span >
< span id = "cb8-32" > < a href = "#cb8-32" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " INFEASIBLE" < / span > )< / span >
< span id = "cb8-33" > < a href = "#cb8-33" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > elif< / span > modell.termination_condition < span class = "op" > ==< / span > < span class = "st" > " unbounded" < / span > :< / span >
< span id = "cb8-34" > < a href = "#cb8-34" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " UNBOUNDED" < / span > )< / span >
< span id = "cb8-35" > < a href = "#cb8-35" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "cf" > else< / span > :< / span >
< span id = "cb8-36" > < a href = "#cb8-36" aria-hidden = "true" tabindex = "-1" > < / a > < span class = "bu" > print< / span > (< span class = "st" > " kein Optimum:" < / span > , modell.status, modell.termination_condition)< / span > < / code > < / pre > < / div >
< h3 id = "die-drei-häufigsten-stolpersteine-5" > Die drei häufigsten Stolpersteine< / h3 >
< ol type = "1" >
< li > < strong > Der Solver ist ein eigenes Programm.< / strong > < code > SolverFactory("appsi_highs")< / code > scheitert, wenn HiGHS nicht auffindbar ist — die Fehlermeldung nennt dann das Modell, nicht die fehlende Installation.< / li >
< li > < strong > Schattenpreise kommen nur auf Anforderung.< / strong > Bei Pyomo braucht es < code > Suffix(direction=IMPORT)< / code > < em > vor< / em > dem Lösen; wer ihn vergisst, bekommt einen < code > KeyError< / code > statt einer Warnung.< / li >
< li > < strong > Bei Linopy die Indizes benennen< / strong > (< code > pd.Index(..., name="produkt")< / code > ). Ohne Namen heißen die Achsen < code > dim_0< / code > , und jede spätere Zuordnung wird zum Ratespiel.< / li >
< / ol >
< hr / >
< h2 id = "die-gemeinsame-regel" > Die gemeinsame Regel< / h2 >
< p > Alle sechs Seiten haben denselben längsten Abschnitt: die < strong > Statusauswertung< / strong > . Das ist kein Zufall. Ein Solveraufruf hat nie zwei Ausgänge, sondern mindestens fünf — optimal, zulässig ohne Beweis, unlösbar, unbeschränkt, abgebrochen. Code, der nur < code > if erfolgreich:< / code > prüft, verwechselt früher oder später „keine Lösung gefunden“ mit „es gibt keine Lösung“, und diese Verwechslung merkt niemand, bis sie teuer wird.< / p >
< / article >
< button type = "button" class = "fortschritt-knopf" data-kapitel = "anhang-spickzettel.html" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-check" > < / use > < / svg > < span > Als gelesen markieren< / span > < / button >
Glossar und Literatur trennen, Menue um Glossar und ZIP-Download ergaenzen
94_Anhang_Glossar_und_Literatur.md enthielt zwei verschiedene Nachschlagewerke
in einer Datei. Jetzt sind es zwei Anhaenge: E = Glossar (92 Eintraege),
F = Literaturverzeichnis (6 Kategorien). Aus 5 Anhaengen werden 6, aus 36
Kapiteldateien 37.
Die Teilung war billig: Die Datei trug bereits zwei eigenstaendige
Ueberschriften mit nichts als einem --- dazwischen, und im ganzen Buch gab es
genau einen {ref:anhang:glossar-literatur} - die Weiter-mit-Zeile im
Spickzettel. Geprueft: keine Inhaltszeile verloren, alle 92 Glossareintraege
auf der neuen Seite, Indexmarken unveraendert bei 328.
Das Seitenleisten-Menue bekommt zwei Eintraege:
Beispielprogramme
Notebooks
Download Notebooks als ZIP <- neu, eingerueckt
Glossar <- neu
Stichwortverzeichnis
Gesamtdokument (eine Seite)
Download als PDF
Der ZIP-Link benutzt dieselbe Konstante wie baue_notebooks_seite() beim
Schreiben des Archivs, damit Link und Datei nicht auseinanderlaufen. Das
Glossar erscheint absichtlich doppelt: hier als Abkuerzung neben dem
Stichwortverzeichnis, und unten in der Gruppe "Anhaenge", weil es ein Anhang
ist.
Die verwaiste anhang-glossar-literatur.html von Hand entfernt - der Build
raeumt alte Seiten nicht ab.
Nebenbefund, in PROGRESS.md festgehalten: OR_HTML_04/assets/site.css ist eine
von Hand gepflegte Quelle, die im als "generiert" beschriebenen Verzeichnis
liegt. Der Build schreibt sie nie. Dasselbe gilt fuer site.js, icons.svg,
highlight.css und plotly.min.js.
--check: 5 Teile, 23 Kapitel, 6 Anhaenge, 296 Abschnitte, 825 Querverweise,
328 Indexmarken, 37 Dateien, 28.544 Zeilen, 305 Hauptueberschriften, keine
Warnung. PDF unveraendert 759 Seiten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 15:48:57 +02:00
< nav class = "prev-next" > < a class = "prev-next-knopf prev-next-prev" href = "anhang-fehlerdiagnose.html" > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-chevron-left" > < / use > < / svg > < span > < small > Zurück< / small > Anhang C: Fehlerdiagnose-Handbuch< / span > < / a > < a class = "prev-next-knopf prev-next-next" href = "anhang-glossar.html" > < span > < small > Weiter< / small > Anhang E: Glossar< / span > < svg class = "icon" aria-hidden = "true" > < use href = "#icon-chevron-right" > < / use > < / svg > < / a > < / nav >
Version 04 als eigenes Repository
Erster Commit des Strangs "Optimierte Entscheidungsfindung mit Python"
(Version 04). Die Historie der 71 Commits bis zur Trennung bleibt im
uebergeordneten Repository OR_mit_Python liegen, das ab jetzt nur noch
Version_03 (eingefroren) verwaltet und Version_04/ ignoriert.
Bewusst kein "git subtree split": Der Pfad Version_04/ existiert erst seit
der Verzeichnistrennung, ein Split braechte daher nur 7 der 41 einschlaegigen
Commits - eine Teilhistorie, die vollstaendig aussieht und es nicht ist.
Stand: 5 Teile, 23 Kapitel, 5 Anhaenge, 292 Abschnitte, 703 Querverweise,
325 Indexmarken, 73 Beispielprogramme, 32 SVGs, 4 Plotly-Figuren,
25 Notebooks, PDF mit 715 Seiten.
Zusaetzlich in diesem Commit:
* pyproject.toml mit Abhaengigkeitsgruppen finance, large-scale, api,
figures, dev, empfehlungen. Die abgedruckte requirements.txt bleibt
unveraendert daneben bestehen. ortools steht in der Grundausstattung,
highspy erst in [large-scale] - so kann der HiGHS-Symbolkonflikt bei der
schlanken Installation gar nicht erst auftreten.
* Dabei zwei Funde: graphviz wird von erzeuge_architektur_diagramme.py
importiert, fehlt aber in requirements.txt (jetzt in [figures]); pymoo
steht in requirements.txt, wird aber von keinem Programm importiert,
sondern nur im Kapitel Metaheuristiken empfohlen (jetzt in
[empfehlungen]).
* NEUER_TITEL.md nach Kritik_und_Verbesserungsvorschlaege/ verschoben - es
ist die Vorlage des Titelblatts, kein Bestandteil des Werks. Die beiden
Fundstellen in PROGRESS.md und erzeuge_titelseite.py nachgezogen.
* PROGRESS.md nannte noch den Untertitel der ersten Fassung; auf den
tatsaechlichen aus erzeuge_titelseite.py korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 01:20:09 +02:00
< / main >
< / div >
< footer class = "site-footer" >
< p > © Dieter Schlüter · < a href = "gesamtdokument.html" > Gesamtdokument< / a > ·
< a href = "programme.html" > Beispielprogramme< / a > < / p >
< / footer >
< script defer src = "assets/search-index.js" > < / script >
< script defer src = "assets/programme.js" > < / script >
< script defer src = "assets/site.js" > < / script >
< / body >
< / html >