Einführung in Xpress-Mosel

Transcription

Einführung in Xpress-Mosel
Einführung in Xpress-Mosel
Matthias Silbernagl
Computerblockpraktikum zur linearen Optimierung
1 Mosel-Grundlagen
Gliederung
1.1 Xpress im Überblick
Xpress im Überblick
Inhaltsverzeichnis
1 Mosel-Grundlagen
1.1 Xpress im Überblick . . . . . . . . . . . . . . . . . . . . . .
1.2 Grundlegende Strukturen . . . . . . . . . . . . . . . . . . .
1.3 Ein einführendes Beispiel . . . . . . . . . . . . . . . . . . .
1
1
2
2
2 Mosel für Fortgeschrittene
2.1 Entscheidungsvariable . . . . .
2.2 Mengen, Felder und Parameter
2.3 Ein Beispiel . . . . . . . . . . .
2.4 Daten einlesen und ausgeben .
2.5 Entscheidungen und Schleifen .
2.6 Datensätze . . . . . . . . . . .
2.7 Unterprogramme . . . . . . . .
4
4
4
5
7
8
8
8
3 Optimizer-Modul: Grundlagen
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
• Xpress-MP ist ein Softwarepaket für lineare und gemischt-ganzzahlige
Optimierung
• Mehrere Komponenten:
– Optimizer → Kernkomponente (primaler & dualer Simplex, Barrier, MIP, Presolver, Heuristiken)
– Low-Level Bibliotheken (C/C++/Java/VB)
– Programmier- und Modellierungssprache Mosel
– Bibliotheken zur Einbindung von Mosel in C/C++/Java/VB
– Entwicklungstools (Debugger, Profiler, IDE)
– weitere Module (Datenzugriff, Graphik und GUI, Algorithmen)
9
Xpress im Überblick
1
Variablen-Deklaration
Daten
Modell
• Variablen vor der Verwendung deklarieren!
Umsetzung
• Deklaration zwischen declarations und end-declarations
Mosel
Interaktion
• Variablentypen in Mosel
Optimizer
integer, real: ganze bzw. rationale Zahlen
string: Zeichenketten wie "Lineares Modell"
boolean: Wahrheitswert (true oder false).
Ausgabe
set of . . . : Menge, z. B. set of integer
Lösung
range: ganzzahliges Intervall
array(. . . ) of: Feld , z. B. array(1..3) of real
1.2 Grundlegende Strukturen
record: Datensatz
Mosel-Programmgerüst
mpvar: Entscheidungsvariable
model " Modellname "
options noimplicit , explterm ;
uses " mmxprs " ;
linctr: linearer Ausdruck, z. B. Nebenbedingung
mpproblem: lineares Problem
declarations
! V a r i a b l endeklaration
end-declarations
Achtung: Entscheidungsvariablen sind implizit ≥ 0!
! Programmcode
1.3 Ein einführendes Beispiel
end-model
Einführendes Beispiel
• Programmcode zwischen model "Modellname" und end-model
Aufgabe
Für die Produktion der Produkte P1 und P2 benötigt ein Unternehmen
eine Maschine, die in jedem Monat 160 Stunden zur Verfügung steht. Eine
Einheit von P1 kann in einer Stunde auf der Maschine gefertigt werden, für
eine Einheit P2 werden drei Stunden benötigt. Der Gewinn beim Verkauf
eines Stückes von P1 beträgt 7,– e, ein Stück P2 kann mit einem Gewinn
von 9,– e verkauft werden. Maximal lassen sich pro Monat 100 Stück von
P1 und 40 Stück von P2 absetzen. Welche Produktionsmengen von P1 und
P2 maximieren den Gewinn des Unternehmens?
• options noimplicit: Variablen müssen deklariert werden → vereinfacht
Fehlersuche!
• options explterm: Befehle müssen mit ; beendet werden
• uses "Bibliothek" bindet zusätzliche Bibliotheken ein, z. B. mmxprs für
die Optimierung.
• ! leitet Kommentare ein
2
Einführendes Beispiel
model " Produktion "
options noimplicit , explterm ;
uses " mmxprs " ;
• Restriktionen
declarations
Kriterium
P1
P2
100
1
7
40
3
9
end-declarations
Maximalmengen
Maschinenzeit: 160 h
Gewinn
end-model
• Variablen-Deklaration
• Modellierung
declarations
x , y: mpvar ;
Maschinenzeit: linctr ;
Gewinn: linctr ;
end-declarations
Variablen: Produktionsmengen von P1 bzw. P2 → x, y
Maximalmengen: x ≤ 100,
y ≤ 40
Maschinenzeit: x + 3y ≤ 160
• Nebenbedingungen und Zielfunktion
Zielfunktion: max 7x + 9y
Gewinn := 7 *x + 9 *y ;
Maschinenzeit := x + 3 *y <= 160;
x <= 100;
y <= 40;
max 7x + 9y
x + 3y ≤ 160
• Optimierung und Ausgabe
x ≤ 100
maximize ( Gewinn );
y ≤ 40
writeln ( " Gewinn: " , getobjval );
writeln ( " P1: " , getsol ( x ));
writeln ( " P2: " , getsol ( y ));
Einführendes Beispiel in Mosel
• Modell
Gesamtprogramm
max 7x + 9y
model " Produktion "
options noimplicit , explterm ;
uses " mmxprs " ;
x + 3y ≤ 160
x ≤ 100
y ≤ 40
declarations
x , y: mpvar ;
Maschinenzeit: linctr ;
Gewinn: linctr ;
• Grundgerüst
3
– is_free: freie Variable, d. h. Wertebereich (−∞; ∞)
end-declarations
– is_integer:
{0, 1, 2, . . .}
Gewinn := 7 *x + 9 *y ;
Maschinenzeit := x + 3 *y <= 160;
x <= 100;
y <= 40;
ganzzahlige
Variable,
d. h.
Wertebereich
– is_binary: 0-1-Variable, d. h. Wertebereich {0, 1}
– Selten benötigte Typen auf Kurzreferenz
maximize ( Gewinn );
writeln ( " Gewinn: " , getobjval );
writeln ( " P1: " , getsol ( x ));
writeln ( " P2: " , getsol ( y ));
end-model
• Deklaration z. B. mit x is_binary
2.2 Mengen, Felder und Parameter
Mengen und Intervalle
Wichtige Befehle
• Mengen
• model – end-model klammert das Modell ein
– Deklaration als A, B : set of ...;
• uses zur Einbindung von Bibliotheken
– Schreibweise: A := {1,2,6,9}
– Vereinigung: A + B oder union(i in 1..5) {i*5}
• declarations – end-declarations klammert Variablendeklaration ein
– Differenz: A - B
• maximize bzw. minimize startet die Optimierung
– Schnitt: A*B oder inter(i in 1..5) {1,i}
• write bzw. writeln zur Ausgabe
– Test auf Untermenge: A <= B / Obermenge A >= B
• getobjval liefert den Zielfunktionswert
• Intervalle
– Deklaration als R: range;
• getsol() liefert die Lösung
– Schreibweise: R := 4..20
2 Mosel für Fortgeschrittene
– spezielle Mengen, effizientere Speichernutzung
2.1 Entscheidungsvariable
– Operationen wie bei Mengen (auch gemischt), Ergebnis evtl. kein
Intervall.
Typen von Entscheidungsvariablen
Felder, Summen, Schleifen
• Entscheidungsvariable sind vom Typ mpvar
• Felder
• Vorgabe: stetig aus [0; ∞)
– Deklaration als F: array(Indexmenge) of ... mit einer Menge oder
einem Intervall als Indexmenge
• Spezielle Typen von Entscheidungsvariablen:
4
(bi ≥ 0) bzw. das Angebot an Ostereiern (bi < 0). Dabei sei die Gesamtnachfrage gleich dem Gesamtangebot. Zwischen je zwei Bahnhöfen i und j
existiert eine Zugverbindung, auf der maximal lij Eier transportiert werden können, der Transport koste dabei cij pro Ei. Bestimmen Sie einen
kostenminimalen Transportplan für die Ostereier!
– Schreibweise: F := [1,2,3]
– Zugriff auf einzelne Elemente: F(2)
– Mehrdimensionale Arrays: G: array(Index1, Index2, Index3) of ...
– Beispiel:
G: array ({ " rot " , " blau " } , 1..3) of integer ;
G :: ([ " rot " , " blau " ] , [1 ,2 ,3])[1 , 2 , 3 , 4 , 5 , 6];
G ( " rot " , 2) := 42;
Modellierung
• Variablen:
ergibt [1, 42, 3, 4, 5, 6]
xij = Anzahl Eier, die von i nach j transportiert werden
• Summen über Felder: sum(i in 1..3) F(i)
• Schleifen über Felder:
• Kapazitäten:
forall ( i in { " rot " , " blau " } , j in 1..3) do
writeln ( " G " ,i , " / " , j , " = " , G (i , j ));
end-do
xij ≤ lij
∀(i, j) ∈ {1, . . . , n} × {1, . . . , n}
• Bedarf/Angebot:
Parameter
n
X
• Mosel-Parameter sind Konstanten, die in einem eigenen Block deklariert werden:
xki −
n
X
xik = bi
k=1
k=1
• Zielfunktion
parameters
n = 10;
end-parameters
∀i ∈ {1, . . . , n}
min
n X
n
X
cij xij
i=1 j=1
• Über die Kommandozeile oder die Benutzeroberfläche können andere
Werte für die Parameter übergeben werden.
Modellierung in Mosel
• Modell
• Parameter können nur integer, real, string oder boolean sein.
min
2.3 Ein Beispiel
n X
n
X
cij xij
i=1 j=1
Beispiel
n
X
Aufgabe
Auf dem Schienennetz der Bahn sollen Ostereier transportiert werden. Es
gibt n Bahnhöfe, für jeden Bahnhof sei bi der jeweilige Bedarf an Ostereiern
k=1
xki −
n
X
xik = bi
0 ≤ xij ≤ lij
5
∀i ∈ {1, . . . , n}
k=1
∀(i, j) ∈ {1, . . . , n} × {1, . . . , n}
• Parameter
• Zielfunktion definieren und optimieren
parameters
n = 10; ! Anzahl Bahnhöfe
end-parameters
costs := sum ( i in Stations , j in Stations )
cost (i , j ) * x (i , j );
minimize ( costs );
• Deklarationen
• Ausgabe
declarations
Stations = 1.. n ;
cost: array ( Stations , Stations ) of integer ;
capacity: array ( Stations , Stations ) of integer ;
demand: array ( Stations ) of integer ;
writeln ( " Gesamtkosten: " , getobjval );
forall ( i in Stations , j in Stations |
getsol ( x (i , j )) <> 0) do
writeln ( " Transport von " , i , " nach " , j ,
" : " , getsol ( x (i , j )) , " Ostereier " );
end-do
..
.
..
.
• Deklarationen
Gesamtprogramm
model " Ostereier "
uses " mmxprs " ;
options noimplicit , explterm ;
x: array ( Stations , Stations ) of mpvar ;
c a p a c i tyConstraints: array ( Stations , Stations )
of linctr ;
de ma nd Constraints: array ( Stations ) of linctr ;
costs: linctr ;
end-declarations
parameters
n = 10; ! Anzahl Bahnhöfe
end-parameters
• Initialisieren
declarations
Stations = 1.. n ;
cost: array ( Stations , Stations ) of integer ;
capacity: array ( Stations , Stations ) of integer ;
demand: array ( Stations ) of integer ;
x: array ( Stations , Stations ) of mpvar ;
capacityCon s t r a i n t s : array ( Stations , Stations )
of linctr ;
demandConst ra int s: array ( Stations ) of linctr ;
costs: linctr ;
end-declarations
! initialization
demand := [5 , 20 , 11 , -15 , -17 , 23 , 2 , 7 , -15 , -21 ];
cost := [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 2 , ... ];
capacity := [0 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , ... ];
• Nebenbedingungen und
forall ( i in Stations , j in Stations ) do
c ap a c ityConstraints (i , j ) := x (i , j ) <= capacity (i , j );
end-do
forall ( i in Stations ) do
sum ( k in Stations ) x (k , i ) sum ( k in Stations ) x (i , k ) = demand ( i );
end-do
! initialization
demand := [5 , 20 , 11 , -15 , -17 , 23 , 2 , 7 , -15 , -21 ];
cost := [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 2 , ... ];
capacity := [0 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , ... ];
6
! capacity constraints
forall ( i in Stations , j in Stations ) do
c ap a c it y Constraints (i , j ) := x (i , j ) <=
capacity (i , j );
end-do
! demand constraints
forall ( i in Stations ) do
sum ( k in Stations ) x (k , i ) sum ( k in Stations ) x (i , k ) = demand ( i );
end-do
initializations from " daten . dat "
capacity ;
cost as " Transportkosten " ;
end-initia l iz a ti o n s
Beispiel für Dateneingabe
• Die Datei daten.dat:
’ numOfStations ’: 10
’ demand ’: [5 20 11 -15 -17 23 2 7 -15 -21 ]
! objective
costs := sum ( i in Stations , j in Stations )
cost (i , j ) * x (i , j );
’ Transportkosten ’: [1 2 3 4 5 6 7 8 9 10 2 4 6
8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30
35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14
21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64
72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40
50 60 70 80 90 99]
minimize ( costs );
writeln ( " Gesamtkosten: " , getobjval );
forall ( i in Stations , j in Stations |
getsol ( x (i , j )) <> 0) do
write ( " Transport von " , i , " nach " , j , " : " );
writeln ( getsol ( x (i , j )) , " Ostereier " );
end-do
end-model
’ capacity ’: [0 3 4 5 6 7 8 9 10 11 3 0 5 6 7 8
9 10 11 12 4 5 0 7 8 9 10 11 12 13 5 6 7 0 9
10 11 12 13 14 6 7 8 9 0 11 12 13 14 15 7 8 9
10 11 0 13 14 15 16 8 9 10 11 12 13 0 15 16
17 9 10 11 12 13 14 15 0 17 18 10 11 12 13 14
15 16 17 0 19 11 12 13 14 15 16 17 18 19 0]
2.4 Daten einlesen und ausgeben
Daten Aus- und Eingabe über Dateien
Beispiel für Dateneingabe
• Daten können aus Textdateien eingelesen und in Textdateien ausgegeben werden.
• Die Datei daten.dat:
• Vorteil: Trennung von Daten und Programmcode
’ numOfStations ’: 10
’ demand ’: [5 20 11 -15 -17 23 2 7 -15 -21 ]
.
.
.
• Datenausgabe mit initializations to-Block, mit as wird eine neue Bezeichnung vergeben:
initializations to " daten . dat "
capacity ;
cost as " Transportkosten " ;
e nd - i ni t ializations
• Einlesen der Daten:
initializations from " daten . dat "
n as " numOfStations " ;
capacity ;
• Einlesen von Daten mit initializations from-Block:
7
• repeat-Schleife:
cost as " Transportkosten " ;
demand ;
e nd - i ni t ializations
repeat
writeln ( " Das wird immer ausgeführt " );
until (2 > 5);
2.5 Entscheidungen und Schleifen
• In allen Schleifen:
Entscheidungen
– break bricht die Schleife ab
– next springt zur nächsten Iteration der Schleife
• if-Befehle:
if ( note <= 2.3) then
writeln ( " gut bis sehr gut bestanden " );
elif ( note <= 4.0) then
writeln ( " bestanden " );
else
writeln ( " leider nichts " );
end-if
2.6 Datensätze
Datensätze
• Kapseln mehrere Variablen
• Deklaration als
• Konditionale Summen und Schleifen
MyRecord = record
var: ...;
...
end-record
r: MyRecord ;
ungerade := sum ( i in 1..10 | isodd ( i )) i ;
forall ( i in 1..10 , j in 1..10
| isodd ( i ) and j <> i ) do
writeln ( " i = " , i , " / j = " , j );
end-do
• Zugriff auf einzelne Elemente: r.var
• Beispiel:
Schleifen
declarations
Hyperplane = record
a: array ( Dimensions ) of real ;
b: real ;
end-record ;
H: Hyperplane ;
end-declarations
• forall-Schleife:
forall ( i in 1..10) do
writeln ( " i = " , i );
end-do
• while-Schleife:
H . a := [1 , 0 , 0 , 0];
H . b := -3 ;
writeln ( H . a (1));
while ( i*j < 10) do
writeln ( " i*j = " , i*j );
i += 2;
end-do
2.7 Unterprogramme
8
• Routinen für die Verwaltung von Schnittebenen
Unterprogramme
• Callbacks für Eingriffe in den Ablauf des Optimierungsprozesses
• Kapselung mehrfach verwendeter, eigenständiger Programmteile
• Lokale Deklarationen und rekursive Aufrufe sind möglich
Parameter für den Optimizer
• Prozeduren:
• Auslesen von Parametern: getparam("XPRS_parameter")
procedure writeOddNumbers ( numbers:
array ( r: range ) of integer )
forall ( i in r | isodd ( numbers ( i ))) do
writeln ( numbers ( i ) , " ist ungerade " );
end-do
end-procedure
• Setzen von Parametern: setparam("XPRS_parameter", value)
• Wichtige Parameter:
– XPRS_verbose (true/false): Meldungen des Optimizers anzeigen
– XPRS_presolve (0/1): Presolver aus- bzw. einschalten.
• Funktionen (Wert wird zurückgeliefert – integer, real, boolean oder
string):
– XPRS_cutstrategy (-1,0,1,2,3): Aggressivität der Schnittgenerierung
function isSmallNumber ( r: real ) : boolean
if ( r < 0.1) then
returned := true ;
else
returned := false ;
end-if
end-function
– XPRS_heurstrategy (-1,0,1,2,3): Aggressivität der Heuristiken
• Außerdem: Einstellung von Cut-Strategie, Heuristiken, Ablauf des
Branch & Bound, Simplex-Algorithmus, numerische Toleranzen,
Scaling-Strategie etc.
Weitere wichtige Kommandos
3 Optimizer-Modul: Grundlagen
• getprobstat: aktueller Status des Optimizers:
XPRS_UNF: Optimierung noch nicht beendet
Grundlagen
XPRS_OPT: Optimierung beendet, Optimallösung gefunden
• Xpress-Optimizer wird über das Modul mmxprs eingebunden →
XPRS_INF: Optimierung beendet, unzulässiges Problem
uses "mmxprs"
XPRS_UNB: Optimierung beendet, unbeschränktes Problem
• Eigene Datentypen: mpvar, linctr und mpproblem.
XPRS_OTH: Optimierung beendet, keine Lösung gefunden
• Befehle zur Steuerung des Optimizers
• isintegral(x: mpvar): Variable ganzzahlig? (numerische Toleranzen!)
• Einstellen und Auslesen von Parametern
• sethidden(c: linctr, b: boolean): Vorübergehendes Ein-/Ausschalten
von Nebenbedingungen
• Speichern und Einlesen von LP-Modellen
9
Der Typ mpproblem
• Kapselt ein lineares Problem
• Besteht aus linearen Nebenbedingungen
• Teilt sich Optimierungsvariablen mit allen anderen Problemen
• Beispiel:
declarations
Problem: mpproblem ;
x: array (1..2) of mpvar ;
end-declarations
with Problem do
x (1) + x (2) <= 3;
minimize ( x (1) + 2 *x (2));
end-do
Der Typ mpproblem
• Probleme können:
– kopiert werden: P2 := P1
– eingefügt werden: P2 += P1
– geleert werden: reset(P1)
– anonym verwendet werden:
with mpproblem do
...
end-do
und werden anschließend automatisch gelöscht
• Alle Nebenbedingungen gelten nur für ihr Problem! → Achtung: auch
Wertebereiche (is_binary, ...)
10