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>
840 lines
103 KiB
HTML
840 lines
103 KiB
HTML
<!doctype html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>Kapitel 10: Spaltengenerierung — das Modell umbauen statt die Lösung raten · 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>document.addEventListener("DOMContentLoaded", function () {
|
||
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>
|
||
<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</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></ul></details><details class="sidebar-gruppe" open><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</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 — 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" class="aktiv"><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></ul></details><details class="sidebar-gruppe"><summary>Teil III: Nichtlinearität, Unsicherheit und mehrperiodige Dynamik</summary><ul><li data-kapitel="qp-nlp.html"><a href="qp-nlp.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 11: Quadratische und nichtlineare Optimierung — KKT, Lagrange, Konvexität</span></a></li><li data-kapitel="unsicherheit.html"><a href="unsicherheit.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 12: Optimierung unter Unsicherheit — Monte-Carlo, Stochastik, Robustheit</span></a></li><li data-kapitel="dynamische-programmierung.html"><a href="dynamische-programmierung.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 13: Dynamische Programmierung — Die Bellman-Gleichung und Order-Execution</span></a></li><li data-kapitel="mehrziel.html"><a href="mehrziel.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 14: Mehrere Ziele — Pareto-Fronten statt Gewichte</span></a></li><li data-kapitel="prognose.html"><a href="prognose.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 15: Predict-then-Optimize — die bessere Prognose, die schlechtere Entscheidung</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil IV: Anwendungen — Energiewirtschaft und Finanzmärkte</summary><ul><li data-kapitel="bruecke.html"><a href="bruecke.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 16: Die Strukturbrücke — dieselbe Mathematik, zwei Welten</span></a></li><li data-kapitel="supplychain.html"><a href="supplychain.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 17: Supply-Chain und Energieeinsatz unter Unsicherheit</span></a></li><li data-kapitel="finanzdaten.html"><a href="finanzdaten.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 18: Finanzdaten-Modellierung — Renditen, Kovarianz und Shrinkage</span></a></li><li data-kapitel="markowitz.html"><a href="markowitz.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 19: Die moderne Portfoliotheorie nach Markowitz</span></a></li><li data-kapitel="cvar.html"><a href="cvar.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 20: Tail-Risiko, CVaR und Transaktionskosten</span></a></li><li data-kapitel="handelsmaschine.html"><a href="handelsmaschine.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 21: Die vollständige quantitative Handelsmaschine</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil V: Praxis</summary><ul><li data-kapitel="praxisfallen.html"><a href="praxisfallen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 22: Praxisfallen und der Weg zum produktiven Einsatz</span></a></li><li data-kapitel="testing.html"><a href="testing.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 23: Testen, Messen, Ausliefern</span></a></li><li data-kapitel="projektwerkstatt.html"><a href="projektwerkstatt.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Projektwerkstatt</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Anhänge</summary><ul><li data-kapitel="anhang-loesungen.html"><a href="anhang-loesungen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang A: Lösungen zu allen Übungsaufgaben</span></a></li><li data-kapitel="anhang-modellierungsmuster.html"><a href="anhang-modellierungsmuster.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang B: Katalog der Modellierungsmuster</span></a></li><li data-kapitel="anhang-fehlerdiagnose.html"><a href="anhang-fehlerdiagnose.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang C: Fehlerdiagnose-Handbuch</span></a></li><li data-kapitel="anhang-spickzettel.html"><a href="anhang-spickzettel.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang D: Spickzettel der Solver</span></a></li><li data-kapitel="anhang-glossar-literatur.html"><a href="anhang-glossar-literatur.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang E: Glossar und Literatur</span></a></li></ul></details><ul class="sidebar-extra"><li><a href="programme.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> Beispielprogramme</a></li><li><a href="stichwortverzeichnis.html"><svg class="icon" aria-hidden="true"><use href="#icon-search"></use></svg> Stichwortverzeichnis</a></li><li><a href="gesamtdokument.html"><svg class="icon" aria-hidden="true"><use href="#icon-external-link"></use></svg> Gesamtdokument (eine Seite)</a></li><li><a href="Operations_Research_mit_Python_Version_04.pdf" download><svg class="icon" aria-hidden="true"><use href="#icon-download"></use></svg> Download als PDF</a></li></ul></div></nav>
|
||
<main class="content">
|
||
<nav class="breadcrumb" aria-label="Breadcrumb"><a href="index.html">Start</a> › <span>Teil II</span> › <span>Kapitel 10: Spaltengenerierung — das Modell umbauen statt die Lösung raten</span></nav>
|
||
<nav class="prev-next"><a class="prev-next-knopf prev-next-prev" href="metaheuristiken.html"><svg class="icon" aria-hidden="true"><use href="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 9: Metaheuristiken — wenn der exakte Solver aussteigt</span></a><a class="prev-next-knopf prev-next-next" href="qp-nlp.html"><span><small>Weiter</small>Kapitel 11: Quadratische und nichtlineare Optimierung — KKT, Lagrange, Konvexität</span><svg class="icon" aria-hidden="true"><use href="#icon-chevron-right"></use></svg></a></nav>
|
||
<article>
|
||
<h1 id="kap-dekomposition">Kapitel 10: Spaltengenerierung — das Modell umbauen statt die Lösung raten</h1>
|
||
<div class="card card-blick">
|
||
<blockquote>
|
||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||
<p><strong>Worum geht es?</strong> Um die andere Antwort auf die Frage aus <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a>: Was tun, wenn der Solver an der Größe scheitert? Statt die Lösung zu approximieren, formuliert man das Modell so um, dass exaktes Lösen wieder möglich wird.</p>
|
||
<p><strong>Voraussetzungen:</strong> <a href="lp.html#sec:lp-dualitaet-und-schattenpreise">Abschnitt 5.6</a> (Dualwerte) und <a href="milp.html#kap-milp">Kapitel 6</a> (<code>Rucksack.py</code>). Beides wird gebraucht, aber nicht neu erklärt.</p>
|
||
<p><strong>Danach können Sie:</strong> ein Problem in Master und Teilproblem zerlegen; die Spaltengenerierungsschleife selbst schreiben; und begründen, wann sich der Aufwand lohnt — die Antwort hängt an einer einzigen Kennzahl der Instanz.</p>
|
||
<p><strong>Zeitbedarf:</strong> ca. 3 Stunden.</p>
|
||
<p><strong>Programme:</strong><br />
|
||
<code>Spaltengenerierung.py</code></p>
|
||
<p><strong>Notebook:</strong> <a href="Notebooks_04/dekomposition.ipynb">dekomposition.ipynb</a><br />
|
||
<a href="https://colab.research.google.com/github/dschlueter/or-mit-python/blob/main/Notebooks_04/dekomposition.ipynb">In Google Colab öffnen</a></p>
|
||
</blockquote>
|
||
</div>
|
||
<hr />
|
||
<h2 id="sec:dekomposition-schnellstart">10.1 In 5 Minuten gelöst</h2>
|
||
<div class="card card-schnellstart">
|
||
<blockquote>
|
||
<p><strong>🚀 In 5 Minuten gelöst: Denken Sie in Mustern, nicht in Stücken</strong></p>
|
||
<p>Eine Rolle ist 1 000 mm breit. Bestellt sind 9 Stück à 420 mm, 12 à 310 mm und 14 à 250 mm. Wie viele Rollen braucht man?</p>
|
||
<p>Die naheliegende Frage — <em>„welches Stück kommt auf welche Rolle?“</em> — führt zu 35 Einzelentscheidungen. Die bessere Frage lautet: <em>„Wie oft schneide ich welches Muster?“</em></p>
|
||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> itertools</span>
|
||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> linprog</span>
|
||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>ROLLE <span class="op">=</span> <span class="dv">1000</span> <span class="co"># mm Mutterrolle</span></span>
|
||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>breiten, bedarf <span class="op">=</span> [<span class="dv">420</span>, <span class="dv">310</span>, <span class="dv">250</span>], [<span class="dv">9</span>, <span class="dv">12</span>, <span class="dv">14</span>]</span>
|
||
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="co"># Alle Schnittmuster aufzaehlen, die in die Rolle passen</span></span>
|
||
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>muster <span class="op">=</span> [m <span class="cf">for</span> m <span class="kw">in</span> itertools.product(<span class="op">*</span>[<span class="bu">range</span>(ROLLE <span class="op">//</span> b <span class="op">+</span> <span class="dv">1</span>) <span class="cf">for</span> b <span class="kw">in</span> breiten])</span>
|
||
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="bu">sum</span>(a <span class="op">*</span> b <span class="cf">for</span> a, b <span class="kw">in</span> <span class="bu">zip</span>(m, breiten)) <span class="op"><=</span> ROLLE <span class="kw">and</span> <span class="bu">sum</span>(m) <span class="op">></span> <span class="dv">0</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="co"># Wie oft schneide ich welches Muster? min sum(x) u.d.N. A x >= bedarf</span></span>
|
||
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>loesung <span class="op">=</span> linprog(np.ones(<span class="bu">len</span>(muster)), A_ub<span class="op">=-</span>np.array(muster, <span class="bu">float</span>).T,</span>
|
||
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a> b_ub<span class="op">=-</span>np.array(bedarf, <span class="bu">float</span>), bounds<span class="op">=</span>(<span class="dv">0</span>, <span class="va">None</span>),</span>
|
||
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a> integrality<span class="op">=</span><span class="dv">1</span>, method<span class="op">=</span><span class="st">"highs"</span>)</span>
|
||
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"</span><span class="sc">{</span><span class="bu">len</span>(muster)<span class="sc">}</span><span class="ss"> zulaessige Muster, </span><span class="sc">{</span><span class="bu">int</span>(<span class="bu">round</span>(loesung.fun))<span class="sc">}</span><span class="ss"> Rollen noetig:"</span>)</span>
|
||
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> anzahl, m <span class="kw">in</span> <span class="bu">zip</span>(np.<span class="bu">round</span>(loesung.x).astype(<span class="bu">int</span>), muster):</span>
|
||
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> anzahl:</span>
|
||
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a> rest <span class="op">=</span> ROLLE <span class="op">-</span> <span class="bu">sum</span>(a <span class="op">*</span> b <span class="cf">for</span> a, b <span class="kw">in</span> <span class="bu">zip</span>(m, breiten))</span>
|
||
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span>anzahl<span class="sc">:2d}</span><span class="ss"> x "</span> <span class="op">+</span> <span class="st">" "</span>.join(<span class="ss">f"</span><span class="sc">{</span>a<span class="sc">}</span><span class="ss">x</span><span class="sc">{</span>b<span class="sc">}</span><span class="ss">mm"</span> <span class="cf">for</span> a, b <span class="kw">in</span> <span class="bu">zip</span>(m, breiten))</span>
|
||
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a> <span class="op">+</span> <span class="ss">f" Verschnitt </span><span class="sc">{</span>rest<span class="sc">}</span><span class="ss"> mm"</span>)</span></code></pre></div>
|
||
<p><strong>Ausgabe:</strong></p>
|
||
<pre><code>16 zulaessige Muster, 12 Rollen noetig:
|
||
2 x 0x420mm 0x310mm 4x250mm Verschnitt 0 mm
|
||
1 x 0x420mm 3x310mm 0x250mm Verschnitt 70 mm
|
||
9 x 1x420mm 1x310mm 1x250mm Verschnitt 20 mm</code></pre>
|
||
</blockquote>
|
||
</div>
|
||
<p><strong>Und jetzt der Punkt.</strong> Sehen Sie sich an, was da herauskommt: <strong>drei Schnittmuster</strong>. Kein Zuordnungsplan für 35 Stücke, sondern eine Anweisung, die an der Maschine hängen kann — neunmal dieses Muster, zweimal jenes, einmal das dritte.</p>
|
||
<p>Das ist kein kosmetischer Unterschied. Das Modell hat <strong>eine Variable je Muster</strong> statt einer je Stück-und-Rolle, und es kennt gar keine einzelnen Rollen mehr. Damit verschwindet ein Problem, das das naheliegende Modell praktisch unlösbar macht — dazu gleich mehr.</p>
|
||
<blockquote>
|
||
<p><strong>🎯 Merksatz</strong> Die schwierigste Arbeit an einem Optimierungsmodell ist selten die Zielfunktion. Es ist die Frage, <strong>worüber</strong> die Variablen laufen.</p>
|
||
</blockquote>
|
||
<p><strong>Warum funktioniert das?</strong> Weil hier alle 16 möglichen Muster aufzählbar waren. Bei drei Breiten und einer 1 000-mm-Rolle sind es 16; bei dreizehn Breiten und 5 600 mm sind es zehntausende, und bei einer echten Papierfabrik mehr, als sich speichern lässt. Das ganze Kapitel handelt davon, wie man mit Mustern rechnet, ohne sie aufzuschreiben.</p>
|
||
<hr />
|
||
<h2 id="sec:dekomposition-lernziele">10.2 Lernziele</h2>
|
||
<p>Nach diesem Kapitel können Sie …</p>
|
||
<ol type="1">
|
||
<li>… erklären, warum das naheliegende Zuordnungsmodell an <strong>Symmetrie</strong> scheitert.</li>
|
||
<li>… ein Problem in <strong>Master</strong> und <strong>Pricing-Teilproblem</strong> zerlegen.</li>
|
||
<li>… die Schleife schreiben: Master-LP lösen, Dualwerte auslesen, Teilproblem lösen, Spalte hinzufügen.</li>
|
||
<li>… das Abbruchkriterium über die <strong>reduzierten Kosten</strong> begründen.</li>
|
||
<li>… an einer Kennzahl der Instanz abschätzen, ob sich das Verfahren lohnt.</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="sec:dekomposition-symmetrie">10.3 Warum das naheliegende Modell scheitert</h2>
|
||
<p>Der erste Entwurf eines Zuschnittmodells sieht fast immer so aus: eine Binärvariable <span class="math inline">z_{jr}</span> für „Stück <span class="math inline">j</span> liegt auf Rolle <span class="math inline">r</span>“, dazu <span class="math inline">y_r</span> für „Rolle <span class="math inline">r</span> wird benutzt”.</p>
|
||
<p>Zwei Dinge gehen dabei schief.</p>
|
||
<p><strong>Die Größe.</strong> Bei 219 Zuschnitten und höchstens 82 Rollen sind das knapp 18 000 Binärvariablen — unangenehm, aber allein noch kein Hindernis.</p>
|
||
<p><strong>Die Symmetrie.</strong> Das ist das eigentliche Problem. Alle Mutterrollen sind <strong>gleich</strong>. Jede Lösung existiert deshalb in unzähligen Umbenennungen: Vertauscht man Rolle 3 und Rolle 47, entsteht eine formal andere, inhaltlich identische Lösung. Branch-and-Bound weiß das nicht und arbeitet sie einzeln ab.</p>
|
||
<blockquote>
|
||
<p><strong>⚠️ Woran man ein Symmetrieproblem erkennt</strong></p>
|
||
<p>Der Suchbaum wächst, aber die <strong>Schranke bewegt sich nicht.</strong> Im Protokoll aus <a href="milp.html#sec:milp-gap">Abschnitt 6.8</a> sieht das so aus: Die Zahl der Knoten steigt in die Hunderttausende, der Incumbent verbessert sich hin und wieder, und der Dual Bound steht praktisch still.</p>
|
||
<p>Das ist ein anderes Bild als „das Problem ist einfach zu groß”. Bei einem großen, aber unsymmetrischen Problem nähern sich beide Werte einander an, nur langsam.</p>
|
||
</blockquote>
|
||
<p>Das Mustermodell hat dieses Problem nicht, weil es <strong>keine einzelnen Rollen kennt</strong>. Es zählt nur, wie oft welches Schnittmuster geschnitten wird:</p>
|
||
<p><span class="math display">
|
||
\min \sum_{p \in P} x_p
|
||
\qquad \text{unter} \qquad
|
||
\sum_{p \in P} a_{ip}\, x_p \ge d_i \quad \forall i,
|
||
\qquad x_p \ge 0 \ \text{ganzzahlig}
|
||
</span></p>
|
||
<div class="card card-formel">
|
||
<blockquote>
|
||
<p><strong>🔤 Formel-Übersetzer</strong></p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 50%" />
|
||
<col style="width: 50%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr class="header">
|
||
<th>Mathematik</th>
|
||
<th>Alltagssprache</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td><span class="math inline">P</span></td>
|
||
<td>die Menge aller zulässigen Schnittmuster</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td><span class="math inline">a_{ip}</span></td>
|
||
<td>„Wie viele Stücke der Breite <span class="math inline">i</span> liefert Muster <span class="math inline">p</span>?”</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td><span class="math inline">x_p</span></td>
|
||
<td>„Wie oft schneide ich Muster <span class="math inline">p</span>?” — die einzige Entscheidung</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td><span class="math inline">d_i</span></td>
|
||
<td>die bestellte Stückzahl der Breite <span class="math inline">i</span></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td><span class="math inline">\sum_p x_p</span></td>
|
||
<td>die Zahl der verbrauchten Mutterrollen</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Ohne Formel gesagt:</strong> „Stelle eine Schnittliste zusammen, die alle Bestellungen deckt, und benutze dabei so wenige Rollen wie möglich.”</p>
|
||
<p>Das Modell ist verblüffend klein — eine Zeile je Breite. Sein ganzes Gewicht steckt in <span class="math inline">P</span>, und das ist der Haken.</p>
|
||
</blockquote>
|
||
</div>
|
||
<hr />
|
||
<h2 id="sec:dekomposition-schleife">10.4 Rechnen mit Mustern, ohne sie aufzuschreiben</h2>
|
||
<p>Die Idee ist alt (Gilmore und Gomory, 1961) und in einem Satz gesagt:</p>
|
||
<blockquote>
|
||
<p>Fange mit wenigen Mustern an. Frage nach jeder Lösung, ob es ein <strong>noch nicht bekanntes</strong> Muster gibt, das sich lohnen würde — und wenn ja, nimm nur dieses eine dazu.</p>
|
||
</blockquote>
|
||
<p>Die Frage „lohnt sich noch ein Muster?” beantworten die <strong>Dualwerte</strong> des Master-LPs. Der Dualwert <span class="math inline">\pi_i</span> zur Bedarfszeile <span class="math inline">i</span> ist genau der Schattenpreis aus <a href="lp.html#sec:lp-dualitaet-und-schattenpreise">Abschnitt 5.6</a>: Er sagt, wie viele Rollen ein zusätzliches Stück der Breite <span class="math inline">i</span> kostet.</p>
|
||
<p>Ein neues Muster <span class="math inline">a</span> lohnt sich, wenn seine <strong>reduzierten Kosten</strong> negativ sind:</p>
|
||
<p><span class="math display">
|
||
1 - \sum_i \pi_i\, a_i < 0
|
||
\qquad\Longleftrightarrow\qquad
|
||
\sum_i \pi_i\, a_i > 1
|
||
</span></p>
|
||
<div class="card card-formel">
|
||
<blockquote>
|
||
<p><strong>🔤 Formel-Übersetzer</strong></p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 50%" />
|
||
<col style="width: 50%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr class="header">
|
||
<th>Mathematik</th>
|
||
<th>Alltagssprache</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td>die <span class="math inline">1</span></td>
|
||
<td>„Ein zusätzliches Muster zu schneiden kostet eine Rolle.”</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td><span class="math inline">\sum_i \pi_i a_i</span></td>
|
||
<td>„So viel ist das, was dabei herauskommt, zu den aktuellen Schattenpreisen wert.”</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td><span class="math inline">> 1</span></td>
|
||
<td>„Es bringt mehr, als es kostet — dieses Muster nehmen wir dazu.”</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td><span class="math inline">\le 1</span></td>
|
||
<td>„Kein Muster lohnt sich mehr. <strong>Fertig</strong> — und zwar beweisbar.”</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Die letzte Zeile ist der Grund, warum das Verfahren <strong>exakt</strong> ist und nicht heuristisch: Wenn kein Muster mehr lohnende reduzierte Kosten hat, ist die LP-Lösung über <em>allen</em> Mustern optimal — auch über den nie erzeugten.</p>
|
||
</blockquote>
|
||
</div>
|
||
<p><strong>Und wie findet man das beste neue Muster?</strong> Man sucht die Zusammenstellung von Stücken mit dem größten Gesamtwert, die noch in die Rolle passt. Das ist ein <strong>Rucksackproblem</strong>:</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th>Rucksack (<a href="milp.html#kap-milp">Kapitel 6</a>)</th>
|
||
<th>hier</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td>Nutzen eines Gegenstands</td>
|
||
<td>Schattenpreis <span class="math inline">\pi_i</span> der Breite</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td>Gewicht</td>
|
||
<td>Breite in mm</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td>Kapazität des Rucksacks</td>
|
||
<td>Rollenbreite</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Das Teilproblem ist also ein Verfahren, das die Leser dieses Buchs schon kennen. <strong>Neu ist allein die Schleife.</strong></p>
|
||
<hr />
|
||
<h2 id="sec:dekomposition-programm">10.5 Das Programm</h2>
|
||
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Spaltengenerierung.py</span></span>
|
||
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="co">"""</span></span>
|
||
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="co">Kapitel Dekomposition: Das Modell umbauen, statt die Loesung zu raten.</span></span>
|
||
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="co">Eine Papierfabrik liefert Rollen von 5.600 mm Breite. Die Kunden bestellen</span></span>
|
||
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="co">schmalere Breiten, und aus jeder Mutterrolle werden mehrere davon geschnitten.</span></span>
|
||
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="co">Gesucht ist der Schnittplan, der mit den wenigsten Mutterrollen auskommt.</span></span>
|
||
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="co">Der naheliegende Modellansatz - "welches Stueck kommt auf welche Rolle?" -</span></span>
|
||
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="co">fuehrt in eine Sackgasse: Er braucht eine Binaervariable je Stueck-und-Rolle,</span></span>
|
||
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a><span class="co">und weil alle Rollen gleich sind, ist er hochgradig symmetrisch. Der Solver</span></span>
|
||
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a><span class="co">probiert dieselbe Loesung in tausend Umbenennungen durch.</span></span>
|
||
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a><span class="co">Die Spaltengenerierung dreht die Frage um:</span></span>
|
||
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a><span class="co"> Nicht "welches Stueck auf welche Rolle",</span></span>
|
||
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a><span class="co"> sondern "wie oft schneide ich welches MUSTER".</span></span>
|
||
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a><span class="co">Damit verschwindet die Symmetrie - aber es entsteht ein neues Problem: Die Zahl</span></span>
|
||
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a><span class="co">der moeglichen Muster waechst kombinatorisch. Man kann sie nicht aufschreiben.</span></span>
|
||
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a><span class="co">Der Trick besteht darin, sie auch nicht aufzuschreiben, sondern nur die wenigen</span></span>
|
||
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a><span class="co">zu erzeugen, die tatsaechlich gebraucht werden - und zwar mit Hilfe der</span></span>
|
||
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a><span class="co">Schattenpreise aus dem Kapitel LP.</span></span>
|
||
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a><span class="co">Das Programm zeigt vier Dinge:</span></span>
|
||
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true" tabindex="-1"></a><span class="co"> 1. Die beiden Formulierungen desselben Problems und ihre Groesse.</span></span>
|
||
<span id="cb3-30"><a href="#cb3-30" aria-hidden="true" tabindex="-1"></a><span class="co"> 2. Wie schnell die Musterzahl waechst - und wie wenige davon genuegen.</span></span>
|
||
<span id="cb3-31"><a href="#cb3-31" aria-hidden="true" tabindex="-1"></a><span class="co"> 3. Die Schleife selbst: Master-LP, Dualwerte, Rucksack, neue Spalte.</span></span>
|
||
<span id="cb3-32"><a href="#cb3-32" aria-hidden="true" tabindex="-1"></a><span class="co"> 4. Wann sich der Aufwand lohnt und wann nicht. Die Antwort haengt an einer</span></span>
|
||
<span id="cb3-33"><a href="#cb3-33" aria-hidden="true" tabindex="-1"></a><span class="co"> einzigen Kennzahl der Instanz, und sie erklaert nebenbei, warum eine</span></span>
|
||
<span id="cb3-34"><a href="#cb3-34" aria-hidden="true" tabindex="-1"></a><span class="co"> Faustregel bei manchen Zuschnittproblemen schon optimal ist.</span></span>
|
||
<span id="cb3-35"><a href="#cb3-35" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-36"><a href="#cb3-36" aria-hidden="true" tabindex="-1"></a><span class="co">Benoetigt: numpy, scipy</span></span>
|
||
<span id="cb3-37"><a href="#cb3-37" aria-hidden="true" tabindex="-1"></a><span class="co">"""</span></span>
|
||
<span id="cb3-38"><a href="#cb3-38" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-39"><a href="#cb3-39" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> __future__ <span class="im">import</span> annotations</span>
|
||
<span id="cb3-40"><a href="#cb3-40" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-41"><a href="#cb3-41" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||
<span id="cb3-42"><a href="#cb3-42" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.optimize <span class="im">import</span> linprog</span>
|
||
<span id="cb3-43"><a href="#cb3-43" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-44"><a href="#cb3-44" aria-hidden="true" tabindex="-1"></a>ROLLENBREITE <span class="op">=</span> <span class="dv">5600</span></span>
|
||
<span id="cb3-45"><a href="#cb3-45" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-46"><a href="#cb3-46" aria-hidden="true" tabindex="-1"></a><span class="co"># Zwei Instanzen mit demselben Bedarf, aber verschiedenen Breiten. Der</span></span>
|
||
<span id="cb3-47"><a href="#cb3-47" aria-hidden="true" tabindex="-1"></a><span class="co"># Unterschied ist die eine Kennzahl, um die es in Teil 4 geht.</span></span>
|
||
<span id="cb3-48"><a href="#cb3-48" aria-hidden="true" tabindex="-1"></a>BEDARF <span class="op">=</span> [<span class="dv">22</span>, <span class="dv">25</span>, <span class="dv">12</span>, <span class="dv">14</span>, <span class="dv">18</span>, <span class="dv">18</span>, <span class="dv">20</span>, <span class="dv">10</span>, <span class="dv">12</span>, <span class="dv">14</span>, <span class="dv">16</span>, <span class="dv">18</span>, <span class="dv">20</span>]</span>
|
||
<span id="cb3-49"><a href="#cb3-49" aria-hidden="true" tabindex="-1"></a>BREIT <span class="op">=</span> [<span class="dv">1380</span>, <span class="dv">1520</span>, <span class="dv">1560</span>, <span class="dv">1710</span>, <span class="dv">1820</span>, <span class="dv">1880</span>, <span class="dv">1930</span>, <span class="dv">2000</span>, <span class="dv">2050</span>, <span class="dv">2100</span>, <span class="dv">2140</span>,</span>
|
||
<span id="cb3-50"><a href="#cb3-50" aria-hidden="true" tabindex="-1"></a> <span class="dv">2150</span>, <span class="dv">2200</span>]</span>
|
||
<span id="cb3-51"><a href="#cb3-51" aria-hidden="true" tabindex="-1"></a>SCHMAL <span class="op">=</span> [<span class="dv">380</span>, <span class="dv">520</span>, <span class="dv">560</span>, <span class="dv">710</span>, <span class="dv">820</span>, <span class="dv">880</span>, <span class="dv">930</span>, <span class="dv">1000</span>, <span class="dv">1050</span>, <span class="dv">1100</span>, <span class="dv">1140</span>,</span>
|
||
<span id="cb3-52"><a href="#cb3-52" aria-hidden="true" tabindex="-1"></a> <span class="dv">1150</span>, <span class="dv">1200</span>]</span>
|
||
<span id="cb3-53"><a href="#cb3-53" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-54"><a href="#cb3-54" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-55"><a href="#cb3-55" aria-hidden="true" tabindex="-1"></a><span class="co"># --- Die Musterzahl ---------------------------------------------------------</span></span>
|
||
<span id="cb3-56"><a href="#cb3-56" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-57"><a href="#cb3-57" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> zaehle_muster(breiten, rollenbreite: <span class="bu">int</span> <span class="op">=</span> ROLLENBREITE) <span class="op">-></span> <span class="bu">int</span>:</span>
|
||
<span id="cb3-58"><a href="#cb3-58" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Wie viele zulaessige Schnittmuster gibt es ueberhaupt?</span></span>
|
||
<span id="cb3-59"><a href="#cb3-59" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-60"><a href="#cb3-60" aria-hidden="true" tabindex="-1"></a><span class="co"> Nur zum Zeigen - in einem produktiven Programm wuerde man das nie</span></span>
|
||
<span id="cb3-61"><a href="#cb3-61" aria-hidden="true" tabindex="-1"></a><span class="co"> ausrechnen, weil die Zahl bei realistischen Instanzen jede Vorstellung</span></span>
|
||
<span id="cb3-62"><a href="#cb3-62" aria-hidden="true" tabindex="-1"></a><span class="co"> sprengt. Genau das ist der Punkt.</span></span>
|
||
<span id="cb3-63"><a href="#cb3-63" aria-hidden="true" tabindex="-1"></a><span class="co"> """</span></span>
|
||
<span id="cb3-64"><a href="#cb3-64" aria-hidden="true" tabindex="-1"></a> speicher: <span class="bu">dict</span>[<span class="bu">tuple</span>[<span class="bu">int</span>, <span class="bu">int</span>], <span class="bu">int</span>] <span class="op">=</span> {}</span>
|
||
<span id="cb3-65"><a href="#cb3-65" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-66"><a href="#cb3-66" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> ab(i: <span class="bu">int</span>, rest: <span class="bu">int</span>) <span class="op">-></span> <span class="bu">int</span>:</span>
|
||
<span id="cb3-67"><a href="#cb3-67" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> i <span class="op">==</span> <span class="bu">len</span>(breiten):</span>
|
||
<span id="cb3-68"><a href="#cb3-68" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="dv">1</span></span>
|
||
<span id="cb3-69"><a href="#cb3-69" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> (i, rest) <span class="kw">in</span> speicher:</span>
|
||
<span id="cb3-70"><a href="#cb3-70" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> speicher[(i, rest)]</span>
|
||
<span id="cb3-71"><a href="#cb3-71" aria-hidden="true" tabindex="-1"></a> summe <span class="op">=</span> <span class="bu">sum</span>(ab(i <span class="op">+</span> <span class="dv">1</span>, rest <span class="op">-</span> anzahl <span class="op">*</span> breiten[i])</span>
|
||
<span id="cb3-72"><a href="#cb3-72" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> anzahl <span class="kw">in</span> <span class="bu">range</span>(rest <span class="op">//</span> breiten[i] <span class="op">+</span> <span class="dv">1</span>))</span>
|
||
<span id="cb3-73"><a href="#cb3-73" aria-hidden="true" tabindex="-1"></a> speicher[(i, rest)] <span class="op">=</span> summe</span>
|
||
<span id="cb3-74"><a href="#cb3-74" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> summe</span>
|
||
<span id="cb3-75"><a href="#cb3-75" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-76"><a href="#cb3-76" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> ab(<span class="dv">0</span>, rollenbreite)</span>
|
||
<span id="cb3-77"><a href="#cb3-77" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-78"><a href="#cb3-78" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-79"><a href="#cb3-79" aria-hidden="true" tabindex="-1"></a><span class="co"># --- Die beiden Bausteine der Schleife --------------------------------------</span></span>
|
||
<span id="cb3-80"><a href="#cb3-80" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-81"><a href="#cb3-81" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> loese_master(muster, bedarf, ganzzahlig: <span class="bu">bool</span> <span class="op">=</span> <span class="va">False</span>):</span>
|
||
<span id="cb3-82"><a href="#cb3-82" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Restringiertes Master: Wie oft schneide ich jedes bekannte Muster?</span></span>
|
||
<span id="cb3-83"><a href="#cb3-83" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-84"><a href="#cb3-84" aria-hidden="true" tabindex="-1"></a><span class="co"> min sum_p x_p unter sum_p a_ip * x_p >= bedarf_i</span></span>
|
||
<span id="cb3-85"><a href="#cb3-85" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-86"><a href="#cb3-86" aria-hidden="true" tabindex="-1"></a><span class="co"> Als LP gerechnet liefert es zusaetzlich die DUALWERTE - und die sind der</span></span>
|
||
<span id="cb3-87"><a href="#cb3-87" aria-hidden="true" tabindex="-1"></a><span class="co"> eigentliche Ertrag: Der Dualwert zu Breite i sagt, was ein zusaetzliches</span></span>
|
||
<span id="cb3-88"><a href="#cb3-88" aria-hidden="true" tabindex="-1"></a><span class="co"> Stueck dieser Breite an Rollen kostet. Es ist derselbe Schattenpreis wie</span></span>
|
||
<span id="cb3-89"><a href="#cb3-89" aria-hidden="true" tabindex="-1"></a><span class="co"> im Kapitel LP, nur dass er hier nicht berichtet, sondern weiterverarbeitet</span></span>
|
||
<span id="cb3-90"><a href="#cb3-90" aria-hidden="true" tabindex="-1"></a><span class="co"> wird.</span></span>
|
||
<span id="cb3-91"><a href="#cb3-91" aria-hidden="true" tabindex="-1"></a><span class="co"> """</span></span>
|
||
<span id="cb3-92"><a href="#cb3-92" aria-hidden="true" tabindex="-1"></a> matrix <span class="op">=</span> <span class="op">-</span>np.array(muster, dtype<span class="op">=</span><span class="bu">float</span>).T <span class="co"># >= wird zu <= mit Minus</span></span>
|
||
<span id="cb3-93"><a href="#cb3-93" aria-hidden="true" tabindex="-1"></a> ergebnis <span class="op">=</span> linprog(np.ones(<span class="bu">len</span>(muster)),</span>
|
||
<span id="cb3-94"><a href="#cb3-94" aria-hidden="true" tabindex="-1"></a> A_ub<span class="op">=</span>matrix, b_ub<span class="op">=-</span>np.array(bedarf, dtype<span class="op">=</span><span class="bu">float</span>),</span>
|
||
<span id="cb3-95"><a href="#cb3-95" aria-hidden="true" tabindex="-1"></a> bounds<span class="op">=</span>(<span class="dv">0</span>, <span class="va">None</span>),</span>
|
||
<span id="cb3-96"><a href="#cb3-96" aria-hidden="true" tabindex="-1"></a> integrality<span class="op">=</span>(<span class="dv">1</span> <span class="cf">if</span> ganzzahlig <span class="cf">else</span> <span class="dv">0</span>), method<span class="op">=</span><span class="st">"highs"</span>)</span>
|
||
<span id="cb3-97"><a href="#cb3-97" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="kw">not</span> ergebnis.success:</span>
|
||
<span id="cb3-98"><a href="#cb3-98" aria-hidden="true" tabindex="-1"></a> <span class="cf">raise</span> <span class="pp">SystemExit</span>(<span class="ss">f"Master nicht loesbar: </span><span class="sc">{</span>ergebnis<span class="sc">.</span>message<span class="sc">}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-99"><a href="#cb3-99" aria-hidden="true" tabindex="-1"></a> dual <span class="op">=</span> <span class="va">None</span> <span class="cf">if</span> ganzzahlig <span class="cf">else</span> <span class="op">-</span>ergebnis.ineqlin.marginals</span>
|
||
<span id="cb3-100"><a href="#cb3-100" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> ergebnis.fun, ergebnis.x, dual</span>
|
||
<span id="cb3-101"><a href="#cb3-101" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-102"><a href="#cb3-102" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-103"><a href="#cb3-103" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> bestes_neues_muster(dual, breiten, rollenbreite: <span class="bu">int</span> <span class="op">=</span> ROLLENBREITE):</span>
|
||
<span id="cb3-104"><a href="#cb3-104" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Pricing: Gibt es ein Muster, das sich noch lohnt?</span></span>
|
||
<span id="cb3-105"><a href="#cb3-105" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-106"><a href="#cb3-106" aria-hidden="true" tabindex="-1"></a><span class="co"> Gesucht ist das Muster mit dem groessten Gesamtwert zu den aktuellen</span></span>
|
||
<span id="cb3-107"><a href="#cb3-107" aria-hidden="true" tabindex="-1"></a><span class="co"> Schattenpreisen - unter der Bedingung, dass es in die Rolle passt. Das ist</span></span>
|
||
<span id="cb3-108"><a href="#cb3-108" aria-hidden="true" tabindex="-1"></a><span class="co"> ein RUCKSACKPROBLEM (Kapitel MILP, Rucksack.py): Preise sind der Nutzen,</span></span>
|
||
<span id="cb3-109"><a href="#cb3-109" aria-hidden="true" tabindex="-1"></a><span class="co"> Breiten das Gewicht, die Rollenbreite die Kapazitaet. Hier mit dynamischer</span></span>
|
||
<span id="cb3-110"><a href="#cb3-110" aria-hidden="true" tabindex="-1"></a><span class="co"> Programmierung geloest, weil die Breiten ganzzahlig sind.</span></span>
|
||
<span id="cb3-111"><a href="#cb3-111" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-112"><a href="#cb3-112" aria-hidden="true" tabindex="-1"></a><span class="co"> Bei Gleichstand wird bewusst der KLEINSTE Index bevorzugt (>-Vergleich mit</span></span>
|
||
<span id="cb3-113"><a href="#cb3-113" aria-hidden="true" tabindex="-1"></a><span class="co"> Toleranz statt >=). Sonst haengt das erzeugte Muster von der Reihenfolge</span></span>
|
||
<span id="cb3-114"><a href="#cb3-114" aria-hidden="true" tabindex="-1"></a><span class="co"> der Gleitkommaoperationen ab, und das Programm liefert von Lauf zu Lauf</span></span>
|
||
<span id="cb3-115"><a href="#cb3-115" aria-hidden="true" tabindex="-1"></a><span class="co"> verschiedene Ausgaben.</span></span>
|
||
<span id="cb3-116"><a href="#cb3-116" aria-hidden="true" tabindex="-1"></a><span class="co"> """</span></span>
|
||
<span id="cb3-117"><a href="#cb3-117" aria-hidden="true" tabindex="-1"></a> wert <span class="op">=</span> np.zeros(rollenbreite <span class="op">+</span> <span class="dv">1</span>)</span>
|
||
<span id="cb3-118"><a href="#cb3-118" aria-hidden="true" tabindex="-1"></a> herkunft <span class="op">=</span> [<span class="op">-</span><span class="dv">1</span>] <span class="op">*</span> (rollenbreite <span class="op">+</span> <span class="dv">1</span>)</span>
|
||
<span id="cb3-119"><a href="#cb3-119" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> platz <span class="kw">in</span> <span class="bu">range</span>(rollenbreite <span class="op">+</span> <span class="dv">1</span>):</span>
|
||
<span id="cb3-120"><a href="#cb3-120" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> i, breite <span class="kw">in</span> <span class="bu">enumerate</span>(breiten):</span>
|
||
<span id="cb3-121"><a href="#cb3-121" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> breite <span class="op"><=</span> platz <span class="kw">and</span> wert[platz <span class="op">-</span> breite] <span class="op">+</span> dual[i] <span class="op">></span> wert[platz] <span class="op">+</span> <span class="fl">1e-9</span>:</span>
|
||
<span id="cb3-122"><a href="#cb3-122" aria-hidden="true" tabindex="-1"></a> wert[platz] <span class="op">=</span> wert[platz <span class="op">-</span> breite] <span class="op">+</span> dual[i]</span>
|
||
<span id="cb3-123"><a href="#cb3-123" aria-hidden="true" tabindex="-1"></a> herkunft[platz] <span class="op">=</span> i</span>
|
||
<span id="cb3-124"><a href="#cb3-124" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-125"><a href="#cb3-125" aria-hidden="true" tabindex="-1"></a> muster <span class="op">=</span> [<span class="dv">0</span>] <span class="op">*</span> <span class="bu">len</span>(breiten)</span>
|
||
<span id="cb3-126"><a href="#cb3-126" aria-hidden="true" tabindex="-1"></a> platz <span class="op">=</span> rollenbreite</span>
|
||
<span id="cb3-127"><a href="#cb3-127" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span> herkunft[platz] <span class="op">>=</span> <span class="dv">0</span>:</span>
|
||
<span id="cb3-128"><a href="#cb3-128" aria-hidden="true" tabindex="-1"></a> i <span class="op">=</span> herkunft[platz]</span>
|
||
<span id="cb3-129"><a href="#cb3-129" aria-hidden="true" tabindex="-1"></a> muster[i] <span class="op">+=</span> <span class="dv">1</span></span>
|
||
<span id="cb3-130"><a href="#cb3-130" aria-hidden="true" tabindex="-1"></a> platz <span class="op">-=</span> breiten[i]</span>
|
||
<span id="cb3-131"><a href="#cb3-131" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="bu">float</span>(wert[rollenbreite]), muster</span>
|
||
<span id="cb3-132"><a href="#cb3-132" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-133"><a href="#cb3-133" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-134"><a href="#cb3-134" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> spaltengenerierung(breiten, bedarf, rollenbreite: <span class="bu">int</span> <span class="op">=</span> ROLLENBREITE):</span>
|
||
<span id="cb3-135"><a href="#cb3-135" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Die Schleife. Startbasis: je ein Muster mit nur einer Breite.</span></span>
|
||
<span id="cb3-136"><a href="#cb3-136" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-137"><a href="#cb3-137" aria-hidden="true" tabindex="-1"></a><span class="co"> Abbruch, wenn kein Muster mehr einen Wert ueber 1 hat: Eine zusaetzliche</span></span>
|
||
<span id="cb3-138"><a href="#cb3-138" aria-hidden="true" tabindex="-1"></a><span class="co"> Rolle kostet 1, also lohnt sich ein neues Muster nur, wenn es zu den</span></span>
|
||
<span id="cb3-139"><a href="#cb3-139" aria-hidden="true" tabindex="-1"></a><span class="co"> aktuellen Preisen mehr als 1 wert ist. Das ist das Kriterium der</span></span>
|
||
<span id="cb3-140"><a href="#cb3-140" aria-hidden="true" tabindex="-1"></a><span class="co"> reduzierten Kosten.</span></span>
|
||
<span id="cb3-141"><a href="#cb3-141" aria-hidden="true" tabindex="-1"></a><span class="co"> """</span></span>
|
||
<span id="cb3-142"><a href="#cb3-142" aria-hidden="true" tabindex="-1"></a> anzahl <span class="op">=</span> <span class="bu">len</span>(breiten)</span>
|
||
<span id="cb3-143"><a href="#cb3-143" aria-hidden="true" tabindex="-1"></a> muster <span class="op">=</span> [[<span class="dv">0</span>] <span class="op">*</span> anzahl <span class="cf">for</span> _ <span class="kw">in</span> <span class="bu">range</span>(anzahl)]</span>
|
||
<span id="cb3-144"><a href="#cb3-144" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(anzahl):</span>
|
||
<span id="cb3-145"><a href="#cb3-145" aria-hidden="true" tabindex="-1"></a> muster[i][i] <span class="op">=</span> rollenbreite <span class="op">//</span> breiten[i]</span>
|
||
<span id="cb3-146"><a href="#cb3-146" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-147"><a href="#cb3-147" aria-hidden="true" tabindex="-1"></a> runden <span class="op">=</span> <span class="dv">0</span></span>
|
||
<span id="cb3-148"><a href="#cb3-148" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span> <span class="va">True</span>:</span>
|
||
<span id="cb3-149"><a href="#cb3-149" aria-hidden="true" tabindex="-1"></a> zielwert, _, dual <span class="op">=</span> loese_master(muster, bedarf)</span>
|
||
<span id="cb3-150"><a href="#cb3-150" aria-hidden="true" tabindex="-1"></a> wert, neu <span class="op">=</span> bestes_neues_muster(dual, breiten, rollenbreite)</span>
|
||
<span id="cb3-151"><a href="#cb3-151" aria-hidden="true" tabindex="-1"></a> runden <span class="op">+=</span> <span class="dv">1</span></span>
|
||
<span id="cb3-152"><a href="#cb3-152" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> wert <span class="op"><=</span> <span class="dv">1</span> <span class="op">+</span> <span class="fl">1e-6</span>:</span>
|
||
<span id="cb3-153"><a href="#cb3-153" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> muster, zielwert, runden</span>
|
||
<span id="cb3-154"><a href="#cb3-154" aria-hidden="true" tabindex="-1"></a> muster.append(neu)</span>
|
||
<span id="cb3-155"><a href="#cb3-155" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-156"><a href="#cb3-156" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-157"><a href="#cb3-157" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> first_fit(breiten, bedarf, rollenbreite: <span class="bu">int</span> <span class="op">=</span> ROLLENBREITE) <span class="op">-></span> <span class="bu">int</span>:</span>
|
||
<span id="cb3-158"><a href="#cb3-158" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Die Faustregel: groesstes Stueck zuerst, auf die erste passende Rolle."""</span></span>
|
||
<span id="cb3-159"><a href="#cb3-159" aria-hidden="true" tabindex="-1"></a> stuecke <span class="op">=</span> <span class="bu">sorted</span>([b <span class="cf">for</span> b, menge <span class="kw">in</span> <span class="bu">zip</span>(breiten, bedarf)</span>
|
||
<span id="cb3-160"><a href="#cb3-160" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> _ <span class="kw">in</span> <span class="bu">range</span>(menge)], reverse<span class="op">=</span><span class="va">True</span>)</span>
|
||
<span id="cb3-161"><a href="#cb3-161" aria-hidden="true" tabindex="-1"></a> rollen: <span class="bu">list</span>[<span class="bu">list</span>[<span class="bu">int</span>]] <span class="op">=</span> []</span>
|
||
<span id="cb3-162"><a href="#cb3-162" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> stueck <span class="kw">in</span> stuecke:</span>
|
||
<span id="cb3-163"><a href="#cb3-163" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> rolle <span class="kw">in</span> rollen:</span>
|
||
<span id="cb3-164"><a href="#cb3-164" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="bu">sum</span>(rolle) <span class="op">+</span> stueck <span class="op"><=</span> rollenbreite:</span>
|
||
<span id="cb3-165"><a href="#cb3-165" aria-hidden="true" tabindex="-1"></a> rolle.append(stueck)</span>
|
||
<span id="cb3-166"><a href="#cb3-166" aria-hidden="true" tabindex="-1"></a> <span class="cf">break</span></span>
|
||
<span id="cb3-167"><a href="#cb3-167" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span>:</span>
|
||
<span id="cb3-168"><a href="#cb3-168" aria-hidden="true" tabindex="-1"></a> rollen.append([stueck])</span>
|
||
<span id="cb3-169"><a href="#cb3-169" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="bu">len</span>(rollen)</span>
|
||
<span id="cb3-170"><a href="#cb3-170" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-171"><a href="#cb3-171" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-172"><a href="#cb3-172" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> auswerten(name: <span class="bu">str</span>, breiten, bedarf) <span class="op">-></span> <span class="bu">dict</span>:</span>
|
||
<span id="cb3-173"><a href="#cb3-173" aria-hidden="true" tabindex="-1"></a> muster, schranke, runden <span class="op">=</span> spaltengenerierung(breiten, bedarf)</span>
|
||
<span id="cb3-174"><a href="#cb3-174" aria-hidden="true" tabindex="-1"></a> ganz, _, _ <span class="op">=</span> loese_master(muster, bedarf, ganzzahlig<span class="op">=</span><span class="va">True</span>)</span>
|
||
<span id="cb3-175"><a href="#cb3-175" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> {<span class="st">"name"</span>: name, <span class="st">"muster_gesamt"</span>: zaehle_muster(breiten),</span>
|
||
<span id="cb3-176"><a href="#cb3-176" aria-hidden="true" tabindex="-1"></a> <span class="st">"muster_erzeugt"</span>: <span class="bu">len</span>(muster), <span class="st">"runden"</span>: runden,</span>
|
||
<span id="cb3-177"><a href="#cb3-177" aria-hidden="true" tabindex="-1"></a> <span class="st">"schranke"</span>: schranke, <span class="st">"ganzzahlig"</span>: <span class="bu">int</span>(<span class="bu">round</span>(ganz)),</span>
|
||
<span id="cb3-178"><a href="#cb3-178" aria-hidden="true" tabindex="-1"></a> <span class="st">"first_fit"</span>: first_fit(breiten, bedarf),</span>
|
||
<span id="cb3-179"><a href="#cb3-179" aria-hidden="true" tabindex="-1"></a> <span class="st">"stuecke_je_rolle"</span>: ROLLENBREITE <span class="op">/</span> np.mean(breiten)}</span>
|
||
<span id="cb3-180"><a href="#cb3-180" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-181"><a href="#cb3-181" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-182"><a href="#cb3-182" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="va">__name__</span> <span class="op">==</span> <span class="st">"__main__"</span>:</span>
|
||
<span id="cb3-183"><a href="#cb3-183" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb3-184"><a href="#cb3-184" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" SPALTENGENERIERUNG: NUR DIE MUSTER ERZEUGEN, DIE MAN BRAUCHT"</span>)</span>
|
||
<span id="cb3-185"><a href="#cb3-185" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb3-186"><a href="#cb3-186" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Mutterrolle </span><span class="sc">{</span>ROLLENBREITE<span class="sc">:,}</span><span class="ss"> mm, </span><span class="sc">{</span><span class="bu">len</span>(BREIT)<span class="sc">}</span><span class="ss"> bestellte Breiten, "</span></span>
|
||
<span id="cb3-187"><a href="#cb3-187" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="bu">sum</span>(BEDARF)<span class="sc">}</span><span class="ss"> Zuschnitte.</span><span class="ch">\n</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-188"><a href="#cb3-188" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-189"><a href="#cb3-189" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- 1. Zwei Formulierungen ------------------------------------------</span></span>
|
||
<span id="cb3-190"><a href="#cb3-190" aria-hidden="true" tabindex="-1"></a> stuecke <span class="op">=</span> <span class="bu">sum</span>(BEDARF)</span>
|
||
<span id="cb3-191"><a href="#cb3-191" aria-hidden="true" tabindex="-1"></a> <span class="co"># Wie viele Rollen braucht man hoechstens? Die Faustregel liefert eine</span></span>
|
||
<span id="cb3-192"><a href="#cb3-192" aria-hidden="true" tabindex="-1"></a> <span class="co"># brauchbare Obergrenze - mehr Rollen als das wird niemand benoetigen.</span></span>
|
||
<span id="cb3-193"><a href="#cb3-193" aria-hidden="true" tabindex="-1"></a> rollen_obergrenze <span class="op">=</span> first_fit(BREIT, BEDARF)</span>
|
||
<span id="cb3-194"><a href="#cb3-194" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"1. Zwei Modelle fuer dieselbe Aufgabe</span><span class="ch">\n</span><span class="st">"</span>)</span>
|
||
<span id="cb3-195"><a href="#cb3-195" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span><span class="st">'Formulierung'</span><span class="sc">:<34}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Binaervariablen'</span><span class="sc">:>16}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'symmetrisch?'</span><span class="sc">:>16}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-196"><a href="#cb3-196" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" "</span> <span class="op">+</span> <span class="st">"-"</span> <span class="op">*</span> <span class="dv">70</span>)</span>
|
||
<span id="cb3-197"><a href="#cb3-197" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span><span class="st">'Stueck -> Rolle (naheliegend)'</span><span class="sc">:<34}</span><span class="ss"> "</span></span>
|
||
<span id="cb3-198"><a href="#cb3-198" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>stuecke <span class="op">*</span> rollen_obergrenze<span class="sc">:>16,}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'ja'</span><span class="sc">:>16}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-199"><a href="#cb3-199" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span><span class="st">'wie oft welches Muster'</span><span class="sc">:<34}</span><span class="ss"> "</span></span>
|
||
<span id="cb3-200"><a href="#cb3-200" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="st">'eine je Muster'</span><span class="sc">:>16}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'nein'</span><span class="sc">:>16}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-201"><a href="#cb3-201" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss"> Der naheliegende Ansatz braucht eine Variable je Stueck und Rolle:"</span>)</span>
|
||
<span id="cb3-202"><a href="#cb3-202" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span>stuecke<span class="sc">}</span><span class="ss"> Zuschnitte x </span><span class="sc">{</span>rollen_obergrenze<span class="sc">}</span><span class="ss"> Rollen (Obergrenze aus der Faustregel)"</span>)</span>
|
||
<span id="cb3-203"><a href="#cb3-203" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" = </span><span class="sc">{</span>stuecke <span class="op">*</span> rollen_obergrenze<span class="sc">:,}</span><span class="ss"> Binaervariablen."</span>)</span>
|
||
<span id="cb3-204"><a href="#cb3-204" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st"> Schlimmer als die Zahl ist die Symmetrie: Alle Mutterrollen sind"</span>)</span>
|
||
<span id="cb3-205"><a href="#cb3-205" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" gleich, also beschreibt jede Loesung dieselbe Schnittvorschrift in"</span>)</span>
|
||
<span id="cb3-206"><a href="#cb3-206" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" unzaehligen Umbenennungen. Branch-and-Bound probiert sie einzeln"</span>)</span>
|
||
<span id="cb3-207"><a href="#cb3-207" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" durch und kommt nicht voran - der Suchbaum waechst, ohne dass sich"</span>)</span>
|
||
<span id="cb3-208"><a href="#cb3-208" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" die Schranke bewegt."</span>)</span>
|
||
<span id="cb3-209"><a href="#cb3-209" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st"> Das Mustermodell hat je Muster genau eine Variable und kennt keine"</span>)</span>
|
||
<span id="cb3-210"><a href="#cb3-210" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" einzelnen Rollen mehr. Damit ist die Symmetrie weg. Sein Problem ist"</span>)</span>
|
||
<span id="cb3-211"><a href="#cb3-211" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" ein anderes - und zwar das folgende."</span>)</span>
|
||
<span id="cb3-212"><a href="#cb3-212" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-213"><a href="#cb3-213" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- 2. Die Musterzahl ------------------------------------------------</span></span>
|
||
<span id="cb3-214"><a href="#cb3-214" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">"</span> <span class="op">+</span> <span class="st">"-"</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb3-215"><a href="#cb3-215" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"2. Warum man die Muster nicht aufschreiben kann</span><span class="ch">\n</span><span class="st">"</span>)</span>
|
||
<span id="cb3-216"><a href="#cb3-216" aria-hidden="true" tabindex="-1"></a> gross <span class="op">=</span> auswerten(<span class="st">"breite Zuschnitte (1.380-2.200 mm)"</span>, BREIT, BEDARF)</span>
|
||
<span id="cb3-217"><a href="#cb3-217" aria-hidden="true" tabindex="-1"></a> schmal <span class="op">=</span> auswerten(<span class="st">"schmale Zuschnitte (380-1.200 mm)"</span>, SCHMAL, BEDARF)</span>
|
||
<span id="cb3-218"><a href="#cb3-218" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-219"><a href="#cb3-219" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span><span class="st">'Instanz'</span><span class="sc">:<36}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Muster'</span><span class="sc">:>12}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'davon erzeugt'</span><span class="sc">:>14}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Anteil'</span><span class="sc">:>9}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-220"><a href="#cb3-220" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" "</span> <span class="op">+</span> <span class="st">"-"</span> <span class="op">*</span> <span class="dv">76</span>)</span>
|
||
<span id="cb3-221"><a href="#cb3-221" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> fall <span class="kw">in</span> (gross, schmal):</span>
|
||
<span id="cb3-222"><a href="#cb3-222" aria-hidden="true" tabindex="-1"></a> anteil <span class="op">=</span> fall[<span class="st">"muster_erzeugt"</span>] <span class="op">/</span> fall[<span class="st">"muster_gesamt"</span>]</span>
|
||
<span id="cb3-223"><a href="#cb3-223" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span>fall[<span class="st">'name'</span>]<span class="sc">:<36}</span><span class="ss"> </span><span class="sc">{</span>fall[<span class="st">'muster_gesamt'</span>]<span class="sc">:>12,}</span><span class="ss"> "</span></span>
|
||
<span id="cb3-224"><a href="#cb3-224" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>fall[<span class="st">'muster_erzeugt'</span>]<span class="sc">:>14}</span><span class="ss"> </span><span class="sc">{</span>anteil<span class="sc">:>8.1%}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-225"><a href="#cb3-225" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-226"><a href="#cb3-226" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss"> Schon das Halbieren der Breiten laesst die Musterzahl von "</span></span>
|
||
<span id="cb3-227"><a href="#cb3-227" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>gross[<span class="st">'muster_gesamt'</span>]<span class="sc">:,}</span><span class="ss"> auf"</span>)</span>
|
||
<span id="cb3-228"><a href="#cb3-228" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span>schmal[<span class="st">'muster_gesamt'</span>]<span class="sc">:,}</span><span class="ss"> springen - Faktor "</span></span>
|
||
<span id="cb3-229"><a href="#cb3-229" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>schmal[<span class="st">'muster_gesamt'</span>] <span class="op">/</span> gross[<span class="st">'muster_gesamt'</span>]<span class="sc">:.0f}</span><span class="ss">. Bei einer echten "</span></span>
|
||
<span id="cb3-230"><a href="#cb3-230" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"Papierfabrik mit"</span>)</span>
|
||
<span id="cb3-231"><a href="#cb3-231" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" vierzig Breiten und Millimeterschritten sind es mehr, als sich"</span>)</span>
|
||
<span id="cb3-232"><a href="#cb3-232" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" speichern liesse."</span>)</span>
|
||
<span id="cb3-233"><a href="#cb3-233" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss"> Gebraucht werden davon </span><span class="sc">{</span>schmal[<span class="st">'muster_erzeugt'</span>]<span class="sc">}</span><span class="ss"> - "</span></span>
|
||
<span id="cb3-234"><a href="#cb3-234" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>schmal[<span class="st">'muster_erzeugt'</span>] <span class="op">/</span> schmal[<span class="st">'muster_gesamt'</span>]<span class="sc">:.2%}</span><span class="ss"> der Gesamtzahl."</span>)</span>
|
||
<span id="cb3-235"><a href="#cb3-235" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-236"><a href="#cb3-236" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- 3. Die Schleife --------------------------------------------------</span></span>
|
||
<span id="cb3-237"><a href="#cb3-237" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">"</span> <span class="op">+</span> <span class="st">"-"</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb3-238"><a href="#cb3-238" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"3. Die Schleife an der breiten Instanz</span><span class="ch">\n</span><span class="st">"</span>)</span>
|
||
<span id="cb3-239"><a href="#cb3-239" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Startbasis: </span><span class="sc">{</span><span class="bu">len</span>(BREIT)<span class="sc">}</span><span class="ss"> triviale Muster (je Rolle nur eine Breite)"</span>)</span>
|
||
<span id="cb3-240"><a href="#cb3-240" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Runden bis kein Muster mehr lohnt: </span><span class="sc">{</span>gross[<span class="st">'runden'</span>]<span class="sc">}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-241"><a href="#cb3-241" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Muster am Ende: </span><span class="sc">{</span>gross[<span class="st">'muster_erzeugt'</span>]<span class="sc">}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-242"><a href="#cb3-242" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" LP-Schranke: </span><span class="sc">{</span>gross[<span class="st">'schranke'</span>]<span class="sc">:.4f}</span><span class="ss"> Rollen"</span>)</span>
|
||
<span id="cb3-243"><a href="#cb3-243" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss"> Die LP-Schranke ist eine ZUSAGE: Weniger als "</span></span>
|
||
<span id="cb3-244"><a href="#cb3-244" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>np<span class="sc">.</span>ceil(gross[<span class="st">'schranke'</span>] <span class="op">-</span> <span class="fl">1e-9</span>)<span class="sc">:.0f}</span><span class="ss"> Rollen sind"</span>)</span>
|
||
<span id="cb3-245"><a href="#cb3-245" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" nicht moeglich - unabhaengig davon, wie clever man weiterschneidet."</span>)</span>
|
||
<span id="cb3-246"><a href="#cb3-246" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Genau diese Aussage fehlt einer Heuristik (Kapitel Metaheuristiken)."</span>)</span>
|
||
<span id="cb3-247"><a href="#cb3-247" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-248"><a href="#cb3-248" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- 4. Wann es sich lohnt --------------------------------------------</span></span>
|
||
<span id="cb3-249"><a href="#cb3-249" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">"</span> <span class="op">+</span> <span class="st">"-"</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb3-250"><a href="#cb3-250" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"4. Wann sich der Aufwand lohnt - und wann nicht</span><span class="ch">\n</span><span class="st">"</span>)</span>
|
||
<span id="cb3-251"><a href="#cb3-251" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span><span class="st">'Instanz'</span><span class="sc">:<36}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Faustregel'</span><span class="sc">:>11}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'exakt'</span><span class="sc">:>8}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Schranke'</span><span class="sc">:>10}</span><span class="ss"> "</span></span>
|
||
<span id="cb3-252"><a href="#cb3-252" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span><span class="st">'Ersparnis'</span><span class="sc">:>11}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-253"><a href="#cb3-253" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" "</span> <span class="op">+</span> <span class="st">"-"</span> <span class="op">*</span> <span class="dv">80</span>)</span>
|
||
<span id="cb3-254"><a href="#cb3-254" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> fall <span class="kw">in</span> (gross, schmal):</span>
|
||
<span id="cb3-255"><a href="#cb3-255" aria-hidden="true" tabindex="-1"></a> ersparnis <span class="op">=</span> (fall[<span class="st">"first_fit"</span>] <span class="op">-</span> fall[<span class="st">"ganzzahlig"</span>]) <span class="op">/</span> fall[<span class="st">"first_fit"</span>]</span>
|
||
<span id="cb3-256"><a href="#cb3-256" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span>fall[<span class="st">'name'</span>]<span class="sc">:<36}</span><span class="ss"> </span><span class="sc">{</span>fall[<span class="st">'first_fit'</span>]<span class="sc">:>11}</span><span class="ss"> "</span></span>
|
||
<span id="cb3-257"><a href="#cb3-257" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>fall[<span class="st">'ganzzahlig'</span>]<span class="sc">:>8}</span><span class="ss"> </span><span class="sc">{</span>fall[<span class="st">'schranke'</span>]<span class="sc">:>10.2f}</span><span class="ss"> "</span></span>
|
||
<span id="cb3-258"><a href="#cb3-258" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>ersparnis<span class="sc">:>10.0%}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-259"><a href="#cb3-259" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-260"><a href="#cb3-260" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss"> Bei den breiten Zuschnitten spart die Spaltengenerierung "</span></span>
|
||
<span id="cb3-261"><a href="#cb3-261" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>gross[<span class="st">'first_fit'</span>] <span class="op">-</span> gross[<span class="st">'ganzzahlig'</span>]<span class="sc">}</span><span class="ss"> von"</span>)</span>
|
||
<span id="cb3-262"><a href="#cb3-262" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span>gross[<span class="st">'first_fit'</span>]<span class="sc">}</span><span class="ss"> Rollen. Bei den schmalen spart sie NICHTS - dort ist die"</span>)</span>
|
||
<span id="cb3-263"><a href="#cb3-263" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Faustregel bereits optimal."</span>)</span>
|
||
<span id="cb3-264"><a href="#cb3-264" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss"> Der Unterschied haengt an einer einzigen Kennzahl:</span><span class="ch">\n</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-265"><a href="#cb3-265" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span><span class="st">'Instanz'</span><span class="sc">:<36}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Stuecke je Rolle (etwa)'</span><span class="sc">:>24}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-266"><a href="#cb3-266" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" "</span> <span class="op">+</span> <span class="st">"-"</span> <span class="op">*</span> <span class="dv">62</span>)</span>
|
||
<span id="cb3-267"><a href="#cb3-267" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> fall <span class="kw">in</span> (gross, schmal):</span>
|
||
<span id="cb3-268"><a href="#cb3-268" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span>fall[<span class="st">'name'</span>]<span class="sc">:<36}</span><span class="ss"> </span><span class="sc">{</span>fall[<span class="st">'stuecke_je_rolle'</span>]<span class="sc">:>24.1f}</span><span class="ss">"</span>)</span>
|
||
<span id="cb3-269"><a href="#cb3-269" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-270"><a href="#cb3-270" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st"> Passen nur zwei bis drei Stuecke auf eine Rolle, entscheidet jede"</span>)</span>
|
||
<span id="cb3-271"><a href="#cb3-271" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" einzelne Zuordnung viel, und eine kurzsichtige Regel verschenkt"</span>)</span>
|
||
<span id="cb3-272"><a href="#cb3-272" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" ganze Rollen. Passen sechs oder mehr darauf, gleichen sich die"</span>)</span>
|
||
<span id="cb3-273"><a href="#cb3-273" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Fehler aus - die Reste sind klein gegen die Rollenbreite, und die"</span>)</span>
|
||
<span id="cb3-274"><a href="#cb3-274" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Faustregel trifft es fast immer."</span>)</span>
|
||
<span id="cb3-275"><a href="#cb3-275" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-276"><a href="#cb3-276" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">"</span> <span class="op">+</span> <span class="st">"="</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb3-277"><a href="#cb3-277" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" WAS MAN DARAUS MITNIMMT"</span>)</span>
|
||
<span id="cb3-278"><a href="#cb3-278" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb3-279"><a href="#cb3-279" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"1. Der Perspektivwechsel ist die eigentliche Arbeit: nicht 'welches"</span>)</span>
|
||
<span id="cb3-280"><a href="#cb3-280" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Stueck wohin', sondern 'wie oft welches Muster'. Damit verschwindet"</span>)</span>
|
||
<span id="cb3-281"><a href="#cb3-281" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" die Symmetrie, die das naheliegende Modell unloesbar macht."</span>)</span>
|
||
<span id="cb3-282"><a href="#cb3-282" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"2. Der Preis dafuer ist eine unaufschreibbare Zahl von Variablen. Die"</span>)</span>
|
||
<span id="cb3-283"><a href="#cb3-283" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Spaltengenerierung zahlt ihn nicht, sondern erzeugt nur die wenigen"</span>)</span>
|
||
<span id="cb3-284"><a href="#cb3-284" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Spalten, die die Dualwerte als lohnend ausweisen."</span>)</span>
|
||
<span id="cb3-285"><a href="#cb3-285" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"3. Das Teilproblem ist ein Rucksack - ein Verfahren, das die Leser"</span>)</span>
|
||
<span id="cb3-286"><a href="#cb3-286" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" dieses Buchs schon kennen. Neu ist allein die Schleife."</span>)</span>
|
||
<span id="cb3-287"><a href="#cb3-287" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"4. Und die unbequeme Erkenntnis: Ob sich das alles lohnt, entscheidet"</span>)</span>
|
||
<span id="cb3-288"><a href="#cb3-288" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" die Instanz, nicht die Methode. Bei sechs Stuecken je Rolle ist die"</span>)</span>
|
||
<span id="cb3-289"><a href="#cb3-289" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Faustregel so gut wie das Optimum - und der Ertrag der"</span>)</span>
|
||
<span id="cb3-290"><a href="#cb3-290" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Spaltengenerierung liegt dann allein in der SCHRANKE, die beweist,"</span>)</span>
|
||
<span id="cb3-291"><a href="#cb3-291" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" dass man aufhoeren kann zu suchen."</span>)</span>
|
||
<span id="cb3-292"><a href="#cb3-292" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">84</span>)</span></code></pre></div>
|
||
<p><strong>Erwartete Ausgabe:</strong></p>
|
||
<pre><code>====================================================================================
|
||
SPALTENGENERIERUNG: NUR DIE MUSTER ERZEUGEN, DIE MAN BRAUCHT
|
||
====================================================================================
|
||
Mutterrolle 5,600 mm, 13 bestellte Breiten, 219 Zuschnitte.
|
||
|
||
1. Zwei Modelle fuer dieselbe Aufgabe
|
||
|
||
Formulierung Binaervariablen symmetrisch?
|
||
----------------------------------------------------------------------
|
||
Stueck -> Rolle (naheliegend) 17,958 ja
|
||
wie oft welches Muster eine je Muster nein
|
||
|
||
Der naheliegende Ansatz braucht eine Variable je Stueck und Rolle:
|
||
219 Zuschnitte x 82 Rollen (Obergrenze aus der Faustregel)
|
||
= 17,958 Binaervariablen.
|
||
|
||
Schlimmer als die Zahl ist die Symmetrie: Alle Mutterrollen sind
|
||
gleich, also beschreibt jede Loesung dieselbe Schnittvorschrift in
|
||
unzaehligen Umbenennungen. Branch-and-Bound probiert sie einzeln
|
||
durch und kommt nicht voran - der Suchbaum waechst, ohne dass sich
|
||
die Schranke bewegt.
|
||
|
||
Das Mustermodell hat je Muster genau eine Variable und kennt keine
|
||
einzelnen Rollen mehr. Damit ist die Symmetrie weg. Sein Problem ist
|
||
ein anderes - und zwar das folgende.
|
||
|
||
------------------------------------------------------------------------------------
|
||
2. Warum man die Muster nicht aufschreiben kann
|
||
|
||
Instanz Muster davon erzeugt Anteil
|
||
----------------------------------------------------------------------------
|
||
breite Zuschnitte (1.380-2.200 mm) 309 38 12.3%
|
||
schmale Zuschnitte (380-1.200 mm) 46,408 28 0.1%
|
||
|
||
Schon das Halbieren der Breiten laesst die Musterzahl von 309 auf
|
||
46,408 springen - Faktor 150. Bei einer echten Papierfabrik mit
|
||
vierzig Breiten und Millimeterschritten sind es mehr, als sich
|
||
speichern liesse.
|
||
|
||
Gebraucht werden davon 28 - 0.06% der Gesamtzahl.
|
||
|
||
------------------------------------------------------------------------------------
|
||
3. Die Schleife an der breiten Instanz
|
||
|
||
Startbasis: 13 triviale Muster (je Rolle nur eine Breite)
|
||
Runden bis kein Muster mehr lohnt: 26
|
||
Muster am Ende: 38
|
||
LP-Schranke: 72.9167 Rollen
|
||
|
||
Die LP-Schranke ist eine ZUSAGE: Weniger als 73 Rollen sind
|
||
nicht moeglich - unabhaengig davon, wie clever man weiterschneidet.
|
||
Genau diese Aussage fehlt einer Heuristik (Kapitel Metaheuristiken).
|
||
|
||
------------------------------------------------------------------------------------
|
||
4. Wann sich der Aufwand lohnt - und wann nicht
|
||
|
||
Instanz Faustregel exakt Schranke Ersparnis
|
||
--------------------------------------------------------------------------------
|
||
breite Zuschnitte (1.380-2.200 mm) 82 73 72.92 11%
|
||
schmale Zuschnitte (380-1.200 mm) 35 35 33.60 0%
|
||
|
||
Bei den breiten Zuschnitten spart die Spaltengenerierung 9 von
|
||
82 Rollen. Bei den schmalen spart sie NICHTS - dort ist die
|
||
Faustregel bereits optimal.
|
||
|
||
Der Unterschied haengt an einer einzigen Kennzahl:
|
||
|
||
Instanz Stuecke je Rolle (etwa)
|
||
--------------------------------------------------------------
|
||
breite Zuschnitte (1.380-2.200 mm) 3.0
|
||
schmale Zuschnitte (380-1.200 mm) 6.4
|
||
|
||
Passen nur zwei bis drei Stuecke auf eine Rolle, entscheidet jede
|
||
einzelne Zuordnung viel, und eine kurzsichtige Regel verschenkt
|
||
ganze Rollen. Passen sechs oder mehr darauf, gleichen sich die
|
||
Fehler aus - die Reste sind klein gegen die Rollenbreite, und die
|
||
Faustregel trifft es fast immer.
|
||
|
||
====================================================================================
|
||
WAS MAN DARAUS MITNIMMT
|
||
====================================================================================
|
||
1. Der Perspektivwechsel ist die eigentliche Arbeit: nicht 'welches
|
||
Stueck wohin', sondern 'wie oft welches Muster'. Damit verschwindet
|
||
die Symmetrie, die das naheliegende Modell unloesbar macht.
|
||
2. Der Preis dafuer ist eine unaufschreibbare Zahl von Variablen. Die
|
||
Spaltengenerierung zahlt ihn nicht, sondern erzeugt nur die wenigen
|
||
Spalten, die die Dualwerte als lohnend ausweisen.
|
||
3. Das Teilproblem ist ein Rucksack - ein Verfahren, das die Leser
|
||
dieses Buchs schon kennen. Neu ist allein die Schleife.
|
||
4. Und die unbequeme Erkenntnis: Ob sich das alles lohnt, entscheidet
|
||
die Instanz, nicht die Methode. Bei sechs Stuecken je Rolle ist die
|
||
Faustregel so gut wie das Optimum - und der Ertrag der
|
||
Spaltengenerierung liegt dann allein in der SCHRANKE, die beweist,
|
||
dass man aufhoeren kann zu suchen.
|
||
====================================================================================</code></pre>
|
||
<hr />
|
||
<h2 id="sec:dekomposition-befund">10.6 Was die Zahlen zeigen</h2>
|
||
<h3 id="die-musterzahl-explodiert-der-bedarf-nicht">Die Musterzahl explodiert, der Bedarf nicht</h3>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th>Instanz</th>
|
||
<th style="text-align: right;">mögliche Muster</th>
|
||
<th style="text-align: right;">erzeugt</th>
|
||
<th style="text-align: right;">Anteil</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td>breite Zuschnitte (1 380–2 200 mm)</td>
|
||
<td style="text-align: right;">309</td>
|
||
<td style="text-align: right;">38</td>
|
||
<td style="text-align: right;">12,3 %</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td>schmale Zuschnitte (380–1 200 mm)</td>
|
||
<td style="text-align: right;">46 408</td>
|
||
<td style="text-align: right;">28</td>
|
||
<td style="text-align: right;"><strong>0,06 %</strong></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Schon das Halbieren der Breiten lässt die Musterzahl um den <strong>Faktor 150</strong> springen. Die Zahl der <em>gebrauchten</em> Muster bleibt dagegen konstant — sie steigt sogar nicht, sie sinkt leicht. Das ist der ganze Ertrag des Verfahrens: Der Aufwand hängt an der Zahl der <strong>Bedarfszeilen</strong>, nicht an der Zahl der Muster.</p>
|
||
<h3 id="der-unbequeme-teil-es-lohnt-sich-nicht-immer">Der unbequeme Teil: Es lohnt sich nicht immer</h3>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th>Instanz</th>
|
||
<th style="text-align: right;">Faustregel</th>
|
||
<th style="text-align: right;">exakt</th>
|
||
<th style="text-align: right;">Schranke</th>
|
||
<th style="text-align: right;">Ersparnis</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td>breite Zuschnitte</td>
|
||
<td style="text-align: right;">82 Rollen</td>
|
||
<td style="text-align: right;"><strong>73</strong></td>
|
||
<td style="text-align: right;">72,92</td>
|
||
<td style="text-align: right;"><strong>11 %</strong></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td>schmale Zuschnitte</td>
|
||
<td style="text-align: right;">35 Rollen</td>
|
||
<td style="text-align: right;">35</td>
|
||
<td style="text-align: right;">33,60</td>
|
||
<td style="text-align: right;"><strong>0 %</strong></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Bei den breiten Zuschnitten spart die Spaltengenerierung neun von 82 Rollen. Bei den schmalen spart sie <strong>nichts</strong> — dort ist First-Fit-Decreasing bereits optimal.</p>
|
||
<p>Der Unterschied hängt an einer einzigen Kennzahl:</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th>Instanz</th>
|
||
<th style="text-align: right;">Stücke je Rolle</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td>breite Zuschnitte</td>
|
||
<td style="text-align: right;">3,0</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td>schmale Zuschnitte</td>
|
||
<td style="text-align: right;">6,4</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Passen nur zwei bis drei Stücke auf eine Rolle</strong>, entscheidet jede einzelne Zuordnung viel, und eine kurzsichtige Regel verschenkt ganze Rollen. <strong>Passen sechs oder mehr darauf</strong>, gleichen sich die Fehler aus: Die Reste sind klein gegen die Rollenbreite, und die Faustregel trifft es fast immer.</p>
|
||
<blockquote>
|
||
<p><strong>💡 Das erklärt einen Befund aus <a href="metaheuristiken.html#kap-metaheuristiken">Kapitel 9</a></strong></p>
|
||
<p>Dort steht, dass Bin Packing als Aufhänger für Metaheuristiken <strong>nicht</strong> taugt, weil First-Fit in den geprüften Größen bereits optimal war. Der Grund ist jetzt benennbar: Die dortige Instanz hatte Stücke von 700 bis 2 600 mm bei 5 600 mm Rollenbreite — im Mittel gut drei je Rolle, aber mit viel kleineren Stücken durchsetzt, so dass die Reste sich auffüllen ließen.</p>
|
||
<p>Die brauchbare Faustregel lautet also nicht „Bin Packing ist einfach”, sondern: <strong>Je weniger Stücke auf einen Behälter passen, desto mehr ist mit exakter Optimierung zu holen.</strong> Das ist eine Zahl, die man vor dem Projekt ausrechnen kann.</p>
|
||
</blockquote>
|
||
<p>Und selbst dort, wo die Ersparnis null ist, liefert das Verfahren etwas, das die Faustregel nicht kann: die <strong>Schranke 33,60</strong>. Sie beweist, dass 34 Rollen das Minimum wären und 35 höchstens eine daneben liegen — also dass man aufhören kann zu suchen.</p>
|
||
<hr />
|
||
<h2 id="sec:dekomposition-uebungsaufgaben">10.7 Übungsaufgaben</h2>
|
||
<blockquote>
|
||
<p>Lösungen: <a href="anhang-loesungen.html#sec:loesungen-dekomposition">Abschnitt A.10</a>.</p>
|
||
</blockquote>
|
||
<p><strong>Aufgabe 10.1 ⭐ — Das Abbruchkriterium.</strong> Warum lautet die Schwelle beim Pricing genau <code>1</code> und nicht <code>0</code>? Woher kommt die Eins?</p>
|
||
<p><strong>Aufgabe 10.2 ⭐ — Die Startbasis.</strong> Das Programm startet mit Mustern, die je nur eine Breite enthalten. Warum ist das immer zulässig, und warum wäre eine leere Startmenge ein Problem?</p>
|
||
<p><strong>Aufgabe 10.3 ⭐⭐ — Die Kennzahl prüfen.</strong> Erzeugen Sie Instanzen mit 2, 4, 8 und 16 Stücken je Rolle und tragen Sie die Ersparnis gegenüber First-Fit auf. Bestätigt sich der Zusammenhang aus <a href="#sec:dekomposition-befund">Abschnitt 10.6</a>?</p>
|
||
<p><strong>Aufgabe 10.4 ⭐⭐ — Dienstplanung.</strong> Formulieren Sie die Wochendienstplanung als Spaltengenerierung: Ein „Muster” ist ein zulässiger Wochenplan <strong>einer</strong> Person. Was ist das Teilproblem, und welche Nebenbedingungen stehen im Master, welche im Teilproblem?</p>
|
||
<p><strong>Aufgabe 10.5 ⭐⭐⭐ — Branch-and-Price.</strong> Das ganzzahlige Master über die erzeugten Spalten ist nicht garantiert optimal — es könnte Muster geben, die erst <em>nach</em> einer Verzweigung lohnend werden. Recherchieren Sie, was Branch-and-Price daran ändert, und erklären Sie, warum man nicht einfach auf den erzeugten Spalten verzweigen kann.</p>
|
||
<hr />
|
||
<h2 id="sec:dekomposition-denkfehler">10.8 Finde den Denkfehler</h2>
|
||
<div class="card card-denkfehler">
|
||
<blockquote>
|
||
<p><strong>🐛 „Die LP-Lösung sagt 72,92 — also runden wir auf”</strong></p>
|
||
<p>Ein Kollege hat die Spaltengenerierung implementiert und ist zufrieden:</p>
|
||
<blockquote>
|
||
<p><em>„Das Master-LP liefert 72,92 Rollen, verteilt auf 13 Muster. Halbe Rollen kann man > nicht schneiden, also runde ich jedes Muster auf die nächste ganze Zahl auf. Damit sind > alle Bestellungen sicher gedeckt — aufrunden kann ja nur zu viel liefern, nie zu wenig. > Ergebnis: ein zulässiger Schnittplan, und die Schranke sagt mir, dass ich höchstens eine > Rolle daneben liege.”</em></p>
|
||
</blockquote>
|
||
<p>Der erste Teil stimmt: Aufrunden liefert tatsächlich einen zulässigen Plan. Der zweite Satz über die Schranke ist der Fehler — und er ist teuer.</p>
|
||
<p><strong>Wie viele Rollen kostet das Aufrunden hier wirklich, und was hätte der Kollege stattdessen tun müssen?</strong></p>
|
||
<p>Ein Hinweis: Er hat alles, was er dafür braucht, bereits vorliegen.</p>
|
||
</blockquote>
|
||
</div>
|
||
<hr />
|
||
<h2 id="sec:dekomposition-quiz">10.9 Micro-Quiz</h2>
|
||
<div class="card card-quiz">
|
||
<blockquote>
|
||
<p><strong>❓ Drei Fragen</strong></p>
|
||
<p><strong>1. Warum ist das Mustermodell dem Zuordnungsmodell überlegen?</strong> a) Weil es weniger Nebenbedingungen hat. b) Weil es keine einzelnen Rollen kennt und damit die Symmetrie verschwindet. c) Weil Musterprobleme immer ganzzahlige LP-Lösungen haben.</p>
|
||
<p><strong>2. Was ist das Pricing-Teilproblem beim Zuschnitt?</strong> a) Ein zweites LP über dieselben Variablen. b) Ein Rucksackproblem: Welche Stücke passen in eine Rolle und sind zu den aktuellen Schattenpreisen am meisten wert? c) Eine Heuristik, die neue Muster zufällig erzeugt.</p>
|
||
<p><strong>3. Bei der schmalen Instanz spart die Spaltengenerierung null Rollen gegenüber First-Fit. War der Aufwand umsonst?</strong> a) Ja — wo nichts gespart wird, hat sich das Verfahren nicht gelohnt. b) Nein — sie liefert die untere Schranke und damit den Beweis, dass die Faustregel höchstens eine Rolle danebenliegt. c) Nein — sie wird bei der nächsten Instanz mehr sparen.</p>
|
||
</blockquote>
|
||
</div>
|
||
<hr />
|
||
<h2 id="sec:dekomposition-selbsttest">10.10 Selbsttest</h2>
|
||
<ol type="1">
|
||
<li>Erklären Sie Symmetrie in einem MILP an einem Beispiel aus Ihrem Arbeitsumfeld.</li>
|
||
<li>Was ist beim Zuschnitt eine „Spalte”, und was steht darin?</li>
|
||
<li>Woher kommen die Preise, mit denen das Teilproblem rechnet?</li>
|
||
<li>Warum ist das Verfahren exakt, obwohl es fast alle Muster nie ansieht?</li>
|
||
<li>Sie sollen vor dem Projekt abschätzen, ob sich Spaltengenerierung lohnt. Welche eine Zahl rechnen Sie aus?</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="sec:dekomposition-zusammenfassung">10.11 Zusammenfassung</h2>
|
||
<ul>
|
||
<li>Die folgenreichste Entscheidung an einem Modell ist, <strong>worüber die Variablen laufen</strong>. Beim Zuschnitt schlägt „wie oft welches Muster” das naheliegende „welches Stück auf welche Rolle” — weil damit die <strong>Symmetrie</strong> verschwindet, an der Branch-and-Bound scheitert.</li>
|
||
<li>Der Preis dafür ist eine Variablenmenge, die man nicht aufschreiben kann. Die <strong>Spaltengenerierung</strong> zahlt ihn nicht: Sie erzeugt nur die Muster, die die <strong>Dualwerte</strong> als lohnend ausweisen — im Beispiel 28 von 46 408.</li>
|
||
<li>Das Abbruchkriterium sind die <strong>reduzierten Kosten</strong>: Solange ein Muster zu den aktuellen Schattenpreisen mehr als eine Rolle wert ist, lohnt es sich. Danach ist die Lösung beweisbar optimal — auch über die nie erzeugten Muster.</li>
|
||
<li>Das <strong>Teilproblem ist ein Rucksack</strong>. Neu ist allein die Schleife.</li>
|
||
<li><strong>Ob sich das lohnt, entscheidet die Instanz.</strong> Bei drei Stücken je Rolle bringt das Verfahren 11 %, bei sechs nichts. Diese Kennzahl lässt sich vor dem Projekt ausrechnen.</li>
|
||
<li>Auch wo es nichts spart, liefert es die <strong>Schranke</strong> — und damit die Erlaubnis, aufzuhören.</li>
|
||
</ul>
|
||
|
||
</article>
|
||
<button type="button" class="fortschritt-knopf" data-kapitel="dekomposition.html"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg> <span>Als gelesen markieren</span></button>
|
||
<nav class="prev-next"><a class="prev-next-knopf prev-next-prev" href="metaheuristiken.html"><svg class="icon" aria-hidden="true"><use href="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 9: Metaheuristiken — wenn der exakte Solver aussteigt</span></a><a class="prev-next-knopf prev-next-next" href="qp-nlp.html"><span><small>Weiter</small>Kapitel 11: Quadratische und nichtlineare Optimierung — KKT, Lagrange, Konvexität</span><svg class="icon" aria-hidden="true"><use href="#icon-chevron-right"></use></svg></a></nav>
|
||
</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>
|