Vorlesung 08: Ganzzahlige Optimierung

Grundlagen Operations Research

Ganzzahlige Optimierung

Nur ganze Einheiten

Was ist neu?

Für einige oder alle Variablen sind nur ganze Zahlen zulässig:

  • Ganzzahlig: X0X \ge 0 und ganzzahlig (Stückzahlen, Fahrzeuge, …).
  • Binär: X{0,1}X \in \{0, 1\} für Ja/Nein-Entscheidungen.
  • Gemischt-ganzzahlig: ganzzahlige und kontinuierliche Variablen.

Lässt man die Ganzzahligkeit weg, entsteht die LP-Relaxation, ein gewöhnliches lineares Problem.

Warum schwierig?

  • Ganzzahlige Probleme gelten als schwer: kein Algorithmus mit polynomialem Aufwand für die optimale Lösung bekannt.
  • Naiv: vollständige Enumeration aller ganzzahligen Möglichkeiten.
  • In der Praxis: Meta-Heuristiken (Genetische Algorithmen, Tabu-Suche, …) oder das exakte Branch-&-Bound-Verfahren.

LP-Relaxation grafisch

Die schwarzen Punkte sind die ganzzahligen Kandidaten.

Das LP-Optimum (2,29;1,57)(2{,}29;\, 1{,}57) ist nicht ganzzahlig.

Frage: Warum nicht einfach runden?

Die Antwort folgt am Ende des Kapitels.

Branch & Bound

Ausgangsproblem P0P_0

maxF=X1+2X2X1+3X273X1+2X210X1,X20 und ganzzahlig \begin{aligned} \max \; & F = X_1 + 2 X_2 \\ & X_1 + 3 X_2 \le 7 \\ & 3 X_1 + 2 X_2 \le 10 \\ & X_1, X_2 \ge 0 \text{ und ganzzahlig} \end{aligned}

LP-Relaxation P0P_0': X1*=2,286X_1^* = 2{,}286, X2*=1,571X_2^* = 1{,}571, F0*=5,429F_0^* = 5{,}429 \Rightarrow obere Schranke F¯0=5,429\overline{F}_0 = 5{,}429.

Schranken (Bounding)

  • Jede LP-Relaxation liefert eine obere Schranke für ihr Teilproblem.
  • Jede bekannte ganzzahlige Lösung liefert eine globale untere Schranke F_\underline{F}.
  • Start: X1=X2=0X_1 = X_2 = 0 ist ganzzahlig zulässig F_=0\Rightarrow \underline{F} = 0.

Ein Teilproblem ist ausgelotet, wenn seine obere Schranke F_\underline{F} nicht mehr übertrifft.

Die Auslotungsregeln

Ein Teilproblem PiP_i wird nicht weiter verzweigt, wenn:

  • (3a) F¯iF_\overline{F}_i \le \underline{F}: es kann nichts Besseres mehr liefern.
  • (3b) die Relaxationslösung ganzzahlig ist und F_\underline{F} verbessert (F¯i>F_\overline{F}_i > \underline{F}): neue beste Lösung.
  • (3c) die Relaxation unzulässig ist: dann auch PiP_i.

Bei Minimierung tauschen obere und untere Schranke die Rollen.

Relaxationen

Die LP-Relaxation ist nur eine Möglichkeit, Schranken zu gewinnen:

  • LP-Relaxation: Ganzzahligkeit weglassen (unser Standard).
  • Weglassen von Nebenbedingungen: jedes entspannte Problem schrankt.
  • Lagrange-Relaxation: verletzte Restriktionen wandern bestraft in die Zielfunktion.

Verzweigen (Branching)

Wähle eine nicht ganzzahlige Variable und verzweige, um den nicht ganzzahligen Bereich auszuschließen:

P1:P0 und X12P2:P0 und X13 P_1:\; P_0 \text{ und } X_1 \le 2 \qquad P_2:\; P_0 \text{ und } X_1 \ge 3

