Branch and bound

Da testwiki.
Vai alla navigazione Vai alla ricerca

Il branch and bound è una tecnica generale per la risoluzione di problemi di ottimizzazione combinatoria (cioè problemi con spazio di soluzioni finito) e si basa sulla scomposizione del problema originale in sottoproblemi più semplici da risolvere.

Questo metodo è stato inizialmente proposto da A. H. Land e A. G. Doig nel 1960 per risolvere problemi di programmazione lineare intera.

Gli algoritmi Branch and Bound sono detti di enumerazione implicita perché si comportano esattamente come un algoritmo di enumerazione -cioè "provano" tutte le soluzioni possibili fino a trovare quella ottima (o quella corretta)- ma ne scartano alcune dimostrando a priori la loro non ottimalità.

Descrizione[1]

Supponiamo di avere un problema P0=(z,F(P0)) dove z è la funzione obiettivo del problema, mentre F(P0) è la regione ammissibile. La miglior soluzione ottima sarà z*=z(P0)={z(x):xF(P0)} mentre zbest rappresenta la miglior soluzione ammissibile nota. Suddividiamo il problema P0 in K sottoproblemi: P1,P2,...,PK la cui totalità rappresenti P0, ad esempio si può suddividere F(P0) in K sottoinsiemi F(P1),F(P2),...,F(PK) tali che:

i=1KF(Pi)=F(P0)

Preferibilmente le sottoregioni vanno partizionate in modo che:

F(Pi)F(Pj)=Pi,Pj:ij

Questo processo di ramificazione (branching) si può rappresentare mediante un albero decisionale (branch decision tree), dove ogni nodo rappresenta il sottoproblema mentre ogni arco la relazione di discendenza.

Risolvere il problema P0 è quindi equivalente a risolvere la totalità dei suoi PK sottoproblemi generati:

z*=z(P0)=min{z(P1),z(P2),...,z(PK)}

Un sottoproblema Pi si può considerare risolto se si verifica almeno uno dei seguenti casi:

  1. Si determina la soluzione ottima di Pi;
  2. Si dimostra che F(Pi) è vuota (cioè Piè inammissibile);
  3. Si dimostra che z(Pi)zbest (la soluzione del sottoproblema è peggiore della migliore conosciuta).

Se non riesco a risolvere un nodo lo devo suddividere in altri sottoproblemi. Inoltre per ogni sottoproblema Pi, è possibile determinare un lower bound della soluzione in modo da seguire una strategia di esplorazione dell'albero più efficiente.

L(Pi)(Pi)

Se verifico che L(Pi)zbest posso escludere quel nodo visto che la miglior soluzione che posso sperare di ottenere è peggiore della soluzione ammissibile del problema originale. Per ottenere un lower bound di Pi=(z,F(P0)) devo trovare un rilassamento del problema R(Pi)=(zr,Fr(Pi)) tale che:

  1. Fr(Pi)F(Pi);
  2. zr(y)z(y)yF(Pi);

Il problema rilassato è risolvibile in modo più semplice rispetto al problema originale, quindi posso trovarne la soluzione ottima che rappresenta il lower bound del problema originale. Il rilassamento inoltre deve essere scelto in modo che sia più vicino possibile (tight) al problema originale, in alcuni casi basta un rilassamento continuo (facilmente risolvibile attraverso l'algoritmo del simplesso), in altri casi può essere conveniente utilizzare altri rilassamenti come il rilassamento surrogato o il rilassamento lagrangiano.

Esempio

L'obiettivo è trovare la soluzione ottima intera per il problema dello zaino assegnato:

{max 6x1+3x2+4x3+2x4+x52x1+x2+2x3+x4+x54x{0,1}

Poiché ogni variabile ha un costo ci ed un peso ai, il primo passo da compiere è ordinare le variabili secondo il criterio: c1a1c2a2...cnan.

In questo caso le variabili sono già ordinate poiché 6231422111 , quindi posso procedere alla determinazione di una soluzione ottima intera corrente a cui corrisponde un valore ottimo della funzione obiettivo.

Una possibile soluzione x* ottima intera è x*=[10000] a cui corrisponde un valore ottimo della funzione obiettivo z*=6.

Sotto queste ipotesi, il vincolo viene rispettato ma non è del tutto ottimizzato, infatti ottengo la disequazione 2x1+x2+2x3+x4+x5424. Devono quindi essere cercate le soluzioni tali che il vincolo di capacità possa essere saturato.

Viene posto quindi x1=1,x2=1,x3=12,x4=0,x5=0 , ovvero x*=[111200] che corrisponde al valore ottimo z*=11. La soluzione x* però non è intera, quindi genero due sottoproblemi in corrispondenza della componente non intera, cioè x3:

P1)x¯3=x3=12x¯3=0

x¯3=0x(1)=[11010] che corrisponde all'ottimo z(1)=11 (migliore dell'ottimo precedente). In questo caso, poiché il valore ottimo risulta migliore e la soluzione è intera, posso chiudere P1 ed aggiornare la soluzione x* e l'ottimo corrente z* rispettivamente con i valori di x(1) e z(1) appena trovati.

P2)x¯3=x3=12x¯3=1

x¯3=1x(2)=[10100] che corrisponde all'ottimo z(2)=10 (peggiore dell'ottimo precedente). Poiché la soluzione x(2) è intera ma z(2)<z*, posso chiudere P2 senza aggiornare nessun parametro.

Non avendo altri sottoproblemi aperti, la soluzione ottima intera ed il valore ottimo della funzione obiettivo risultano rispettivamente x*=[11010] e z*=11.

Applicazioni

Questo approccio è stato usato per alcuni problemi NP-hard, per esempio

Può essere utilizzato anche come base per vari algoritmi euristici. Per esempio, è possibile fermare il branching quando la differenza fra la soluzione trovata e il lower bound diventa inferiore rispetto ad una certa soglia. Questo è utile quando la soluzione trovata è "buona abbastanza" per i nostri scopi con il vantaggio di ridurre notevolmente il tempo di calcolo.

Note

Template:Portale