Upload
others
View
4
Download
0
Embed Size (px)
Citation preview
Constraint Programming con
ILOG SolverILOG Solver
Modellare e risolvere problemi con CP
Michele Lombardi
Cosa ci aspetta
� Modellazione e soluzione di problemi con CP
� Strumenti per modellare (variabili, vincoli)
� Problematiche di modellazione
� Ottimizzazione del modello e del metodo di soluzione
� Risolutore: ILOG solver
Di cosa parleremo...
2
...e come ne parleremo
� Considereremo un unico esempio di riferiento...
� ...e TANTE sue varianti ;-)
� Ad ogni passo sarà introdotto qualcosa di nuovo...
� ...e vi sarà proposto qualche esercizio
Modellare un problemaModellare un problema
Modellare un problema con CP
Introduzione a ILOG Concert & Solver
Il nostro esempio
Supponiamo di dover ottimizzare l’esecuzione di tasks su un
sistema multiprocessore
� T = {t0, t1, ..., tn-1} = insieme degli n tasks
� P = {p0, p1, ..., pp-1} = insieme dei p processori
� dur(ti) = durata del task i-mo
Siano:
4
> Ogni task esegue su un solo processore
> Su ogni processore i task eseguono in sequenza
> Il tempo totale di esecuzione non deve superare una
deadline
Obiettivo: usare il minimo numero di processori
Modellare un problema
t0 t1 t2 t3 t4
p0
p1
t0
t1
t2 t3
t4
5 Modellare un problema
p2
Semplice, no?
� Come lo affrontiamo?
� Vediamo che strumenti abbiamo a disposizione
Introduzione ad ILOG CP
� ILOG è una azienda francese
� Produce strumenti per la gestione efficiente di processi di
manageriali e per la soluzione di problemi di ottimizzazione
Che cosa è ILOG?
6
A noi ci interessano questi
Modellare un problema
� Strumenti per modellare problemi
� Strumenti per risolvere problemi
In particolare:
OPL
Cplex
CPOptimizer
AMPL
Linguaggio di
Modellazione MILP Linguaggio di
modellazione a vincoli
Math Programming
Solver
Semi-automatic CP
solver
CP Solvers
7
OPL
Solver Scheduler
Optimizer
Concert Dispatcher
ILOG CPAPI per modellazione
CP Solvers
Modellare un problema
In pratica...
� AMPL e OPL sono linguaggi per descrivere modelli
� Concert è una libreria in C++
� Fornisce classi e funzioni per costruire modelli
� class IloModel modello
� class IloIntVar variabile intera
Per esempio:
8 Modellare un problema
� class IloIntVar variabile intera
� class IloNumVar variabile reale
� class IloBoolVar variabile logica
� class IloConstraint vincolo
� ...
� Solver è un risolutore (sempre in C++) che dato un modello
(ex. costruito in concert) trova una soluzione
Allora da dove partiamo?
9 Modellare un problema
Da carta e penna
Un primo modello
One dimensional bin packing:
=altrimenti
usatoèpsey
i
i0
1
� Variabili:
=altrimenti
psuètsex
ii
ij0
1
� Vincoli:
10 Modellare un problema
� Vincoli:
∑−
=
=∀
1
0
1p
i
ijxj
∑−
=
⋅≤∀
1
0
)(n
j
iijj ydeadlinextduri
> Ogni task esegue su un solo processore
> Il tempo totale di esecuzione non deve superare una
deadline
∑−
=
=
1
0
minp
i
iyz
∑−
=
=∀
1
0
1p
i
ijxj
∑−
⋅≤∀
1
)(n
iijj ydeadlinextduri
Nel complesso:
obiettivo:
soggetto a:
11 Modellare un problema
Formulato il modello su carta, possiamo “costruirlo” usando
Concert
∑=0j
iijj
}1,0{, ∈iji xy
Struttura di un programma ILOG
#include
#include
ILOSTLBEGIN
int main(int argc, char** argv){
IloEnv env;
IloModel model(env);
Per usare concert e
solver
MACRO: definisce il namespace std
IloEnv: gestore della
memoria, fa da
12 Modellare un problema
IloModel model(env);
}
memoria, fa da
contenitore per il modello
Classe che rappresenta
un modello
Variabili e vincoli vengono
“aggiunti” al modello
Costruzione del modello
� Per inizializzare un modello innanzitutto vanno definite le sue
variabili:
IloIntVarArray Y(env, nproc, 0, 1);
IloArray X(env, nproc);
for(int i = 0; i < nproc; i++){
X[i] = IloIntVarArray(env, ntask, 0, 1);
13 Modellare un problema
X[i] = IloIntVarArray(env, ntask, 0, 1);
}
Array di variabili intere
Array di arrays Parametri di IloIntVarArray:
� IloEnv: gestore della memoria
� IloInt: dimensione
� IloInt: lower bound del dominio
� IloInt: upper bound del dominio
Costruzione del modello
� Poi vanno specificati i vincoli
for(int j = 0; j < ntask; j++){
IloIntExpr sum(env);
Costruisce una
espressione vuota...
...che può essere
estesa con i normali
∑−
=
=∀
1
0
1p
i
ijxj
14 Modellare un problema
IloIntExpr sum(env);
for(int i = 0; i < nproc; i++){
sum += X[i][j];
}
model.add(sum == 1);
}
operatori aritmetici!
I vincoli vanno
aggiunti al modello
(vengono aggiunte
anche le variabili su
cui sono definiti)
L’operatore di confronto
(“==“) tra espressioni
restituisce un vincolo
Costruzione del modello
for(int i = 0; i < nproc; i++){
∑−
=
⋅≤∀
1
0
)(n
j
iijj ydeadlinextduri
15 Modellare un problema
for(int i = 0; i < nproc; i++){
IloIntExpr sum(env);
for(int j = 0; j < ntask; j++){
sum += durations[j]*X[i][j];
}
model.add(sum
Costruzione del modello
� In qualunque punto (dopo la definizione delle variabili) si può
specificare una funzione obiettivo
∑−
=
=
1
0
minp
i
iyz
IloMinimize IloSum
16 Modellare un problema
model.add(IloMinimize(env, IloSum(Y)));
Indica che la soluzione deve
minimizzare l’espressione
specificata
Un modo compatto per
costruire una espressione di
somma (Y è un array)
Utilizzo del solver
IloSolver solver(env);
solver.extract(model);
solver.solve();
Costruisce un solver
(classe IloSolver)
Trova la soluzione
ottima (se esiste)
“estrae” il modello
17 Modellare un problema
� Prima di iniziare la ricerca di una soluzione il modello deve
essere convertito nel formato interno del solver
� Questa operazione si chiama “estrazione”
� Classi concert: Ilo... (ex IloIntVar)
� Classi solver: Ilc... (ex. IlcIntVar)
Input & Output
Number of fails : 9282
Number of choice points : 9312
...
int ntask = 10;
int nproc = 6;
int durations[] = {3, 4, 7, 2, 2, 8, 7, 10, 8, 9};
int deadline = 16;
18 Modellare un problema
...
Running time since creation : 0.2
Y[0]:0
Y[1]:0
Y[2]:1
Y[3]:1
Y[4]:1
Y[5]:1
Stili di modellazioneStili di modellazione
Modelli alternativi
Un altro modello
� CP ha un linguaggio di modellazione molto “ricco” (molti tipi di
vincoli)
� Questo permette di migliorare le performance adottando stili
di modellazione differenti
Esempio:
Cambiamo le variabili! Solo una variabile per
task
20 Stili di modellazione
Cambiamo le variabili!
iij psuètseix =task
IloIntVarArray Proc(env, ntask, 0, nproc-1);
� Tra l’altro in questo modo ogni task esegue per forza su un solo
processore
Un altro modello
� Un vincolo può essere utilizzato all’interno di una espressione:
denota 1 se è vero, 0 se è falso
Come definire i vincoli di deadline? METAVINCOLI
∑−
=
≤==⋅∀
1
0
)()(n
j
jj deadlineixtduri
21 Stili di modellazione
=0j
for(int i = 0; i < ntask; i++){
IloIntExpr sum(env);
for(int j = 0; j < ntask; j++){
sum += durations[j]*(Proc[j] == i);
}
model.add(sum
Un altro modello
Cambia anche la funzione obiettivo:
)(maxmin jj xz =
model.add(IloMinimize(env, IloMax(Proc)));
Il più alto indice di
processore utilizzato
22 Stili di modellazione
model.add(IloMinimize(env, IloMax(Proc)));
Il nuovo modello ha la stessa semantica (=> le stesse soluzioni),
ma un numero minore di variabili e una diversa funzione obiettivo
Output
Number of fails : 425
Number of choice points : 432
...
Running time since creation : 0.03
Proc[0]:0
Proc[1]:0
Proc[2]:0
23 Stili di modellazione
Proc[2]:0
Proc[3]:0
Proc[4]:1
Proc[5]:2
Proc[6]:3
Proc[7]:1
Proc[8]:2
Proc[9]:3
Esercizio 1 (base2.cpp)
� Cosa succede con i due modelli aumentando
il numero di processori a 16?
� Perché?
24 Stili di modellazione
Vincoli globaliVincoli globali
Utilizzo dei vincoli globali
Perché i vincoli globali
� modellazione più compatta
� propagazione più efficace
� (a volte) propagazione più efficiente
I vincoli globali modellano alcune sottostrutture particolarmente
frequenti. Hanno diversi vantaggi:
26 Vincoli globali
Esempio:
Gli ultimi p task devono essere assegnati a processori diversi
Modello con vincoli binari
� Modellando con vincoli “!=“:
for (int i = ntask-nproc; i < ntask; i++){
for (int j = i+1; j < ntask; j++){
model.add(Proc[i] != Proc[j]);
}
}
� Output:
27 Vincoli globali
Number of fails : 44496
Number of choice points : 44505
...
Running time since creation : 1.5
� Output:
Modello con alldifferent
� Alldifferent in ILOG
IloAllDiff(IloEnv, IloIntVarArray)
� Nel nostro caso:
IloIntVarArray diff(env);
for(int j = ntask-nproc; j < ntask; j++)
IloAllDiffCt
IloDistributeCt
IloSequenceCt
IloAllMinDistanceCt
IloPartitionCt
IloAllNullIntersectCt
28 Vincoli globali
for(int j = ntask-nproc; j < ntask; j++)
diff.add(Proc[j]);
model.add(IloAllDiff(env, diff));
� ATTENZIONE! Dopo aver estratto il modello:
solver.setDefaultFilterLevel(IloAllDiffCt, IloExtendedLevel);
IloExtendedLevel
IloMediumLevel
IloBasicLevel
IloLowLevel
IlcFilterLevel
IloAllNullIntersectCt
IloEqUnionCt
IloNotOverlapCt
IloBoxCt
IlcFilterLevelConstraint
Output
Number of fails : 8
Number of choice points : 16
...
Running time since creation : 0
problem solved
Proc[0]:0
Proc[1]:0
29 Vincoli globali
Proc[1]:0
Proc[2]:0
Proc[3]:1
Proc[4]:0
Proc[5]:1
Proc[6]:2
Proc[7]:3
Proc[8]:4
Proc[9]:5
IMPORTANTE:
ILOG Solver permette anche di
definire nuovi vincoli, ma per il
momento non ci interessa...
Esercizio 2 (base2.cpp)
� Nuovo vincolo: non più di tre task per
processore
� SUGGERIMENTO: il vincolo gcc in ILOG è:
IloDistribute(IloEnv, IloIntVarArray cards,
IloIntArray vals, IloIntVarArray vars)
30 Vincoli globali
solver.setDefaultFilterLevel(???, ???);
� Ricordate che dopo l’estrazione va
modificato l’algoritmo di filtering...
Strategie di ricercaStrategie di ricerca
Modificare la strategia di ricerca
Search strategy
� Per esempio si può scegliere il criterio con cui scegliere la
variabile su cui fare branching
CP permette l’impiego di diverse strategie di ricerca
IloGenerate(IloEnv, IloIntVarArray, IloChooseIntIndex)
IloChooseFirstUnboundInt
IloChooseMaxMaxInt
32 Strategie di ricerca
IloChooseMaxMaxInt
IloChooseMaxMinInt
IloChooseMaxRegretMax
IloChooseMaxRegretMin
IloChooseMaxSizeInt
IloChooseMinMaxInt
IloChooseMinMinInt
IloChooseMinRegretMax
IloChooseMinRegretMin
IloChooseMinSizeInt
E’ un IloGoal, va passato
come argomento di solver.solve(...)
First Fail Principle
Output
solver.solve(IloGenerate(env, Proc, IloChooseMinSizeInt))
Number of fails : 71
Number of choice points : 77
...
Running time since creation : 0.01
33 Search stratgies
IMPORTANTE:
ILOG Solver permette anche di definire
nuove strategie o di intervenire sulla
ricerca in modo ancora più complesso,
ma per il momento non ci interessa...
Esercizio 3 (base.cpp, base2.cpp)
� Cosa succede con altre strategie di
ricerca?
� Cosa succede utilizzando il first fail
principle (IloChooseMinSizeInt) nel primo
modello? Perché?
34 Search stratgies
SimmetrieSimmetrie
Eliminazione delle simmetrie
Simmetrie
I processori sono risorse simmetriche; per esempio le due
allocazioni:
Proc[0]:0
Proc[1]:0
Proc[2]:0
Proc[3]:0
Proc[4]:1 e
Proc[0]:1
Proc[1]:1
Proc[2]:1
Proc[3]:1
Proc[4]:0
36 Simmetrie
Proc[4]:1
Proc[5]:2
Proc[6]:3
Proc[7]:1
Proc[8]:2
Proc[9]:3
e Proc[4]:0Proc[5]:2
Proc[6]:3
Proc[7]:0
Proc[8]:2
Proc[9]:3
Sono del tutto equivalenti!
Simmetrie
Una soluzione è quella di forzare un ordine di preferenza tra i
processori: se p0 è libero non utilizzare uno dei processori seguenti
� Si possono aggiungere dei vincoli per vietare le allocazioni che
non rispetterebbero il criterio
� Per ogni processore teniamo traccia del task di indice più basso
allocato su di esso (dopo vedremo come)
37 Simmetrie
IloIntVarArray minItem(env, nproc, 0, ntask-1);
� Il task di indice più basso su p0 deve essere minore di quello su
p1, e così via
for(int i = 0; i < nproc-1; i++){
model.add(minItem[i] < minItem[i+1]);
}
Simmetrie
Come ottenere minItem?
model.add(minItem(Proc[0]) == 0);
for(int i = 1; i < ntask; i++){
IloConstraint xpr = Proc[i] != Proc[i-1];
for(int j = i-2; j >= 0; j--){
xpr = xpr && (Proc[i] != Proc[j]);
}
model.add(IloIfThen(env, xpr, minItem(Proc[i]) == i));
38 Simmetrie
model.add(IloIfThen(env, xpr, minItem(Proc[i]) == i));
}
METAVINCOLI: i vincoli possono
essere combinati in espressioni
logiche!
Element constraint in ILOG
Output
Number of fails : 84
Number of choice points : 92
...
Running time since creation : 0.01
Proc[0]:0
Proc[1]:0
Proc[2]:0
39 Simmetrie
Proc[2]:0
Proc[3]:0
Proc[4]:1
Proc[5]:2
Proc[6]:3
Proc[7]:1
Proc[8]:2
Proc[9]:3
Scheduling con ILOGScheduling con ILOG
Introduzione ad ILOG Scheduler
ILOG Scheduler
� Un’altra libreria in C++
� Fornisce strumenti per modellare e risolvere problemi di
scheduling
� Si appoggia al Solver per la soluzione del problema
� La classe IlcScheduler permette di accedere alla soluzione
Alcuni concetti chiave:
41 Scheduling con ILOG
Alcuni concetti chiave:
� Attività
� Vincoli temporali
� Risorse
� ...
Attività
Definite con:
IloActivity(env, IloInt duration);
IloActivity(env, IloNumVar duration);
Una attività introduce tre variabili: START, END, DUR
� END = START + DUR
42 Scheduling con ILOG
� END = START + DUR
IloArray acts(env, ntask);
for(int i = 0; i < ntask; i++){
acts[i] = IloActivity(env, durations[i]);
}
Vincoli temporali
IloActivity::startsAfterEnd(IloActivity);
IloActivity::startsAfterStart(IloActivity);
...
...Restituiscono vincoli che forzano relazioni di precedenza
IloActivity::startsBefore(...);
IloActivity::startsAfter(...);
43 Scheduling con ILOG
IloActivity::startsAfter(...);
...
...Restituiscono vincoli temporali rispetto ad istanti fissati (o a
variabili intere)
for(int i = 0; i < nprec; i++){
model.add(acts[precTo[i]].startsAfterEnd(acts[precFrom[i]]));
}
Risorse
Per ora consideriamo solo risorse unarie:
IloUnaryResource(IloEnv)
� Il metodo IloActivity::requires(...) restituisce un
vincolo che va aggiunto al modello
IloArray pres(env, nproc);
for(int i = 0; i < nproc; i++)
44 Scheduling con ILOG
for(int i = 0; i < nproc; i++)
pres[i] = IloUnaryResource(env);
for(int i = 0; i < nproc; i++){
for(int j = 0; j < ntask; j++){
model.add(IloIfThen(env, Proc[j] == i,
acts[j].requires(pres[i])));
}
}
Input & Output
Proc[0]:0 task[0]: [0 -- 3 --> 3]
Proc[1]:0 task[1]: [3 -- 4 --> 7]
int nprec = 5;
int precFrom[] = {0, 0, 4, 6, 3};
int precTo[] = {1, 2, 5, 5, 8};
Goal: IloGenerate(env, Proc, ...) && IloSetTimesForward(env)
45 Scheduling con ILOG
Proc[1]:0 task[1]: [3 -- 4 --> 7]
Proc[2]:1 task[2]: [9 -- 7 --> 16]
Proc[3]:2 task[3]: [2 -- 2 --> 4]
Proc[4]:2 task[4]: [0 -- 2 --> 2]
Proc[5]:0 task[5]: [7 -- 8 --> 15]
Proc[6]:3 task[6]: [0 -- 7 --> 7]
Proc[7]:2 task[7]: [4 -- 10 --> 14]
Proc[8]:3 task[8]: [7 -- 8 --> 15]
Proc[9]:1 task[9]: [0 -- 9 --> 9]
Esercizio 4 (sched.cpp)
� Cosa succede modificando il livello di
propagazione?
IloSchedulerEnv schedEnv(env);
schedEnv.getResourceParam().setCapacityEnforcement(...);
Notate che IloExtended abilita edge finder
46 Scheduling con ILOG
Notate che IloExtended abilita edge finder
� Nuovo vincolo: i task 0, 3, 6, 9 devono
accedere ad una memoria a due vie
Risorsa a capacità maggiore di 1: IloDiscreteResource
Minimizzare il tempo di esecuzione
Introduciamo una nuova variabile (makespan):
IloIntVar makespan(env);
Tutte le attività devono terminare prima del tempo di esecuzione:
for(int i = 0; i < ntask; i++)
model.add(acts[i].endsBefore(makespan));
47 Scheduling con ILOG
Nuovo obiettivo:
model.add(IloMinimize(env, makespan));
Goal ottimizzato: IloGenerate(env, Proc, ...)&& IloSetTimesForward(env, makespan)
Output
Proc[0]:0 task[0]: [0 -- 3 --> 3]
Proc[1]:0 task[1]: [10 -- 4 --> 14]
Proc[2]:0 task[2]: [3 -- 7 --> 10]
Proc[3]:1 task[3]: [2 -- 2 --> 4]
Proc[4]:1 task[4]: [0 -- 2 --> 2]
Proc[5]:1 task[5]: [7 -- 8 --> 15]
Proc[6]:2 task[6]: [0 -- 7 --> 7]
Proc[7]:3 task[7]: [0 -- 10 --> 10]
48 Scheduling con ILOG
Proc[7]:3 task[7]: [0 -- 10 --> 10]
Proc[8]:2 task[8]: [7 -- 8 --> 15]
Proc[9]:4 task[9]: [0 -- 9 --> 9]
Esercizio 5 (schedMK.cpp)
� Cosa succede usando il goal
IloSetTimesFOrward non ottimizzato?
� Cosa succede eliminando le relazioni di
precedenza?
49 Scheduling con ILOG
Basta teoria ;-)Basta teoria ;-)
Adesso mettiamo le mani in pasta
Istruzioni
� Fate login su windows
� Dal sito del corso scaricate il template di progetto
� Aprite il file “template.sln” con visual studio 2005
� Nel pacchetto con il template ci sono anche alcuni file
sorgente, che contengono il codice di partenza: in ogni
esercizio è specificato da quali sorgenti dovete partire per
51
esercizio è specificato da quali sorgenti dovete partire per
risolverlo
� Per lanciare gli eseguibili aprite un prompt dei comandi usando
il file batch “START.bat”, sempre nel pacchetto con il template:
serve per accedere alla licenza per l’uso di ILOG
BUON LAVORO!