Übliche Regel: die Variable mit dem geringsten Abstand zur nächsten ganzen Zahl, hier X1X_1 (0,286<0,4290{,}286 < 0{,}429).

Die optimale ganzzahlige Lösung von P0P_0 steckt in P1P_1 oder P2P_2.

Suchstrategien

Frage: Welches offene Teilproblem als Nächstes?

  • Reine Tiefensuche: einen Ast bis zum Ende, schnell eine erste Lösung.
  • Tiefensuche + MUB: nach vollständiger Verzweigung den Ast mit größter oberer Schranke (Maximum Upper Bound).
  • Breitensuche: unter allen offenen Knoten den mit größter Schranke.

Teilprobleme P1P_1 und P2P_2

P1(X12)P_1\,(X_1 \le 2): (2,1,67)(2,\, 1{,}67), F¯1=5,33\overline{F}_1 = 5{,}33

P2(X13)P_2\,(X_1 \ge 3): (3,0,5)(3,\, 0{,}5), F¯2=4\overline{F}_2 = 4

Weiter mit dem besten Ast

F¯1=5,33>F¯2=4\overline{F}_1 = 5{,}33 > \overline{F}_2 = 4 \Rightarrow verzweige zuerst P1P_1 (Maximum-Upper-Bound).

In P1P_1 ist X2=1,667X_2 = 1{,}667 nicht ganzzahlig:

P3:P1 und X21P4:P1 und X22 P_3:\; P_1 \text{ und } X_2 \le 1 \qquad P_4:\; P_1 \text{ und } X_2 \ge 2

Teilprobleme P3P_3 und P4P_4

P3P_3: (2,1)(2,\, 1), F3=4F_3 = 4, ganzzahlig F_=4\Rightarrow \underline{F} = 4

P4P_4: (1,2)(1,\, 2), F4=5F_4 = 5, ganzzahlig F_=5\Rightarrow \underline{F} = 5

P2P_2 wird ausgelotet

P3P_3 und P4P_4 sind ganzzahlig gelöst. Die beste untere Schranke ist jetzt F_=5\underline{F} = 5.

F¯2=4F_=5P2 ausgelotet \overline{F}_2 = 4 \;\le\; \underline{F} = 5 \;\Rightarrow\; P_2 \text{ ausgelotet}

P2P_2 kann keine bessere Lösung mehr enthalten. Es muss nicht weiter untersucht werden.

Der Branch-&-Bound-Baum

P0P_0: LP-Optimum gebrochen, UB (= F¯\overline{F}) 5,43, verzweigen nach X1X_1.

P1P_1 verspricht mehr (MUB). P2P_2 wartet.

P3P_3 und P4P_4 sind ganzzahlig (3b); F_=5\underline{F} = 5 lotet P2P_2 aus (3a).

Optimale Lösung

Alle Teilprobleme sind ausgelotet. Die beste ganzzahlige Lösung ist optimal:

WichtigOptimale Lösung

X1*=1,X2*=2,F0*=5 X_1^* = 1, \quad X_2^* = 2, \quad F_0^* = 5

Beachten Sie: das gerundete LP-Optimum (2,2)(2, 2) ist gar nicht zulässig. Runden führt oft in die Irre.

Kontrolle mit Julia

Ganzzahlig mit JuMP

Ganzzahligkeit ist in JuMP nur ein Zusatz. HiGHS führt Branch & Bound automatisch aus:

using JuMP, HiGHS

modell = Model(HiGHS.Optimizer); set_silent(modell)
@variable(modell, X1 >= 0, Int)          # ganzzahlig
@variable(modell, X2 >= 0, Int)
@objective(modell, Max, X1 + 2X2)
@constraint(modell, X1 + 3X2 <= 7)
@constraint(modell, 3X1 + 2X2 <= 10)

optimize!(modell)
println("F* = ", objective_value(modell),
        " mit X1 = ", value(X1), ", X2 = ", value(X2))
F* = 5.0 mit X1 = 1.0, X2 = 2.0

