Vorlesung 03: Dualer Simplex
Grundlagen Operations Research
Motivation
Eine zusätzliche Auflage
Worum geht es heute?
Wir kennen den primalen Simplex. Doch was tun, wenn nach der Lösung eine neue Nebenbedingung hinzukommt?
- Alles von vorn rechnen? Bei großen Problemen enorm aufwendig.
- Besser: auf der optimalen Zwischenlösung aufbauen.
Das leistet der duale Simplex-Algorithmus: er ist auch Grundlage der ganzzahligen Optimierung (Vorlesung 08).
Wiederholung
Das Optimaltableau
Der primale Simplex lieferte für den Frachtführer:
| BV | |||||
|---|---|---|---|---|---|
| 1 | 0 | 3/2 | −1/2 | 3 | |
| 0 | 1 | −1/2 | 1/2 | 2 | |
| 0 | 0 | 15 | 5 | 120 |
Eine neue Nebenbedingung
Aus ladungstechnischen Gründen soll Auftrag 1 nicht mehr Paletten umfassen als Auftrag 2:
Mit einer weiteren Schlupfvariablen :
Grafische Deutung
Die Grenzgerade der neuen Restriktion (durchgezogen) schneidet den zulässigen Bereich zum Dreieck.
Das neue Optimum liegt bei .
(gepunktet) ist jetzt redundant: es könnte entfallen.
Reoptimierung
Idee der Reoptimierung
Statt das erweiterte Problem neu zu lösen, fügen wir die neue Restriktion in das vorhandene Optimaltableau ein und stellen mit wenigen Basistauschen die Zulässigkeit wieder her.
- Vermeidet die Wiederholung vieler primaler Iterationen.
- Oft genügt eine einzige Iteration.
- Grundlage der Reoptimierung im Branch-and-Bound (Vorlesung 8).
Neue Restriktion einfügen
Die Zeile kommt ins Optimaltableau:
| BV | ||||||
|---|---|---|---|---|---|---|
| 1 | 0 | 3/2 | −1/2 | 0 | 3 | |
| 0 | 1 | −1/2 | 1/2 | 0 | 2 | |
| 1 | −1 | 0 | 0 | 1 | 0 | |
| 0 | 0 | 15 | 5 | 0 | 120 |
| BV | ||||||
|---|---|---|---|---|---|---|
| 1 | 0 | 3/2 | −1/2 | 0 | 3 | |
| 0 | 1 | −1/2 | 1/2 | 0 | 2 | |
| 0 | 0 | −2 | 1 | 1 | −1 | |
| 0 | 0 | 15 | 5 | 0 | 120 |
Die Basisvariablen stehen noch in der neuen Zeile: sie werden mit Elementaroperationen isoliert (Zeile 1 subtrahieren, Zeile 2 addieren).
: die Basislösung ist unzulässig. muss die Basis verlassen. Aber die -Zeile ist weiter optimal!
Dualer Simplex: Pivotwahl
Erst Pivotzeile, dann Pivotspalte.
- Pivotzeile : negativste -Zeile, verletzt die Nichtnegativität am stärksten:
- Pivotspalte : Basistausch verschlechtert am wenigsten, nur negative Koeffizienten der Pivotzeile kommen infrage:
Reoptimierung durchführen
Pivotzeile ; einziger negativer Koeffizient: unter Pivotelement [−2]:
| BV | ||||||
|---|---|---|---|---|---|---|
| 1 | 0 | 3/2 | −1/2 | 0 | 3 | |
| 0 | 1 | −1/2 | 1/2 | 0 | 2 | |
| 0 | 0 | −2 | 1 | 1 | −1 | |
| 0 | 0 | 15 | 5 | 0 | 120 |
| BV | ||||||
|---|---|---|---|---|---|---|
| 1 | 0 | 0 | 1/4 | 3/4 | 9/4 | |
| 0 | 1 | 0 | 1/4 | −1/4 | 9/4 | |
| 0 | 0 | 1 | −1/2 | −1/2 | 1/2 | |
| 0 | 0 | 0 | 25/2 | 15/2 | 225/2 |
kommt für in die Basis: ein einziger Basistausch.
Alle und -Zeile : zulässig und optimal, , .
Der duale Simplex-Algorithmus
Eine Basislösung, die unzulässig ist (Basisvariablen negativ), aber die Optimalitätsbedingung erfüllt.
- Phase 1 (Zulässigkeit herstellen): Basistausche (erst Pivotzeile, dann Pivotspalte), bis alle .
- Phase 2 (falls zulässig, aber nicht optimal): mit dem primalen Simplex weiterrechnen.
Ganzzahligkeit
Nicht ganzzahlige Lösung
Die reoptimierte Lösung ist : nicht ganzzahlig.
Sinnvoll sind nur ganze Paletten. Wir spalten in zwei Teilprobleme:
Jedes Teilproblem lässt sich per Reoptimierung (dualer Simplex) lösen: kein Neustart nötig.
Teilproblem 1 einfügen
Die Zeile wird eingefügt und isoliert, wieder wird eine -Zeile negativ:
| BV | |||||||
|---|---|---|---|---|---|---|---|
| 1 | 0 | 0 | 1/4 | 3/4 | 0 | 9/4 | |
| 0 | 1 | 0 | 1/4 | −1/4 | 0 | 9/4 | |
| 0 | 0 | 1 | −1/2 | −1/2 | 0 | 1/2 | |
| 0 | 0 | 0 | −1/4 | 1/4 | 1 | −1/4 | |
| 0 | 0 | 0 | 25/2 | 15/2 | 0 | 225/2 |
| BV | |||||||
|---|---|---|---|---|---|---|---|
| 1 | 0 | 0 | 0 | 1 | 1 | 2 | |
| 0 | 1 | 0 | 0 | 0 | 1 | 2 | |
| 0 | 0 | 1 | 0 | −1 | −2 | 1 | |
| 0 | 0 | 0 | 1 | −1 | −4 | 1 | |
| 0 | 0 | 0 | 0 | 20 | 50 | 100 |
Pivotzeile ; einziger negativer Koeffizient unter Pivot [−1/4].
Ein Basistausch genügt: , , , ganzzahlig! Teilproblem 2 () läuft genauso.
Zwei Teilprobleme
1. Teilproblem ()
2. Teilproblem ()
(aus dem 1. Teilproblem).
Dieses systematische Aufspalten ist die Grundidee von Branch & Bound (Vorlesung 08).
Reduzierte Kosten
Ein drittes Auftragsangebot
Ein weiterer Auftrag wird angeboten: 24 EUR je Palette, 1 Stellplatz, 2 Tonnen.
Frage: Lohnt sich Auftrag 3 überhaupt?
Das verrät ein Blick auf die reduzierten Kosten, ohne das Problem neu zu lösen.
Simplex-Multiplikatoren
Im Optimaltableau stehen unter den Schlupfvariablen die Simplex-Multiplikatoren:
Sie entstehen dadurch, dass das -fache der 1. und das -fache der 2. Ausgangsgleichung zur Zielfunktion addiert wurden:
Definitionen
- : Zielfunktionskoeffizient der Variablen
- : aktueller Wert in der -Zeile unter
- : reduzierte Kosten der Variablen
- : Simplex-Multiplikator der Zeile
Im Ausgangstableau gilt stets und .
Reduzierte Kosten berechnen
Bei zwei Nebenbedingungen:
Für den dritten Auftrag (, , ):
Optimalitätsbedingung
heißt: kein Zielfunktionsgewinn durch Aufnahme von (bei Maximierung). Optimal, wenn für alle .
Wegen ist Auftrag 3 keine lohnende Alternative.
Preisuntergrenze
Ein vierter Auftrag: , , .
Frage: Ab welchem Erlös würde sich Auftrag 4 lohnen?
Auftrag 4 wird nicht übernommen, aber ab einem Erlös wäre er lohnend.
Die reduzierten Kosten liefern eine Preis- bzw. Erlösuntergrenze für zusätzliche Aufträge.
Kontrolle mit Julia
Erweitertes Problem mit JuMP
Wir lösen das Problem mit der Zusatzrestriktion :
using JuMP, HiGHS
modell = Model(HiGHS.Optimizer)
set_silent(modell)
@variable(modell, X1 >= 0) # Abnahmemenge Auftrag 1
@variable(modell, X2 >= 0) # Abnahmemenge Auftrag 2
@objective(modell, Max, 20X1 + 30X2)
@constraint(modell, Paletten, X1 + X2 <= 5)
@constraint(modell, Gewicht, X1 + 3X2 <= 9)
@constraint(modell, Auflage, X1 <= X2) # neue Nebenbedingung
optimize!(modell)
println("F* = ", objective_value(modell),
" mit X1 = ", value(X1), ", X2 = ", value(X2))F* = 112.5 mit X1 = 2.25, X2 = 2.25
Ganzzahlige Lösung mit JuMP
Fordern wir Ganzzahligkeit, liefert HiGHS direkt die beste ganzzahlige Lösung:
set_integer(X1)
set_integer(X2)
optimize!(modell)
println("F* = ", objective_value(modell),
" mit X1 = ", value(X1), ", X2 = ", value(X2))F* = 100.0 mit X1 = 2.0, X2 = 2.0
Zusammenfassung
Das Wichtigste auf einen Blick
- Reoptimierung baut auf dem Optimaltableau auf, statt neu zu rechnen.
- Der duale Simplex stellt Zulässigkeit her: erst Pivotzeile, dann Pivotspalte.
- Nicht ganzzahlige Lösungen werden in Teilprobleme zerlegt (→ Branch & Bound).
- Reduzierte Kosten beurteilen zusätzliche Alternativen und liefern Preisuntergrenzen.