51
Constraint Programming con ILOG Solver ILOG Solver Modellare e risolvere problemi con CP Michele Lombardi <[email protected]>

Constraint Programming con ILOG Solver - unibo.itlia.deis.unibo.it/.../Lucidi/es-ILOGCP.pdf · 2009. 2. 24. · Constraint Programming con ILOG Solver Modellare e risolvere problemi

  • 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!