Parte III:
Algoritmo di Branch-and-Bound
Divide et Impera
Sia
z* = max {cTx : x ∈ S} (1)
un problema di ottimizzazione combinatoria difficile da risolvere.
Domanda: E’ possibile decomporre il problema (1) in una collezione di sottoproblemi tali che
– ogni nuovo sottoproblema sia facile da risolvere, e
– le informazioni ottenute risolvendo la collezione di sottoproblemi ci guidino nella ricerca della soluzione ottima del problema (1)?
Proposizione: Sia S = S1 ∪ S2 ∪… ∪ SK una decomposizione della regione ammissibile S in K sottoinsiemi, e sia zh = max {cTx : x ∈ Sh}, per h = 1,…,K. Allora z* = maxh zh.
Osservazione: Non abbiamo richiesto che la decomposizione sia una partizione (ovvero, che Si ∩ Sj = ∅), ma non abbiamo nemmeno escluso che possa esserlo!
Una tipica rappresentazione dell’approccio divide et impera è tramite un albero di enumerazione.
Divide et Impera
Un esempio
Se S ⊆ {0,1}3, possiamo costruire il seguente albero di enumerazione S
S0
x1=0
S1 x1=1
S00 x2=0
S01 x2=1
S10 x2=0
S11 x2=1
S000 x3=0
S001 x3=1
S010 x3=0
S011 x3=1
S100 x3=0
S101 x3=1
S110 x3=0
S111 x3=1
Le foglie dell’albero corrispondono esattamente ai punti che andremmo a esaminare se potessimo fare un’enumerazione completa.
Osservazione: Costruendo in questo modo l’albero di enumerazione stiamo semplicemente enumerando TUTTI gli insiemi ammissibili!!!!
Per la maggior parte dei problemi è impossibile effettuare una enumerazione completa.
Poiché per un problema di ottimizzazione combinatoria conosciamo i bound “primali” e i bound “duali”, l’idea è quella di utilizzare tali bound per enumerare gli insiemi ammissibili in modo più efficace.
Divide et Impera
Potatura per ottimalità
S0
z0UB= 27 z0LB=13
Le informazioni su upper e lower bound per il valore ottimo z* permettono di decidere quali nodi dell’albero ha senso continuare ad esaminare per trovare la soluzione ottima.
Poiché z1LB = z1UB = 20, sicuramente z1 = 20. Pertanto, non c’è bisogno di esplorare ulteriormente il nodo S1 che può essere potato per ottimalità.
S2
x1=1
z2UB= 25 z2LB= 15
S1
x1= 0
z1UB= 20 z1LB=20
Potatura per ottimalità
S0
z0UB= 27 z0LB=13
zLB= 20
Ad ogni passo teniamo traccia di un lower bound globale zL B. Per il nodo S0 , zL B = z0L B (alternativamente, zL B = -∞).
Per ciascun nodo di ogni livello dell’albero, aggiorniamo il valore di zL B se in corrispondenza di quel nodo abbiamo calcolato un lower bound MIGLIORE (ossia maggiore) di quello corrente.
S2
x1=1
z2UB= 25 z2LB= 15
S1
x1= 0
z1UB= 20 z1LB=20
= zLB
Potatura per bound
S0
z0UB= 27 z0LB=13
S2
x1=1
z2UB= 26 z2LB= 21
S1
x1= 0
z1UB= 20 z1LB= 18
Poiché zLB = 21, la soluzione ottima del problema iniziale ha valore almeno pari a 21. Dal momento che z1UB = 20, sicuramente non è possibile ottenere l’ottimo esplorando il nodo S1. Pertanto, S1 può essere potato per bound.
zLB= 21
= zLB
Potatura per inammissibilità
S0
z0UB= 27 z0LB=13
S2
x1=1
S2 = ∅
S1
x1= 0
z0UB= 20 z0LB= 18
Poiché il sottoproblema associato al nodo S2 è inammissibile, non è possibile ottenere l’ottimo esplorando il nodo S2. Pertanto S2 può essere potato per inammissibilità.
= zLB
zLB= 18
Nessuna potatura
In questo caso non possiamo fare nessuna osservazione che permetta di potare uno dei due nodi in esame e quindi è necessario esplorare sia S1 che S2.
S0
z0UB= 40 z0LB=0
S2
x1=1
z2UB = 37 z2LB = 0
S1
x1= 0
z1UB= 20 z1LB= 18
= zLB
zLB= 18
max 4x
1− x
27x
1−2x
2≤14
x
2≤3
2x
1−2x
2≤3 x
1≥0
x
2≥0 x ∈Z
21 2
3/2
(20/7,3)
(11/5,7/10) 3
x2
x1
Esempio
P
Problema al nodo radice S0: Rilassamento lineare di P.
1 2
3/2
x0UB=(20/7,3)
(11/5,7/10) 3
x2
x1
Valore dell'UB al nodo radice: z0UB = 59/7.
Poiché non abbiamo una soluzione ammissibile, fissiamo z0LB = - ∞
Esempio
S1 =S0∩
{
x : x1≤⌊
x1⌋ }
Esempio
z0LB= − ∞ = zLB
S0 z
0
UB=59/7
Consideriamo la variabile frazionaria x1 del vettore x0UB e generiamo i sottoproblemi di S0 applicando la seguente regola di branching:
S2 =S0∩
{
x : x1≥⌈
x 1⌉ }
S1 =S0∩
{
x : x1≤⌊
20/ 7⌋
=2}
S2=S0∩
{
x : x1≥⌈
20 /7⌉
=3}
Memorizziamo S1 e S2 in una lista di sottoproblemi che devono essere esplorati: L = {S1, S2}
Scegliamo di analizzare il sottoproblema S1.
S0
S1 S2
Esempio
z0LB= − ∞ = zLB z0UB=59/7
S1=S0∩
{
x : x1≤2}
S2=S0∩{
x : x1≥3}
Risolviamo il sottoproblema al nodo S1.
max 4x
1− x
27x
1−2x
2≤14
x
2≤3
2x
1−2x
2≤3 x
1≤2
x
1≥0 x
2≥0
1 2
3 x2
x1
Esempio
x1UB=(2,1/2)
Valore dell'UB per il sottoproblema S1: z1UB = 15/2.
Poiché non possiamo applicare nessun criterio di potatura, il nodo S1 dovrà essere esplorato.
Esempio
S0
S1 S2
z0LB= − ∞ = zLB z0UB=59/7
z1UB=15/2
z1LB= − ∞ = zLB
Risolviamo il sottoproblema al nodo S2.
max 4x
1− x
27x
1−2x
2≤14
x
2≤3
2x
1−2x
2≤3 x
1≤2
x
1≥3 x
1≥0 x
2≥0
Esempio
1 2
3 x2
x1 3
Il sottoproblema al nodo S è inammissibile!
Il nodo S2 può essere chiuso per inammissibilità.
Esploriamo il nodo S1
Esempio
S0
S1 S2
z0LB= − ∞ = zLB z0UB=59/7
z1UB=15/2
z1LB= − ∞ = zLB
Esempio
S3=S1∩
{
x : x2≤0}
S4=S1∩{
x : x2≥1}
S0
S1 S2
z0LB= − ∞ = zLB z0UB=59/7
z1UB=15/2
z1LB= − ∞ = zLB
S3 S4
Memorizziamo S3 e S4 nella lista di sottoproblemi che devono essere esplorati: L = {S3, S4}. Scegliamo di analizzare il sottoproblema S3.
Risolviamo il sottoproblema al nodo S3.
max 4x
1− x
27x
1− 2x
2≤14 2x
1− 2x
2≤3
x
1≤2 x
2≤ 0 x
1≥0 x
2≥0
1 2
3 x2
x1
Esempio
x3UB=(3/2,0)
Valore dell'UB per il sottoproblema S3: z3UB = 6.
Esempio
S0
S1 S2
z0LB= − ∞ = zLB z0UB=59/7
z1UB=15/2
z1LB= − ∞ = zLB
S3 S4
z3UB=6
z3LB= − ∞ = zLB
Poiché in questo momento non possiamo applicare nessun criterio di potatura, il nodo S3 dovrà essere esplorato.
max 4x
1− x
27x
1− 2x
2≤14
x
2≤3
2x
1− 2x
2≤3 x
1≤2
x
2≥1 x
1,x
2≥ 0
1 2
3 x2
x1 1
Esempio
Risolviamo il sottoproblema al nodo S4.
x4UB=(2,1)
Valore dell'UB per il sottoproblema S4: z4UB = 7.
Osserviamo che la soluzione trovata è intera! Possiamo aggiornare il valore del lower bound globale!
Il nodo S4 può essere chiuso per ottimalità.
Esempio
S0
S1 S2
z0LB= − ∞ = zLB z0UB=59/7
z1UB=15/2 z1LB= − ∞
S3 S4
z3UB=6
z3LB= − ∞ z4UB=7
z4LB= 7 = zLB
In seguito all'aggiornamento del valore del lower bound possiamo chiudere anche il nodo S3 per bound. Infatti: z3UB = 6 < z4LB.
Esempio
S0
S1 S2
z0LB= − ∞ = zLB z0UB=59/7
z1UB=15/2 z1LB= − ∞
S3 S4
z3UB=6 z3LB= − ∞
z4UB=7
z4LB= 7 = zLB
Poiché non ci sono altri nodi da esplorare nella lista L, l'algoritmo di Branch & Bound termina con la soluzione ottima intera x* = (2, 1) di valore z* = 7.
Esempio
S0
S1 S2
z0LB= − ∞ = zLB z0UB=59/7
z1UB=15/2 z1LB= − ∞
S3 S4
z3UB=6 z3LB= − ∞
z4UB=7
z4LB= 7 = zLB
Procedura di Branch-and-Bound
Tramite l’albero di enumerazione, enumeriamo un insieme di soluzioni
“implicitamente” perché alcuni rami dell’albero vengono potati per:
– ottimalità, oppure – bound, oppure – inammissibilità.
Nella procedura di Branch & Bound è importante
• Scegliere la strategia per il calcolo del bound duale.
• Scegliere la variabile su cui applicare la procedura di branching.
• Scegliere la strategia di esplorazione dell'albero di enumerazione.
Procedura di Branch-and-Bound
Scelta della strategia di esplorazione dell'albero di enumerazione
VISITA DEL NODO CON MAX zUB
(Vantaggio: limita il numero di nodi visitati
Svantaggio: si impiega più tempo per generare soluzioni ammissibili.)
VISITA IN PROFONDITA'
(Vantaggi: genera rapidamente una soluzione ammissibile, limita la memoria necessaria per memorizzare l'albero delle soluzioni
Svantaggio: rischio di esplorare completamente sotto-alberi con soluzioni scadenti)
Procedura di Branch-and-Bound
Siano
• P0 = problema di ottimizzazione iniziale associato al nodo S0.
• L = lista dei sottoproblemi che devono essere risolti
• Pi = formulazione del sottoproblema associato al nodo Si.
L'algoritmo di Branch-and-Bound può essere schematizzato come segue.
Procedura di Branch-and-Bound
Step 0. Inizializzazione: L = S0; zLB = – ∞(max); x* = 0.
Step 1. Criterio di arresto: Se L = ∅, allora STOP: x* è la soluzione ottima.
Step 2. Selezione del nodo: Seleziona il sottoproblema Pi (nodo Si) da esplorare dalla lista L.
Step 3. Bounding: Risolvi un rilassamento di Pi. Step 4. Fathoming:
● Se Pi non è ammissibile, elimina Pi da L e vai allo Step 1.
● Se ziUB < zLB, elimina Pi da L e vai allo Step 1.
● Se xiUB è intera, elimina Pi da L. Se, inoltre, ziLB > zLB, aggiorna zLB e vai allo Step 1.
Step 5. Branching: Individua una componente frazionaria di xiUB e genera i sottoproblemi di P da aggiungere alla lista L. count = count+1. Vai allo Step 1.
Inizializzazione
L=S0, zLB= - ∞; x* = 0;
Test: L = ∅?
Scegli un problema Pi dalla lista
Risolvi un Rilassamento di Pi
Caso 2: Bound
Pi ≠ ∅, ziUB valore della soluzione ottima xiUB di RLi. Se ziUB < zLB elimina Pi per bound, vai a Test
Caso 3: Ottimalità
Se Pi ≠ ∅ e xiUB è una soluzione ottima intera di Rli elimina Pi per ottimalità.
Se ziLB > zLB allora zLB =ziLB, vai a Test Individua una componente frazionaria k di xiUB e ramifica Pi aggiungendo i nuovi sottoproblemi ad L. vai a Test
Caso 1: Inammissibilità Se Pi = ∅ elimina Pi per inammissibilità, vai a Test
Branch-and-Bound
Esempio
Consideriamo il problema di knapsack
max 30 x1 + 36 x2 + 15 x3 + 11 x4 + 5 x5 + 3 x6
9 x1 + 12 x2 + 6 x3 + 5 x4 + 3 x5 + 2 x6 < 17 (1) x ∈ {0,1}6
La soluzione ottima del Knapsack continuo è x0U B = (1, 2/3, 0, 0, 0, 0) di valore 54 (z0U B)
Inizializziamo il valore del lower bound uguale al valore di una soluzione ammissibile del problema x0L B = (1, 0, 0, 0, 0, 0) di valore 30 (z0L B).
Inizializziamo il valore del lower bound globale zL B = 30.
Osservazione: Poiché la funzione obiettivo ha coefficienti interi, possiamo scrivere la condizione di potatura per bound (caso 2) come ziU B < zL B.
Esercizio 1
S0
S1 S2
z1UB = 49.4 z1LB = 45
x2 = 0 x2 = 1
zLB = 45
z0UB = 54
z0LB = 30 = zLB
z2UB = 52.6 z2LB = 36
S5 S6
x4 = 0 x4 = 1
z5UB = 48.33 z5LB = 45
z6UB = 48.5
z6LB = 41 S3 S4
x1 = 0 x1 = 1
z3UB = 48.5
z3LB = 36 inammissibilità
×
S7 S8
x5 = 0 x5 = 1
S7
z7UB = 48 z7LB = 48
×
zLB = 48
z8UB = 47.5 z8LB = 35
bound.
×
×
bound. bound.
×
Algoritmo di programmazione
dinamica
Programmazione Dinamica
Schema di principio: Sia P un problema di OC. La Programmazione Dinamica (PD):
– risolve un sottoproblema di P all’ottimo.
– iterativamente “estende” la soluzione a P.
Proprietà fondamentale (optimal substructure)
Sia KP (N, b) un problema di knapsack con soluzione ottima x*.
Consideriamo il problema di knapsack KP(N \ r, b – ar) che si ottiene da KP eliminando un qualsiasi oggetto r e diminuendo la capacità dello zaino della quantità ar..
La soluzione ottima di KP(r, b–ar) si ottiene da x* semplicemente eliminando la variabile xr .
Esempio
Consideriamo il seguente problema di knapsack:
max 6 x1 + 10 x2 + 12 x3
x1 + 2x2 + 3 x3 < 5 (1) x ∈ {0,1}3
La soluzione ottima è x*(1) = (0, 1, 1), di valore 22.
Consideriamo il problema che si ottiene eliminando l’oggetto 2 e diminuendo la capacità b del corrispondente ingombro a2:
max 6 x1 + 12 x3
x1 + 3 x3 < 5 – 2 = 3 (2) x ∈ {0,1}2
La soluzione ottima è x*(2)=(0, 1), di valore 12.
Osservazione: La soluzione x*(2)= (0, 1) è una “sottosoluzione” di x*(1) = (0, 1, 1), ovvero si ottiene da x*(1) semplicemente eliminando la variabile x2.
Notazione
Siano r e d due interi tali che 1 ≤ r ≤ n, 0 ≤ d ≤ b.
Sia KP (r, d) il problema di knapsack:
max
Σ
pjxj
Σ
ajxj < dx∈ {0, 1}r
KP (r, d) è un sottoproblema di KP, avente soluzione ottima di valore zr(d).
j = 1 r
r j = 1
Programmazione dinamica
Con questo formalismo, il valore della soluzione ottima di KP vale zn (b).
Calcolo di zn (b):
1. Calcolo zr (d) per r = {1, …, n}.
2. Per ogni r, calcolo zr (d) per d = {0, …, b}.
Osservazione:
zr (d) si calcola in modo ricorsivo se conosco i valori zr – 1 (d) per d = {0, …, b}.
Formula ricorsiva
z1
d
={
p01 perper d≥ad<a11}
Condizione iniziale di ricorsione:
Questa condizione implica:
• Se z
1(d) = 0 ⇒ x
1= 0
• Se z
1(d) = p
1⇒ x
1= 1
Formula ricorsiva
Formula di ricorsione:
La formula implica
•
Se zr(d) = zr-1(d) ⇒ xr = 0 [l’oggetto r NON è stato scelto]•
Se zr(d) = zr-1(d–ar)+cr ⇒ xr = 1 [l’oggetto r E’ stato scelto]zr(d) =
zr–1 (d) se d < ar
max{zr–1 (d), zr–1(d–ar)+pr } se d > ar
Algoritmo e complessità
DP-KP n, b, a, c for d = 0 to a1−1
z1d =0;
for d=a1 to b z1 d =p1;
for m= 2 to n
for d= 0 to am−1 zmd =zm−1d
for d=am to b
if zm−1d >zm−1d−am+pm then max =zm−1d ;
else max =zm−1 b−am+pm; zmd =max;
return znb
Osservazione: La complessità dell’algoritmo è O(nb). Poiché dipende dall’intero b si dice che l’algoritmo ha complessità pseudo polinomiale.