Binäres Beispiel

Auftragsauswahl

Ein Fuhrunternehmer kann vier Aufträge annehmen. Welche maximieren den Erlös? Kapazität: 30 t und 50 Paletten.

Auftrag 1 2 3 4
Gewicht [t] 10 15 12 14
Paletten 12 30 16 10
Erlös 200 350 250 180

Das Binärmodell

Mit Xj{0,1}X_j \in \{0, 1\} (Auftrag jj annehmen?):

maxF=jejXjjgjXjG(Gewicht)jpjXjP(Paletten)Xj{0,1} \begin{aligned} \max \; & F = \sum_j e_j\, X_j \\ & \sum_j g_j\, X_j \le G && (\text{Gewicht}) \\ & \sum_j p_j\, X_j \le P && (\text{Paletten}) \\ & X_j \in \{0, 1\} \end{aligned}

LP-Relaxation: statt Xj{0,1}X_j \in \{0,1\} nur 0Xj10 \le X_j \le 1.

LP-Relaxation lösen

Die LP-Relaxation ist nicht ganzzahlig:

X*=(0,3,1,1,0),F0*=660 X^* = (0{,}3,\; 1,\; 1,\; 0), \quad F_0^* = 660

X1=0,3X_1 = 0{,}3 ist gebrochen \Rightarrow verzweige nach X1X_1, und zwar, da binär, in die Äste X1=0X_1 = 0 und X1=1X_1 = 1.

Reine Tiefensuche

Immer Xj=0X_j = 0 zuerst, tief hinab: P2=(0,1,1,0)P_2 = (0,1,1,0) ist ganzzahlig (3b) F_=600\Rightarrow \underline{F} = 600.

Zurück und rechts: P3P_3 mit 550,8600550{,}8 \le 600, ausgelotet (3a).

Rechter Ast: P5P_5 verspricht 614,3614{,}3, aber P6P_6 und P7P_7 (beide 3a) bringen nichts Besseres.

P9P_9 (3a) und P10P_{10} (unzulässig, 3c) beenden die Suche. P2P_2 bleibt optimal.

Optimum

WichtigBeste Auftragsauswahl

Aufträge 2 und 3: X*=(0,1,1,0)X^* = (0, 1, 1, 0), F*=600F^* = 600.

Von 24=162^4 = 16 möglichen Auftragskombinationen hat Branch & Bound nur einen Teil explizit geprüft. Der Rest war implizit ausgelotet: implizite vollständige Enumeration.

Kontrolle mit Julia

using JuMP, HiGHS
e = [200,350,250,180]; g = [10,15,12,14]; p = [12,30,16,10]
G, P, J = 30, 50, 1:4

modell = Model(HiGHS.Optimizer); set_silent(modell)
@variable(modell, X[J], Bin)
@objective(modell, Max, sum(e[j]*X[j] for j in J))
@constraint(modell, sum(g[j]*X[j] for j in J) <= G)
@constraint(modell, sum(p[j]*X[j] for j in J) <= P)

optimize!(modell)
println("F* = ", round(Int, objective_value(modell)),
        ", angenommen: ", [j for j in J if value(X[j]) > 0.5])
F* = 600, angenommen: [2, 3]

Zusammenfassung

Das Wichtigste auf einen Blick

  • Die LP-Relaxation lässt die Ganzzahligkeit weg und liefert eine obere Schranke.
  • Branch & Bound verzweigt nach nicht ganzzahligen Variablen und lotet Teilprobleme über Schranken aus.
  • Ein Teilproblem ist erledigt, wenn es ganzzahlig ist oder seine obere Schranke F_\underline{F} nicht übertrifft.
  • Runden der LP-Lösung ist keine verlässliche Methode.

Literatur

Literaturverzeichnis

Domschke, Wolfgang, Andreas Drexl, Robert Klein, und Armin Scholl. 2015. Einführung in Operations Research. 9. Aufl. Springer Gabler. https://doi.org/10.1007/978-3-662-48216-2.