You are on page 1of 173

1

Ai miei genitori e a Laura

Prefazione

Il presente lavoro di tesi nato con l'intento di sviluppare idee interessanti per la progettazione di un algoritmo in grado di risolvere il Multidimensional Knapsack

Problem, uno dei problemi di tipo NP-Hard in forma Strong pi noti e complessi in
letteratura. Al momento della stesura di questa tesi non esistono algoritmi in grado di risolvere in modo esatto istanze particolarmente complesse del Multidimensional Knapsack

Problem e la ricerca attualmente direzionata verso strade euristiche, con lo scopo


di fornire soluzioni di buona qualit in tempi ragionevoli. Il fatto che, nonostante il problema sia noto ormai dalla ne degli anni 60, non esista una vasta letteratura di metodologie ecaci per la sua risoluzione, ci ha motivato nello sviluppo di una strategia esatta per istanze di medie dimensioni da poter comunque adattare in modo euristico ad istanze pi complesse, con lo scopo di competere con i risultati migliori recentemente ottenuti su istanze benchmark da un algoritmo Tabu Search [39]. Il Multidimensional Knapsack Problem noto per la sua complessit: pur disponendo a posteriori di una soluzione vericata essere ottima, la certica dell'ottimalit un'operazione talmente ardua da richiedere diverse settimane di calcolo sulle macchine di ultima generazione. La bont dell'algoritmo da noi proposta in buona parte ottenuta tramite la riduzione della dimensione del problema di partenza mediante un operazione di xing delle variabili del problema al valore assunto dalle stesse nella soluzione ottima. La riformulazione basata sulla riduzione ricorsiva permette di risolvere la stessa istanza in un tempo di parecchi ordini di grandezza inferiore al caso senza riduzione. Lo studio da noi eettuato riprende alcuni concetti presentati all'interno di un lavoro di tesi dell'anno accademico 2002/2003 dell'Universit degli Studi di Brescia [35] introducendo tuttavia idee innovative sull'applicazione degli stessi con palesi miglioramenti in termini di ecacia ed ecienza. La tesi organizzata come segue:

Il Capitolo 1 presenta una breve panoramica introduttiva sul Multidimensional

Knapsack Problem, denendone il modello, la complessit e i contesti reali in cui il


problema pu essere applicato. Il Capitolo 2 descrive sinteticamente le metodologie risolutive proposte in pi di 30 anni di ricerca, classicandole in base alla strategia utilizzata e soermandosi maggiormente sulle sosticate metaeuristiche sviluppate negli ultimi anni. Il Capitolo 3 descrive in dettaglio il funzionamento dell'algoritmo da noi realizzato. Vengono poste in evidenza le nuove soluzioni da noi proposte e alcune originali applicazioni di principi teorici noti. L'intero algoritmo presentato in modo rigoroso, alternando notazioni matematiche a spiegazioni meno formali dei vari passaggi in modo da facilitarne la comprensione. Il Capitolo 4 contiene i risultati di tutte le prove sperimentali che abbiamo eseguito. Abbiamo applicato il nostro algoritmo sulle 270 istanze proposte da P.C. Chu e J.E. Beasley [9] che rappresentano le istanze meglio conosciute e pi complesse disponibili in letteratura per questa tipologia di problemi. Il Capitolo 5 entra nel merito dell'implementazione dell'algoritmo in Java 5.0, presentando sia la struttura gerarchica dei packages in cui sono organizzate le classi che costituiscono il software sia lo pseudo codice delle principali funzioni e procedure che rappresentano i mattoni portanti dell'intero algoritmo. Il Capitolo 6 conclude il nostro lavoro di tesi riepilogando i risultati emersi dal nostro studio e le strade di ricerca futura su cui dare maggior attenzione. L'algoritmo da noi realizzato in grado di risolvere in tempi eccellenti istanze correlate con pochi vincoli e un numero elevato di variabili, rendendo assolutamente non competitivi i metodi pi sosticati contemporanei, tra cui lo stesso ILOG CPLEX 10.0, il risolutore per problemi di programmazione lineare intera pi eciente e commercializzato. Oltre a fornire soluzioni ottime a istanze mai risolte in precedenza, il nostro algoritmo si comporta decisamente bene per le istanze pi complesse presenti in letteratura, fornendo delle soluzioni euristiche di qualit elevata in tempi ragionevoli.

Indice

1 Il Multidimensional Knapsack Problem


1.1 1.2 1.3 Modello formale del Problema . . . . . . . . . . . . . . . . . . . . . . Complessit del problema . . . . . . . . . . . . . . . . . . . . . . . .

7
7 9 10

Applicazioni pratiche . . . . . . . . . . . . . . . . . . . . . . . . . . .

2 Stato dell'arte
2.1 2.2 Generazione di istanze . . . . . . . . . . . . . . . . . . . . . . . . . . Algoritmi esatti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.1 2.2.2 2.2.3 2.3 Algoritmi Branch and Bound . . . . . . . . . . . . . . . . . .

12
13 14 15 18 21 22 23 25 30 31

Algoritmi Branch and Cut . . . . . . . . . . . . . . . . . . . . Algoritmi basati sulla programmazione dinamica . . . . . . . .

Algoritmi euristici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3.1 2.3.2 2.3.3 Algoritmi greedy . . . . . . . . . . . . . . . . . . . . . . . . .

Metaeuristiche . . . . . . . . . . . . . . . . . . . . . . . . . . . Algoritmi euristici basati sul rilassamento continuo . . . . . .

2.4

ILOG CPLEX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3 Il nostro algoritmo
3.1 3.2 Il concetto di Core del Multidimensional Knapsack Problem Creazione ed espansione del Core 3.2.1 3.2.2 3.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

33
33 41 42 47 48 49

Valutazione dell'ecacia delle variabili

Criterio di terminazione dell'espansione del Core . . . . . . . .

Risoluzione del problema Core . . . . . . . . . . . . . . . . . . . . . . 3.3.1 AAR: Analisi degli Alberi di Ricerca . . . . . . . . . . . . . .

INDICE

3.3.1.1 3.3.1.2 3.3.1.3 3.3.1.4 3.3.1.5 3.3.1.6 3.3.2

Cardinalit

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

50 53 55 64 68 68 74 75 76 76 77 81 84 85 87 87 88

Enumerazione delle soluzioni Applicazione dei tagli

. . . . . . . . . . . . . . . . . . . . . . . .

Funzionamento dell'algoritmo di ricerca

Calcolo della soluzione ottima . . . . . . . . . . . . . Aspetti di contorno . . . . . . . . . . . . . . . . . . .

RR: Riduzione ricorsiva del problema . . . . . . . . . . . . . . 3.3.2.1 3.3.2.2 3.3.2.3 3.3.2.4 3.3.2.5 3.3.2.6 3.3.2.7 Inizializzazione di RR . . . . . . . . . . . . . . . . .

Fixing diretto delle variabili . . . . . . . . . . . . . . Fixing indiretto delle variabili . . . . . . . . . . . . . Schema generale di xing delle variabili . . . . . . .

Risoluzione del problema riformulato . . . . . . . . . Schema riassiuntivo di RR . . . . . . . . . . . . . . . RR con distinzione di cardinalit . . . . . . . . . . .

3.4

Core, EC, AAR e RR: calcolo della soluzione ottima di un MKP . . . 3.4.1 3.4.2 Approccio senza distinzione di cardinalit Approccio con distinzione di cardinalit . . . . . . . . . . . . . . . . . . . . . . .

4 Prove computazionali
4.1 4.2 Java 5.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Applicazione dell'algoritmo esatto . . . . . . . . . . . . . . . . . . . . 4.2.1 4.2.2 4.2.3 4.2.4 Istanze di P.C. Chu e J.E. Beasley 100.5 , 250.5 e 500.5 . . . . Istanze di P.C. Chu e J.E. Beasley 100.10 e 250.10 . . . . . . . Analisi separata delle cardinalit

90
91 93 93 95

. . . . . . . . . . . . . . . . 102

Ordinamento delle variabili nell'enumerazione delle soluzioni in AAR . . . . . . . . . . . . . . . . . . . . . . . . . 109

4.3

Algoritmo euristico . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 Valutazione dei problemi ridotti . . . . . . . . . . . . . . . . . 111 Istanze di P.C. Chu e J.E. Beasley 500.10 . . . . . . . . . . . . 112 Istanze di P.C. Chu e J.E. Beasley 500.30 . . . . . . . . . . . . 114 Confronto con le migliori euristiche . . . . . . . . . . . . . . . 114

Risultati per le istanze P.C. Chu e J.E. Beasley 250.10, 100.30, 250.30 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118

INDICE

5 Descrizione del Software


5.1 5.2 Pseudocodice dell'algoritmo 5.2.1 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3

122
. . . . . . . . . . . . . . . . . . . . . . . 125 . . . . . . . . . . . . . . . . . . . 128

Il Packager mkp.* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

Avviamento del programma

Inizializzazione del risolutore . . . . . . . . . . . . . . . . . . . 130 Creazione del Core . . . . . . . . . . . . . . . . . . . . . . . . 130

Risoluzione del problema con Core minimale . . . . . . . . . . 134 Espansione del Core . . . . . . . . . . . . . . . . . . . . . . . 136

Risoluzione del problema con Core espanso . . . . . . . . . . . 136 Applicazione dell'algoritmo RR Applicazione dell'algoritmo AAR Altre note implementative . . . . . . . . . . . . . . . . . 140 . . . . . . . . . . . . . . . . 151

. . . . . . . . . . . . . . . . . . . . 155

Diagrammi UML delle interazioni . . . . . . . . . . . . . . . . . . . . 158

6 Conclusione
6.1 6.2

166

Riepilogo del lavoro di tesi . . . . . . . . . . . . . . . . . . . . . . . . 166 Sviluppi futuri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167

Capitolo

Il Multidimensional Knapsack Problem


In questo capitolo verr introdotto il Multidimensional Knapsack Problem, denendone il modello e le caratteristiche principali che lo rendono uno dei problemi di ottimizzazione combinatoria pi complessi da risolvere presenti in letteratura.

1.1

Modello formale del Problema


1
un problema di ottimizzazione

Il Multidimensional Knapsack Problem (MKP )

combinatoria che pu essere formulato nel seguente modo:

max
j=1 n

pj xj

wij xj ci i = 1, .., m
j=1

(1.1)

xj {0, 1} j = 1, .., n
Si tratta di un problema di massimizzazione denito su a

vincoli strutturalmente identici, con

n variabili binarie e soggetto pj > 0, wij 0 e ci > 0. Come il nome del

problema suggerisce, il MKP una generalizzazione del noto problema dello zaino unidimensionale, meglio conosciuto come 0-1 Knapsack Problem con la seguente

1 In alcune trattazioni la sigla MKP anche usata in riferimento al


che non ha nulla a che vedere con il di tesi.

Multiple Knapsack Problem Multidimensional Knapsack Problem, descritto nel nostro lavoro
7

CAPITOLO 1.

IL MULTIDIMENSIONAL KNAPSACK PROBLEM

formulazione:

max
j=1 n

pj xj

wj xj c
j=1

(1.2)

xj {0, 1} j = 1, .., n
Le variabili peso

xj

rappresentano gli

n oggetti (o items) ognuno avente un prezzo pj c

e un

wj .

Il meccanismo risolutivo del problema denito in (1.2) consiste nell'inserire un sottoinsieme di oggetti

all'interno di uno zaino avente capacit massima pari a

in modo che venga massimizzato il prezzo totale degli stessi senza violare il vincolo di capacit dello zaino. Il MKP un problema dello zaino m-dimensionale nel senso che soggetto con-

m vincoli di capacit distinti. Ogni oggetto j caratterizzato da un prezzo pj e da m pesi wij che variano in relazione allo zaino in cui vengono inseriti. Selezionare un oggetto j (quindi porre xj = 1) corrisponde a doverlo inserire in tutti gli m zaini del problema. L'obiettivo della risoluzione del MKP sempre quello
temporaneamente a di massimizzare il prezzo totale del set di oggetti selezionati con l'unica dierenza che tale sottoinsieme di oggetti deve poter essere inserito in ogni zaino senza che ne venga ecceduta la relativa capacit. Di fatto la notazione utilizzata nel modello (1.1) assume il seguente signicato:

il valore di

xj

determina lo stato dell'item

j esimo:

se

xj = 1,

l'oggetto

selezionato e viene inserito in tutti gli zaini del problema; in caso contrario si ha che

xj = 0. j
caratterizzato da un proprio prezzo

ogni item

pj

indipendente dagli zaini.

qualora un item venga selezionato, deve essere inserito in tutti gli zaini. Il peso dell'oggetto varia a seconda dello zaino in cui inserito. Il valore di tale peso contenuto nei parametri l'oggetto inserito.

wij ,

con

l'oggetto selezionato e

lo zaino in cui

ogni zaino

i ha una capacit massima pari a ci . m

Il peso complessivo degli oggetti

contenuti nello zaino non pu eccedere la relativa capacit. Questo deve valere contemporaneamente per tutti gli zaini su cui il problema denito.

CAPITOLO 1.

IL MULTIDIMENSIONAL KNAPSACK PROBLEM

Inoltre, per evitare riformulazioni banali del problema di partenza in un problema di dimensioni ridotte, vengono fatte le seguenti assunzioni:

wij ci j = 1, .., n , i = 1, .., m : xj = 0.


n j=1

in caso contrario l'oggetto

non pu essere

mai inserito in uno zaino senza violare il vincolo di capacit e si pone subito

wij > ci , i = 1, .., m

: in caso contrario il vincolo

i esimo

diventa

inutile e pu essere eliminato.

Presi due qualunque zaini siano uguali in

non si deve avere che i pesi di tutti gli oggetti

ma almeno un oggetto deve avere peso nello zaino

diverso

da quello nello zaino

. In caso contrario si hanno due vincoli di minoranza

aventi primo membro uguale e secondo membro dierente. Di fatto il vincolo con capacit maggiore diventa ridontante e viene scartato dalla denizione del problema.

1.2

Complessit del problema

Il Multidimensional Knapsack Problem appartiene alla classe dei problemi

NP

Hard Strong

. Un problema

N P Hard se non ancora stato trovato un algoritdove

mo polinomiale che lo risolve. Un algoritmo si dice polinomiale se nel caso peggiore richiede un tempo di calcolo e

f (n) = O nk

la dimensione del problema

una costante ssata. Un problema appartiene alla classe

se esiste un algo-

ritmo polinomiale che lo risolve.

Un problema appartiene alla classe

NP

qualora

venga risolto in un numero di passi polinomiale solo nel caso in cui si possa disporre di un numero indeterminato di macchine. Di fatto tutti gli algoritmi in grado di risolvere un problema tempo esponenziale

N P implementabili f (n) = O (hn ) per essere

su calcolatori sici necessitano di un eseguiti. Un problema

N P Hard

Strong se anche limitando con un polinomio i dati in ingresso il problema ancora N P Hard. Attualmente, pur sapendo che P N P , non si ancora riuscito a dimostrare se P = N P oppure P N P . Inoltre, secondo la teoria della complessit, un problema N P Hard se N P log , ossia che un qualunque algoritmo in grado di risolvere pu essere ridotto in spazio logaritmico in un algoritmo in grado di risolvere un qualunque problema appartenente a N P . Di fatto, se si riuscisse a trovare un algoritmo polinomiale per un problema N P Hard, ogni

CAPITOLO 1.

IL MULTIDIMENSIONAL KNAPSACK PROBLEM

10

problema in

NP

pu essere risolto in tempo polinomiale, facendo collassare la classe

NP.
Da queste considerazioni risulta chiaro che il Multidimensional Knapsack Problem

di non facile risoluzione anche per istanze di medie dimensioni.

1.3

Applicazioni pratiche

Il Multidimensional Knapsack Problem tanto complesso quanto utile, in quanto il suo modello pu essere utilizzato per formalizzare una moltitudine di problemi reali. Tra le sue applicazioni pratiche spiccano sicuramente le aste combinatorie a tal punto che molti autori, per semplicare la spiegazione delle proprie metodologie risolutive, identicano gli elementi del modello del MKP con gli elementi caratteristici del contesto delle aste. In un'asta combinatoria, un venditore (il banditore d'asta) mette in vendita un insieme di beni ed i partecipanti all'asta possono formulare oerte per una qualsiasi combinazione dei beni stessi. In un'asta combinatoria sono in vendita una o, nel

caso generale, pi copie dello stesso bene. Il modello del MKP pu essere descritto tramite gli elementi del dominio dell'asta combinatoria e in particolare si ha che:

il numero di vincoli del problema corrisponde al numero di tipologie di beni distinti che vengono messi all'asta dal banditore;

la capacit

ci

del vincolo

i esimo

corrisponde alla quantit massima di beni

della tipologia

messi all'asta;

il numero di variabili del problema corrisponde al numero di oerte che sono state fatte dai partecipanti all'asta. La variabile associata

xj

assume valore 1 se l'oerta

stata accettata, 0 se stata riutata;

il coeciente

pj

della variabile

xj

nella funzione obiettivo corrisponde al valore

dell'oerta eettuata da un partecipante all'asta;

ogni oerta viene fatta su tutti i tipi di beni, richiedendo per ognuno di essi una determinata quantita. Il numero di beni del tipo valorizzato in

richiesto dall'oerta

wij ;

CAPITOLO 1.

IL MULTIDIMENSIONAL KNAPSACK PROBLEM

11

il banditore d'asta deve selezionare, tra tutti i set di oerte tali che la somma dei beni totali richiesti per ogni tipo sia minore di quella da lui messa a disposizione, quello che gli consente di massimizzare i protti.

Data l'estrema semplicit nel descrivere il modello del MKP tramite concetti quali oerte, beni, prezzi ecc, tali notazioni saranno pi volte utilizzate anche nel seguito della trattazione. Ma il Multidimensional Knapsack Problem trova applicazioni in tanti altri casi reali. Tra i pi importanti ricordiamo i problemi di capital budgeting, project

selection, cutting stock e problemi di allocazione di risorse. Inne, molti problemi di programmazione intera necessitano la risoluzione di un sottoproblema che pu essere ricondotto a qualche forma particolare del MKP (numero pressato di vincoli, capacit dei vincoli unitaria, capacit dei vincoli tutte uguali ecc.).

Capitolo

Stato dell'arte
Il Multidimensional Knapsack Problem stato uno dei problemi maggiormente studiati in letteratura sin dalla ne degli anni 60, sia per l'eterogeneit delle sue applicazioni pratiche, sia perch l'estrema dicolt nel trovare un metodo risolutivo eciente ha stimolato i ricercatori a sviluppare idee su svariati fronti. Molti autori hanno proposto e stanno tuttora proponendo soluzioni volte a trovare un compromesso tra l'ecacia (la ricerca della soluzione ottima) e l'ecienza (il tempo impiegato per trovarla) e i risultati migliori in quest'ottica sono stati ottenuti proprio in questi anni. La ricerca ha spaziato nelle direzioni pi variegate: da metodi per ridurre la dimensione del problema ad algoritmi in grado di trovare buone soluzioni in tempi accettabili, dalla generazione di tagli ecaci per ridurre lo spazio di ricerca delle soluzioni a metauristiche complesse per la ricerca di un buon lower bound al problema da cui eventualmente far partire algoritmi esatti di tipo branch and cut. Nonostante l'enorme impiego di risorse ed energie nella ricerca di una metodologia risolutiva denitiva per questa classe di problemi, la realt dei fatti che si ancora ben lontani dal raggiungere questa meta. Attualmente non esiste alcun algoritmo

in grado di risolvere in modo esatto istanze correlate di medie dimensioni (n

> 250,

m > 5)

in tempi accettabili e l'impossibilit data dalla semplicit del modello di

ridurre ragionevolmente lo spazio di ricerca della soluzione ottima ha scoraggiato la ricerca di una metodologia esatta per questo tipo di problemi. Di conseguenza, data l'incapacit di risolvere in modo polinomiale problemi di tipo

N P Hard,

gli sforzi

maggiori sono concentrati tuttora nel raorzare metodi euristici complessi volti a trovare soluzioni ammissibili sempre migliori e in tempi sempre pi brevi. In questo capitolo cercheremo di presentare una sintetica panoramica dei metodi

12

CAPITOLO 2.

STATO DELL'ARTE

13

risolutivi che a nostro avviso sono da considerarsi i pi ecaci tra tutti quelli proposti in pi di 40 anni di ricerca. I risultati computazionali di alcuni di essi verranno

presentati nel capitolo 4, quando sar necessario confrontare i risultati ottenuti dal nostro algoritmo con quanto di meglio c' in letteratura.

2.1

Generazione di istanze

Prima di entrare nel merito degli algoritmi risolutivi per il MKP, opportuno aprire una breve parentesi per quanto concerne le istanze su cui questi algoritmi possono essere testati per valutarne l'ecacia e l'ecienza. In letteratura non esistono istanze su problemi reali sulle quali basare i test di valutazione degli algoritmi progettati. L'unico set di istanze estrapolate da casi reali consta di 56 problemi di dimensione variabile da

n = 6

a 105 oerte e da

m = 2

a 30 beni.

Queste istanze tuttavia

sono molto facili da risolvere e la soluzione ottima allo stato dell'arte attuale pu essere determinata in una frazione di secondo. Di fatto nata l'esigenza di trovare un meccanismo che permettesse di generare delle istanze benchmark con lo scopo di valutare oggettivamente la qualit delle varie metodologie risolutive senza che i risultati potessero essere inuenzati dall'estrema semplicit dei problemi formulati. Le istanze utilizzate per testare l'algoritmo descritto in questo lavoro di tesi sono state generate da P.C. Chu e J.E. Beasley utilizzando una procedura da loro stessi suggerita in [9]. Queste istanze, disponibili al sito internet [45], nonostante

siano state proposte ormai da 10 anni, rappresentano tuttora una sda per chiunque intenda valutare la bont del proprio algoritmo, in quanto la loro complessit tale che per la maggior parte di esse non ancora nota la soluzione ottima. Il numero dei vincoli ssato a

m = 5, 10, 30

e il numero delle variabili a

n = 100, 250, 500.

Sono I

presenti 30 problemi per ogni combinazione di pesi

m e n per un totale di 270 problemi. m


e

wij

delle oerte nei vincoli sono numeri interi ottenuti da un generatore discreto

uniforme

U (0, 1000).

Per ogni combinazione

le capacit

ci

dei vincoli sono

ssate dalla relazione

ci =

n j=1

wij

dove

una costante che assume i valori 0.25 I

per le prime dieci istanze, 0.50 per le seconde dieci e 0.75 per le ultime dieci. coecienti della funzione obiettivo sono correlati ai pesi

wij

dalla seguente relazione:

pj =

m i=1

wij

+ 500qj

CAPITOLO 2.

STATO DELL'ARTE

14

dove

qj

un numero reale ottenuto da un generatore uniforme continuo

U (0, 1).

La complessit delle istanze dipende da diversi parametri: il numero di item, il numero di vincoli, i pesi nei vincoli, i termini noti dei vincoli, il numero di item presenti nella soluzione ottima e la correlazione fra essi. Le istanze di P.C. Chu e J.E. Beasley sono complesse proprio perch il peso dei vincoli e i loro termini noti, il numero di item presenti nella soluzione ottima e la correlazione tra gli stessi sono elevati. Per una esauriente trattazione sulla complessit dei problemi correlati si

rimanda a [16] e [31]. Le istanze di P.C. Chu e J.E. Beasley sono quelle pi note in letteratura e la progettazione di un metodo risolutivo per il Multidimensional Knapsack Problem non pu prescindere dal testare l'algoritmo su questo set di problemi, anche per ottenere un valido raronto con i risultati forniti da altri autori. Per completezza, bene segnalare che recentemente sono stati proposti set di istanze complesse, ottenute aumentando la dimensione del problema e utilizzando diversi meccanismi di generazione per aumentare la correlazione tra le variabili. Tra i pi importanti si cita il meccanismo di generazione di istanze proposto da Bertsimas e Demir [7] adottato per i problemi di test per l'algoritmo da loro sviluppato, le 7 istanze proposte da Glover e Kochenberger [17] nel 1996 e le 11 istanze pubblicate sempre da Glover e Kochenberger [46] nel 2001 di elevate dimensioni sino a

n = 2500

m = 100.

2.2

Algoritmi esatti

Allo stato dell'arte attuale, non esiste alcun algoritmo esatto in grado di risolvere in modo soddisfacente il Multidimensional Knapsack Problem. Sebbene sia possibile calcolare la soluzione ottima di istanze molto semplici anche con un risolutore generico per problemi di Programmazione Lineare Intera, al crescere della dimensione del problema nessun algoritmo presente in letteratura risulta scalabile in termini di tempo speso per la determinazione dell'ottimo. Chiaramente sono stati sviluppati diversi approcci per poter risolvere in modo esatto questa categoria di problemi. Considerata l'inecienza dei vari approcci su istanze complesse, la ricerca si spesso focalizzata nell'integrare ai vari metodi esatti alcune procedure euristiche per velocizzare la scansione dello spazio di ricerca delle soluzioni. In questo modo lo stesso algoritmo pu essere utilizzato sia come algoritmo esatto per istanze di dimensioni ridotte, sia come euristica per istanze pi complesse altrimenti risolvibili all'ottimo

CAPITOLO 2.

STATO DELL'ARTE

15

in tempi non accettabili. Gli algoritmi esatti per la risoluzione del Multidimensional Knapsack Problem fanno riferimento a:

algoritmi basati su analisi Branch and Bound; algoritmi basati su analisi Branch and Cut; algoritmi basati sulla programmazione dinamica; algoritmi basati sulla generazione di alberi binari.

Di seguito viene presentata un'introduzione sintetica ai primi tre approcci. Per quanto riguarda l'ultimo approccio, verr dato ampio spazio nel capitolo 3 costituendo esso una parte fondamentale alla base dell'algoritmo sviluppato durante questo lavoro di tesi.

2.2.1 Algoritmi Branch and Bound


Il Branch and Bound una tecnica generale per la risoluzione di problemi di ottimizzazione combinatoria e si basa sulla scomposizione del problema originale in sottoproblemi pi semplici da risolvere. Questo metodo viene detto anche di enumerazione implicita in quanto prova tutte le soluzioni possibili no a trovare quella ottima ma ne scarta alcune dimostrando a priori la loro non ottimalit. Supponiamo di avere un problema di massimizzazione obiettivo del problema e

P 0 = (z, F (P 0 )) dove z

la funzione

F (P ) la regione ammissibile. La miglior soluzione ottima 0 best sar z = z (P ) = {z (x) : x F (P )} mentre z rappresenta la miglior soluzione 0 1 2 k ammissibile nota. Suddividiamo il problema P in K sottoproblemi P , P , ...,P K i 0 i j i j tali che i=1 F (P ) = F (P ) e F (P ) F (P ) = , P , P : i = j . Questo processo
0
di ramicazione (branching) viene solitamente rappresentato mediante un albero decisionale dove ogni nodo rappresenta un sottoproblema. Risolvere il problema quindi equivalente a risolvere la totalit dei suoi che

P0

sottoproblemi generati in modo

z = min z (P 1 ) , z (P 2 ) , ..., z P K

Un sottoproblema

Pi

pu considerarsi

risolto se verica almeno uno dei seguenti casi:

1 Il discorso del tutto analogo al caso di problemi di minimizzazione. Aver scelto un problema
di massimizzazione in linea con l'analisi del

Multidimensional Knapsack Problem.

CAPITOLO 2.

STATO DELL'ARTE

16

1. Si determina la soluzione ottima di 2. Si dimostra che 3. Si dimostra che

Pi

F (P i )

impossibile (se il problema di massimizzazione)

z (P i ) < z best

Se non si riesce a risolvere un nodo (in quanto operazione troppo complessa) necessario suddividerlo in altri sottoproblemi. possibile determinare un upper bound Inoltre per ogni sottoproblema

Pi

U B (P )

della soluzione in modo da seguire

una strategia di esplorazione pi eciente. Infatti, qualora

U B (P i ) < z best

il nodo

pu essere escluso visto che la miglior soluzione che si pu sperare di ottenere comunque peggiore della migliore soluzione ammissibile sinora nota del problema originale. Gli algoritmi Branch and Bound dieriscono sostanzialmente da come

viene portata avanti la scomposizione del problema, dal tipo di discesa dell'albero per esplorare i nodi da risolvere e dalle tecniche per determinare lower bound e upper bound ai problemi. Applicato al MKP, le cui variabili possono assumere solo valore 1 o 0, l'albero decisionale di branching binario e i due gli sono ottenuti partendo dal problema padre e settando rispettivamente una variabile

xj

a 0 o a 1. Per problemi di grosse

dimensioni non possibile risolvere all'ottimo un sottoproblema n tanto che non sono state ssate un numero sucientemente elevato di variabili. Questo, tradotto in termini di Branch and Bound, signica scendere a fondo nell'esplorazione dell'albero decisionale il cui numero di nodi cresce esponenzialmente. L'handicap di questo

approccio l'elevato consumo di memoria richiesto dai sottoproblemi che devono ancora essere valutati e di fatto si cercato di perfezionare le tecniche di potatura (fathoming) dell'albero per evitare di creare nodi superui in termini di residenza della soluzione ottima. Molti autori hanno proposto dei miglioramenti al metodo classico di Branch and Bound applicato alla risoluzione del MKP, quasi tutti volti a determinare un valore di un upper bound che potesse escludere l'analisi dei vari nodi ai pi alti livelli possibili dell'albero decisionale. Shin [37] ha presentato un metodo che sfrutta un upper bound cos formulato: dati

(KP )i

problemi con

i {1, ..., m},

siano

zi

le soluzioni dei problemi:

CAPITOLO 2.

STATO DELL'ARTE

17

max
j=1 n

pj xj

wij xj ci
j=1

(2.1)

xj {0, 1} j = 1, .., n
segue che:

z U1 = min {zi | i = 1, ..., m}


dove

(2.2)

la soluzione ottima cercata.

Un upper bound pi debole ma di pi rapido calcolo :

z U1 U2 = min ziLP | i = 1, ..., m ziLP i esimo.


dove

(2.3)

la soluzione del problema originale rilassato considerando solo il vincolo

I migliori risultati in termini di qualit dell'upper bound relativo ai sottoproblemi sono stati ottenuti dagli studi svolti da Gavish e Pirkul pubblicati in [31] e [30]. Sono stati paragonati diversi tipi di rilassamento oltre a quello continuo, tra cui il lagrangiano, il surrogato e il composito. I risultati sperimentali evidenziano

che il rilassamento composito trova il miglior upper bound anche se con un tempo computazionale maggiore rispetto agli altri rilassamenti. K. L. Brown [8] ha sviluppato l'algoritmo CAMUS (Combinatorial Auctions Multi-Unit Search) che rappresenta il primo tentativo di risoluzione del Multidimen-

sional Knapsack Problem nel contesto delle aste combinatorie multi-unit. Il metodo
risolutivo garantisce la soluzione ottima attraverso una tecnica Branch and Bound di tipo depth-rst

che cerca un'allocazione full assegnando tutti i beni a disposizione I risultati presentati sono relativi a

e migliorandola con tecniche di backtracking.

problemi generati dagli autori stessi con un metodo spiegato nell'articolo che prevede che per ogni oerta i beni richiesti siano comunque pochi.

2 Il metodo di analisi depth-rst percorre l'albero di ricerca dando la precedenza ai nodi pi


profondi.

CAPITOLO 2.

STATO DELL'ARTE

18

L'algoritmo di Gonen-Lehmann [20] si basa anch'esso su un'approccio di tipo Branch and Bound in cui l'analisi dell'albero di ricerca viene velocizzata disponendo di lower bound e upper bound vicini all'ottimo. Entrambi gli algoritmi di GonenLehmann e CAMUS risolvono facilmente istanze scarsamente correlate di grandi dimensioni. Tuttavia il set di problemi preso in considerazione poco realistico e si dimostrano inecaci per istanze benchmark pi complesse come quelle proposte da P.C. Chu e J.E. Beasley.

2.2.2 Algoritmi Branch and Cut


Il Branch and Cut un metodo di risoluzione classico per problemi con variabili intere. L'idea quella di combinare due tecniche distinte per la Programmazione Lineare Intera: il Branch and Bound e il Cutting Planes. Della tecnica Branch and Bound si gi ampliamente parlato nel paragrafo precedente. Il Cutting Planes una tecnica basata sulla generazione di disuguaglianze valide da aggiungere al problema in modo da ridurre la regione di ammissibilit del problema stesso eliminando parte dello spazio delle soluzioni in cui sicuramente non localizzata la soluzione ottima. L'idea quella di partire dalla soluzione ottima del rilassato continuo del problema e generare un taglio che la escluda in modo che ne venga determinata una nuova su uno spazio di ricerca ridotto, iterando il procedimento no a che la soluzione del rilassato continuo non contenga pi valori frazionari. La dicolt di questa tecnica risiede dunque nella generazione di disuguaglianze valide, che siano ecienti da trovare ed ecaci nel tagliare lo spazio di ammissibilit del problema. Il Branch and Cut dunque una tecnica mista che consiste nel progettare un Branch and Bound in cui ad ogni nodo dell'albero decisionale si generano dei tagli validi al ne di ottenere o una soluzione del rilassamento continuo intera o un upper bound (lower bound) pi stretto. Il limite del branch and bound risiede nella generazione di un numero elevato di sottoproblemi da risolvere la cui semplice memorizzazione al ne di valutarli successivamente richiede un dispendio di risorse hardware non indierente al crescere del numero di variabili del problema. L'upper bound

(lower bound), anche se ottenuto attraverso sosticate tecniche di rilassamento, ha comunque un valore tale da consentire l'eliminazione del nodo analizzato solo in profondit elevate dell'albero, quando cio il numero di nodi generati gi esploso.

CAPITOLO 2.

STATO DELL'ARTE

19

L'utilizzo di disuguaglianze valide al rilassato continuo dei vari sottoproblemi consente di migliorare notevolmente il bound ottenuto vericando prima la condizione di potatura del ramo e tagliando il nodo stesso evitando di procedere con ulteriori quanto inutili operazioni di branching. Di fatto i pi sosticati algoritmi esatti per problemi di Programmazione Intera si sviluppano tutti a partire direttamente da un framework Branch and Cut anzich Branch and Bound, ivi inclusi gli algoritmi specici per il Multidimensional Knapsack Problem. Le dierenze sostanziali tra questi algoritmi, oltre che includere le diverse scelte implementative tipiche di un approccio Branch and Bound, includono anche il tipo di disuguaglianze valide generate, se sono valide localmente (solo per il nodo analizzato e i relativi gli) o globalmente (per tutti i nodi dell'albero) e i criteri in base ai quali si decide se relativamente ad un nodo opportuno applicare un taglio piuttosto che un operazione di branching. Sebbene in letteratura siano noti molti tagli nel contesto generico della Programmazione Linera Intera, la maggior parte di essi risulta del tutto inecace se applicata specicatamente al caso del Multidimensional Knapsack Problem. La semplicit e l'assenza di informazioni signicative estrapolate dal modello del MKP evidenzia l'inutilit di disuguaglianze che per altre tipologie di problemi risultano valide. L'unico approccio di tipo Cutting Planes che sembra aver contribuito a ottenere risultati positivi in termini di miglioramento dell'upper bound basato sulle lifted

cover inequalities (LCIs ), introdotte separatamente da Balas [3] e Wolsey [40] nel
1975, e ampliate successivamente da Gu et al. [21].

Q := conv x {0, 1}n : aT x b .L'insieme C N = {1, ..., n} si denisce cover se soddisfa la relazione jC aj > b. Data una cover C , la cover inequality jC xj |C| 1 sicuramente valida per Q. Inoltre, le disuguaglianze di copertura pi forti si ottengono se la cover C minimale, vale a dire se nessun sottoinsieme di C a sua volta una cover. In generale per ogni vincolo del problema possibile
Sia generare pi tagli di copertura minimale. Osorio et al. [28] hanno proposto un semplice algoritmo per la generazione di tutte le cover minimali associate ad un

MKP e hanno denito, partendo da esse, una nuova classe di disuguaglianze da loro
denite contiguous cuts. Le lifted cover inequalities sono ottenute applicando tecniche di lifting delle variabili ai tagli di copertura minimali generati. Come noto dalla programmazione lineare, se fosse possibile generare dei tagli in grado di ridurre il poliedro del problema continuo nel suo convex hull, il problema intero verrebbe risolto all'ottimo in tempi polinomiali attraverso l'algoritmo del simplesso. Tuttavia la determinazione di tutti i

CAPITOLO 2.

STATO DELL'ARTE

20

tagli cosidetti facet-inducin g a sua volta un problema dicile quanto la risoluzione del MKP. Le tecniche di lifting permettono di generare dei tagli facet-inducing su una porzione ridotta del poliedro del problema. In particolare, una lifted cover inequality assume la forma seguente:

xj +
jC
dove i coecienti di lifting

j xj |C| 1
jN \C

(2.4)

soddisfano la relazione

0 j |C| 1. C.

L'operazione

di lifting consiste dunque nel raorzare il taglio di copertura minimale portando al suo interno tutte le variabili non contenute nella cover per computare i coecienti di lifting. Esistono diverse tecniche

Tra le pi importanti si cita un algoritmo

molto veloce basato sulla programmazione dinamica proposto da Zemel in [41]. I migliori risultati sono stati ottenuti da Kaparis et al. [24] che hanno ulteriormente raorzato le LCIs attraverso dei coecienti di down-lifting. Pi precisamente hanno osservato che per ogni vincolo la disuguaglianza

i,

data una cover

e un sottoinsieme

D C,
(2.5)

xj |C \ D| 1
jC\D
valida per il poliedro ristretto

conv x {0, 1}

|N \D|

:
jN \D

aj x j b i
jD

aj

(2.6)

Applicando un lifting classico per le variabili contenute in per le variabili contenute in

N \C

e un down-lifting

si ottiene la seguente disuguaglianza

xj +
jC\D jN \C

j xj +
jD

j xj |C \ D| +
jD

j 1

(2.7)

che facet-inducing per il poliedro (2.6). Kaparis et al. spiegano nel dettaglio come procedere nelle operazioni di lifting per ottenere dei tagli pi ecaci per il problema MKP di partenza. Inoltre introducono una nuova classe di disuguaglianze, chiamate global lifted cover inequalities (GLCIs ), ottenute semplicemente creando i tagli di copertura considerando contemporaneamente tutti i vincoli del problema. I risultati computazionali del loro

lavoro evidenziano un netto miglioramento dell'upper bound per problemi di medie

CAPITOLO 2.

STATO DELL'ARTE

21

dimensioni mentre si osservato come per le istanze pi complesse di P.C. Chu e J.E. Beasley (n

= 500, m 10)

le LCIs sono del tutto inecaci mentre una lieve

restrizione del bound si ha con le GLCIs, che necessitano tuttavia di un tempo di calcolo maggiore. Gupta, Buln e Smith [22] hanno sviluppato un metodo per determinare LCIs con coecienti di lifting frazionari. Sebbene questa classe di disuguaglianze risulti essere pi ecace delle LCIs a coecienti interi, la tecnica per calcolare i migliori coecienti frazionari possibili si basa su un problema di separazione

N P Completo

e non trovano applicazioni pratiche nelle istanze di grandi dimensioni. In generale l'applicazione di questi tagli nell'ambito di un framework Branch and Cut commerciale velocizza la navigazione dell'albero decisionale ma non sucientemente ecace da evidenziare sostanziali miglioramenti per quanto riguarda la risoluzione di istanze medio-complesse. La realt dei fatti che non esiste tuttora alcun metodo che applicato al Branch and Cut lo renda adatto a risolvere all'ottimo problemi correlati di grandi dimensioni. Di conseguenza, allo stato attuale, molti

algoritmi che si basano su questo approccio prevedono diversi rilassamenti delle condizioni di fathoming dei nodi, l'utilizzo delle quali, pur velocizzando di molto la navigazione dell'albero, non garantisce la determinazione della soluzione ottima.

2.2.3 Algoritmi basati sulla programmazione dinamica


La programmazione dinamica una tecnica di risoluzione di problemi di ottimizzazione basata sulla scomposizione ricorsiva del problema di partenza in sottoproblemi pi trattabili. A dierenza del divide et impera che prevede la creazione di due (o pi) sottoproblemi a partire da un problema padre, nella programmazione dinamica l'obiettivo quello di risolvere tutti i sottoproblemi possibili sin dall'inizio e attraverso opportune tecniche bottom up risalire alle soluzioni dei problemi genitori no a raggiungere quella del problema iniziale. Non c' un modo rigoroso per denire la programmazione dinamica in quanto una tecnica che dipende molto dalla struttura interna del problema da risolvere. Nell'ambito del Multidimensional

Knapsack Problem l'algoritmo dinamico pu essere formalizzato come segue:


Per

j = 1, ..., n, i = 1, ..., m, gi = 0, ..., ci

del sottoproblema denito sull'insieme di

z (j, g1 , ..., gm ) la soluzione ottima variabili {1, ..., j} e con le capacit dei
, sia

CAPITOLO 2.

STATO DELL'ARTE

22

vincoli pari a

g1 , ..., gm :
j

max
k=1 j

pk xk

wik xk gi i = 1, ..., m
k=1

(2.8)

xk {0, 1} k = 1, ..., j
Per il calcolo del valore

z (j, g1 , ..., gm )

si utilizza la seguente ricorsione: se

z (j, g1 , ..., gm ) = z (j 1, g1 , ..., gm )

gi wij

per alcuni

i {1, ..., m}

z (j, g1 , ..., gm ) = max {z (j 1, g1 , ..., gm ) , pj + z (j 1, g1 w1j , ..., gm wmj )} se gi wij per tutti gli i {1, ..., m}
La soluzione ottima

n c1 ... cm

z (n, c1 , ..., cm ) pu essere trovata con una tabella di dimensioni m m approsimabile a O (ncmax ) dove cmax = max {c1 , ..., cm } che richiede = 100 e m = 5) hanno ci 10000:

alti tempi di computazione e grande spazio di memoria. Tanto per rendere l'idea, le istanze pi semplici di P.C. Chu e J.E. Beasley (n questo implica circa

10

22

elementi in memoria. Non dunque pensabile utilizzare la

programmazione dinamica per risolvere in modo esatto il Multidimensional Knapsack

Problem.
Un primo tentativo di sviluppare un algoritmo dinamico competivo dovuto al lavoro svolto da Balev, Yanev, Freville e Andonov [4] grazie a tecniche di riformulazione per ridurre la dimensione del problema di partenza. Bertsimas e Demir [7] hanno proposto un approccio alla programmazione dinamica approssimata basata su una metodologia parametrica per semplicare la valutazione dei sottoproblemi. L'algoritmo sviluppato, denominato ADP (Adaptive

Dynamic Programming ), riduce il numero di sottoproblemi risolvendo la maggior


parte di essi tramite una funzione di valutazione euristica da loro stessi implementata. I risultati computazionali sembrano dimostrare una buona qualit delle soluzioni sulle istanze di test anche se il metodo in generale non pu essere considerato competitivo con le tecniche metauristiche sviluppate negli ultimi anni.

2.3

Algoritmi euristici

Gli algoritmi euristici si pongono come obiettivo quello di determinare una buona soluzione ammissibile in tempi accettabili senza che vi sia comunque la garanzia che

CAPITOLO 2.

STATO DELL'ARTE

23

la soluzione trovata coincida con quella ottima. Si tratta di un compromesso tra ecienza ed ecacia del meccanismo risolutivo utile in quei contesti in cui la soluzione ottima non pu essere determinata in tempi ragionevoli. L'aspetto che accomuna i vari algoritmi euristici il tentativo di ridurre nel modo migliore possibile lo spazio di ricerca delle soluzioni del problema, evitando di analizzare a priori un insieme di soluzioni all'interno del quale non presente quella ottima. La bont di un algoritmo dipende sostanzialmente da come la navigazione dello spazio di ricerca viene portata avanti. Esistono diverse tecniche consolidate per una scansione euristica dello spazio di ricerca, a prescindere dalla classe di problemi che si sta cercando di risolvere. Nell'ambito del MKP, si cercato di fatto di adattare queste tecniche generali nel contesto del problema di riferimento integrandole con le informazioni contenute nel suo modello. Non lo scopo di questa sede procedere in una trattazione esaustiva di tutti gli algoritmi euristici sviluppati per risolvere il MKP. Si tenga presente infatti che la dicolt nel risolvere in modo esatto questa categoria di problemi ha spinto la ricerca degli ultimi decenni nella direzione euristica e di fatto gli approcci risolutivi proposti in quest'ottica sono molti, ognuno con i propri pregi e i propri difetti. Di seguito verranno descritti sinteticamente quelli che a nostro avviso sono gli algoritmi di maggior portata, sia per la qualit dei risultati ottenuti sia per le idee introdotte, che hanno contribuito o possono contribuire a nuove strade di ricerca. In particolare ci soermeremo sulle seguenti classi di algoritmi euristici:

algoritmi di tipo greedy; metaeuristiche; algoritmi euristici basati sul rilassamento continuo.

2.3.1 Algoritmi greedy


Gli algoritmi greedy (o algoritmi euristici costruttivi) si basano sulla semplice idea di costruire dinamicamente una soluzione ammissibile aggiungendo un'oerta alla volta all'allocazione no a quando i vincoli non vengono violati. La dierenza sostanziale tra i vari algoritmi greedy riguarda il modo in cui le oerte vengono ordinate, criterio questo da cui dipende la selezione delle oerte da inserire nella soluzione. Nonostante questi algoritmi nascano nel contesto dello zaino unidimensionale, possono essere applicati anche al caso multidimensionale sebbene con uno sforzo maggiore nel trovare

CAPITOLO 2.

STATO DELL'ARTE

24

un'ecace funzione di ordinamento delle oerte, attivit questa non banale considerando i diversi parametri in gioco (prezzi delle oerte nella funzione obiettivo e costi delle stesse per ogni vincolo del problema). Dobson [12] ha proposto un ordinamento secondo la funzione:

ej =

pj m i=1 wij

(2.9)

Senju e Toyoda [36] propongono invece un ordinamento che tiene in considerazione anche delle capacit dei vincoli:

ej =

pj
m i=1

wij

n j=1

wij ci

(2.10)

Kellerer et al.

[25] hanno formulato una funzione di ecienza generica tramite

l'utilizzo di un coeciente di rilevanza

ri , i (1, ..., m): pj m i=1 ri wij


(2.11)

ej =
I coecienti

ri

possono essere visti come una sorta di moltiplicatori surrogati, come Si noti che ponendo

riportato in uno studio di Pirkul [31].

ri =

n j=1

wij ci

si

ottiene la relazione ( 2.10 ). Freville e Plateau [15] suggeriscono i seguenti valori dei coecienti

ri : ri =
n j=1 wij ci n j=1 wij
(2.12)

Gli algoritmi greedy, a prescindere dalla funzione di ordinamento delle oerte su cui si basano, sono molto inecaci in quanto la soluzione trovata con essi ben lontana da essere quella ottima, soprattutto per istanze complesse. Tuttavia, considerando l'ecienza del meccanismo risolutivo che permette di determinare una soluzione ammissibile in tempi polinomiali, gli algoritmi greedy vengono generalmente utilizzati come punto di partenza di approcci pi complessi che necessitano di un lower bound iniziale e di un sistema ecace di ordinamento delle variabili.

CAPITOLO 2.

STATO DELL'ARTE

25

2.3.2 Metaeuristiche
Per metaeuristica si intende una qualunque tecnica basata sulla Ricerca Locale in grado di partire da una soluzione ammissibile non vuota e di migliorarla iterativamente eettuando semplici modiche (o mosse) della soluzione corrente. L'algoritmo termina quando non esistono pi modiche in grado di migliorare la soluzione corrente. A dierenza dei semplici algoritmi di Local Search, le tecnice metaeuristiche utilizzano speciali meccanismi per uscire dai minimi locali incontrati e per evitare il vericarsi di cicli nell'evoluzione dell'algoritmo. In letteratura esistono molte tecniche metaeuristiche consolidate. Nell'ambito

del Multidimensional Knapsack Problem molti autori hanno adattato algoritmi gi esistenti introducendo nuovi aspetti per l'analisi del vicinato delle soluzioni in modo da tagliare buona parte dello spazio di ammissibilit del problema.

Algoritmi genetici

Gli algoritmi genetici prendono spunto dal processo evoluDurante il corso dell'evoluzione le

zionistico degli organismi biologici in natura.

popolazioni evolvono secondo dei principi di selezione naturale in cui gli individui che meglio si adattano al loro ambiente hanno maggiori possibilit di sopravvivere e riprodursi rispetto agli altri. Nel contesto di un problema di ottimizzazione, gli

individui di una popolazione vengono codicati in una stringa di cromosomi che rappresenta una possibile soluzione del problema. Vengono poi utilizzate delle funzioni per valutare la robustezza genetica dei vari individui secondo dierenti criteri. Agli individui ritenuti pi forti geneticamente vengono applicate delle procedure di

crossover attraverso le quali pezzi di cromosomi vengono alterati creando nuovi individui che possono integrarsi o sostituirsi alla popolazione attuale. Questo processo di valutazione-selezione-riproduzione viene iterato no a quando non viene trovata una soluzione che soddisfa opportuni criteri. genetico sono qui di seguito elencati: 1. Generazione di una popolazione iniziale; 2. Valutazione della robustezza genetica degli individui nella popolazione; 3. Selezione di due o pi genitori dalla popolazione; 4. Ricombinazione delle informazioni genetiche dei genitori per generare i gli; 5. Valutazione della robustezza genetica dei gli; I passi principali di un algoritmo

CAPITOLO 2.

STATO DELL'ARTE

26

6. Sostituzione della popolazione ( tutta o una sua parte ) con i gli generati; 7. Se non si ottiene una soluzione che soddisfa opportuni criteri, tornare al passo 3. P.C. Chu e J.E. Beasley[9] hanno sviluppato un algoritmo genetico per il Multidimen-

sional Knapsack Problem basandosi sul meccanismo risolutivo descritto in precedenza e denendo nel dettaglio le strategie di valutazione, selezione e riproduzione degli individui utilizzando le informazioni contenute nel modello del problema. Il generico individuo viene rappresentato come un vettore in

S [j]

posto a 1 o a 0 a seconda se l'oerta

S di n bits. Il j esima del

valore contenuto problema con-

tenuta o meno nella soluzione. Gli individui vengono valutati secondo una funzione

f (S) =

n j=1

pj S [j]

che tiene in considerazione i prezzi delle oerte del problema. I

gli vengono generati sia attraverso processi di mutazione in cui vengono alterati i bits di un unico genitore, sia attraverso operatori di crossover che combinano i bits di due genitori per generare un unico glio. I gli generati attraverso le procedure di mutazione e di crossover possono corrispondere a soluzioni che non soddisfano tutti i vincoli del problema. Per garantirne l'ammissibilit, i gli vengono sottoposti a Un algoritmo

operatori di riparazione basati su semplici algoritmi di tipo greedy.

greedy viene utilizzato anche per generare la popolazione iniziale costituita da 100 unit suddivise in due gruppi. Il processo di selezione dei genitori per la creazione dei nuovi individui viene attivato su entrambi i gruppi in base alla funzione di valutazione della robustezza genetica

f (S) .

I nuovi individui vanno a sostituire i meno

promettenti tra quelli gi esistenti (sempre secondo la funzione

f (S))

in modo che

ogni popolazione non ecceda mai le 100 unit. Per una pi approfondita trattazione dell'algoritmo proposto da P.C. Chu e J.E. Beasley si rimanda a [9]. L'algoritmo proposto da P.C. Chu e J.E. Beasley stato testato sulle 270 istanze da loro generate, ottenendo risultati di elevata qualit. Allo stato dell'arte attuale, nonostante in 10 anni siano stati evidenziati progessi nella ricerca nell'ambito del

MKP, l'algoritmo genetico da loro progettato ancora uno di quelli che permette di
ottenere le soluzioni migliori anche in relazione al tempo necessario per ottenerle. Recentemente Puchinger, Raild e Gruber [34] hanno sviluppato un approccio ibrido in cui un algoritmo genetico e un risolutore general purpouse per problemi lineari interi basato su Branch and Cut vengono eseguiti in parallelo scambiandosi continuamente informazioni in modo sincrono e bidirezionale. L'algoritmo consta di due parti fondamentali: la procedura genetica vera e propria (AG ) e il framework

CAPITOLO 2.

STATO DELL'ARTE

27

Branch and Cut (B&C ). AG non si discosta molto dal lavoro svolto da P.C. Chu e J.E. Beasley seppur con dei miglioramenti per quanto riguarda la generazione della popolazione iniziale e la valutazione della robustezza genetica degli individui. Il

framework B&C utilizza CPLEX come risolutore per problemi di programmazione lineare intera a cui vengono aggiunti ulteriori tagli per ridurre lo spazio di ricerca della soluzione ottima. Puchinger et al. hanno osservato, analizzando le istanze di P.C. Chu e J.E. Beasley per le quali era nota la soluzione ottima, che la distanza di

Hamming tra la soluzione ottima stessa

e la soluzione

xRLP = xLP 0.5 j j

con

xLP

soluzione del rilassato continuo, quasi sempre pi piccola del 10% del numero

totale di variabili del problema. Alla luce di questa considerazione empirica stato generato un nuovo taglio da applicare al framework B&C del tipo:

x, xRLP =
jS LP

(1 xj ) +
j S LP /

xj k

con

la distanza di Hamming massima desiderata e

S LP = j = 1, ..., n |xLP = 1 j

I due algoritmi vengono eseguiti in parallelo in modo che possano scambiarsi le informazioni che serviranno poi per orientare la ricerca in opportune direzioni dello spazio delle soluzioni. In particolare se AG trova una soluzione migliore di quella attuale, questa viene utilizzata per incrementare il valore del lower bound utilizzato nel framework B&C. Nel caso sia il framework B&C a determinare una soluzione migliore questa viene aggiunta nella popolazione analizzata da AG e i valori della soluzione duale vengono utilizzati nella funzione di ordinamento delle variabili su cui si basa la riparazione delle soluzioni glie generate non ammissibili. I risultati ottenuti da Puchinger et al. sono stati ricavati applicando diverse

strategie di combinazione dei due algoritmi, a seconda di quante informazioni venivano scambiate nell'esecuzione parallela dei due processi. In generale si osserva un miglioramento complessivo della qualit delle soluzioni che rendono questo approccio ibrido una delle migliori strategie risolutive, ottenendo soluzioni di alta qualit in tempi molto brevi sulle istanze complesse di P.C. Chu e J.E. Beasley.

Tabu Search

La tecnica del Tabu Search stata proposta da Fred Glover [18],

[19] nel 1989 per far fronte al problema principale dei classici metodi di ricerca locale relativo all'arresto dell'algoritmo qualora nel vicinato della soluzione corrente non esista una soluzione migliore, cadendo appunto in quelli che comunemente vengono

CAPITOLO 2.

STATO DELL'ARTE

28

deniti minimi (o massimi) locali. L'idea principale su cui si basa il Tabu Search quella di consentire delle mosse peggioranti proibendo le ultime mosse eseguite (tabu ) nel cammino di ricerca, in modo che l'algoritmo non ricada subito nel minimo locale. Caratteristica basilare

di ogni algoritmo di Tabu Search quindi il sistematico utilizzo della memoria nel senso che, per aumentare l'ecacia del processo di ricerca, viene tenuta traccia nella

tabu list non solo delle informazioni locali (come il valore corrente della funzione
obiettivo) ma anche di informazioni aggiuntive relative all'itinerario percorso. Tali informazioni vengono impiegate per guidare la mossa dalla soluzione corrente alla soluzione successiva, da scegliersi all'interno del vicinato. Esiste una vastissima letteratura dedicata all'argomento, in quanto il Tabu Search rappresenta la procedura euristica pi diusa per risolvere una moltitudine di problemi, sia per l'ecacia dei risultati trovati, sia per la semplicit di implementazione della tecnica. La ricerca nel campo del Tabu Search per risolvere il Multidimensional Knapsack

Problem inizia con il lavoro di Dammayer e Voss [10] in cui sono state comparate diverse strategie statiche e dinamiche per gestire la tabu list. In particolare sono stati ottenuti interessanti risultati utilizzando una versione dinamica del Tabu Search, chiamato Reverse Elimination Method [11]. Recenti estensioni al metodo introdotto da Dammeyer e Voss sono state presentate da Hana e Freville [23] che hanno proposto nuove regole dinamiche di intensicazione e diversicazione nell'applicazione delle mosse. Indubbiamente i migliori risultati sono stati ottenuti combinando il Tabu Search classico con la programmazione lineare intera. Per esempio, Glover e Kochenberger [46] hanno proposto una schema oscillatorio di navigazione del vicinato della soluzione corrente alternando fasi costruttive e distruttive nell'alterazione della soluzione, il tutto guidato da informazioni ottenute dai vincoli surrogati e dalle variabili duali del problema. Il loro lavoro stato testato sia sulle istanze di P.C. Chu e J.E. Beasley, sia su un set di problemi complessi da loro generati (no a

n = 500

m = 25)

ottenendo risultati di alta qualit. Nel 2001 Vasquez e Hao [38] hanno pre-

sentato un'altra tecnica ibrida costruendo un set di soluzioni ammissibili partendo dal rilassato continuo risolto con un vincolo addizionale di cardinalit

n j=1

xj = k .

Lo stesso vincolo viene utilizzato anche per ridurre il vicinato della soluzione corrente, visitato attraverso una versione modicata della Reactive Tabu Search proposta da Battiti e Tecchiolli [5] che utilizza due tipologie distinte di tabu list.

CAPITOLO 2.

STATO DELL'ARTE

29

Nel 2005 Vasquez [39], in collaborazione con Vimont, ha ripreso il lavoro iniziato con Hao introducendo dei miglioramenti nella gestione della tabu list e risolvendo le istanze di test proposte da P.C. Chu e J.E. Beasley e da Glover e Kochenberger, applicando l'algoritmo per un numero molto elevato di iterazioni. Al tempo di stesura di questo lavoro di tesi, le migliori soluzioni note per i principali problemi di benchmark in letteratura sono state trovate con i metodi di Vasquez e Hao [38] e di Vasquez e Vimont [39]. L'aspetto negativo di tutti i metodi basati su Tabu Search, come evidenziato anche dagli stessi Vasquez, Hao e Vimont nelle loro ricerche, l'inecienza nella risoluzione di problemi con un numero di variabili elevato (n

> 500)

in quanto il

vicinato delle soluzioni cresce esponenzialmente ed estremamente dicile poterlo valutare completamente in tempi accettabili.

Simulated Annealing, Reti Neurali e RGVNS

Esistono altre tecniche meta-

euristiche che sono state studiate nell'ambito del Multidimensional Knapsack Prob-

lem. Nonostante alcuni risultati potevano considerarsi interessanti ai tempi in cui


sono stati trovati, attualmente la ricerca tutta direzionata verso il Tabu Search e gli algoritmi genetici considerati i continui ranamenti delle tecniche appena citate. Il simulated annealing una metaeuristica che consente di portare lo stato di un sistema al valore minimo di qualche genere di funzione di valutazione. Anche

per il simulated annealing necessario scegliere se, a partire da uno stato corrente

s,

spostarsi verso lo stato

s1

piuttosto che

s2 .

Questa tecnica permette anche di

correggere le transazioni tra gli stati attraverso opportune procedure di backtracking. Il primo tentativo di utilizzo del simulated annealing nell'ambito del MKP lo si deve a Drexl [13] che ha introdotto uno speciale movimento casuale tra stati in modo da garantire l'ammissibilit di tutte le soluzioni generate durante il processo. Battiti

e Tecchiolli [6] hanno introdotto una funzione di penalit per trasformare il MKP in un problema non vincolato, ottenendo risultati comunque peggiori rispetto ad approcci basati su Tabu Search. Dueck e Scheuer [14] hanno invece proposto una

versione deterministica del simulated annealing, chiamata threshold accepting, che ha migliorato i risultati ottenuti da Drexl. Le reti neurali si basano principalmente sulla simulazione di neuroni articiali opportunamente collegati, i quali ricevono in ingresso dei segnali e li elaborano. Solitamente le reti neurali vengono progettate per approssimare algoritmi molto complessi ottenendo risultati simili ma in tempi di elaborazione molto inferiori. La ricerca

CAPITOLO 2.

STATO DELL'ARTE

30

sulle reti neurali nell'ambito del MKP si limita ai tentativi proposti da Battiti e Tecchiolli in [6] e Ohlssen et al. in [26], incontrando enormi dicolt nel mantenere ammissibile la soluzione in uscita dalla rete neurale. Gli studi volti a determinare l'ecacia delle tecniche di simulated annealing e reti neurali nel contesto del Multidimensional Knapsack Problem sono molto datati rispetto a Tabu Search e algoritmi genetici. Uno studio invece molto recente e

di grande impatto per la ricerca dei prossimi anni stato pubblicato nel 2006 da Puchinger e Raidl [33]. L'idea quella di studiare una porzione ridotta ma signicativa del problema di partenza denendone un Core a cui applicare una procedura

RGVNS (Relaxation Guided Variable Neighborhood Search ) per modicarlo dinamicamente. Nonostante la ricerca in questa direzione sia ancora agli albori, Puchinger e Raild hanno dimostrato che si possono ottenere risultati interessanti che possono competere con le pi consolidate tecniche metaeuristiche basate su Tabu Search.

2.3.3 Algoritmi euristici basati sul rilassamento continuo


Si tratta di algoritmi che sfruttano le informazioni del modello matematico del Mul-

tidimensional Knapsack Problem ottenuto eliminando i vincoli di interezza delle


variabili. Un'euristica semplice e veloce stata proposta da Bertsimas e Demir [7] nell'ambito dell'algoritmo ADP da loro implementato. L'euristica divisa in due parti ed ha l'obiettivo di trovare una soluzione ammissibile

xH .

La prima parte risolve il rilassamento continuo del problema e pone:

xH j
dove

1 = 0

se se

xLP = 1 j LP xj < [0, 1].

(2.13)

xLP

la soluzione del rilassato continuo e

La seconda parte invece risolve il rilassamento continuo del sottoproblema composto dalle variabili

xH j

non denite nella prima parte, vale a dire quelle per cui

xLP < 1. j

In particolare si pone:

1 se xLP = 1 j H xj = 0 se xLP = 0 j 0 se j = argmin xLP | 0 < xLP < 1 k k

(2.14)

CAPITOLO 2.

STATO DELL'ARTE

31

L'ultima assegnazione garantisce che almeno una variabile sia posta a 0 (quella con il valore frazionario minore nella soluzione del rilassamento continuo). Questa seconda parte iterata no a quando le variabili sono tutte poste a 0 o a 1. Pi basso il valore di

, migliore la soluzione e maggiore il tempo di computazione. Gli autori propongono = 0.25. Si noti che = 1 equivalente al calcolo del rilassamento
continuo arrotondato al numero intero inferiore. Questa euristica migliore di tutti gli algoritmi greedy. Un'euristica molto citata in letteratura quella dovuta a Balas e Martin [2]. L'idea principale si basa sul fatto che in ogni soluzione ammissibile di base del rilassamento continuo ci sono variabili originali

variabili non in base.

Se queste corrispondono alle

x1 , ..., xn

o alle variabili di slack che rappresentano il gap

1 xj

la

soluzione intera. Quindi una buona soluzione pu essere trovata mettendo in base pi variabili di slack possibili. In generale le euristiche basate sul rilassamento continuo, pur essendo estremamente veloci, non permettono di ottenere soluzioni di buona qualit quanto quelle ottenute dalle tecniche metaeuristiche precedentemente descritte. Solitamente un

euristica di base come quelle presentate in questo paragrafo determina un set di soluzioni ammissibili di buona qualit da cui partire per esplorare lo spazio adiacente attraverso strategie di ricerca locale avanzata.

2.4

ILOG CPLEX

ILOG CPLEX un risolutore di problemi di programmazione di tre categorie:

lineare quadratica lineare intera

La versione 10.0 del software (commercializzata nel 2005) in grado di risolvere in tempi ragionevoli istanze generate in qualunque modo del Multidimensional Knap-

sack Problem. ILOG CPLEX si appoggia su un potente framework Branch and Cut
altamente personalizzabile in cui sono implementati ecientemente pi di 50 tipologie di tagli. Sebbene ILOG CPLEX non sia nato per risolvere alcuna specica classe di problemi, rappresenta attualmente la metodologia pi eciente per risolvere in

CAPITOLO 2.

STATO DELL'ARTE

32

modo esatto le istanze del MKP, fornendo soluzioni ottime anche per problemi di medie dimensioni in tempi anche migliori delle pi sosticate euristiche. Per le istanze complesse (n

> 250

m > 5)

anche ILOG CPLEX risulta tuttavia essere

ineciente ed preferibile utilizzare un'altro strumento che adotta un'approccio di tipo euristico alla loro risoluzione. Per una trattazione completa del software CPLEX 10.0 si rimanda alla guida [42].

Capitolo

3
1

Il nostro algoritmo
Nel presente capitolo verr descritto l'algoritmo sviluppato per risolvere il Multidi-

mensional Knapsack Problem. Tale algoritmo stato pensato per risolvere in modo
esatto il problema . Nonostante questo, sono state apportate delle semplici varianti per poter utilizzare il software come una vera e propria euristica in grado di fornire delle soluzioni molto buone per istanze particolarmente complesse, non risolvibili all'ottimo in tempi accettabili. L'idea sui cui basa il nostro algoritmo molto semplice e pu essere riassunta nella risoluzione iterativa di problemi di dimensioni sempre maggiori ma pi facili da riformulare. In altre parole, anche se il numero delle variabili presenti nel problema cresce, aumenta anche la facilit con cui queste possono essere ssate al loro valore binario (0 piuttosto che 1).

3.1

Il concetto di Core del Multidimensional Knapsack Problem

Prima di descrivere in modo dettagliato il funzionamento dell'algoritmo doveroso denire il concetto di Core del Multidimensional Knapsack Problem poich una sua variante costituir una parte saliente di tutto il meccanismo di risoluzione del problema. Il concetto di Core stato presentato inizialmente nel contesto dello 0/1

Knapsack Problem a singolo bene da Balas e Zemel [1] e ampliato da Pisinger [32]. L'obiettivo principale quello di ridurre il problema originale considerando solo

1 Un algoritmo si denisce esatto se in grado di trovare la soluzione ottima al problema che sta
risolvendo.

33

CAPITOLO 3.

IL NOSTRO ALGORITMO

34

un nucleo di oerte per le quali sia dicile valutare la loro presenza all'interno di una soluzione ottima, mentre tutte le altre oerte non presenti nel Core sono state opportunamente ssate a 1 o a 0. La costruzione del Core dipende dalla scelta di una funzione di valutazione dell'ecacia delle oerte che permette di decidere se una data variabile possa essere ssata a 1, a 0 o in alternativa entrar a far parte delle oerte non valorizzate (ossia facenti parte del Core). Il Core rappresenta di

conseguenza un vero e proprio mini-problema che pu essere risolto molto facilmente grazie alla sua dimensione notevolmente ridotta rispetto al problema di partenza. Puchinger et al. [33] hanno esteso il concetto di Knapsack Core al caso multidimensionale valutando i risultati ottenuti utilizzando dierenti funzioni per determinare l'ecacia delle oerte, tra cui quelle di Senju e Toyoda (2.10) , Kellerer at al. (2.11) , Freville e Plateau (2.12). Hanno inoltre proposto una metodologia basata su dierenti metaeuristiche per modicare la dimensione del Core, aumentando la essibilit del meccanismo che altrimenti non avrebbe permesso ad alcuna variabile esterna al Core di assumere un valore diverso da quello a cui stata ssata. Per una maggiore trattazione sulle tecniche utilizzate da Puchinger et al. e i relativi risultati su istanze benchmark si rimanda a [33]. Il nostro algoritmo riprende l'idea del Core dierenziandosi tuttavia dagli autori precedenti per diversi aspetti. Senza perdere di generalit deniamo ecacia,

la funzione di

ej

il valore di tale funzione associato all'oerta

al di sopra del quale la variabile

xj

assume valore 1 e

j , emax il valore dell'ecacia emin il valore al di sotto del


2
del problema nei

quale assume valore 0. Ordinando le oerte in modo decrescente rispetto al valore di

possibile partizionare l'insieme

degli indici delle variabili

3 sottoinsiemi:

N1 = {j N | ej emax } N0 = {j N | ej emin } Ncore = {j N | emin < ej < emax }


Le oerte in (3.1)

N1

vengono ssate a 1, le oerte in

N0

vengono ssate a 0 mentre

2 Per garantire maggiore essibilit nell'utilizzo delle notazioni seguenti si scelto di inserire
all'interno di

gli indici

delle variabili con

j = 1, ..., n.

Tali indici rappresentano le oerte ( o

gli items ) del problema . Ogni volta che si fa riferimento ad un'oerta sottointende un'oerta la cui variabile

settata a 1 ( o a 0 ) si

xj

assume valore 1 ( o 0 ).

CAPITOLO 3.

IL NOSTRO ALGORITMO

35

quelle contenute in

Ncore

costituiscono il core del problema.

Come stato fatto

notare in precedenza, al Core associato un Multidimensional Knapsack Problem di ridotte dimensioni, con la seguente formulazione:

max
jNcore

pj xj

wij xj ci
jNcore jN1

wij i = 1, ..., m

(3.2)

xj {0, 1} j Ncore
Sia ora noto un algoritmo in grado di risolvere il problema denito in (3.2). Il valore della funzione obiettivo (z ) del problema di partenza ottenuto semplicemente sommando i prezzi delle oerte contenute in a 1 dopo la risoluzione del problema core:

N1

e quelli delle oerte in

Ncore

settate

z=
jN1

pj +
jNcore

pj x j

(3.3)

Supponiamo che nella soluzione ottima del problema ci sia un'oerta settata a 0 ma che appartiene a

N1 o un'oerta settata a 1 ma che appartiene a N0 .

Risulta piut-

tosto evidente che il valore della funzione obiettivo cos come calcolato in (3.3) non sar mai uguale all'ottimo. E' necessario di conseguenza pensare ad un meccanismo che permetta di modicare il valore delle variabili associate alle oerte contenute nel Core. Infatti la funzione di ecacia rappresenta solamente una stima della probabilit che una variabile possa essere settata ad un certo valore ma, per quanto buona possa essere, non vi alcuna garanzia che tale valore sia proprio quello assunto dalla variabile nella soluzione ottima. Si prenda l'oerta appartenente a nel Core e la si identichi con

N1

o a

N0

che sia pi promettente ad entrare

. j

Il signicato di promettente piuttosto relativo.

Anch la trattazione non perda di concretezza si denisca

0 (j) = |emin ej |. Sia j1 tale che 0 (j0 ) = min {0 (j) | j N0 }. Pi il valore dell'ecacia ej di un'oerta j

1 (j) = |emax ej | e 1 (j1 ) = min {1 (j) | j N1 } e j0 tale che


contenuta in

N1

si discosta da

emax

maggiore la probabilit che tale oerta sia eettivamente settata a 1 anche nella

CAPITOLO 3.

IL NOSTRO ALGORITMO

36

soluzione ottima. Viceversa, se la dierenza tra

ej

emax

molto piccola, la variabile

xj

viene settata a 1 con probabilit alquanto bassa a tal punto che, scegliendo un

valore leggermente pi alto di

emax , j
e

passarebbe dall'insieme

N1

all'insieme

Considerazioni analoghe possono essere applicate anche alle oerte contenute Di conseguenza le funzioni

Ncore . in N0 .

forniscono una buona valutazione di quanto

un'oerta, rispettivamente appartente inizialmente a entrare a far parte del Core. Per denizione,

N1

e a

N0 ,

sia promettente per

j1 e j0 sono rispettivamente le oerte settate a 1 e a 0 con maggiori


pi piccolo. Una volta determinata

probabilit di entrare nel Core. Tra le due, viene scelta ovviamente l'oerta con il valore di

viene modicata nel modo seguente (supponendo che

, la partizione j = j1 ): j

delle oerte

N1 = N1 \ {j1 } N0 = N0 Ncore = Ncore {j1 }


Il problema core ora denito sull'insieme (3.4)

Ncore

che contiene un'oerta in pi

rispetto al problema (3.2). Il valore della funzione obiettivo del problema di partenza sar data da:

z =
jN1
Se

pj +
jNcore

pj x j j

(3.5)

z > z

evidente che la valutazione iniziale secondo cui l'oerta

doveva

essere esclusa dal Core risulta errata in quanto inserendo tale oerta all'interno del Core si ottiene una soluzione del problema originale migliore di quella ottenuta con un core ridotto. La dicolt principale resta nel capire quali oerte debbano essere inserite nel Core. Iterare il procedimento che porta di volta in volta a scegliere un'oerta da

includere nel Core non una soluzione fattibile in quanto prima o poi il Core avrebbe una dimensione tale da rendere il problema ad esso associato troppo dicile da risolvere. Il nostro algoritmo utilizza un approccio leggermente diverso che evita la creazione della partizione riportata in (3.4). Supponiamo che inserire

= j1 N 1 . j

Anzich

in

Ncore ,

si setta il valore di

x j

a 0 in modo che siano

CAPITOLO 3.

IL NOSTRO ALGORITMO

37

N1 = N1 \ {j1 } N0 = N0 {j1 } Ncore = Ncore


e si risolve il problema core denito su non sia cambiato (Ncore (3.6)

Ncore .

Si tenga presente che nonostante il Core

= Ncore ),

il problema da risolvere diverso da (3.2) poich Si calcoli il valore

N1 = N1

e di conseguenza le capacit dei vincoli sono variate.

della funzione obiettivo del problema originale come descritto in (3.5). A seconda di tale valore, ci si imbatte in uno dei seguenti casi:

1.

z < z:
con

ssando il valore di

x a 0, il valore della funzione obiettivo del problema j

originale diminuisce. Non necessario valutare come si comporta il problema

x = 1 perch la partizione delle variabili coinciderebbe con (3.1) e il valore j risultante sarebbe appunto pari a z .
2.

z z:

ssando il valore di

x j

a 0, il valore della funzione obiettivo del proNon possibile stabilire a

blema originale aumenta o al pi rimane uguale. priori se, nella soluzione ottima,

x j

assuma proprio il valore 0, in quanto tale

risultato stato ottenuto partendo dall'ipotesi che tutte le oerte contenute in

N1

assumano valore 1 e tutte quelle contenute in

N0

assumano valore 0, cosa

che non aatto dimostrata. Il risultato tuttavia non da scartare in quanto contribuisce ad aumentare (nel caso

z > z)

il lower bound del problema. In

questo caso salviamo il valore appena trovato (LB

=z

), altrimenti si ha che

LB = z .
Iteriamo ora il processo di scelta dell'oerta pi promettente ad entrare nel Core come descritto in precedenza. Identichiamo tale oerta come notare che, prima di procedere con questo passaggio, senza tuttavia risolvere alcun problema associato.

j2 .

E' doveroso far

j1

viene aggiunta al Core,

Questa operazione necessaria

in quanto, se cos non fosse, banalmente si avrebbe che

j1 = j2 .

Supponiamo che

j 2 N0

e che il valore di

xj2

sia dunque settato a 0. Costruiamo la partizione degli

indici delle variabili del problema nel seguente modo:

CAPITOLO 3.

IL NOSTRO ALGORITMO

38

N1 N0

= N1 {j2 } = N0 \ {j1 , j2 }
(3.7)

Ncore = Ncore {j1 }


con

N1

N0

deniti in (3.6).

L'oerta

j1

viene inserita all'interno del Core che quindi incrementa di uno la

propria dimensione rispetto al Core di partenza. Come nel caso precedente, l'oerta

j2

non entra a far parte subito del Core ma viene cambiato semplicemente il valore

della variabile

xj2

associata portandolo da 0 a 1 e si risolve il seguente sottoproblema:

max
jNcore

pj xj

wij xj ci
jNcore jN1

wij i = 1, ..., m

(3.8)

xj {0, 1}
Si calcola il valore della funzione obiettivo del problema originale nell'ormai solito modo:

z =
jN1
con le seguenti considerazioni:

pj +
jNcore

pj x j

(3.9)

1.

z < LB

: ssando il valore di

xj2

a 1, il valore della funzione obiettivo del

problema originale diminuisce. Non necessario valutare come si comporta il problema con

xj2 = 0

perch la partizione delle variabili coinciderebbe con :

N1 N0

= N1 = N0 \ {j1 }
(3.10)

Ncore = Ncore {j1 }


con

N1

N0

deniti in (3.6) e il valore non pu essere migliore di

LB

in quanto

se lo fosse lo avremmo trovato dalle considerazioni fatte risolvendo il problema

CAPITOLO 3.

IL NOSTRO ALGORITMO

39

core sugli insiemi in (3.6). Infatti, in base alla partizione di (3.10), se

xj1 = 1, la funzione obiettivo del problema originale assume il valore z mentre se xj1 = 0 assume il valore z , il massimo dei quali coincide con il lower bound attuale. z LB
: ssando il valore di

2.

xj2

a 1, il valore della funzione obiettivo del

problema originale aumenta. Anche in questo caso possiamo solo constatare che il lower bound del problema aumenta.

Al termine di questa iterazione, in

LB

memorizzato il miglior valore possibile

della funzione obiettivo del problema originale considerando le variabili presenti in

N1 \{j2 } settate a 1 e quelle contenute in N0

settate a 0, con

N1

N0

deniti in (3.7).

Si noti come il numero di oerte libere (ossia non settate) sia maggiore di un'unit della dimensione del problema Core in quanto

j2

non vi inclusa, aspetto questo che

semplica la risoluzione dello stesso e che non contemplato in un approccio simile a quello di (3.4). Risulta ora intuitivo come l'algoritmo prosegua andando di volta in volta a selezionare un'oerta da togliere da

N0

o da

N1

e risolvere il problema core denito

sulla nuova partizione delle oerte ottenuta. Ad ogni iterazione sar suciente inserire nel Core l'oerta il cui valore stato cambiato nell'iterazione precedente e cambiare il valore dell'oerta pi promettente ad entrare nel Core (spostandola da

N0

N1

o viceversa). Alla luce di ci doveroso fare alcune considerazioni:

L' oerta che viene tolta da

N0

o da

N1

, nell'iterazione successiva va ad ag-

giungersi al core che di conseguenza cresce rendendo il problema di dicile soluzione. Questo vero sino ad un certo punto. Fermo e restando che l'algoritmo atto a risolvere il problema core non stato ancora descritto, una semplicazione nella risoluzione stata indirettamente apportata nel momento in cui un'oerta viene ssata al valore opposto a quello che la funzione di ecacia la porterebbe ad avere. E' infatti vero che, anche se le oerte contenute in

N0

e in

N1

non compaiono nel problema core, queste ne determinano la

formulazione (per esempio le oerte in

N1

assumono valore 1 e di conseguenza

le capacit dei vincoli del problema diminuiscono di un valore pari al costo di tali oerte nel vincolo). Qualora si forzasse un'oerta a spostarsi da o viceversa, il problema core diventa pi facile da risolvere.

N0

N1

Per valorizzare

l'importanza di questa aermazione prendiamo in considerazione il problema core ottenuto dopo un numero

di iterazioni del processo di espansione dello

CAPITOLO 3.

IL NOSTRO ALGORITMO

40

stesso. Sia e

LB k

il lower bound del problema originale sin qui trovato,

k k N 1 , N0

k Ncore

le classi di partizione delle oerte e si identichi con

k LBcore

il lower

bound del problema core, ottenuto come:

k LBcore = LB k
k jN1

pj

(3.11)

L'algoritmo in grado di risolvere il problema core non ha come obiettivo quello di fornire la soluzione ottima (come allocazione di oerte) del suddetto problema ma esclusivamente quello di dire se la funzione obiettivo del problema core all'ottimo abbia un valore maggiore di va, questo valore (che indichiamo con

k LBcore .

Se la risposta aermati-

k core ) viene calcolato e utilizzato per

migliorare il lower bound del problema di partenza che sar logicamente uguale a:

LB k = z k + core
k jN1

pj

(3.12)

Di fatto la risoluzione del problema core non ne a se stessa ma al problema originale. Calcolare sempre e comunque l'allocazione ottima delle oerte per il problema core e solo in seguito vericare che tali oerte, unite a quelle presenti in

k N1

, diano un valore della funzione obiettivo maggiore di

LB k

un'oper-

azione tanto dispendiosa quanto superua. Se per esempio l'oerta

contenuta in

k N1

(e quindi teoricamente ssata a 1)

k viene valorizzata a 0, il valore di LBcore (3.11) aumenterebbe e di conseguenza


pi dicile che esista un'allocazione delle oerte del problema core che dia un valore maggiore di

k LBcore .

O in altre parole, pi facile che parte dello

spazio di ricerca della soluzione ottima del problema core venga tagliato in quanto non in grado di fornire un valore maggiore di

k LBcore

riducendo pertan-

to il tempo di risoluzione del problema stesso. Questo approccio dipendente dal lower bound di partenza verr sicuramente compreso meglio quando verr

3 Ogni qualvolta abbiamo a che fare con un problema


di partenza

Ph

ottenuto dalla riduzione del problema

associamo ad esso un lower bound

LBh

il cui signicato leggermente diverso dalla

denizione classica. In questo contesto si intende infatti un valore al di sotto del quale l'ottimo di sia superiore a

Ph

non dovrebbe mai stare ma senza alcuna garanzia che questo accada realmente. Nel caso l'ottimo

LBh ,

quest'ultimo a tutti gli eetti un lower bound. Qualora si dimostrasse, senza

necessit di trovarlo, che l'ottimo sia invece inferiore a upper bound. Alla quantit sia un lower bound di

LBh ,

associata al problema

bound in quanto, anch il lower bound del problema

LBh , quest'ultimo diverrebbe di fatto un P h , si dato il nome improprio di lower originale P migliori, necessario che LBh

P h.

CAPITOLO 3.

IL NOSTRO ALGORITMO

41

presentato in dettaglio l'algoritmo di risoluzione del problema core.

L'approccio sin qui descritto molto utile per calcolare un lower bound sempre migliore che, terminato l'algoritmo, coincide con l'ottimo del problema originale. Risulta evidente che la costruzione del core non casuale e che pertanto, all'ottimo, la maggior parte delle oerte inizialmente inserite in 1 e la maggior parte di quelle collocate in

N1 abbia valore

N0

abbia valore 0. Di conseguenza

gi il lower bound calcolato alla prima iterazione (quando cio il core non stato ancora espanso) risulta di qualit molto buona e, a seconda dell'istanza da risolvere, persino coincidente con l'ottimo. Supponiamo che esista un

criterio di terminazione dell'algoritmo di espansione dierente dal caso in cui

N1 = , N0 = e Ncore = N . In particolare sia elim il valore tale per cui se 1 (j) > elim e j N1 allora nella soluzione ottima del problema di partenza si ha (con certezza) che xj = 1, mentre se 0 (j) > elim e j N0 allora si ha che xj = 0. Sia k l'iterazione per cui la variabile xh il cui valore deve essere k permutato abbia un valore di ecienza tale per cui 1 (h) > elim se h N1 k o 0 (h) > elim se h N0 . E' inutile proseguire nella permutazione del suo valore in quanto il valore di xh all'ottimo gi noto alla luce del criterio sopra k k enunciato ( sar 0 o 1 a seconda che h N0 o che h N1 ). Allora si pu facilk mente dimostrare come LB coincida con l'ottimo del problema di partenza. k Infatti LB il miglior valore della funzione obiettivo del problema originale k supponendo che tutte le oerte contenute in N1 siano settate a 1 e tutte quelle k contenute in N0 siano settate a 0. Indichiamo con (j) il valore di 1 (j) se k k j N1 o di 0 (j) se j N0 . Considerando che le oerte vengono di volta in k k volta tolte da N1 e da N0 in ordine crescente rispetto a , se (h) > elim k k allora vero anche che (j) > elim , j N1 N0 . Quindi all'ottimo xj = 1 k k k se j N1 e xj = 0 se j N0 . Ne consegue che LB = z , valore ottimo del
problema originale.

3.2

Creazione ed espansione del Core

Nel paragrafo 3.1 si introdotto il meccanismo che sta alla base del funzionamento del nostro algoritmo senza minimamente entrare in dettaglio nei suoi aspetti principali. In questo paragrafo verr ampiamente descritto tutto ci che in precedenza stato introdotto in modo molto generale, vale a dire la funzione di valutazione dell'ecacia

CAPITOLO 3.

IL NOSTRO ALGORITMO

42

delle variabili e il criterio di terminazione dell'espansione del Core.

L'algoritmo

iterativo che ne deriva verr denominato con la sigla EC (acronimo che sta per Espansione del Core).

3.2.1 Valutazione dell'ecacia delle variabili


Si detto che le oerte vengono ordinate secondo un valore di ecacia ad esse associato e in base a tale ordinamento si selezionano le oerte che entrano a far parte del Core e quelle che invece vengono direttamente settate a 1 o a 0, determinando la partizione degli indici delle variabili riportata in (3.1). Anzich fare riferimento ad una delle funzioni citate da Puchinger et al. [33], utilizzate tra l'altro in molti approcci risolutivi di tipo greedy, il nostro algoritmo sfrutta un importante risultato ottenuto da Osorio, Glover e Hammer in [28] e ampliato da Oliva, Michelon e Artigues in [27]. Osorio et al [28] hanno utilizzato tecniche basate su Constraint Pairing

e rilassa-

mento surrogato per ssare alcune variabili a zero e generare dei tagli logici in grado di ridurre lo spazio di ricerca della soluzione ottima a qualunque livello dell'albero in un algoritmo esatto di tipo branch and bound. Oliva et al [27] vanno oltre generando un taglio logico da loro denominato Reduced

Cost Constraint che, sfruttando i coecienti di costo ridotto ottenuti risolvendo


il rilassamento continuo del problema, permette di ssare direttamente un set di variabili a 0 e a 1, riducendo di fatto la dimensione del problema originale. particolare, sia In

il seguente Multidimensional Knapsack Problem :

4 Il Constraint Pairing una tecnica che permette di generare nuovi vincoli a partire da due o
pi vincoli agendo opportunamente sui membri delle disuguaglianze. seguenti vincoli di un problema Per esempio, partendo dai

P
n

cj xj
j=1 n

<

(3.13)

sj xj
j=1

>

(3.14)

sottraendo membro a membro ( 3.13 ) da ( 3.14 ) si ottiene la seguente disuguaglianza

(sj cj ) xj
j=1
che risulta essere ancora valida per

>

BA

P.

CAPITOLO 3.

IL NOSTRO ALGORITMO

43

max
j=1 n

pj xj

wij xj ci i = 1, ..., m
j=1

(3.15)

xj {0, 1} j = 1, ..., n
e

Pl

il suo rilassamento continuo, ottenuto eliminando i vincoli di interezza delle

variabili:

max
j=1

pj xj

wij xj ci i = 1, ..., m
j=1

(3.16)

0 xj 1 j = 1, ..., n
Siano che

le variabili slack di

Pl

e siano

(b, u)

i costi ridotti associati a

(x, s).

E' noto

Pl

pu essere riformulato come segue:

max U B +
jN

bj x j
jN +

bj (1 xj ) +
i=0

u i si

W x + Ss = c

(3.17)

0 xj 1 j = 1, ..., n si 0 i = 1, ..., m
con

dipendenti dalla base associata a

(x, s), U B

l'upper bound di

ottenuto

risolvendo

Pl

e:

CAPITOLO 3.

IL NOSTRO ALGORITMO

44

N = {j N | xj N + = {j N | xj

una variabile non in base al suo lower bound} una variabile non in base al suo upper bound}

Per un problema di programmazione lineare del tipo (3.16), una variabile :

non in base al suo upper bound, se assume valore 1 e ha un coeciente di costo ridotto positivo;

non in base al suo lower bound, se assume valore 0 e ha un coeciente di costo ridotto negativo;

in base, se assume valore frazionario compreso tra 0 e 1 ha un coeciente di costo ridotto nullo.

Dal punto di vista del rilassamento continuo di un Multidimensional Knapsack Prob-

lem, i coecienti di costo ridotto positivi corrispondono alle oerte contenute interamente nella soluzione continua, i coecienti nulli corrispondono alle oerte contenute parzialmente nella soluzione continua mentre i coecienti negativi corrispondono alle oerte non contenute nella soluzione continua. La relazione (3.17) ancora valida se vengono aggiunti i vincoli di interezza:

xj {0, 1} , j = 1, ..., n.

Sia nota ora una soluzione ammissibile di

con valore della

funzione obiettivo pari a

LB .

Dato che l'interesse trovarne una migliore, se esiste,

pu essere formulato il seguente vincolo:

UB +
jN
equivalente a

bj x j
jN +

bj (1 xj ) +
i=0

ui si LB

(3.18)

jN

bj x j +
jN +

bj (1 xj )
i=0

ui si U B LB

(3.19)

CAPITOLO 3.

IL NOSTRO ALGORITMO

45

Ora, ricordando che:

se

j N

allora

bj < 0

sono i costi ridotti associati alle variabili di slack di un problema lineare di

massimizzazione, quindi

u0

essendo

s0

u 0,

si ha che

m i=0

ui si 0,

e togliendo tale quantit da

(3.19) si ottiene ancora una disuguaglianza valida,

possibile riformulare il vincolo (3.19) come segue:

|bj | xj +
jN jN +

bj (1 xj ) U B LB

(3.20)

La disuguaglianza (3.20) una semplice riformulazione del risultato ottenuto da Oliva et al. (3.19) ma che assume un ruolo fondamentale in molteplici aspetti del nostro algoritmo. Tale disuguaglianza a tutti gli eetti un taglio logico in quanto, non essendo violato dalla soluzione ottima del rilassato continuo

Pl ,

non produrr alcun

miglioramento dell'upper bound se utilizzato in un algoritmo di Cutting Planes. Pu tuttavia fornire interessanti informazioni sul comportamento relativo delle variabili per quanto riguarda i valori assunti all'ottimo intero nonch permettere di ssare direttamente alcune variabili a 0 piuttosto che a 1 riducendo le dimensioni del problema. Per comodit si far riferimento alla disuguaglianza (3.20) nel corso della

trattazione con la sigla RCC (acronimo che sta per Reduced Cost Constraint ). Ora che si hanno a disposizione gli strumenti matematici necessari, possibile continuare nella presentazione di quello che sar il metodo di ordinamento delle variabili che verr utilizzato nel nostro algoritmo. Sia il suo rilassamento continuo e di

un problema di tipo MKP,

Pl

b il vettore dei coecienti di costo ridotto delle variabili

Pl .

Le variabili di

vengono ordinate in modo decrescente per il valore assoluto

del proprio coeciente di costo ridotto in modo che, senza perdere di generalit, sia:

|b1 | |b2 | .... |bj | |bj+1 | ... |bn1 | |bn |

(3.21)

Questo permetter una prima discriminazione delle oerte: quelle che vengono inserite inizialmente nel Core e quelle che invece ne sono escluse, indipendentemente dal fatto che queste ultime vengano poi ssate a 0 o a 1.

CAPITOLO 3.

IL NOSTRO ALGORITMO

46

Anzich utilizzare opportuni valori di degli indici delle variabili (3.1), l'insieme sione prestabilita pari a

emax Ncore

emin

per determinare la partizione

viene creato a partire da una dimen-

DIMcore

(per ora si supponga che sia nota a priori). In base

all'ordinamento (3.21) si inseriscono nel Core le ultime seguente partizione:

DIMcore

oerte generando la

Nf ix = {j N | j < n DIMcore + 1} Ncore = N \ Nf ix


In base al segno del coeciente di costo ridotto si ottengono gli insieme cui le variabili vengono settate, rispettivamente, a 1 e a 0:

(3.22)

N1

N0

in

N1 = {j Nf ix | bj > 0} N0 = {j Nf ix | bj < 0}
Viene in seguito risolto il problema core denito su timo con il prezzo delle oerte contenute in

(3.23)

Ncore (3.22)

e sommandone l'ot-

N1

si ottiene il lower bound iniziale del

problema di partenza e, come gi descritto in precedenza, lo si migliora permutando il valore delle variabili i cui indici sono contenuti in della variabile

N1

N0 .

Nel nostro caso la scelta

x j

il cui valore deve essere cambiato molto semplice e corrisponde a:

x j
e, se

con

b = min {|bj | | j Nf ix } j N0 j

(3.24)

N1 j

il suo valore viene portato a 0 mentre se

il suo valore viene

portato a 1. In entrambi i casi si ottiene un nuovo problema core che deve essere risolto. Il procedimento di espansione del Core non si discosta dal meccanismo

generale illustrato nel paragrafo (3.1). Si tenga presente che attribuire ai costi ridotti il metro di valutazione dell'ecacia di una variabile del tutto lecito alla luce del RCC. Tenendo presente che questo vincolo non pu essere violato da

, ci si aspetta che maggiore il costo ridotto in

modulo di una variabile e pi alta la propabilit che questa variabile venga ssata a 0, se il suo costo ridotto fortemente negativo, o a 1, se il suo costo ridotto

CAPITOLO 3.

IL NOSTRO ALGORITMO

47

fortemente positivo.

3.2.2 Criterio di terminazione dell'espansione del Core


E' stato detto che il criterio di terminazione dell'espansione del Core evita di permutare i valori di tutte le oerte contenute in del meccanismo un insieme core uguale a

Nf ix

e di avere all'ultima iterazione

N.

Questo possibile solo se la funzione di

ecacia delle variabili garantisce in modo certo che una data oerta in

Nf ix

assuma

nella soluzione ottima lo stesso valore a cui stata ssata. Nessuna funzione di tipo greedy proposta da Puchinger et al. [34] possiede questa caratteristica. Al contrario, il valore del coeciente di costo ridotto, unitamente al fatto che il RCC non deve essere violato e al modo con cui viene selezionata la successiva oerta da inserire nel Core, fornisce in modo sicuro un criterio di terminazione di espansione del Core. Prendiamo come esempio un semplice problema MKP caratterizzato dal seguente

RCC :

39.31(1 x12 ) + 22.44(1 x13 ) + 5.11 + 10.62x14 + 10.65x5 +20.47x4 + 24.36x1 + 24.41x15 + 35.73x10 + 40.89xx8 + 43.21x7 34.62
Non stata riportata la formulazione del problema perch ritenuta superua ai nostri ni. Quello che interessante evidenziare sono le importanti informazioni fornite dal

RCC. Anch il vincolo non venga violato, le variabili


a 0 mentre la variabile

x7 , x8

x10

vengono poste

x12

viene posta a 1.

E' interessante sottolineare come le

variabili settate a 0 abbiano tutti coecienti di costo ridotto negativi e inferiori a

34.62 mentre l'unica variabile settata a 1 ha un coeciente di costo ridotto positivo maggiore di 34.62. Risulta ora chiaro che se la variabile da permutare x10 il meccanismo di espansione del Core termina e il lower bound trovato a quella iterazione coincide con l'ottimo del problema originale. Infatti

x10

la variabile che, tra tutte quelle con

coeciente di costo ridotto in modulo maggiore di in modulo pi piccolo. Essendo = 10 j l'oerta in

34.62, ha il valore di costo ridotto Nf ix da permutare e ricordando il

modo con cui queste oerte vengono selezionate, facile intuire che tutte le variabili associate alle oerte contenute in

Nf ix

hanno costo ridotto in modulo maggiore di

CAPITOLO 3.

IL NOSTRO ALGORITMO

48

34.62

e di conseguenza devono essere ssate al loro valore di bound anch il RCC

non venga violato. Il risultato importante e permette di comprendere il perch il RCC non venga utilizzato subito per settare alcune variabili a 0 e a 1 e ridurre di conseguenza la dimensione del problema, proprio come proposto da Oliva et al. [27]. Come sap-

piamo, la formulazione del RCC non univoca ma dipende dal valore del lower bound trovato per il problema: maggiore il valore di

LB ,

pi forte risulta essere

il vincolo dei costi ridotti in quanto il secondo membro della disuguaglianza diventa pi piccolo. Anzich utilizzare un approccio euristico per determinare un buon lower bound e applicare il RCC per ssare opportunatamente alcune variabili, si deciso di procedere in un modo conforme all'algoritmo e rinforzare nel tempo tale vincolo ogni qual volta ci si imbatte in valori del lower bound migliori. Infatti, una volta creato il Core, si risolve un problema di bound per il problema originale (3.3).

DIMcore

variabili ricavando un primo lower

Procedendo con l'espansione del Core, da

una parte il lower bound tende a migliorare no al raggiungimento del valore ottimo (rinforzando di fatto il RCC ), dall'altro la variabile

xh

, con

h Nf ix ,

il cui valore

deve essere cambiato cresce nel suo coeciente di costo ridotto (in modulo). Alla

k esima iterazione tale per cui la variabile xh da permutare abbia un costo ridotto |bh | > U B LB k , l'algoritmo si arresta avendo trovato l'ottimo z = LB k . Il criterio di terminazione perde di ecacia solo se |bj | U B z j N con z valore ottimo del problema intero P . In altre parole, anche conoscendo il miglior
lower bound possibile (coincidente con l'ottimo) il RCC non permette di ssare nessuna variabile a 0 o a 1. In questa situazione tutte le oerte contenute in

Nf ix

devono essere permutate e l'algoritmo di espansione del Core termina solo quando

Nf ix = .

3.3

Risoluzione del problema Core

In questa sezione ci occuperemo di descrivere in dettaglio l'algoritmo in grado di risolvere il problema Core. E' bene ricordare che il ne di questo algoritmo quello di vericare l'esistenza di un valore della funzione obiettivo migliore di

LBcore

fornito

in ingresso. Se tale valore esiste, viene fornito come output insieme all'allocazione delle oerte ad esso associato, quest'ultima necessaria per aggiornare la soluzione temporaneamente ottima del problema di partenza. Di fatto, l'algoritmo non pu

CAPITOLO 3.

IL NOSTRO ALGORITMO

49

funzionare se non gli viene indicato un valore di

LBcore

come input. Per ora sup-

poniamo che tale valore sia noto. Risulta ormai evidente che la bont dell'algoritmo in termini di ecienza computazionale dipende molto dal valore di

LBcore .

In realt sono stati deniti due approcci risolutivi per il problema Core:

1. un approccio basato sull'analisi di alberi di ricerca attraverso la generazione di disuaguaglianze valide (che indichiamo con AAR = Analisi Alberi Ricerca ), utilizzato per risolvere problemi di ridotte dimensioni (con numero di variabili minore o uguale a

V ARmax ).

2. un approccio basato sulla riduzione ricorsiva di problemi di grandi dimensioni (che indichiamo con RR = Riduzione Ricorsiva ) che termina con una risoluzione di tipo AAR quando il problema ridotto ha un numero di variabili al pi uguale a

V ARmax .

E' utile premettere che entrambi gli algoritmi risolvono problemi di tipo MKP a patto che sia fornito un lower bound iniziale (o presunto tale) al problema. Di

fatto possibile utilizzare AAR o RR per risolvere direttamente il problema di partenza il cui lower bound pu essere ottenuto da una qualsiasi euristica. Sebbene questo sia possibile, AAR e RR sono pensati per risolvere in modo eciente problemi di tipo MKP sotto particolari condizioni e, come verr fatto presente pi avanti quando verranno illustrati i risultati computazionali, conviene utilizzarli entrambi nel contesto dell'algoritmo di espansione del Core che, tra l'altro, non necessita di alcuna particolare funzione euristica per poter funzionare. Maggiori dettagli sull'utilizzo

combinato di AAR, RR e EC verranno descritti al termine del capitolo.

3.3.1 AAR: Analisi degli Alberi di Ricerca


L'analisi di alberi di ricerca attraverso la generazione di disuguaglianze valide un algoritmo esatto che porta sempre alla soluzione ottima del problema. L'algoritmo da noi elaborato si basa sull'enumerazione esplicita delle soluzioni avvalendosi del concetto di cardinalit e di tagli che portano ad una riduzione delle soluzioni da vericare. Questo algoritmo riprende quello presentato da R. Mansini e M.G. Speranza in [29] introducendo interessanti novit al ne di ridurre ulteriormente lo spazio di ricerca delle soluzioni.

CAPITOLO 3.

IL NOSTRO ALGORITMO

50

3.3.1.1 Cardinalit
Per cardinalit di un insieme di oerte si intende il numero di oerte contenute nell'insieme stesso. A dierenza dei classici algoritmi branch and cut che analizzano un solo albero delle soluzioni, il nostro algoritmo scompone il problema in sottoproblemi ognuno caratterizzato da una propria cardinalit, analizzando le soluzioni che contengono un numero di oerte pari alla cardinalit considerata e rendendo i tagli pi ecaci. E' necessario determinare la cardinalit minima e la cardinalit massima del problema, che rispettivamente indichiamo con che, denito sia:

CARDmin

e con

CARDmax

in modo

il numero di oerte contenute nella soluzione ottima del problema,

CARDmin k CARDmax
Sono stati implementati due distinti metodi per calcolare il valore di

(3.25)

CARDmin

CARDmax :

il primo si avvale di informazioni ottenute ordinando in modo opportuno

le variabili del problema, il secondo invece consiste nella risoluzione di un problema lineare di supporto. rispettivi pregi e i difetti. Verranno presentati entrambi gli approcci, unitamente ai

1. La cardinalit minima viene calcolata utilizzando il valore del lower bound del problema. L'idea quella di creare un vettore

Vp

nel quale vengono inserite

le oerte ordinate per prezzo in modo decrescente no a quando la somma complessiva dei prezzi delle oerte contenute nel vettore bound. Sia

Vp

non ecceda il lower

il vettore dei prezzi delle oerte tale per cui, senza perdere di

generalit:

p1 p2 .... pj pj+1 ... pn1 pn


Le oerte vengono inserite in

(3.26)

Vp

seguendo l'ordinamento ( 3.26 ) no a quando:

pj LB
jVp

(3.27)

Il numero di oerte presenti in questo vettore rappresenta la cardinalit minima iniziale

CARDmin

poich, prendendo le prime

maggiore, il prezzo complessivo ottenuto

CARDmin 1 oerte con prezzo dalla loro somma non raggiunge LB

e, pertanto, tale valore non verr raggiunto da nessun'altra combinazione di

CAPITOLO 3.

IL NOSTRO ALGORITMO

51

CARDmin 1 oerte.

Si tenga presente che

iniziale in quanto, migliorando il valore di

CARDmin la cardinalit minima LB durante l'esecuzione dell'algoCARDmin .


Per quan-

ritmo, anch (3.27) rimanga valido possibile che si debbano aggiungere ulteriori oerte in

Vp

incrementando di fatto il valore di

to riguarda la cardinalit massima, questa dipende dal numero complessivo dei beni messi a disposizione (le capacit dei vincoli del problema). Anche in questo caso viene generato un vettore in cui le oerte sono inserite in ordine crescente rispetto alla somma dei loro pesi nei vari vincoli. In particolare, sia

benij =

m i=1

wij

con

j = 1, ..., n

e si ordinino le oerte in modo che:

beni1 ... benij benij+1 ... benin


Sia

(3.28)

benitot =

m i=1 ci .

Si sommano i valori di

benij

secondo l'ordinamento (

3.28 ) no a quando:

benij > benitot


j=1
Il valore di

(3.29)

(h 1) corrisponde alla cardinalit massima desiderata. j

In generale

ogni oerta viene fatta su tutti i beni, richiesti in una certa quantit. La quantit totale dei beni (senza distinzione) richiesti da un'oerta e salvata in viene calcolata

benij .

Si ha che

CARDmax = h 1

in quanto, prendendo le prime

oerte con il valore totale di beni minore, la somma complessiva dei beni

ottenuta dalla loro somma eccede il numero totale di beni messi a disposizione (3.29) e, pertanto, ogni altra combinazione di

h oerte ecceder tale valore.

In

questo caso, non dipendendo dal lower bound, la cardinalit massima salvata in

CARDmax

non pu essere migliorata utilizzando lo stesso procedimento di

calcolo. 2. Le cardinalit minima e massima vengono calcolate risolvendo due problemi lineari molto simili fra loro. Sia

l'insieme degli indici delle variabili su cui

denito il problema originale avente

m vincoli.

L'idea quella di massimizzare

e minimizzare il numero delle oerte contenute in

che assumono valore 1

aggiungendo ai vincoli del problema originale il fatto che la funzione obiettivo di quest'ultimo debba essere almeno pari a

LB .

CAPITOLO 3.

IL NOSTRO ALGORITMO

52

Sia

Pmax

il seguente problema:

kmax = max
jN

xj

wij xj ci i = 1, ..., m
jN

(3.30)

pj xj LB
jN

0 xj 1 j N
e sia

Pmin

kmin = min
jN

xj
(3.31)

wij xj ci i = 1, ..., m
jN

pj xj LB
jN

0 xj 1 j N
Entrambi i problemi sono lineari e possono essere risolti in tempi polinomiali da un risolutore come CPLEX. Ne risulta semplicemente che:

CARDmin = CARDmax =

kmin + 1 kmax

(3.32)

Sebbene il primo approccio possa risultare pi eciente rispetto al secondo, che prevede la formulazione e la risoluzione di due ulteriori problemi, anche meno ecace in quanto i valori di

CARDmax

CARDmin

vengono calcolati considerando

informazioni parziali del problema (rispettivamente beni totali e prezzi delle oerte).

Pmin e Pmax xj .

sono formulati includendo tutte le informazioni note e i risultati ottenuti

soddisfano la relazione (3.25) anche aggiungendo i vincoli di interezza sulle variabili Di fatto i valori di

CARDmin

CARDmax

ottenuti con il secondo metodo

sono molto pi stringenti di quelli forniti dal primo approccio, evitando quindi di analizzare un numero considerevole di alberi di ricerca.

CAPITOLO 3.

IL NOSTRO ALGORITMO

53

3.3.1.2 Enumerazione delle soluzioni


Si riporta un'esempio di enumerazione delle soluzioni ssata una cardinalit che permette di motivare l'utilizzo del termine albero di ricerca per l'algoritmo AAR. Sia

n = 5

il numero delle oerte e

k = 3

la cardinalit considerata.

Le possibili

soluzioni (ammissibili e non) vengono cos enumerate:

1, 2, 3 1, 2, 4 1, 2, 5 1, 3, 4 1, 3, 5 1, 4, 5 2, 3, 4 2, 3, 5 2, 4, 5 3, 4, 5
Il metodo di enumerazione si basa sull'incremento dell'ultima oerta dell'allocazione sino al raggiungimento della cardinalit dell'ultima oerta inserita no a sizione

k.

Successivamente si incrementa il valore

n.

Quando l'ultima oerta dell'allocazione (in po-

k)

uguale a

si incrementa il valore dell'oerta precedente (nella posizione Se tale

k 1) e di quelle successive di uno no al raggiungimento della cardinalit k .


ta

cardinalit non pu essere raggiunta perch le oerte sono esaurite (si inserisce l'oer-

in una posizione minore di

k ),

si seleziona nell'allocazione, a partire dall'ultima

oerta inserita, la prima oerta tale per cui, inserendo nelle posizioni successive le oerte a lei consecutive, possibile il raggiungimento della cardinalit

k.

Questo tipo

di analisi pu essere visualizzata attraverso un albero di ricerca binario. Riportiamo un esempio graco di albero binario con

n=4

k=3

le cui soluzioni sono:

1, 2, 3 1, 2, 4 1, 3, 4 2, 3, 4

CAPITOLO 3.

IL NOSTRO ALGORITMO

54

Figura 3.1: Albero di ricerca binario delle soluzioni con n = 4 e k = 3

L'aver ridotto il numero di oerte dettato esclusivamente da ragioni estetiche, per non avere un albero binario troppo grande da rappresentare: Ogni livello dell'albero rappresenta un'oerta che viene inserita o esclusa nell'allocazione a seconda che si percorra il ramo di sinistra o quello di destra. L'albero riportato in gura non completo in quanto non tutti i sottoalberi vengono analizzati: per esempio, il nodo A non viene espanso ulteriormente in quanto gi stata raggiunta un'allocazione di 3 oerte, mentre il nodo B non ha il sottoalbero destro in quanto non includere l'oerta numero 3, unitamente al fatto che gi stata esclusa la numero 2, non consente di ottenere un allocazione di cardinalit 3 (rimanendo a disposizione solo l'oerta 1, gi inclusa, e l'oerta 4). In generale, se

sono le oerte e

la cardinalit, il numero (massimo) di

soluzioni prese in considerazione equivale al numero di combinazioni semplici di n

elementi di classe k :

Cn,k

n n! = = k! (n k)! k

(3.33)

L'enumerazione delle soluzioni richiede un tempo non accettabile all'aumentare di

k:

l'introduzione dei tagli serve appunto per ridurre lo spazio di ricerca delle

soluzioni semplicemente rendendo superua la visita di alcuni nodi dell'albero. Prima di discutere in dettaglio i tipi di tagli utilizzati, bene capire come l'algoritmo

CAPITOLO 3.

IL NOSTRO ALGORITMO

55

AAR costruisce le soluzioni. In [29] viene generata sempre un'allocazione full

alla

quale si applicano i tagli secondo un determinato ordine e, selezionando il taglio pi profondo, si risale l'albero tramite back-tracking. A questo punto si costruisce nuovamente un'allocazione full secondo il criterio di enumerazione incrementale delle oerte descritto in precedenza. Ogni volta che viene generata un'allocazione full si verica la sua ammissibilit e se risulta essere migliore della soluzione ottima attuale quest'ultima viene aggiornata. Il procedimento termina quando l'albero binario

stato completamente navigato. Il nostro algoritmo utilizza un approccio dierente attraverso il quale si ottiene un'allocazione full delle oerte solo nel caso in cui tale allocazione sia ammissibile e dia un valore della funzione obiettivo migliore del lower bound noto. Nella maggior parte dei casi il nostro algoritmo tratta allocazioni parziali in cui sono inserite oerte in numero minore rispetto alla cardinalit analizzata. A questo punto seleziona secondo opportuni criteri la prossima oerta da inserire e successivamente vengono applicati i tagli in un determinato ordine. Il primo di essi che viene applicato con successo determina la nuova allocazione parziale che dipender proprio dal tipo di taglio utilizzato. Il procedimento viene iterato no al raggiungimento di un'allocazione full (ammissibile) che in ogni caso avr un valore migliore o al pi uguale al lower bound attuale (altrimenti l'allocazione full non verrebbe mai generata). Inne si verica se dall'allocazione full trovata possa essere derivata una nuova allocazione parziale da cui far ripartire il procedimento, altrimenti l'algoritmo termina. Una descrizione rigorosa dell'algoritmo fornita nei paragra 3.3.1.4 e 3.3.1.5.

3.3.1.3 Applicazione dei tagli


Sono state implementate quattro tipi di disuguaglianze valide:

taglio sui prezzi : consente di eliminare allocazioni parziali che danno origine
esclusivamente ad allocazioni full il cui valore minore del lower bound;

taglio sui beni : verica che non vengano assegnati pi beni di quelli complessivamente a disposizione;

taglio sui coecienti : utilizza il Reduced Cost Constraint per eliminare alcune
allocazioni;

5 Un'allocazione di

oerte si dice

full se si inseriscono esattamente k oerte indipendentemente

dal fatto che l'allocazione cos ottenuta sia ammissibile o non.

CAPITOLO 3.

IL NOSTRO ALGORITMO

56

taglio di ammissibilit : verica che le oerte incluse in un'allocazione soddisno


tutti i vincoli di capacit del problema.

L'enumerazione delle soluzioni avviene considerando le oerte ordinate per prezzi in modo decrescente.

Taglio sui prezzi:

Si supponga che le oerte siano ordinate in modo decrescente

per prezzi. Si costruisca un vettore bidimensionale alla somma dei prezzi delle prime

Sp (a, b) i cui elementi equivalgono b oerte da

oerte con prezzo maggiore tra tutte quelle che

hanno prezzo pi piccolo dell'oerta

a.

In base all'ordinamento (3.26), le

considerare sono esattamente le prime

oerte consecutive all'oerta

a + 1, a + 2, ..., a + b. a + b card con card

Per evitare inutili calcoli si limita il valore di

a, vale a dire b tale per cui

la cardinalit analizzata. Formalmente si ha che:

a+b

Sp (a, b) =
i=a+1
Sia

pj con a + b card ktemp

(3.34)

ztemp

la somma dei prezzi delle

oerte presenti nell'allocazione parziale

costruita relativamente al nodo corrente dell'albero. Sia

j1

l'ultima oerta inserita e

l'oerta selezionata per entrare nell'allocazione ( quindi con

p pj1 j

> j1 j

). Il

taglio sui prezzi risulta essere ecace se vale la seguente disuguaglianza:

ztemp + p + Sp ( card ktemp 1) < LB j, j

(3.35)

Al primo membro di (3.35) si somma il prezzo dell'allocazione parziale al prezzo dell'oerta

inserita, a cui si aggiunge il prezzo massimo complessivo tra tutte le

combinazioni di

card ktemp 1 oerte rimaste da allocare. . j

In altre parole si ottiene

il prezzo massimo tra tutti quelli delle allocazioni full che posso ottenere partendo dall'allocazione parziale considerata e aggiungendo piccolo di Se tale prezzo rimane pi

LB

inutile inserire

nell'allocazione perch sicuramente la navigazione

del sottoalbero equivalente non condurr al miglioramento (o al raggiungimento) del lower bound. Una situazione particolare si ha quando

card = ktemp + 1,

vale a dire

quando deve essere inserita solamente un'oerta per ottenere un'allocazione full. In questo caso il taglio applicabile se vale semplicemente che:

ztemp + p < LB j

(3.36)

CAPITOLO 3.

IL NOSTRO ALGORITMO

57

Il taglio sui prezzi in generale pi profondo

di tutti gli altri tagli, anche se questo

direttamente legato al fatto che le oerte vengono inserite nell'allocazione ordinate per prezzi decrescenti. Riportiamo dei semplici esempi per capire la profondit del taglio sui prezzi e del modo con cui, applicato con successo, possa determinare la prossima allocazione parziale da valutare nonch la prima oerta da inserire in questa nuova allocazione.

n = 10 e k = 6 e si ipotizzi parziale:[1, 2, 3, , , ] con 6 la prossima oerta


Si supponga del tipo

di avere la seguente allocazione da inserire. Se il taglio sui prezzi

risulta ecace la prossima oerta da inserire non sar la

7 in quanto se un'allocazione

[1, 2, 3, 6, , ] non dar mai un'allocazione full con valore maggiore o uguale a LB , sicuramente non lo dar mai neppure un'allocazione del tipo [1, 2, 3, 7, , ] essendo p7 p6 . La prossima allocazione parziale diventa quindi [1, 2, , , , ] con 4 la prossima oerta da inserire. E' importante far notare come l'allocazione parziale da valutare non sia [1, 2, 4, , , ] come invece ci si potrebbe attendere
conoscendo il meccanismo di enumerazione incrementale delle oerte gi presentato in precedenza. Infatti la costruzione dell'allocazione full verte sul fatto che non si possa mai passare per un'allocazione parziale errata. garanzia che In eetti non si ha alcuna

[1, 2, 4, , , ] sia un'allocazione parziale valida, in quanto non detto che l'inserimento dell'oerta 4 venga consentito da uno dei tagli da applicare. Si supponga ora n = 14 e k = 7 e si analizzi la seguente allocazione parziale: [1, 2, 3, 7, 10, , ] con 11 la prossima oerta da aggiungere. Se il taglio sui prezzi ecace la prossima oerta da inserire non sicuramente la 12 per quanto visto
nell'esempio precedente. La prossima allocazione parziale dovrebbe quindi essere In realt l'analisi di que-

[1, 2, 3, 7, , , ] con 11 la prossima oerta da aggiungere.

sta allocazione inutile in quanto se l'allocazione full ottenuta da

[1, 2, 3, 7, 10, 11, ]

non migliora il lower bound, non lo far neppure una qualunque allocazione ottenuta partendo da

[1, 2, 3, 7, 11, , ].

Di conseguenza il taglio pi profondo rispetto all'e-

sempio precedente, dato che in questo caso il taglio applicato con successo quando cerco di inserire l'oerta consecutiva all'ultima presente nell'allocazione. Pertanto la prossima allocazione parziale da valutare da aggiungere. Si vada oltre e si consideri lo stesso esempio appena mostrato considerando tuttavia la seguente allocazione parziale:

[1, 2, 3, , , , ]

con

la prima oerta

[1, 2, 3, 8, 10, , ]. 11

la prossima oer-

6 Un taglio pi profondo di altri se in grado di tagliare una porzione maggiore dell'albero


delle soluzioni.

CAPITOLO 3.

IL NOSTRO ALGORITMO

58

ta da aggiungere e il taglio risulta ecace. lutare non

La nuova allocazione parziale da va-

[1, 2, 3, , , , ] con 9 la prima oerta da inserire poich se partendo da [1, 2, 3, 8, 10, , ] non miglioro il lower bound, questo non verr migliorato neppure partendo da [1, 2, 3, 9, 10, , ] (essendo p9 p8 ) e quindi nemmeno da [1, 2, 3, 9, , , ]. Di conseguenza la nuova allocazione parziale da valutare risulta essere [1, 2, , , , , ] con 4 la prossima oerta da includere. Per un ragionamento analogo se l'allocazione [1, 2, 7, 8, 10, , ], con 11 la prossima oerta da inserire, viene tagliata, la nuova allocazione parziale diventa

[1, , , , , , ]

con prossima oerta da aggiungere uguale a

3.
Sia

Come si evince dagli esempi, il taglio risulta tanto pi profondo quanto pi sono

j l'oerta da inserire nell'allocazione, h il numero di oerte sinora inserite e getX (i) una funzione che restituisce l'oerta presente nell'allocazione nella posizione i con i h. Se il taglio viene applicato con successo si esegua il seguente algoritmo:
contigue le oerte nell'allocazione parziale a partire dall'ultima posizione. 1. 2.

dif f erenza 2 temp , getX (h), h h 1 j j h=0


allora vai al punto 7 allora vai al punto 7

3. se 4. se 5. se

(temp > dif f erenza j) (temp = 2 j)


allora

dif f erenza = 1

6. torna al punto 2 7.

hnew h, new + 1 j j

Il semplice algoritmo proposto in grado di determinare la migliore allocazione parziale (che anche quella pi piccola) da cui far ripartire AAR. Si noti la condizione nel punto 3: l'allocazione parziale di partenza stata ridotta no al primo elemento; questo signica che AAR non ha trovato (prima) e non trover (poi) nessuna allocazione full ottimale che contenga l'oerta presente nella prima posizione. Al termine di questo semplice algoritmo la nuova allocazione parziale ottenuta prendendo le prime

hnew

oerte presenti nella precedente allocazione mentre la prossima

variabile da inserire (nella posizione

hnew + 1)

new . j

CAPITOLO 3.

IL NOSTRO ALGORITMO

59

Taglio sui beni:

Il ragionamento che sta alla base del taglio sui beni molto

semplice: non si possono assegnare pi beni di quelli che si hanno a disposizione. Per applicare con ecienza questo taglio necessario precalcolare alcune quantit prima che la navigazione dell'albero delle soluzioni venga avviata. Sia complessiva dei beni associati all'oerta

benij

la somma

wij . Si costruisca un vettore So (a, b) il cui elemento equivale alla delle b oerte con benij pi piccolo, selezionate tra tutte le oerte che hanno prezzo minore di quello di a( vale a dire, ricordando l'ordinamento delle oerte per prezzi decrescenti, a+1, a+2, ..., a+b ). Per evitare inutili calcoli, anche qui si ipotizzi che a + b card con card la j
tale che

benij = somma di benij

m i=1

cardinalit analizzata.

Esempio:

n = 10, a = 3, b = 4. Si devono considerare solo le oerte con prezzo minore di p3 che sono semplicemente 4, 5, 6, 7, 8, 9 e 10. Siano tali oerte incluse in un insieme che per comodit chiamiamo Ntemp . Si ordinano le oerte contenute in Ntemp in modo crescente rispetto al loro valore di benij e si selezionano le prime 4 oerte. La somma dei valori di benij di quelle 4 oerte viene salvato in So (3, 4).
sia il numero complessivo di beni associato alle

Sia

objtemp

ktemp

oerte presenti nell'al-

locazione parziale,

la prossima oerta da aggiungere nell'allocazione e benitot = m i=1 ci il numero di beni a disposizione. Il taglio sui beni ecace se valida la

seguente disuaguaglianza:

objtemp + benij + So ( card ktemp 1) > benitot j,

(3.37)

Al primo membro si considera l'allocazione full ottenuta partendo da quella parziale analizzata che, tra tutte, richiede il minor numero di beni complessivi. Se questo

valore supera il numero totale di beni a disposizione, inutile proseguire nell'analisi del sottoalbero associato a tale allocazione parziale in quanto non verranno generate mai allocazioni full ammissibili.

n = 10 e k = 6 e si analizzi la seguente allocazione parziale [1, 2, 3, , , ] con 4 la prossima oerta da inserire. Se il taglio sui beni applicato con successo l'allocazione da valutare rimane sempre [1, 2, 3, , , ] ma cercando di includere l'oerta 5 (incrementale rispetto all'ultima come stabilito nel criterio di
Si supponga enumerazione delle oerte). Tuttavia pu essere fatto di meglio, valutando il numero di beni associati all'oerta

rispetto all'oerta precedente. Infatti, se

beni5 beni4

CAPITOLO 3.

IL NOSTRO ALGORITMO

60

non si inserisce l'oerta

ma si passa direttamente all'oerta

(senza quindi appli-

beni6 beni4 si passa all'oerta 7 e via dicendo. La motivazione molto semplice. Partendo dall'allocazione [1, 2, 3, , , ] con 4 l'oerta da inserire, le oerte restanti sono 5, 6, 7, 8, 9 e 10 (stato A). Ne vengono scelte le due con il numero di beni minore (la cui somma salvata in So (4, 2)). Indichiamole con j1 e j2 . Applicato con successo il taglio sui beni, si cerca di inserire l'oerta 5, pertanto le oerte ancora disponibili sono 6, 7, 8, 9 e 10 (stato B).
care ulteriormente il taglio 3.37) . Se Si presentano due casi: 1. Se

j1 = 5 j2 = 5,

le oerte con il numero di beni pi piccolo non cambiano in

quanto per entrambi gli stati ci sono le stesse oerte tranne appunto la numero

5.

Di conseguenza l'allocazione full ottenuta da B uguale a quella ottenuta

da A tranne che al posto dell'oerta

stata inserita la

5.

Ma

beni5 beni4 ,

quindi se l'allocazione full ottenuta da A non soddisfa il vincolo sui beni, a maggior ragione tale vincolo verr violato anche dall'allocazione full generata da B. 2. Se

j1 = 5 j2 = 5,

le oerte con il numero di beni pi piccolo dieriscono nei

due stati in quanto in A una di esse la

che non risulta disponibile in B

(in quanto gi inserita di suo nell'allocazione). Ne verr selezionata una terza che chiamiamo

j3 .

Sicuramente

benij3 benij1

benij3 benij2

altrimenti in

A una delle due oerte sarebbe stata proprio

j3 .

Quindi in B le due oerte

da aggiungere hanno complessivamente un numero di beni maggiori rispetto ad A. Se a questo si aggiunge anche che la

in B sostituisce la

in A e che

beni5 beni4 ,

si evince come anche l'allocazione full ottenuta da B viola il

vincolo sui beni se questo non soddisfatto dall'allocazione full generata da A. Alla luce dell'esempio proposto, sia

l'oerta da inserire nell'allocazione parziale. j

Se

il taglio sui beni applicato con successo si determina la nuova allocazione parziale nonch la prossima oerta da aggiungere tramite il seguente algoritmo: 1.

temp j beni benitemp j+1 =n j


allora

2. se 3. se

+1 j j

altrimenti vai al passo 5

vai al passo 5

4. torna al passo 2

CAPITOLO 3.

IL NOSTRO ALGORITMO

61

5. con

new j j
la nuova oerta da aggiungere nell'allocazione parziale alla prossima iter-

new j

azione di AAR.

Taglio sui coecienti

Nel contesto di AAR un'allocazione valida non deve es-

sere solo ammissibile in relazione ai vincoli del problema, ma deve anche fornire un valore della funzione obiettivo migliore del lower bound. Di conseguenza lecito

utilizzare le informazioni contenute nel RCC (3.20) per tagliare porzioni dell'albero che sicuramente non lo soddisfano. I costi ridotti associati alle variabili costituiscono un input dell'algoritmo proprio come il valore di

LB

e di

UB

(senza il quale non sarebbe possibile costruire il RCC ).

Tali coecienti sono computati semplicemente risolvendo il rilassamento continuo del MKP considerato. Per semplicit si assume che:

|bj | U B LB j N

(3.38)

Se cos non fosse alcune variabili possono essere ssate a 0 e a 1 e l'algoritmo AAR verrebbe quindi applicato al problema riformulato non considerando tali variabili. Come vedremo in seguito, AAR verr utilizzato in un contesto in cui la condizione (3.38) sempre vera.

[1, 2, , ] con 3 la prossima oerta da aggiungere. Siano b1 = 30.00, b2 = 10.23 e b3 = 20.31 i coecienti di costo ridotto associati alle tre variabili di interesse e sia 32.12 il termine noto di RCC. L'allocazione successiva diventa [1, 2, , ] con 4 la nuova oerta da inserire poich i coecienti 30.00 e 20.31 (che si ricorda devono essere presi in modulo) sommati violano il vincolo (|30.00 20.31| > 32.12). Si supponga di analizzare l'allocazione [1, 2, , ..., ] e di voler aggiungere l'oerta 5. Siano b1 = 0.00, b2 = 5.23, b3 = 10.12, b4 = 0.00 e b5 = 20.13 i coecienti di costo ridotto rispettivamente delle oerte 1, 2, 3, 4 e 5, e sia 35.34 il termine noto di RCC. Si osservi come il voler aggiungere l'oerta 5 presuppone che nell'eventuale
Si supponga

n = 10

k=4

e si analizzi l'allocazione parziale

allocazione full non ci saranno le oerte 3 e 4 in quanto, se ci fossero, comparirebbero in posizioni precedenti a quella occupata dall'oerta 5 a causa del loro prezzo maggiore. Si osservi inoltre che la presenza delle oerte 2 e 5 unitamente all'assenza dell'oerta 3 portano a violare il vincolo. Infatti, le oerte 2 e 5 forniscono un contributo al primo membro di (3.20) pari a

|5.23 20.13| = 25.36

come visto

CAPITOLO 3.

IL NOSTRO ALGORITMO

62

nell'esempio precedente. Se l'oerta 3 non inclusa, ossia

x3 = 0,

il suo contributo

b3 (1 x3 )

pari a 10.12. La somma dei contributi complessiva delle oerte 2,5 e 3

di 35.48 che maggiore di 35.34, violando di conseguenza il vincolo. Per applicare questo taglio in modo eciente, sia

la prossima oerta da ag-

giungere nell'allocazione parziale. Le oerte gi valutate, che possono essere quindi presenti in tale allocazione, sono

1, 2, ..., 1. j

Sia

l'insieme delle oerte valutate

con costo ridotto negativo e presenti nell'allocazione e sia

C+

l'insieme delle oerte

valutate con costo ridotto positivo ma non presenti nell'allocazione. Si denisca:

range = (U B LB) j
jC
Il valore di violato.

|bj |

range j

rappresenta una sorta di bonus esaurito il quale il RCC viene

Chiaramente

range1 = U B LB

in quanto non stata valutata ancora

alcuna variabile (l'oerta 1 non ancora stata allocata) e il bonus corrisponde interamente al termine noto del RCC. Man mano che vengono inserite oerte con costo ridotto negativo il valore di

range

diminuisce di una quantit pari al modulo

del costo ridotto stesso. Una prima applicazione del taglio viene provata quando ha costo ridotto negativo. Se:

range b < 0 j j

(3.39)

il taglio ecace perch il RCC viene violato. Se l'esito negativo si applica una condizione pi stringente che tiene in considerazione anche le oerte contenute in

C +.

La disuguaglianza diventa:

range b j j
jC +

bj < 0

(3.40)

e se valida il taglio sui costi ridotti diventa ecace. Si potrebbe applicare direttamente il taglio (3.40) ma richiede un calcolo aggiuntivo ( che, di conseguenza, viene valutato per primo. Qualora

jC + bj ) rispetto a (3.39)

abbia costo ridotto positivo, si verica semplicemente che:

range j
jC +

bj < 0

(3.41)

che, se vero, porta ad un taglio ecace delle soluzioni. In tutti i casi in cui il taglio

CAPITOLO 3.

IL NOSTRO ALGORITMO

63

applicato con successo, si mantiene l'allocazione parziale valutata e si incrementa semplicemente di un'unit l'oerta che si vuole aggiungere.

Taglio di ammissibilit
particolare sia

E' tra i quattro il taglio pi semplice da applicare daIn

to che si limita a valutare l'ammissibilit dei vincoli originali del problema.

la prossima oerta da aggiungere nell'allocazione parziale e sia

l'insieme delle oerte gi contenute in tale allocazione. Si valutino poi le seguenti disuguaglianze:

wij + wi > ci i = 1, ..., m j


jV

(3.42)

Se almeno una delle disuguaglianze riportate valida, il taglio di ammissibilit ecace,

non j

viene aggiunta nell'allocazione e si passa a valutare l'eventuale inseri-

mento dell'oerta valida tra le

+ 1. j

E' logico che, non appena viene trovata una disuaguaglianza

possibili, le rimamenti non vengono valutate.

In realt l'algoritmo AAR adotta una strategia dierente, del tutto simile a quella utilizzata nell'applicazione del taglio sui beni. Le disuguaglianze in (3.42) valutano l'ammisibilit attuale dell'allocazione parziale con l'aggiunta dell'oerta

. j

In al-

tre parole sono valide se i costi delle oerte presenti nell'allocazione, compresa

, j

violano uno dei vincoli del problema. Il nuovo approccio orientato alla valutazione dell'ammissibilit futura, cio di quella dell'allocazione full ottenuta partendo dall'allocazione parziale considerata. Chiaramente a partire da un'allocazione parziale possibile ottenere un elevato numero di allocazioni full a seconda di come vengono scelte le rimanenti oerte da aggiungere. Analogamente al ragionamento che sta

dietro il funzionamento dei tagli dei prezzi e dei beni, in questo caso si considera l'allocazione full costruita aggiungendo le oerte con costo minore all'interno del vincolo.

1 i m. Si costruisca un vettore Vi (a, b) il cui elemento corrisponde alla somma dei costi wij delle b oerte con costo wij pi piccolo tra tutte quelle con prezzo minore dell'oerta a (vale a dire, ricordando l'ordinamento decrescente per prezzi delle oerte, a + 1 , a + 2, ..., a + b). Per evitare inutili calcoli temp si ponga a + b card, dove card la cardinalit analizzata. Sia costoi il costo complessivo delle ktemp oerte nore allocate relativamente al vincolo i. Sia la j
Si consideri il vincolo

con

prossima oerta da aggiungere nell'allocazione parziale. Il taglio di ammissibilit del

CAPITOLO 3.

IL NOSTRO ALGORITMO

64

vincolo

ecace se valida la seguente disuaguaglianza:

costotemp + wi + Vi ( card ktemp 1) > ci j, j i

(3.43)

Al primo membro si sommano il costo dell'allocazione parziale, il costo dell'oerta

j
di

che si vuole aggiungere e il costo pi piccolo possibile tra tutte le combinazioni

card ktemp 1

oerte rimaste da allocare. Se il valore complessivo maggiore

della capacit del vincolo, non possibile costruire un'allocazione full ammissibile a partire da quella allocazione parziale. Il taglio espresso da (3.43) guarda molto pi avanti rispetto a (3.42) e permette di potare rami nell'albero delle soluzioni senza valutare sottorami e foglie ad essi associati. E' chiaro che le considerazioni fatte in precedenza sul singolo vincolo sono replicate per tutti gli ,

V2 (a, b),

....,

m vincoli. E' suciente costruire diversi vettori del tipo V1 (a, b) Vm (a, b) e vericare che almeno una delle m disuguaglianze sia valida + 1 come prossima j

per poter applicare il taglio. Anche in questo caso, se il taglio ha successo, la nuova allocazione parziale da valutare non cambia mentre si considera oerta da aggiungere.

3.3.1.4 Funzionamento dell'algoritmo di ricerca


In questa sezione cercheremo di unire tutte le informazioni riguardanti l'enumerazione delle soluzioni e l'applicazione dei tagli riportate in precedenza per mostrare il funzionamento dell'algoritmo AAR e il meccanismo tramite cui viene trovata soluzione ottima del problema. Supponiamo di analizzare l'albero di cardinalit

la

k.

Si identichi con

cont

la po-

sizione in cui inserire la prossima oerta nell'allocazione parziale. Sia Di fatto se l'allocazione costituita da 3 variabili si valuter posizione

tale variabile. j l'inserimento di nella j 1


essendo

cont = 4.

Chiaramente il valore di

cont

all'inizio sar uguale a 1 e non

potr mai eccedere

k.

La prima oerta che si cerca di allocare l'oerta

h dell'algoritmo di ricerca lavora su un valore qualunque di cont e di j , determinati al passo h 1. Rimaniamo nell'ipotesi in cui si sta eseguendo il generico passo h di AAR. Si
quella con prezzo maggiore. Il generico passo vericano nell'ordine il taglio sui prezzi, sui beni, sui coecienti di costo ridotto e per ultimo quello di ammissibilit. Il primo taglio applicato con successo determi-

7 Si ricordi che la soluzione pu non essere trovata qualora l'ottimo del problema non sia superiore
al lower bound fornito in ingresso.

CAPITOLO 3.

IL NOSTRO ALGORITMO

65

na la nuova allocazione parziale e la prossima oerta da valutare secondo le regole denite quando sono stati descritti i vari tagli. Il valore di

cont viene dunque aggiorcont


incrementa di

nato in base alla dimensione della nuova allocazione parziale. Qualora nessuno dei tagli risulti essere ecace l'oerta viene aggiunta all'allocazione,

un'unit il suo valore e la prossima oerta che si cercher di aggiungere la prima nell'ordinamento tra tutte le oerte rimaste (vale a dire quella seguente a oerta inserita). Il procedimento viene iterato (passo

, j

l'ultima

h + 1)

con i nuovi valori di

cont
1.

e termina quando si incorre in una della seguenti situazioni: stata costruita un'allocazione full valida. Viene salvata la soluzione

cont = k :

ottima temporanea ottenuta settando a 1 le oerte presenti nell'allocazione e inoltre la somma dei prezzi delle oerte presenti diventa il nuovo lower bound (il che implica un raorzamento del taglio sui prezzi e di quello sui costi ridotti per i passaggi successivi). 2.

cont < k ma non ci sono pi oerte da allocare. Nel caso generale signica che, se u l'ultima oerta aggiunta e n quella con prezzo pi piccolo, si ha che u+1, u+2,....,n sono state tutte escluse dall'allocazione in virt dell'ecacia di
qualche taglio. E' importante capire la valenza di questo risultato. Per come strutturato l'algoritmo, non possibile raggiungere un'allocazione parziale se le oerte in essa presenti non soddisfano le condizioni esplicitate nei tagli. Di conseguenza ogni allocazione parziale sempre ammissibile e pertanto lo anche l'allocazione parziale nale (quando le oerte disponibili sono esaurite). Pu succedere che le oerte presenti in tale allocazione abbiano un prezzo tale che, sommati fra loro, eccedono il lower bound attuale, anche se l'allocazione non full. Se questo si verica, l'algoritmo si limita ad aggiornare il lower

bound come nella condizione 1., senza tuttavia salvare la soluzione temporanea. Questo possibile se si pensa che si sta analizzando una cardinalit che non detto che sia quella ottima. Di fatto non da escludere che nell'analisi di una cardinalit

k ci si imbatta in un'allocazione parziale (con k > CARDmin ) che pu coincidere con l'ottimo.
trovata con l'analisi della cardinalit

di cardinalit

Si evita di salvare la

soluzione sebbene migliore di quella ottima nota, in quanto sicuramente verr

k 8

8 Questo vero se l'analisi delle cardinalit avviene in ordine decrescente. Nel caso contrario la
soluzione ottima gi stata trovata avendo analizzato la cardinalit algoritmo.

prima di

k.

In seguito

verr comunque descritto come scegliere l'ordine di analisi degli alberi di ricerca adottato nel nostro

CAPITOLO 3.

IL NOSTRO ALGORITMO

66

La funzione appena descritta, che permette di allocare opportunatamente tutte le oerte disponibili a partire da un'allocazione parziale iniziale, viene denita per comodit alloca() e costituisce un pilastro portante di tutto l'algoritmo AAR. L'uscita da alloca() non implica la terminazione di AAR. Una volta aggiornato eventualmente il lower bound, necessario continuare nella navigazione dell'albero. Anche qualora avessimo trovato un'allocazione full, non aatto escluso che non ce ne possano essere altre migliori a partire da dierenti allocazioni parziali. Essendo

AAR un algoritmo esatto, necessario esplorare tutto lo spazio delle soluzioni. Il


primo controllo da eseguire quello di terminazione dell'algoritmo AAR per quanto riguarda l'analisi della cardinalit

k.

Molto semplicemente si verica che la prima

oerta dell'allocazione parziale sia tale da non poter raggiungere un'allocazione full anche bypassando tutti i tagli implementati. Sia La condizione di terminazione si traduce in:

j1

l'oerta nella posizione

cont = 1.

n j1 < k 1
In pratica inserita nella prima posizione l'oerta

(3.44)

j1 ,

le oerte che posso ancora va-

lutare sono quelle successive nell'ordinamento decrescente per prezzi, vale a dire

j1 + 1, j1 + 2,...,n , in numero pari a n j1 . Se le n j1 oerte disponibili, sommate a j1 gi inserita, non danno un'allocazione di k elementi, inutile continuare a considerare l'allocazione parziale [j1 , , , ....., ]. D'altra parte la prossima allocazione parziale da valutare sarebbe [j1 + 1, , , ...., ] che tuttavia darebbe origine
ad un'allocazione full ancora pi piccola della precedente avendo meno oerte a disposizione. Lo stesso discorso valido per tutte le allocazioni del tipo con

[f, , , ...., ]

j1 f n .

Arrivati all'allocazione

[n, , , ..., ],

non pi espandibile, lo

spazio delle soluzioni di cardinalit

stato completamente visitato e, qualora si

sia trovata un'allocazione full valida, questa andata a sostituire la soluzione ottima temporanea. Se la condizione (3.44) non soddisfatta, l'albero delle soluzioni di cardinalit

ha ancora dei rami che non sono stati visitati. L'idea quella di prendere

l'ultima allocazione calcolata (full o parziale, in uscita da alloca() ) e di generarne una nuova da inviare alla funzione alloca(). Verr generata una nuova allocazione nale, ottenuta esplorando altri rami dell'albero delle soluzioni, dalla quale generare ancora un'allocazione parziale da far computare da alloca(). Il procedimento termina solo quando la condizione (3.44) soddisfatta. Il meccanismo in grado di generare una nuova allocazione parziale a partire dal-

CAPITOLO 3.

IL NOSTRO ALGORITMO

67

l'allocazione in uscita da alloca() molto semplice e si basa sulla possibilit di creare l'allocazione parziale pi grande possibile, dalla quale ottenere almeno un'allocazione full anche non ammissibile. Il fatto che l'allocazione full possa non essere ammissibile implica che l'unica condizione per la sua determinazione che ci sia un numero suciente di oerte non ancora valutate da inserire nell'allocazione parziale per raggiungere la cardinalit

k,

senza preoccuparsi di una possibile eliminazione di tali

oerte causa tagli applicati con esito positivo. Sia ferta allocata,

cont

la posizione dell'ultima of-

getX(i) una funzione che restituisce l'oerta inserita nella posizione i dell'allocazione e sia n il numero complessivo di oerte. Si ricordi inoltre che le oerte
vengono aggiunte (o sostituite) secondo un criterio incrementale rispetto all'oerta allocata nella posizione precedente. La nuova allocazione viene generata applicando il seguente algoritmo:

1.

getX (cont) , dif f k cont j n ( + 1) dif f j


allora vai al passo 5

2. se 3.

dif f dif f + 1, cont cont 1 , getX (cont) j

4. torna al passo 2 5.

hnew cont 1 , new + 1 j j dif f


il numero di oerte da allocare per avere cardinalit

Si memorizza in

e si

incrementa di uno l'ultima oerta allocata che da delle oerte disponibili (

passa a

+ 1. j

Se il numero

n ( + 1)) j

almeno pari a

dif f

l'allocazione ottenuta

valida perch pu originare un'allocazione full.

Se la condizione al passo 2 non

soddisfatta, si elimina l'ultima oerta allocata e si itera il procedimento. Di fatto il numero delle oerte da allocare incrementa di uno mentre la posizione dell'ultima oerta allocata diminuisce di uno. Vengono proposti alcuni esempi per mostrare con maggior chiarezza l'algoritmo descritto. Sia

n = 10

k =5

e sia

[1, 2, 5, 7, 8]

l'allocazione full in uscita da allo-

ca(). La nuova allocazione parziale da cui far ripartire la computazione di alloca()

[1, 2, 5, 7, ] con 9 la prossima oerta da inserire. Se l'allocazione invece [1, 2, 5, 7, ] la nuova allocazione parziale diventa [1, 2, 5, , ] con 8 la prossima oerta da aggiungere. Inne se l'allocazione [1, 2, 7, 8, 9] la nuova allocazione [1, , , , ]
con 3 come nuova oerta da inserire.

CAPITOLO 3.

IL NOSTRO ALGORITMO

68

3.3.1.5 Calcolo della soluzione ottima


Il calcolo della soluzione ottima un'operazione che avviene automaticamente applicando l'algoritmo AAR per ogni albero di ricerca avente cardinalit compresa tra quella minima

CARDmin

e quella massima

CARDmax .

Se al problema si fornisce un

lower bound pi grande del suo ottimo, nessuna soluzione verr trovata. Se il lower bound invece pi piccolo, l'ottimo (e l'allocazione di oerte ad esso associato) viene trovato in modo certo durante l'analisi di una delle cardinalit consentite. Di fatto l'algoritmo per il calcolo della soluzione ottima ad alto livello prevede i seguenti passaggi:

1. Determinazione di

CARDmax

CARDmin ;

2. Calcolo di una serie di valori memorizzati in vettori e utilizzati durante l'applicazione dei tagli per incrementarne l'ecienza; 3. Applicazione dell'algoritmo AAR per ogni cardinalit e

k compresa tra CARDmin

CARDmax ,

in un ordine (crescente o decrescente) che per ora consideriamo

selezionabile liberamente. 4. Se l'ottimo esiste, stato salvato insieme all'allocazione di oerte durante l'esecuzione di AAR con cardinalit ottima

k.

3.3.1.6 Aspetti di contorno


In questo paragrafo verr illustrata una serie di aspetti signicativi per migliorare l'ecienza dell'algoritmo AAR.

Se il lower bound pi piccolo dell'ottimo del problema, quest'ultimo viene prima o poi determinato dall'analisi di una delle cardinalit possibili. Di fatto l'ordine con cui queste cardinalit vengono analizzate non dovrebbe essere rilevante. Questo non propriamente vero e la motivazione piuttosto evidente da quanto visto in (3.3.1.4). Si detto che, navigando l'albero di cardinalit

ci si pu imbattere in allocazioni ammissibili di cardinalit minore e di prezzo complessivo maggiore del lower bound. Allocazioni di questo genere, se trovate, permettono di aggiornare il lower bound e di rinforzare i tagli che dipendono da esso (il taglio sui prezzi e quello sui costi ridotti), rendendo l'analisi delle

CAPITOLO 3.

IL NOSTRO ALGORITMO

69

altre cardinalit (e l'analisi rimanente della cardinalit seguenza un'analisi delle cardinalit da rispetto a quella di ordine inverso.

CARDmax

k ) pi veloci. Di conCARDmin preferibile

L'applicazione dei tagli prevede, oltre all'utilizzo di quantit statiche precalcolate, anche di valutare lo stato dell'allocazione parziale. Per fare un esempio, nel taglio sui prezzi, necessario calcolare il prezzo totale delle oerte allocate cos come in quello sui beni si deve conoscere il numero complessivo dei beni associati alle oerte presenti nell'allocazione. Chiaramente, per

questioni di ecienza, lo stato non viene valutato nuovamente per ogni allocazione parziale ma si predilige calcolare lo stato attuale partendo da quello precedente a cui si applica una transizione specica per il taglio analizzato. Si supponga che dall'allocazione A

[1, 4, 6, 10, , ..., ]

si passi ad un'allocazione

[1, 4, 6, 10, 11, , ..., ].

Sia

pA

il prezzo totale delle oerte contenute in A.

pB

(il prezzo delle oerte contenute in B) equivale a :

pB =
jB

pj

(3.45)

pB (che rappresenta lo stato dell'allocazione B


dove

associato al taglio sui prezzi) non

viene calcolato usando (3.45) ma viene visto semplicemente come

jA

pj + p11

jA

pj = pA .

Il vantaggio evidente considerato che

pA equivale allo sta-

to dell'allocazione precedente e quindi gi calcolato. In questo modo non viene eseguito un numero di somme pari al numero di oerte presenti in A diminuito di 1. Per ottenere questo risultato suciente memorizzare lo stato dell'allocazione e aggiornarlo continuamente. In realt l'approccio adottato nel nostro algoritmo leggermente dierente e ne migliora ancor pi fortemente l'ecienza. Supponiamo che dall'allocazione B si arrivi ad un'allocazione C siatta Se volessimo calcolare

[1, 4, 7, , ..., ].

questo sarebbe uguale a

pC in funzione dello stato precedente, pB p6 p10 p11 + p7 . Il numero delle somme alQuesto dovuto al fatto che le due

gebriche svolte superiore alle oerte presenti in C e di fatto un'approccio di calcolo del tipo (3.45) preferibile.

allocazioni parziali contigue (B e C ) dieriscono di molte oerte fra loro. E'

ptemp delle oerte contenute nell'allocazione [1, 4, , ..., ] avremmo che pC = ptemp +p7 . In pratica ci che si
naturale che se potessimo conoscere il prezzo totale desidera ottenere il valore dello stato attuale in funzione di uno stato passato

CAPITOLO 3.

IL NOSTRO ALGORITMO

70

(non prettamente quello precedente) e dell'ultima oerta aggiunta. Dopotutto se stiamo analizzando l'allocazione

[1, 4, 6, 10, 11, , ..., ],

considerando che le

oerte vengono aggiunte una a una, evidente che in qualche iterazione passata l'algoritmo abbia valutato anche l'allocazione con

[1, 4, , ..., ] il cui stato coincide

ptemp .

Quello che viene fatto costruire una struttura dati che contenga

tutti gli stati passati non in funzione dell'allocazione parziale ma dell'ultima oerta inserita. Viene ora proposto un esempio per spiegare meglio il concetto. Si supponga che iterazioni consecutive all'interno della stessa funzione alloca() determino le seguenti allocazioni:

[1, , , , ] [1, 2, , , ] [1, 2, 4, , ] [1, 2, 4, 6, ] [1, 3, , , ] [1, 3, 5, , ]


Si costruisce un vettore

Statop (a)

che contiente il valore dello stato dell'al-

locazione parziale ottenuta dopo l'inserimento dell'oerta presente nella posizione

a.

Se

a = 0

ovviamente anche

Statop (0) = 0.

In questo contesto Tuttavia il ra-

lo stato equivale alla somma dei prezzi delle oerte allocate.

gionamento non dierisce aatto qualora vengano considerate altre grandezze, quali la somma dei beni totali (taglio sui beni) o locali (taglio sui vincoli) associati alle oerte. seconda alla Alla prima iterazione si ha che

Statop (2) = Statop (1) + p2 , alla terza quarta Statop (4) = Statop (3) + p6 . Con la quinta

Statop (1) = 0 + p1 , alla Statop (3) = Statop (2) + p4 e


iterazione l'allocazione

parziale cambia radicalmente riducendosi a due sole variabili. Di fatto si ha una riscrittura dello stato in riferimento all'ultima oerta inserita in modo che

Statop (2) = Statop (1) + p3 . Continuando con lo stesso ragionamento alla sesta iterazione si ha che Statop (3) = Statop (2) + p5 , anche qui una riscrittura
dello stato nella posizione 3. In generale, dunque, lo stato di un'allocazione parziale non viene determinato dallo stato dell'allocazione precedente ma dell'allocazione ottenuta eliminando da quella attuale l'ultima oerta inserita (e che sicuramente gi stato valutato in precedenza).

CAPITOLO 3.

IL NOSTRO ALGORITMO

71

Figura

3.2:

Ordinamento

delle

oerte

per

prezzi

decrescenti.

Si

noti

la

corrispondenza biunivoca tra vecchi e nuovi indici

Il funzionamento di AAR implica un'ordinamento delle oerte per prezzi decrescenti in modo che valga (3.26). Le oerte sono numerate rispettando questo criterio. Di fatto nel contesto dell'algoritmo la relazione esistente tra le oerte

j1

j2

che il prezzo di

j1

maggiore di quello di

j2 .

Tuttavia poco prob-

abile che le oerte del problema siano numerate conformemente al criterio di ordinamento. Quello che viene fatto ordinarle e rinominarle in modo che un oerta di indice

abbia un prezzo maggiore dell'oerta di indice

j + 1.

E'

necessario pertanto tener traccia del legame che intercorre tra i nuovi indici (quelli ottenuti dopo l'ordinamento) e i vecchi indici (quelli che identicano la variabile nella formulazione originale del problema). Ci che importante sottolineare che l'ordinamento delle oerte per prezzi decrescenti solamente una delle possibili scelte a disposizione e, tra l'altro, non risulta nemmeno la sola adottata nella progettazione del nostro algoritmo. La seconda tipologia di ordinamento delle oerte quella per numero totale di beni dal pi piccolo al pi grande in modo che:

beni1 beni2 ... benij benij+1 ... benin

CAPITOLO 3.

IL NOSTRO ALGORITMO

72

La modalit di applicazione dei tagli sostanzialmente non dierisce dal caso precedente. signicativi: Si devono tuttavia tenere in considerazione un paio di aspetti

Le quantit precalcolate necessarie per applicare i tagli vengono computate in modo dierente a seconda dell'ordinamento delle oerte. esempio, per calcolare Per

Sp (a, b) si devono considerare le prime b oerte con

prezzo maggiore tra tutte quelle rimaste da allocare. Se le oerte sono ordinate per prezzi decrescenti, quelle rimaste hanno tutte un prezzo minore dell'oerta

a.

Le oerte desiderate sono dunque

a + 1, a + 2,

... ,

a + b.

Se le oerte sono ordinate per beni crescenti questo non aatto vero ed necessario prima determinare tutte le oerte rimaste, ossia quelle aventi un numero di beni totali maggiore dell'oerta

a,

e successivamente ordi-

narle per prezzi decrescenti scegliendo le prime

b.

Un discorso analogo

viene fatto per tutte le altre quantit precalcolate (So

(a, b) ,V1 (a, b) ,...

Vm (a, b)).
Se il taglio viene applicato con successo, cambia la modalit di determinazione della nuova allocazione parziale e della prossima eventuale oerta da aggiungere. Si gi detto che il taglio dei prezzi in generale quello pi profondo. La profondit del taglio tuttavia dovuta esclusivamente al tipo di ordinamento eettuato. Sia

[1, 2, 4, 6, , ]

l'allocazione valutata

con 7 la prossima oerta da inserire. Se il taglio dei prezzi ecace avevamo gi osservato che la nuova allocazione diventa

[1, , , , , ]

con 3

la prossima oerta da aggiungere. Se le oerte sono ordinate per beni crescenti questo non pi vero. Infatti l'allocazione rimane

[1, 2, 4, 6, , ]

e l'oerta da inserire passa a 8. La motivazione semplice: non c' alcuna garanzia che

p 7 > p8

in quanto il fatto che l'oerta 8 sia consecutiva

all'oerta 7 implica solamente che ai ni del taglio sui prezzi. prezzo maggiore la

[1, 2, 4, 6, 8, 11]

che,

11, da se p8 > p7 ,

beni8 < beni7 il che non rilevante Di fatto se da [1, 2, 4, 6, 7, ] l' oerta con [1, 2, 4, 6, 8, ] posso arrivare all'allocazione
ha un prezzo maggiore della migliore allo-

[1, 2, 4, 6, 7, ]. L'unico controllo che non richiede troppo tempo per essere eseguito appunto p8 > p7 : se questo non vero, anche da [1, 2, 4, 6, 8, ] non verr mai generata un'allocazione
cazione full ottenuta partendo da full di valore maggiore del lower bound e di conseguenza l'allocazione da

CAPITOLO 3.

IL NOSTRO ALGORITMO

73

valutare diventerebbe

[1, 2, 4, 6, , ] con 9 la prossima oerta da aggiun-

gere. In denitiva, se le variabili sono ordinate per beni totali crescenti e il taglio sui prezzi ecace, si determinano nuova allocazione parziale e nuova oerta da aggiungere attraverso il seguente algoritmo: 1.

temp j j j p ptemp allora + 1 j+1 = n vai al passo 5 j


altrimenti vai al passo 5

2. se 3. se

4. torna al passo 2 5.

new j j j
l'oerta che si cercato di aggiungere nell'allo-

dove inizialmente cazione.

La nuova allocazione ottenuta partendo dalle stesse oerte

della precedente allocazione con

new j

la nuova oerta da inserire.

Per

quanto riguarda il taglio sui beni, esso tanto profondo quanto lo era il taglio sui prezzi quando le oerte erano ordinate per prezzi decrescenti e di fatto l'algoritmo per determinare la nuova allocazione parziale esattamente identico. Dopotutto questo algoritmo si basa sull'idea che se da un'allocazione non posso ottenere un'allocazione full di prezzo maggiore del lower bound, un'allocazione del genere non pu essere ottenuta nemmeno se dall'allocazione parziale iniziale sostituisco oerte con altre a loro incrementali, cio con prezzo pi piccolo. In questo caso invece, se da un'allocazione non posso ottenere un'allocazione full con un numero di beni minore di quello a disposizione, un'allocazione siatta non potr essere ottenuta nemmeno se dall'allocazione iniziale sostituisco oerte con altre a loro incrementali, cio con un numero di beni totale associato maggiore. Il taglio sui coecienti di costo ridotto e il taglio di ammissibilit sono invece indipendenti dall'ordinamento delle oerte e di conseguenza non subiscono variazioni nella metodologia di computazione della nuova allocazione parziale da valutare.

L'aver introdotto nella trattazione un secondo tipo di ordinamento dovuto al fatto che entrambi gli ordinamenti sono stati utilizzati per implementare l'algoritmo AAR. In particolare abbiamo osservato, alla luce di un suciente numero di istanze benchmark, che i risultati migliori in termini di prestazioni si ottengono analizzando le cardinalit alte mediante un ordinamento per beni

CAPITOLO 3.

IL NOSTRO ALGORITMO

74

crescenti e le cardinalit basse tramite un ordinamento per prezzi decrescenti. E' bene far presente anche che solitamente la cardinalit ottima ben lontana dagli estremi del range di cardinalit valide e in particolare si aggira in un intorno del valor medio tra

CARDmin e CARDmax .

Queste sono considerazioni

puramente empiriche. Tuttavia, considerando che apportano un miglioramento delle prestazioni dell'algoritmo e che, in ogni caso, un peggioramento (sia in termini di ecacia che di ecienza) non fattibile, si ritenuto opportuno tenerle in considerazione nella strategia di analisi degli alberi che diventa:

1.

CARDmedia =

CARDmax +CARDmin ; 2

2. analisi degli alberi a partire da

CARDmedia + 1

no a

CARDmax

con le

oerte ordinate per beni totali crescenti; 3. analisi degli alberi a partire da

CARDmedia

no a

CARDmin

con le oerte

ordinate per prezzi decrescenti.

Analizzare le cardinalit superiori a

CARDmedia k
(con

e via via sempre crescenti

permette di determinare l'ottimo (se esiste) molto pi velocemente, perch pi probabile che sia ottima la cardinalit che la cardinalit

k + 1.

Qualora la cardinalit

k > CARDmedia ) piuttosto ottima sia k CARDmedia ,

la soluzione ottima pu essere trovata anche analizzando cardinalit superiori, che infatti vengono valutate per prima. Se invece la soluzione ottima

non viene trovata analizzando le cardinalit maggiori di

CARDmedia ,

sicura-

mente verr determinata valutando tutte le cardinalit possibili minori o uguali a

CARDmedia

e partendo proprio da quest'ultima, sempre per un motivo di

maggior probabilit di essere quella ottima rispetto alle rimanenti.

3.3.2 RR: Riduzione ricorsiva del problema


E' un algoritmo pensato per risolvere un problema di dimensioni elevate. Lo spazio delle soluzioni da navigare cresce esponenzialmente con il numero delle variabili del problema e, sebbene i tagli risultino essere ecaci, dicilmente ne vengono ignorate grandi porzioni. Di conseguenza un approccio di tipo AAR non la soluzione ideale in termini di prestazioni. L'idea su cui si basa RR quella di ssare a 1 o 0 un

set di variabili anch il problema riformulato abbia una dimensione tale da poter essere risolto attraverso AAR. Si tenga presente che il xing delle variabili sempre

CAPITOLO 3.

IL NOSTRO ALGORITMO

75

possibile a prescindere dalla durata dell'operazione in quanto nella soluzione ottima necessariamente una variabile

xj

settata o a 1 o a 0 e di fatto si utilizzano opportune

strategie per determinare a quale dei due valori deve essere ssata all'ottimo. Il nome di Riduzione Ricorsiva sta a sottolineare come la ricorsione sia una delle principali strategie per ottenere questo risultato.

3.3.2.1 Inizializzazione di RR
Anche per RR la risoluzione del problema equivale a vericare che, dato un lower bound

LB ,

esista un'allocazione ammissibile di oerte la cui somma dei prezzi

migliore o al limite uguale al lower bound stesso. Come vedremo in seguito le strategie di xing delle variabili si basano sulla risoluzione di sottoproblemi aventi dimensioni ridotte. Essendo l'obiettivo di queste strategie quello di ssare variabili nel problema di partenza, la risoluzione del sottoproblema non nalizzata alla ricerca dell'ottimo e anche qualora la soluzione ottima esista e abbia un valore complessivo migliore di

LB ,

questa non viene computata limitandosi esclusivamente ad aggiornare il lower

bound. In altre parole RR ssa una serie di variabili tenendo traccia dei miglioramenti del lower bound senza tuttavia interessarsi dell'allocazione di oerte associata al miglior lower bound trovato. Sar compito dell'algoritmo AAR che risolve il problema ridotto a memorizzare la soluzione ottima (se esiste), esattamente nel modo esposto in (3.3.1.5). Sia

il numero di variabili del problema e sia

V ARmax

il numero massimo di

variabili che un problema deve avere per poter essere risolto tramite AAR. Il compito dell'algoritmo RR quello di ssare un numero di oerte almeno pari a

nV ARmax in

modo da ottenere un problema ridotto di dimensioni gestibili anche da un approccio di tipo AAR. Lo strumento principale utilizzato da RR il RCC denito in (3.20). E' suciente dunque risolvere il rilassamento continuo del problema e utilizzare i costi ridotti e il valore della funzione obiettivo, unitamente al lower bound in input, per costruire tale vincolo logico. Fatto questo, le variabili del problema vengono ordinate per costi ridotti

bj

decrescenti in modo che:

b1 b2 ... bj bj+1 ... bn1 bn

(3.46)

CAPITOLO 3.

IL NOSTRO ALGORITMO

76

Per comodit riportiamo anche la denizione di RCC:

|bj | xj +
jN jN +

bj (1 xj ) U B LB

(3.47)

3.3.2.2 Fixing diretto delle variabili


In questa fase vengono ssate tutte quelle variabili che, assumendo il valore opposto, determinano una violazione del RCC. Di fatto se una variabile ha un costo ridotto positivo maggiore del termine noto del vincolo viene settata a 1; analogamente se una variabile ha un costo ridotto negativo minore del termine noto del vincolo viene settata a 0. In generale:

1. se 2. se

bj > U B LB

allora

xj 1 xj 0

bj < (U B LB)

allora

Questo permette di ottenere una prima sostanziale riduzione della dimensione del problema.

3.3.2.3 Fixing indiretto delle variabili


In questa fase viene eettuata un'analisi avanzata adottata anche in [35] ma completamente rivista. L'idea quella di ssare temporaneamente una variabile ad un certo valore binario

val

e vericare che, cosi facendo, non si possa ottenere un valore Se la verica va a buon ne, la variabile viene settata

migliore del lower bound. a

1 val, questa volta in modo denitivo. In generale il xing temporaneo della variabile xj in funzione del segno del proprio costo ridotto: se bj > 0 , xj viene ssata temporaneamente a 0 mentre se bj < 0 , xj viene ssata a 1. In questo modo
avremo sempre un raorzamento del RCC dovuto ad una diminuzione del termine noto di una quantit pari a casi possibili:

|bj |.

Sia

xj

la variabile da ssare e si analizzino i due

1.

bj > 0: xj

viene settata a 0 e apporta un contributo positivo al primo membro

di (3.47) pari a

bj ,

che va dunque a sottrarsi al termine noto

U B LB .

questo punto si elimina l'oerta

xj

dal problema e si applica nuovamente il

xing diretto descritto in (3.3.2.2). Di fatto, ssando

xj

a 0, possibile che

altre variabili debbano essere ssate a 0 o a 1 onde evitare la violazione del RCC.

CAPITOLO 3.

IL NOSTRO ALGORITMO

77

Il xing temporaneo di

xj ,

dunque, comporta una riduzione della dimensione

del problema di un numero maggiore o al pi uguale a uno (visto che almeno una variabile, ossia

xj ,

viene ssata).

Esempio:

Si supponga di avere il seguente RCC :

23.13 (1 x12 ) + 22.44 (1 x13 ) + 5.11x6 + 10.62x14 +10.65x5 + 20.47x4 + 24.36x1 + 24.41x15 34.62 x12 venisse ssata a 0 si avrebbero ancora a disposizione 34.62 23.13 = 11.49 unit perch la disuguaglianza sia corretta. Da questa considerazione si pu aermare che x13 deve essere posta a 1 e che x4 , x1 e x15 devono essere poste a 0.
Se la variabile 2.

bj < 0 : x j

viene settata a 1 e apporta un contributo positivo al primo membro

di (3.47) pari a

|bj |,

che va a sottrarsi al termine noto

U B LB .

A questo

punto si elimina l'oerta

xj

dal problema e si applica nuovamente il xing Di fatto, ssando a

diretto descritto in (3.47).

xj

a 1 possibile che altre

variabili debbano essere ssate a 0 o a 1 onde evitare la violazione del RCC. Il problema viene quindi ridotto di un numero di variabili maggiore o al pi uguale a 1 (visto che almeno

xj

viene ssata).

Esempio:

Si supponga di avere il seguente RCC :

23.13 (1 x12 ) + 22.44 (1 x13 ) + 5.11x6 + 10.62x14 +10.65x5 + 20.47x4 + 24.36x1 + 24.41x15 34.62 x15 viene ssata a 1 34.62 24.41 = 10.21 unit perch
Se la variabile a 1 mentre si avrebbero a disposizione ancora la disuguaglianza sia corretta. Da

questa considerazione si pu aermare che

x12

x13

devono essere poste

x14 , x5 , x4

x1

devono essere poste a 0.

3.3.2.4 Schema generale di xing delle variabili


Sia

x j

la variabile che si vuole ssare e la si ponga a

val

(con

val

uguale a 0 o

a 1) in accordo ai due casi enunciati pocanzi.

Si denisca

Ndirf ix

l'insieme degli

indici delle variabili ssate tramite xing diretto e

Nindf ix

l'insieme degli indici delle

CAPITOLO 3.

IL NOSTRO ALGORITMO

78

variabili ssate tramite xing indiretto. Sia

Nf ix+

Nnotf ix = N/ (Ndirf ix Nindf ix { e j}) = {j (Ndirf ix Nindf ix { | xj = 1}. Si formula ora il seguente problema: j}) max
jNnotf ix

pj xj

wij xj ci
jNnotf ix jNf ix+

wij i = 1, ..., m

(3.48)

j {0, 1} j Nnotf ix
Se

LB

il lower bound del problema di partenza, il lower bound del problema (3.48)

corrisponde a:

LBrif ormulato = LB
jNf ix+
Si risolva il problema (3.48) e si valuti il valore ottimo

pj
zrif ormulato :

(3.49)

1.

zrif ormulato < LBrif ormulato

: non esiste alcuna allocazione di oerte del pro-

blema riformulato che ha un valore complessivo pari a

LBrif ormulato , LB

che a sua

volta il minimo valore che sommato ai prezzi delle oerte gi ssate a 1 (appartenenti a

Nf ix+ )

permette di ottenere il lower bound

del problema

di partenza. Il altre parole se zrif ormulato jNf ix+

pj < LB . x, j

Considerando che

< LBrif ormulato si ha che zrif ormulato + le oerte in Ndirf ix sono ssate al loro

valore ottimo e quelle in assunto da

Nindf ix

sono ssate ad un valore funzionale a quello

si conclude facilmente che porre

x = val j

equivale a trovare

come miglior soluzione ammissibile un'allocazione di oerte il cui prezzo totale non raggiunge il lower bound del problema originale. all'ottimo necessario che 2. Di fatto

x = val, j

xj = 1 val.
se sommo il valore ottimo del problema riformulato

zrif ormulato > LBrif ormulato :

con i prezzi delle oerte gi settate a 1 (appartenenti a

Nf ix+ )

si ottiene un

valore pi grande del lower bound del problema di partenza. In altre parole l'allocazione (ammissibile) ottenuta considerando le oerte di

Nf ix+

e quelle

valorizzate a 1 nel problema riformulato (3.48) migliore della soluzione ottima attuale. Questo risultato permette di aggiornare il lower bound del problema che diventa quindi

LB =

xi Nf ix+

pi + zrif ormulato .

Non possibile ssare

CAPITOLO 3.

IL NOSTRO ALGORITMO

79

denitivamente la variabile che, ponendo

x j

val

in quanto a priori non c' alcuna garanzia

xj = 1 val,

non ottenga un valore ulteriormente migliore della

funzione obiettivo del problema. 3.

zrif ormulato = LBrif ormulato :

la miglior soluzione ottenuta ponendo

xj = val

ha

un valore identico al lower bound del problema originale. E' l'unico caso in cui n il lower bound viene aggiornato n la variabile

xj

viene ssata a

1 val.

Si osservi, come descritto in (3.3.2.3), che una variabile viene posta temporaneamente ad un valore tale per cui il RCC si raorzi. E' inutile osservare il comportamento del problema ottenuto ssando tale variabile al valore opposto in quanto non verrebbe apportata alcuna semplicazione nella riformulazione del problema e la strategia di xing si ridurrebbe ad un puro approccio di tipo branch and bound. Come vedremo in seguito, la strategia di xing adottata permette di ottenere sottoproblemi (3.48) via via pi semplici da risolvere. Resta da capire come le variabili vengono selezionate per poi ssarne il valore. L'idea quella di indirizzare al xing le variabili che apportono una semplicazione maggiore possibile al RCC. Ci permette di risolvere un problema riformulato pi semplice e quindi di ottenere considerazioni del caso.

zrif ormulato

molto velocemente per poi fare tutte le

Ovviamente il contributo di semplicazione del RCC pi alto

in funzione del coeciente di costo ridotto (in modulo) della variabile:

e maggiore la riduzione del termine noto del vincolo e pi variabili possono essere conseguentemente ssate ad un determinato valore tramite xing indiretto. Dopotutto abbiamo gi valutato come il costo ridotto di una variabile esprima una buona approsimazione di quanto questa variabile assuma il valore 0 piuttosto che 1 all'interno della soluzione ottima. Fissando la variabile al valore opposto di quello che avrebbe nella soluzione ottima, il problema riformulato viene risolto facilmente in quanto pi bassa la probabilit che il suo ottimo possa superare il valore del lower bound desiderato. Inoltre opportuno far notare un aspetto molto importante. Supponiamo che il meccanismo di xing sulla variabile

xj1

si concluda positivamente

e che di conseguenza sia noto il suo valore all'ottimo. processo di xing sulla variabile associato non contiene

Successivamente si itera il

xj2 .

E' facile osservare che il problema riformulato

xj1

in quanto il suo valore gi stato ssato correttamente,

esattamente come quello di tutte le oerte contenute in

Nf ix .

Di fatto pi si procede

a ssare variabili e pi i problemi riformulati avranno dimensioni ridotte e quindi pi semplici da risolvere. Tanto vale dunque tentare di ssare inizialmente le variabili

CAPITOLO 3.

IL NOSTRO ALGORITMO

80

pi facili in modo da poterle eliminare denitivamente dal problema allo stesso modo delle variabili contenute in

Nf ix 9 .

Il meccanismo di xing pu essere descritto

in maniera rigorosa dal seguente algoritmo:

1.

Ntemp = N \ Ndirf ix card (Ntemp ) = 0 xj


allora vai al passo 11

2. se

3. Selezione di 4. se

tale che

bj = max {|bj |}, j Ntemp


altrimenti e

bj > 0

allora

xj 0

xj 1
come descritto in (3.3.2.3)

5. determinazione di

Nindf ix

Nf ix+

6. riformulazione del problema come descritto in (3.48) e calcolo di 7. se

zrif ormulato

zrif ormulato +

jNf ix+
,

pj LB

allora

LB zrif ormulato +

jNf ix+

pj

altrimenti 8. se 9.

xj 1 xj

Ndirf ix = Ndirf ix j
allora vai al passo 11 altrimenti vai al passo 9

n card (Ndirf ix ) V ARmax

Ntemp = Ntemp \ j

10. torna al passo 2 11. exit

Chiaramente una volta ssate tutte le variabili necessarie, queste vengono eliminate dal problema (aggiornando opportunamente il lower bound e le capacit dei vincoli) che viene poi risolto tramite AAR.

9 Sebbene il problema denito in ( 3.48 ) sia un riformulazione del problema di partenza


intermedio variabile

P, a

livello implementativo si eettua un passaggio ulteriore che prevede la creazione di un problema

che non contiene le variabili presenti in

Ndirf ix .

Infatti tali variabili sono sempre

escluse in tutte le riformulazioni a venire in quanto il valore a cui sono poste non funzionale alla

x j

selezionata per il xing. Di conseguenza i problemi riformulati sono ottenuti partendo

direttamente da

anzich da

P.

CAPITOLO 3.

IL NOSTRO ALGORITMO

81

3.3.2.5 Risoluzione del problema riformulato


La risoluzione del problema denito in (3.48) non nalizzata a determinare la soluzione ottima ma la miglior soluzione possibile qualora questa abbia un valore maggiore di

LBrif ormulato . Rlp z

Esistono quindi diversi approcci risolutivi, dipendenti

anche dalla dimensione del problema. Per comodit deniamo riformulato e

il problema intero

il problema riformulato eliminando i vincoli di interezza delle va-

riabili. Il primo passo quello di calcolare la soluzione ottima di indicati con

Rlp . E' noto che, e zlp rispettivamente l'ottimo intero e l'ottimo continuo, vale che

zlp

Rlp pi piccolo di LBrif ormulato sicuramente impossibile che la soluzione ottima di R sia migliore di LBrif ormulato per la propriet transitiva ( z zlp LBrif ormulato ). Questo controllo molto veloce in
. Se il valore della soluzione ottima di termini di tempo ma solitamente poco ecace. E' necessario dunque utilizzare un metodo che navighi lo spazio delle soluzioni intere del problema vericando che ne esista almeno una migliore di quella cercata. Un approccio algoritmico siatto gi stato presentato nel corso di questa trattazione. Dopotutto il problema riformulato

non altro che un MKP e sono stati forniti gli strumenti per risolvere nel modo

desiderato questa tipologia di problemi: AAR e RR. Sussistono due possibilit. Si denisca

nR

il numero di variabili del problema

R:

1.

nR V ARmax :

Il problema risulta sucientemente piccolo da poter essere

risolto tramite AAR. Se esiste un'allocazione ammissibile di oerte di valore complessivo maggiore di

LBrif ormulato

tale valore viene restituito e utilizzato

per aggiornare il lower bound del problema di partenza. In caso contrario viene restituituo un valore negativo. 2.

nR > V ARmax :

Il problema ha dimensioni ancora troppo grandi per essere

risolto tramite AAR. Di conseguenza necessario ssare qualche altra variabile in modo da ricadere nel caso 1. Il xing delle variabili viene eseguito applicando nuovamente l'algoritmo RR questa volta sul problema R. Cos facendo verranno generati altri problemi riformulati problemi ancora maggiore di

R1 , R2 .... Rh . Se la dimensione di tali V ARmax si applica nuovamente RR su questi

problemi e via dicendo. In altre parole RR viene applicato ricorsivamente no a quando non vengono generati sottoproblemi aventi una dimensione tale da poter essere risolti da AAR che, dunque, pu essere considerato come il piede della ricorsione. La terminazione della ricorsione garantita dal fatto che il

CAPITOLO 3.

IL NOSTRO ALGORITMO

82

Figura 3.3: Esempio di riduzione ricorsiva

problema riformulato ha un numero di variabili pi piccolo di almeno un'unit rispetto al proprio problema padre. Figura 3.3: Sia Si faccia un esempio, considerando la

R3 rispettivamente i problemi riformulati ottenuti ssando rispettivamente xj1 = val 1 , xj2 = val 2 e xj3 = val3 . R1 e R3 hanno una dimensione tale da poter essere risolti direttamente da AAR
il problema di partenza e e

R1 , R2

che tuttavia non riesce a determinare ad entrambi un valore migliore rispetto al loro lower bound. Di conseguenza le variabili vengono ssate, e

xj1 = 1 val1
e viene risolto

xj3 = 1 val3 . R2

ha una dimensione maggiore di

V ARmax

applicando nuovamente RR (livello 1). Di fatto su

R2

si calcola un nuovo RCC

partendo dai costi ridotti del suo rilassato continuo e dal lower bound determinato a partire dal lower bound di descritto in precedenza.

LB R2

nel modo che stato ampiamente

Alcune variabili di

R2

vengono ssate direttamente

per non violare il suo RCC e ne rimangono da ssare altre due ( modo che ne restino da ssare un numero pari a e si ottiene il problema riformulato A

V ARmax . LBR2

Si

x1 e x2 ) in j j ssa x = val 1 j1

R1
1

che pu essere risolto tramite AAR. meno il prezzo delle

R1

associato il lower bound

LBR

ottenuto da

oerte settate a 1 in la variabile

R2 . R2

AAR non trova alcuna soluzione migliore di

x1 j

viene settata a

1 val1 .

problema riformulato

con un lower

LBR e 1 2 e si ottiene il Si ssa poi x = val j2 bound pari a LBR . R2 ha un numero


2

di variabili maggiore di

V ARmax

e viene risolto applicato RR (livello 2).

Si

CAPITOLO 3.

IL NOSTRO ALGORITMO

83

calcola un nuovo RCC, si ssano direttamente alcune variabili e si esegue il xing indiretto di altre tre variabili per poter raggiungere una dimensione tale da poter essere risolto da AAR. I tre problemi riformulati

R1 , R2

tutti risolti tramite AAR e in tutti e tre i casi la variabile viene ora un numero di variabili rimaste da ssare uguale a

R3 sono ssata. R2 ha
e

V ARmax e viene risolto tramite AAR. Il risultato tuttavia non migliore di LBR . Nel contesto del liv2 ello ricorsivo superiore, questo comporta che la variabile x deve essere ssata j2 2 . Una volta ssate x e x , la dimensione di R2 tale da poter essere a 1 val j1 j2
risolto tramite AAR. Anche in questo caso il valore trovato non migliore di

LBR2 e nell'ottica del livello ricorsivo superiore signica che xj2 viene ssata a 1 val 2 . A questo punto R si trova ad avere un numero di variabili uguale a V ARmax e viene risolto attraverso AAR. Se il risultato migliore di LBR la
soluzione viene salvata.

E' importante far notare come sebbene il problema da risolvere possa essere in realt il prodotto di un livello ricorsivo precedente, questa informazione del tutto irrilevante dal punto di vista dell'algoritmo risolutivo. L'obiettivo nale sempre

quello di vericare che il problema su cui applicato RR abbia una soluzione ottima migliore del lower bound fornito come input. E' compito di chi invoca l'esecuzione dell'algoritmo (che a sua volta potrebbe essere un'istanza di RR di livello superiore) interpretare correttamente i risultati pervenuti. C' tuttavia una dierenza sostanziale tra l'algoritmo RR applicato al problema radice (livello 0 della ricorsione) e l'algoritmo RR applicato ai livelli successivi. Si faccia riferimento sempre all'esempio di gura 3.3. Solitamente per care la soluzione ottima se questa ha un valore pi grande di della riduzione ricorsiva a

si vuole ricer-

LBR .

L'applicazione

R2

(e cos per tutti gli altri sottoproblemi ai livelli ricor-

sivi successivi) non ha questo ne ma inserita in un contesto pi ampio, volto o a migliorare il lower bound di sola delle variabili di soluzione con valore se

o a ssare la variabile

xj2

1 val2 . R

Se anche una

R2 non viene LBR2 migliore +

ssata, signica che stato trovato per di

R2

una

LBR2 . pj

Nel contesto di

questo signica che

xj2 = val2

si ottiene una soluzione con valore pi grande di

LBR

e pi precisa-

mente almeno pari a LBR 2

jNf ix+

. Di fatto inutile continuare a risolvere

R2
la

in quanto l'obiettivo stato gi raggiunto, ossia che non possibile ssare in variabile

xj2

1 val2 .

E' pur vero che continuando a risolvere

R2

si possa trovare

una soluzione con valore ancora pi grande di

LBR2 (andando

quindi a migliorare

CAPITOLO 3.

IL NOSTRO ALGORITMO

84

ulteriormente il lower bound di to a

R)

ma questo non rilevante in quanto RR applica-

un algoritmo esatto e se esiste un valore migliore dell'attuale lower bound

questo viene prima o poi determinato. Il vantaggio, dunque, risiede nella capacit di spezzare prima la catena ricorsiva guadagnando in termini di prestazioni.

3.3.2.6 Schema riassiuntivo di RR


Alla luce di quanto detto possibile formalizzare meglio la procedura risolutiva di

RR su un problema

con lower bound

LB :

Procedura RR
1. BEGIN 2. Costruzione di RCC e di 3.

Ndirf ix

come descritto in (3.3.2.3)

Ntemp = N \ Ndirf ix card (Ntemp ) = 0 x j


con allora vai al passo 14

4. se

5. selezione di 6. se

b = max {|bj |}, j Ntemp j


altrimenti e

b > 0 j

allora

x 0 j

x 1 j
come descritto in (3.3.2.3)

7. determinazione di

Nindf ix

Nf ix+

8. riformulazione del problema come descritto in (3.48). Sia

tale problema e

nR
9. se

il numero delle sue variabili

nR V ARmax applica AAR altrimenti applica Procedura su R. zrif ormulato l'output fornito da AAR o RR

RR (qui denita)

10. se

zrif ormulato + jNf ix+ pj LB allora LB zrif ormulato + altrimenti x 1 x , Ndirf ix = Ndirf ix { j} j j

jNf ix+

pj

11. se 12 12.

n card (Ndirf ix ) V ARmax

allora vai al passo 14 altrimenti vai al passo

Ntemp = Ntemp \ ( j)

13. torna al passo 2

CAPITOLO 3.

IL NOSTRO ALGORITMO

85

14. formulazione del problema ridotto

Q denito su N q = N \ Ndirf ix .

Sia

q Nf ix+ =

{j Ndirf ix /xj = 1}. Q

formulato come segue:

max
jN q

pj xj wij i = 1, ..., m
jN q
f ix+

wij xj ci
jN q

(3.50)

xj {0, 1} j N q
con lower bound

LBq = LB jN q + pj . Se la migliore soluzione di Q ha un f ix valore LBq maggiore di LBq allora zrif ormulato LBq altrimenti zrif ormulato 1

15. END

3.3.2.7 RR con distinzione di cardinalit


In questo paragrafo verr descritta una variante dell'algoritmo RR utilizzata per risolvere particolari istanze di problemi. L'idea quella di fornire all'algoritmo anche la cardinalit su cui determinare l'eventuale soluzione ottima del problema. In pratica, se

la cardinalit d'ingresso e

LB

il lower bound, RR fornisce come risultato la

migliore allocazione ammissibile di oerte di cardinalit o al pi uguale di

il cui valore sia maggiore

LB .

Se un'allocazione siatta non esiste, viene posto in output

zrif ormulato

= 1

come per il RR tradizionale.

La variante di RR con cardinalit realizzata semplicemente modicando la formulazione del problema di partenza con l'aggiunta del suddetto vincolo di cardinalit:

xj = k
jN
Nel corso della trattazione questa variante di RR verr denita come cardinalit analizzata. Si possono ora fare alcune considerazioni:

(3.51)

RRk

con

la

il RCC si raorza notevolmente in quanto viene costruito partendo dal rilassato continuo del problema intero aggiungendo il vincolo (3.51). da un lato, l'abbassamento dell'upper bound Il risultato ,

UB

che comporta di fatto una

diminuzione del termine noto di RCC e, dall'altro, un incremento in modulo dei coecienti di costo ridotto associati alle variabili. La riduzione ricorsiva,

CAPITOLO 3.

IL NOSTRO ALGORITMO

86

la cui ecacia si basa sul RCC, migliora notevolmente in quanto ai vari livelli ricorsivi il numero di variabili che pu essere ssato in modo diretto e indiretto pi elevato.

l'algoritmo RR si basa sulla risoluzione di vari problemi riformulati che, a loro volta, vengono risolti tramite RR. E' necessario ogni qual volta viene formulato un nuovo sottoproblema, tener traccia del numero di variabili settate a 1 in modo da poter determinare correttamente la cardinalit ad esso associata. E' intuitivo infatti che se il problema radice viene risolto con

RRk

, anche

i sottoproblemi generati nei vari livelli ricorsivi devono essere risolti con tale variante di RR. Chiaramente la cardinalit associata ai vari problemi non pi uguale a

ma sar minore a seconda di quante variabili sono state ssate a 1

nel problema padre. Facciamo un esempio. Sia del problema di partenza.

k = 20

la cardinalit di analisi

Si supponga che siano state ssate direttamente

otto variabili di cui solo tre a 1. Si ponga ora

x = 1 j

e si proceda con il xing Il problema

indiretto che a sua volta ssa quattro variabili di cui due a 1. riformulato viene risolto tramite RR con analisi della cardinalit

krif ormulato =

20 3 1 2 = 14.

In generale la cardinalit del problema riformulato :

krif ormulato = k card (Nf ix+ )


e pertanto il problema riformulato deve essere risolto con

(3.52)

RRkrif ormulato .

Come noto, applicando

RR

e ssando un certo numero di variabili, il pro-

blema ottenuto eliminando tali variabili viene risolto tramite AAR. La prima operazione svolta da AAR quella di determinare

CARDmin

CARDmax

per

poi analizzare tutti gli alberi di cardinalit compresa tra questi valori. Come avvenuto per RR anche per AAR si denisce una sua variante con cardinalit,

AARk ,

che si limita a valutare esclusivamente l'albero delle soluzioni aventi

cardinalit

k.

Di fatto se si risolve un problema con

RRk ,

dopo aver ssato un

numero suciente di variabili, si ottiene un problema ridotto che viene risolto da

AARkridotto

con

kridotto = k card (Nf ix+ ).

Si osservi come il tempo di

esecuzione di

AARkridotto sia inferiore al tempo impiegato per analizzare l'albero di cardinalit kridotto utilizzando il tradizionale approccio AAR, in quanto
nel primo caso viene utilizzato un RCC pi forte, ottenuto grazie al vincolo di cardinalit (3.51), rendendo il taglio sui coecienti di costo ridotto pi

CAPITOLO 3.

IL NOSTRO ALGORITMO

87

ecace.

Inoltre, anche se il calcolo di

CARDmin

uo, questo viene eseguito ugualmente in quanto se

CARDmax pare superkridotto > CARDmax o

kridotto < CARDmin


valore migliore di

l'esecuzione di

AARkridotto

non necessaria e si ottiene lo

stesso risultato del caso in cui non si riesce a determinare una soluzione avente

LBridotto .

3.4

Core, EC, AAR e RR: calcolo della soluzione ottima di un MKP

E' giunto il momento di mettere insieme tutti gli strumenti descritti dettagliamente nei paragra precedenti per poter denire un metodo rigoroso di risoluzione di un generico problema di tipo MKP.

3.4.1 Approccio senza distinzione di cardinalit


1. Si estrae dal problema

DIMcore = V ARmax 10 in base ai costi ridotti ottenuti risolvendo il rilassato continuo di P . Si ssano le rimanenti variabili al loro valore di upper/lower bound e si calcola un primo LBcore P
un core di dimensione

attraverso una qualunque euristica di irrilevante peso computazionale solve il problema Core di lower bound

11

. Si riun

LBcore

tramite AAR. Essendo

LBcore

lower bound eettivo del problema Core, AAR restituisce sicuramente un'allocazione ottima di oerte che, unite a quelle settate a 1 tra le variabili gi ssate, costituisce la soluzione ammissibile di partenza che verr migliorata tramite l'espansione del Core. Questa soluzione viene salvata in il valore ottenuto sommando settate a 1 viene salvato in

soluzione

LBcore ottimo.

ai prezzi delle oerte esterne al Core e

2. Tra tutte la variabili escluse dal Core si seleziona quella con costo ridotto in modulo pi grande. Se tale coeciente risulta pi grande del termine noto del

RCC associato a

l'algoritmo di risoluzione di

termina e la soluzione ottima

e il relativo valore sono contenuti rispettivamente in caso contrario, sia

x j

tale variabile. Se

b > 0 j

allora

soluzione e in ottimo. In x 0 altrimenti x 1. j j

10 Nel Capitolo 4 si suggerisce un valore per


sulle istanze benchmark.

V ARmax

alla luce dei risultati sperimentali ottenuti

11 Nel nostro caso stata utilizzata l'euristica proposta da Bertsimas con il nome di Adaptive

Fixing Base-Heuristic in [7].

CAPITOLO 3.

IL NOSTRO ALGORITMO

88

3. Si risolve il nuovo problema Core tramite RR a cui si fornisce in ingresso un nuovo lower bound

LBcore

ottenuto sottraendo al valore di

ottimo

la somma

dei prezzi delle variabili esterne al Core e ssate a 1. Problema Core e

LBcore
In

cambiano a causa della dierente congurazione delle variabili esterne. uscita a RR viene fornito un valore

uguale a -1 se non stata trovata nessuna

allocazione ammissibile di oerte avente prezzo complessivo maggiore di oppure un valore positivo che corrisponde all'ottimo del problema

LBcore Core (z

LBcore ).

z il prezzo totale delle oerte esterne al Core e settate a 1 e lo si salva in ottimo; inoltre, si aggiorna la soluzione ottima in soluzione. A prescindere dal risultato di RR la variabile xj viene aggiunta
Nel secondo caso si somma a al Core. 4. Tornare al passo 2.

3.4.2 Approccio con distinzione di cardinalit


1. Si costruisce un forte lower bound per il problema descritto nel passo 1 in (3.4.1). rispettivamente in 2. Si calcolano

applicando il procedimento

Si salva tale valore e la relativa soluzione

ottimo
e

e in

soluzione.
di

CARDmin k

CARDmax

P.
e

3. Per ogni cardinalit

compresa tra

CARDmin

CARDmax

si costruisce un

problema Core di dimensione vendo il rilassato continuo di

V ARmax

in base ai costi ridotti ottenuti risol-

con l'aggiunta del vincolo di cardinalit (3.51)

12

Si riapplica il passo 1 descritto in (3.4.1) per ogni problema Core, aggiornando in caso di miglioramento il valore di

ottimo

e di

soluzione.

I problemi Core (e

i relativi stati delle variabili esterne) vengono salvati in un vettore chiamato

cores.
4. Sia

Corek

un problema Core salvato in

Si seleziona tra tutte le variabili modulo pi grande. del

cores con CARDmin k CARDmax . escluse da Corek quella con costo ridotto in k,
l'algoritmo risolutivo di

Se tale coeciente risulta pi grande del termine noto

RCCk

associato a

con vincolo di cardinalit

12 Si osservi che i problemi Core, sebbene abbiano la stessa dimensione e siano ottenuti dallo stesso
problema di partenza, non sono aatto identici in quanto l'aggiunta del vincolo di cardinalit associa alle variabili costi ridotti dierenti.

CAPITOLO 3.

IL NOSTRO ALGORITMO

89

Corek

termina e il suddetto problema viene eliminato dal vettore

caso contrario, sia

xj

tale variabile. Se

bj > 0

allora

cores. In xj 0 altrimenti xj 1.

5. Si applica il passo 3 della procedura descritta in (3.4.1). 6. Si iterano i passi 4 e 5 della procedura qui descritta per ogni cardinalit

con

CARDmin k CARDmax .
7. Se il vettore

cores

vuoto, il problema stato risolto per tutte le cardinalit

possibili. La soluzione ottima e il relativo valore della funzione obiettivo sono salvati rispettivamente in passo 4.

soluzione

ottimo.

In caso contrario si torna al

Capitolo

Prove computazionali
In questo capitolo vengono riportate le prove compiute per testare l'algoritmo descritto comparando i risultati con i pi importanti lavori proposti in letteratura nell'ambito del Multidimensional Knapsack Problem. Abbiamo eseguito il nostro algoritmo su tutti i 270 problemi proposti da P.C. Chu e J.E. Beasley [9] adottando delle strategie risolutive dierenti a seconda della dimensione e della complessit del problema specico. seguito presentati possono essere classicati come segue: In particolare i risultati di

Applicazione dell'algoritmo esatto : per istanze di piccole e medie dimensioni si


utilizzato l'algoritmo cos come descritto nel capitolo 3 riportando la soluzione ottima dei problemi e il tempo computazionale per ricavarla in apposite tabelle. Le tempistiche sono state comparate con quelle di ILOG CPLEX 10.0, attualmente l'unico software in grado di implementare un algoritmo esatto competitivo anche per i problemi di tipo MKP. Le prove sono state eseguite su un Pentium IV a 3 Ghz con 2 GB RAM e sistema operativo Windows XP Professional Service Pack 2.

Applicazione dell'algoritmo euristico : si tratta di una variante dell'algoritmo


esatto descritto nel capitolo 3 e che verr analizzata in modo approfondito nel corso di questo stesso capitolo. Questa versione modicata del software

stata utilizzata per ottenere soluzioni di buona qualit per le istanze pi dicili tra quelle proposte da P.C. Chu e J.E. Beasley, comparando i risultati (bont della soluzione e tempo per ottenerla) con le migliori metaeuristiche attualmente sviluppate. Le prove sono state eseguite su un AMD Athlon 64

90

CAPITOLO 4.

PROVE COMPUTAZIONALI

91

X2 Dual Core 4800+ a 2.4 Ghz con 2 GB RAM e sistema operativo Windows XP Professional Service Pack 2.

Per tutte le prove abbiamo utilizzato la versione 8.1 di CPLEX come risolutore dei rilassamenti continui dei sottoproblemi all'interno del nostro algoritmo in quanto le migliorie introdotte nella versione 10.0 (di cui disponevamo solo di una licenza) riguardano essenzialmente la programmazione intera e non l'algoritmo del simplesso utilizzato per risolvere il rilassato.

4.1

Java 5.0

L'algoritmo stato sviluppato interamente in Java nella recente versione 5.0 [43]. La scelta di utilizzare Java anzich linguaggi come il C o il C++ pu considerarsi a primo impatto poco felice. Java infatti un linguaggio interpretato, cio il codice sorgente viene prima compilato in una sorta di linguaggio intermedio chiamato bytecode che, all'istanziazione del singolo processo, la Java Virtual Machine (JVM ) installata su calcolatore interpreta traducendolo in istruzioni macchina. Sebbene Java sia estremamente portabile in quanto suciente avere installata una JVM per eseguire qualunque programma java, esso risulta molto pi ineciente di un linguaggio compilato, che traduce solo in fase di compilazione il codice sorgente in istruzioni binarie direttamente eseguibili dal calcolatore. Il gap di ecienza tra le due tipologie di linguaggi, che agli albori di Java era di circa un ordine di grandezza, si notevolmente ridotto con il perfezionamento della

JVM. In particolare i risultati presentati in seguito sono stati ottenuti utilizzando la JVM rilasciata gratuitamente da BEA [44], una delle pi importanti software house
di application server in java. Questa JVM dispone di un sosticato compilatore

JIT (Just in time ) in grado di tradurre velocemente il bytecode java in istruzioni


binarie memorizzate poi all'interno di una cache a cui si accede ogni qualvolta che lo stesso bytecode viene eseguito in fase di esecuzione. Questo approccio avvicina notevolmente le prestazioni di Java a quelle di un linguaggio compilato, soprattutto se il codice java di tipo algoritmico, ossia costituito da poche istruzioni eseguite per un numero elevato di volte all'interno di cicli e strutture ricorsive. Infatti queste istruzioni vengono tradotte in codice binario solo la prima volta che vengono eseguite, introducendo di fatto solo un overhead dovuto alla traduzione iniziale e all'accesso alla cache.

CAPITOLO 4.

PROVE COMPUTAZIONALI

92

La scelta di Java dovuta essenzialmente alla necessit di utilizzare un linguaggio potente e essibile per costruire un algoritmo robusto e facilmente modicabile in seguito a studi futuri. Avendo poca dimestichezza con l'utilizzo di C, ho optato per l'adozione di Java, che invece conosco e utilizzo nella pratica, per concentrare la maggior parte degli sforzi negli aspetti concettuali dell'algoritmo anzich in quelli puramente implementativi. Si tenga presente infatti che l'algoritmo descritto nel

capitolo 3 il risultato di un lavoro di parecchi mesi in cui la strategia risolutiva si anata ed evoluta nel tempo, necessitando di modicare dinamicamente il codice in seguito ai risultati delle prove intermedie di verica dell'ecacia ed ecienza della metodologia proposta. Volendo vericare nella pratica l'eettivo divario in termini di ecienza tra Java e C, si deciso di scrivere l'algoritmo AAR per la navigazione degli alberi di ricerca binaria in ANSI C ed eseguire delle prove su istanze realizzate ad hoc comparando i risultati con lo stesso algoritmo scritto in Java. Anch il test sia valido, abbiamo eseguito le prove sulla stessa macchina, un AMD Athlon 64 X2 Dual Core 4800+ a 2.4 Ghz e 2 GB RAM con sistema operativo Linux distribuzione Kubuntu. Per l'algoritmo in Java ci siamo avvalsi della JVM di BEA mentre per quello scritto in C abbiamo utilizzato il compilatore GCC 4.1.1. Le istanze di test sono state generate partendo dai problemi pi semplici tra quelli proposti da P.C. Chu e J.E. Beasley (n

= 100

m = 5)

riducendone il numero delle

variabili a 40, scelte tra quelle pi dicili da settare al relativo valore binario ottimo. La scelta di tradurre esclusivamente l'algoritmo AAR dovuta al fatto che una procedura che non necessita della collaborazione e dello scambio di messaggi con altre parti dell'algoritmo generale EC e pertanto la scrittura del codice si limitata quasi ad una semplice trasposizione dei costrutti Java in costrutti C. Ovviamente, essendo

AAR un algoritmo pensato per risolvere in modo esatto problemi di dimensioni


ridotte, abbiamo scelto un numero di variabili pari a 40 con l'obiettivo di avere tempi di risoluzione non immediati ma comunque ragionevoli. Dai risultati da noi ottenuti abbiamo riscontrato che l'esecuzione della versione C di AAR porta ad un incremento delle prestazioni di circa il 100% rispetto alla versione Java, dimezzando praticamente i tempi di risoluzione. Per avere dei riscontri pi oggettivi necessario tuttavia eettuare una comparazione delle prestazioni dell'intero algoritmo EC scritto nei due linguaggi, in quanto subentrano aspetti, come le chiamate ai metodi di oggetti e l'interfacciamento con CPLEX, non presenti nel solo algoritmo AAR. Tuttavia, considerando che in C possibile scrivere codice

CAPITOLO 4.

PROVE COMPUTAZIONALI

93

procedurale di basso livello meno leggibile ma pi eciente rispetto ai costrutti Java orientati agli oggetti, si pu ritenere realistico il dimezzamento dei tempi ottenuti traducendo l'algoritmo EC in C. Di fatto si pu valutare l'idea di avere una versione compilabile dell'algoritmo prima di procedere ad apportare modiche, in modo da valutare i risultati generati in tempi pi brevi soprattutto nell'ottica euristica, in cui i problemi di test sono complessi e necessitano comunque di tempi elevati prima che i risultati vengano prodotti. In conclusione le tempistiche che sono presentate nel seguito del capitolo si riferiscono all'esecuzione dell'algoritmo EC scritto in Java 5.0. In realt, seppur,

come vedremo, sono tempi gi di per s ottimi, possono essere abbassati di molto, anche per eettuare un confronto pi veritiero con i risultati ottenuti dagli algoritmi concorrenti comparati, tutti implementati in C.

4.2

Applicazione dell'algoritmo esatto

Al momento della stesura di questo lavoro le uniche istanze di P.C. Chu e J.E. Beasley delle quali sono note le soluzioni ottime appartengono alle classi di dimensioni minori, pi precisamente:

Istanze CB 100.5 (n Istanze CB 250.5 (n

= 100 = 250

e e

m = 5) m = 5)
e

Istanze CB 100.10 (n

= 100

m = 10)
Questo

Si tratta di 90 problemi sui 270 presentati da P.C. Chu e J.E. Beasley.

signica che a dieci anni di distanza dalla loro pubblicazione, ben 180 problemi non sono ancora stati risolti.

4.2.1 Istanze di P.C. Chu e J.E. Beasley 100.5 , 250.5 e 500.5


Abbiamo deciso di iniziare i nostri test con le istanze da 5 vincoli comparando i tempi ottenuti con quelli di CPLEX 10.0 non essendoci altri algoritmi esatti competitivi in grado di risolvere questa categoria di problemi. E' stato necessario congurare

CPLEX 10.0 in modo che risolvesse all'ottimo il problema in quanto le impostazioni


di default prevedono un rilassamento delle condizioni di fathoming dei nodi che non permette di trovare la soluzione ottima per molte delle istanze di prova testate. Per

CAPITOLO 4.

PROVE COMPUTAZIONALI

94

quanto riguarda il nostro algoritmo, abbiamo settato la dimensione del Core iniziale a

DIMcore = 30

e il numero massimo di variabili che deve avere il problema per

poter essere risolto tramite AAR a

V ARmax = 30.

In particolare abbiamo osservato

un peggioramento delle prestazioni sia aumentando che diminuendo il valore scelto di

V ARmax ,
per

a cui pu essere data la seguente motivazione:

V ARmax > 30

la dimensione del problema da risolvere con AAR aumenta, In pratica, se

rallentando l'esecuzione del suddetto algoritmo.

V ARmax =
variabili

30 + h,
ssare

il tempo necessario per risolvere un problema con

V ARmax

tramite AAR generalmente pi elevato del tempo impiegato cercando di

variabili con RR e risolvendo il problema riformulato con 30 variabili

tramite AAR.

per

V ARmax < 30 la dimensione del problema da risolvere con AAR diminuisce, necessitando di ssare tramite RR pi variabili. In pratica, se V ARmax = 30 h, il tempo necessario per risolvere un problema con 30 variabili tramite AAR generalmente pi basso del tempo impiegato per ssare h variabili con RR e risolvere il problema riformulato con V ARmax variabili tramite AAR.
Questo dovuto al fatto che la risoluzione con AAR di un problema con 30 variabili quasi sempre immediata e di fatto inutile abbassare la dimensione massima di risoluzione, in quanto il lieve l'incremento computazionale ottenuto viene cancellato dalla necessit di eettuare pi chiamate ricorsive per ssare un numero maggiore di variabili.

In tabella 4.1, 4.2 e 4.3 sono riportati i risultati relativi rispettivamente alle istanze 100.5, 250.5 e 500.5 di P.C. Chu e J.E. Beasley. Per ogni istanza viene indicato

il numero del problema, il valore della soluzione ottima, la cardinalit

dell'al-

locazione ottima e i tempi ottenuti dal nostro algoritmo EC e da CPLEX 10.0 in secondi. In tabella 4.4 sono riportati i tempi medi di risoluzione di ogni set di 10 istanze (dierenziate per

m, n

e il coeciente

della funzione obiettivo) ottenuti

dal nostro algoritmo e da CPLEX 10.0, sempre in secondi.

CAPITOLO 4.

PROVE COMPUTAZIONALI

95

Analisi dei risultati:

i risultati ottenuti dal nostro algoritmo sono sorprendenti

e non sono comparabili ad alcun'altra strategia di risoluzione di questa classe di problemi. Lo stesso CPLEX 10.0 che implementa un risolutore basato su un eciente branch and cut risolve gli stessi problemi in tempi maggiori quasi di un ordine di grandezza rispetto ai nostri. Per le istanze 100.5 i tempi sono dell'ordine del secondo e non si discostano troppo da quelli ottenuti con CPLEX 10.0. Aumentando la

dimensione del problema la dierenza tra i due approcci comincia a farsi pi evidente no a palesarsi nella risoluzione delle istanze 500.5 per le quali il nostro algoritmo impiega un tempo medio per istanza di poco meno di 5 minuti al contrario dei 75 minuti impiegati da CPLEX 10.0. Allo stato dell'arte attuale non esiste nessun

algoritmo (esatto ed euristico) in grado di trovare la soluzione ottima per i problemi della classe 500.5 in un tempo cos ridotto.

4.2.2 Istanze di P.C. Chu e J.E. Beasley 100.10 e 250.10


Il secondo gruppo di istanze che abbiamo provato a risolvere in modo esatto sono quelle appartenenti alle classi 100.10 e 250.10. Di queste istanze vengono forniti solo i risultati ottenuti attraverso il nostro algoritmo. Sebbene CPLEX 10.0 permetta di ottenere tempi dello stesso ordine di grandezza ai nostri per quanto riguarda le istanze 100.10, per le istanze 250.10 il consumo di memoria troppo elevato per pensare di poterle risolvere all'ottimo. Al contrario, l'esecuzione del nostro algoritmo comporta un consumo bene o male costante di RAM (intorno ai 100 MB) pi che altro utilizzata dalla JVM di BEA per ottimizzare il bytecode. istanze abbiamo settato i parametri Anche per queste

DIMcore = 30

V ARmax = 30.

In tabella 4.5 e 4.6 sono riportati i risultati relativi alle istanze rispettivamente delle classi 100.10 e 250.10. Per queste ultime, i tempi di elaborazione sono forniti in ore e minuti, secondo la notazione hh - mm.

CAPITOLO 4.

PROVE COMPUTAZIONALI

96

Tabella 4.1: Istanze 100.5 di P.C. Chu e J.E. Beasley Istanze Tempo elaborazione EC ( s ) Tempo elaborazione CPLEX 10.0 ( s ) 6.14 2.66 4.95 19.81 6.23 2.5 0.64 2.53 4.09 4.28 Tempo elaborazione CPLEX 10.0 ( s ) 1.28 1.83 35.39 6.23 4.03

( = 0.25)
100.5.00 100.5.01 100.5.02 100.5.03 100.5.04 100.5.05 100.5.06 100.5.07 100.5.08 100.5.09 Istanze

Ottimo 24381 24274 23551 23534 23991 24613 25591 23410 24216 24411 Ottimo 42757 42545 41968 45090 42218 42927 42009 45020 43441 44554 Ottimo 59822 62081 69802 60479 61091 58959 61538 61520 59453 59965

K
29 29 29 28 30 30 31 28 28 28

2.00 1.52 2.67 3.11 1.19 1.06 0.53 1.28 0.61 1.0 0.39 0.45 5.66 1.55 0.87 0.34 3.55 0.77 1.69
1.21

( = 0.5)
100.5.10 100.5.11 100.5.12 100.5.13 100.5.14 100.5.15 100.5.16 100.5.17 100.5.18 100.5.19 Istanze

K
52 50 53 52 54 54 55 53 52 53

Tempo elaborazione EC ( s )

0.37
8.59 1.16 3.05 Tempo elaborazione CPLEX 10.0 ( s ) 0.59 0.67 2.06 3.44 1.42 2.58 1.20 1.02 0.59 4.09

1.08

( = 0.75)
100.5.20 100.5.21 100.5.22 100.5.23 100.5.24 100.5.25 100.5.26 100.5.27 100.5.28 100.5.29

K
78 77 77 76 78 76 76 76 76 76

Tempo elaborazione EC ( s )

0.52 0.28 0.52 0.81 0.58 1.39 0.36 1.06 0.34 3.39

CAPITOLO 4.

PROVE COMPUTAZIONALI

97

Tabella 4.2: Istanze 250.5 di P.C. Chu e J.E. Beasley Istanze Tempo elaborazione EC ( s ) Tempo elaborazione CPLEX 10.0 ( s ) 64.48 167.53 14.20 943.37 448.09 428.61 242.22 222.55 60.36 21.37 Tempo elaborazione CPLEX 10.0 ( s ) 209.44 26.44 140.66 219.70 833.22 207.67 147.72 462.87 187.11 253.52 Tempo elaborazione CPLEX 10.0 ( s ) 116.02 80.02 154.92 88.06 134.43 9.13 7.20 140.36 36.16 101.00

( = 0.25)
250.5.00 250.5.01 250.5.02 250.5.03 250.5.04 250.5.05 250.5.06 250.5.07 250.5.08 250.5.09 Istanze

Ottimo 59312 61472 62130 59463 58951 60077 60414 61472 61885 58959 Ottimo 109109 109841 108508 109383 110720 110256 109040 109042 109971 107058 Ottimo 149665 155944 149334 152130 150353 150045 148607 149782 155075 154668

K
73 74 76 71 74 74 76 73 76 72

2.53 15.58 5.44 82.45 21.87 44.09 9.50 47.01 14.05 4.87 24.41 8.55 18.25 37.23 74.03 25.17 12.02 38.37 48.41 33.08 26.62 8.53 23.17 9.78 25.28 3.05 2.58 14.62 4.68 12.65

( = 0.5)
250.5.10 250.5.11 250.5.12 250.5.13 250.5.14 250.5.15 250.5.16 250.5.17 250.5.18 250.5.19 Istanze

K
132 135 130 134 130 132 133 132 130 131

Tempo elaborazione EC ( s )

( = 0.75)
250.5.20 250.5.21 250.5.22 250.5.23 250.5.24 250.5.25 250.5.26 250.5.27 250.5.28 250.5.29

K
191 190 191 193 191 191 192 193 190 191

Tempo elaborazione EC ( s )

CAPITOLO 4.

PROVE COMPUTAZIONALI

98

Tabella 4.3: Istanze 500.5 di P.C. Chu e J.E. Beasley Istanze Tempo elaborazione EC ( s ) Tempo elaborazione CPLEX 10.0 ( s ) 9495.08 2112.22 5188.23 6390.36 2860.30 3657.51 8498.31 3631.08 10424.12 6641.16 Tempo elaborazione CPLEX 10.0 ( s ) 4572.84 2981.42 11637.39 8425.27 648.89 5136.17 2447.30 2955.05 5886.83 5117.97 Tempo elaborazione CPLEX 10.0 ( s ) 218.31 3744.97 746.42 5467.58 2554.25 1218.58 837.47 804.24 2336.92 8301.98

( = 0.25)
500.5.00 500.5.01 500.5.02 500.5.03 500.5.04 500.5.05 500.5.06 500.5.07 500.5.08 500.5.09 Istanze

Ottimo 120148 117879 121131 120804 122319 122024 119127 120568 121586 120717 Ottimo 218428 221202 217542 223560 218966 220530 219989 218215 216976 219719 Ottimo 295828 308086 299796 306480 300342 302571 301339 306454 302828 299910

K
147 148 144 149 147 153 145 150 149 138

563.31 127.20 233.25 192.61 220.92 407.37 559.56 171.37 482.61 261.00

( = 0.5)
500.5.10 500.5.11 500.5.12 500.5.13 500.5.14 500.5.15 500.5.16 500.5.17 500.5.18 500.5.19 Istanze

K
267 265 264 264 267 262 266 249 262 267

Tempo elaborazione

409.47 97.97 1347.89 781.12 65.22 215.22 125.87 188.05 212.41 488.12
Tempo elaborazione EC ( s )

EC ( s )

( = 0.75)
500.5.20 500.5.21 500.5.22 500.5.23 500.5.24 500.5.25 500.5.26 500.5.27 500.5.28 500.5.29

K
371 384 385 384 369 385 385 383 369 378

43.76 247.83 86.64 143.33 203.70 82.34 47.02 39.75 150.20 554.53

CAPITOLO 4.

PROVE COMPUTAZIONALI

99

Tabella 4.4: Sintesi dei risultati per le istanze 100.5, 250.5 e 500.5 di P.C. Chu e J.E. Beasley Istanze 100.5 00-09 10-19 20-29 Tempo di elaborazione medio EC ( s ) Tempo di elaborazione medio CPLEX 10.0 ( s ) 5.38 6.30 1.76 Tempo di elaborazione medio CPLEX 10.0 ( s ) 261.28 268.85 83.86 Tempo di elaborazione medio CPLEX 10.0 ( s ) 5889.83 4980.93 2623.72

( = 0.25) ( = 0.50) ( = 0.75)


250.5

1.50 1.65 0.92

Istanze

Tempo di elaborazione medio EC ( s )

00-09 10-19 20-29

( = 0.25) ( = 0.50) ( = 0.75)


500.5

24.72 31.95 13.10

Istanze

Tempo di elaborazione medio EC ( s )

00-09 10-19 20-29

( = 0.25) ( = 0.50) ( = 0.75)

321.93 393.11 159.90

Analisi dei risultati:

sebbene i tempi di elaborazione per le istanze 100.10 siano

relativamente bassi, sono comunque di un ordine di grandezza pi elevato dei tempi relativi alle istanze 100.5. Si osserva, come era prevedibile, che la dicolt del problema cresce esponenzialmente all'aumentare del numero dei vincoli. A dimostrazione di ci, suciente comparare le tempistiche relative alle istanze 250.10, risolte all'ottimo mediamente in 10 ore rispetto alle istanze 250.5, risolte all'ottimo mediamente in meno di un minuto. Inoltre le istanze identicate in grassetto in tabella 4.6 hanno tempi di risoluzione non accettabili e la situazione non pu che peggiorare con l'aumentare dei vincoli e delle variabili. L'incremento del numero di vincoli del problema aumenta la correlazione tra le variabili, rendendo pi dicile stilare una graduatoria delle oerte con pi possibilit di entrare nell'allocazione ottima. In altre parole gi con istanze correlate da 250 variabili e 10 vincoli, il modello del problema non permette di ottenere informazioni signicative per una riformulazione adeguata. Questo uno dei motivi per cui il Multidimensional Knapsack Problem un problema di dicile trattazione e che ha spinto di fatto molti ricercatori a trovare strategie di tipo euristico per la sua risoluzione. Nel nostro caso specico, l'ecacia dell'algoritmo

dipende completamente dalla robustezza del taglio RCC , responsabile del xing delle

CAPITOLO 4.

PROVE COMPUTAZIONALI

100

Tabella 4.5: Istanze 100.10 di P.C. Chu e J.E. Beasley Istanze Tempo elaborazione EC ( s ) 90.26 83.11 24.14 175.56 19.06 89.84 30.34 7.76 13.42 63.23 Tempo elaborazione EC ( s ) 72.42 21.06 106.37 39.62 24.25 112.14 96.20 28.19 81.09 113.43 Tempo elaborazione EC ( s ) 3.13 36.14 30.28 5.87 5.04 21.25 45.37 6.29 13.09 7.78

( = 0.25)
100.10.00 100.10.01 100.10.02 100.10.03 100.10.04 100.10.05 100.10.06 100.10.07 100.10.08 100.10.09 Istanze

Ottimo 23064 22081 22131 22772 22751 22777 21875 22635 22511 22702 Ottimo 41395 42344 42401 45624 41884 42995 43574 42970 42212 41207 Ottimo 57375 58978 58391 61966 60803 61437 56377 59391 60205 60633

K
27 27 26 27 26 26 27 27 27 27

( = 0.5)
100.10.10 100.10.11 100.10.12 100.10.13 100.10.14 100.10.15 100.10.16 100.10.17 100.10.18 100.10.19 Istanze

K
51 51 51 54 51 52 52 52 52 53

( = 0.75)
100.10.20 100.10.21 100.10.22 100.10.23 100.10.24 100.10.25 100.10.26 100.10.27 100.10.28 100.10.29

K
77 75 75 75 74 76 76 75 76 76

CAPITOLO 4.

PROVE COMPUTAZIONALI

101

Tabella 4.6: Istanze 250.10 di P.C. Chu e J.E. Beasley Istanze Tempo elaborazione EC ( hh - mm ) 10h - 15m 8h - 7m 3h - 6m 35h - 24m 78h - 30m 3h - 39m 3h - 36m 75h - 43m 8h - 36m 14h - 21m Tempo elaborazione EC ( hh - mm ) 7h - 7m 15h - 32m 9h - 48m 38h - 22m 5h - 42m 21h - 30m 19h - 27m 12h - 53m 10h - 58m 2h - 55m Tempo elaborazione EC ( hh - mm ) 2h - 11m 6h - 51m 1h - 22m 1h - 48m 2h - 12m 1h - 37m 14m 10h - 54m 1h - 3m 1h - 8m

( = 0.25)
250.10.00 250.10.01

Ottimo 59187 58781 58097 61000 58092 58824 58704 58936 59387 59208 Ottimo 110913 108717 108932 110086 108485 110845 106077 106686 109829 106723 Ottimo 151809 148772 151909 151324 151966 152109 153131 153578 149160 149704

K
68 69 69 70 67 68 67 69 68 69

250.10.03 250.10.04
250.10.05

250.10.02

250.10.07
250.10.08 250.10.09 Istanze

250.10.06

( = 0.5)

K
129 127 128 131 128 130 129 128 127 131

250.10.11 250.10.13 250.10.15 250.10.16


250.10.17 250.10.18 250.10.19 Istanze 250.10.14 250.10.12

250.10.10

( = 0.75)
250.10.20 250.10.21 250.10.22 250.10.23 250.10.24 250.10.25 250.10.26 250.10.27 250.10.28 250.10.29

K
187 188 189 189 191 189 189 187 187 190

CAPITOLO 4.

PROVE COMPUTAZIONALI

102

variabili e della riduzione del problema. Aumentare la correlazione tra le variabili comporta un avvicinamento dei loro costi ridotti i cui valori sono fondamentali per classicare le variabili prima e creare ed espandere il Core dopo. Inoltre, pi vincoli ha un problema, maggiore il numero della variabili in base. Ora, a meno che non entrino in base solo variabili di slack, una variabile

xj

del problema in base ha costo

ridotto nullo e di fatto non viene inserita nella formulazione del RCC . Se la funzione di valutazione delle variabili, basata sui costi ridotti, restituisce valori tra loro simili, il relativo vincolo RCC meno forte e di conseguenza tutto l'algoritmo diventa pi debole. Nonostante questo aspetto fosse noto a priori, abbiamo deciso comunque di risolvere all'ottimo le istanze 250-10 per due semplici motivi:

trovare il limite, in termini di dimensione del problema, dell'ecacia risolutiva del nostro algoritmo;

entrare in possesso di dati oggettivi (soluzione ottima e tempo necessario per calcolarla) da confrontare con i risultati ottenuti risolvendo le stesse istanze con un approccio di tipo euristico.

4.2.3 Analisi separata delle cardinalit


Il nostro algoritmo in grado di risolvere il problema adottando due strategie distinte: 1. distinguendo le cardinalit delle allocazioni ammissibili solo nei problemi risolvibili mediante AAR; 2. distinguendo le

cardinalit delle allocazioni ammissibili gi a partire dall'ap-

plicazione di RR, risolvendo di fatto il vincolo di cardinalit 3.51.

problemi separati a cui viene aggiunto

Con il secondo metodo sono stati risolti i problemi 250-5, 500-5 e 100-10.

Con il

primo metodo sono state risolte le istanze 100-5 e tutti i problemi appartenenti alle classi pi complesse di P.C. Chu e J.E. Beasley risolte in modo euristico. In tabella 4.7, 4.8, 4.9, 4.10 e 4.11 sono riportati i risultati relativi alle quattro classi di istanze risolte all'ottimo, comparando le tempistiche ottenute applicando entrambi i metodi risolutivi descritti. . Considerata la trascurabile dierenza di tempistiche tra i due metodi applicati alle istanze 100.5, dalle nostre prove emerso che per istanze con un numero ridotto

CAPITOLO 4.

PROVE COMPUTAZIONALI

103

Tabella 4.7: Istanze 100-5 di P.C. Chu e J.E. Beasley Istanza Tempo EC ( s ) card. distinte 2.31 1.95 2.87 4.51 1.83 1.16 0.59 1.89 1.17 1.47 Tempo EC ( s ) card. distinte 0.63 0.70 8.21 2.19 0.91 0.49 1.45 3.86 0.94 2.00 Tempo EC ( s ) card. distinte 0.56 0.29 0.61 1.17 0.59 2.05 0.47 1.19 Tempo EC ( s ) card. non distinte

( = 0.25)
100-5-00 100-5-01 100-5-02 100-5-03 100-5-04 100-5-05 100-5-06 100-5-07 100-5-08 100-5-09 Istanza

2.00 1.52 2.67 3.11 1.19 1.06 0.53 1.28 0.61 1.0

Tempo EC ( s ) card. non distinte

( = 0.5)
100-5-10 100-5-11 100-5-12 100-5-13 100-5-14 100-5-15 100-5-16 100-5-17 100-5-18 100-5-19 Istanza

0.39 0.45 5.66 1.55 0.87 0.34 1.21 3.55 0.77 1.69

Tempo EC ( s ) card. non distinte

( = 0.75)
100-5-20 100-5-21 100-5-22 100-5-23 100-5-24 100-5-25 100-5-26 100-5-27 100-5-28 100-5-29

2.41

0.42

0.52 0.28 0.52 0.81 0.58 1.39 0.36 1.06 0.34


3.39

CAPITOLO 4.

PROVE COMPUTAZIONALI

104

Tabella 4.8: Istanze 250-5 di P.C. Chu e J.E. Beasley Istanza Tempo EC ( s ) card. distinte Tempo EC ( s ) card. non distinte 8.39 19.41 6.51

( = 0.25)
250-5-00 250-5-01 250-5-02 250-5-03 250-5-04 250-5-05 250-5-06 250-5-07 250-5-08 250-5-09 Istanza

2.53 15.58 5.44 82.45


21.87

44.09 9.50 47.01


14.05 4.87 Tempo EC ( s ) card. distinte

18.45
59.62 14.02

89.22

13.16 3.20
Tempo EC ( s ) card. non distinte 78.55

89.28

( = 0.5)
250-5-10 250-5-11 250-5-12 250-5-13 250-5-14 250-5-15 250-5-16 250-5-17 250-5-18 250-5-19 Istanza

24.41
8.55

18.25 37.23 74.03 25.17 12.02


38.37

7.64

18.66 43.92 102.16 35.30

33.08
Tempo EC ( s ) card. distinte

48.41

35.26 39.70
38.55 Tempo EC ( s ) card. non distinte 28.36

15.77

( = 0.75)
250-5-20 250-5-21 250-5-22 250-5-23 250-5-24 250-5-25 250-5-26 250-5-27 250-5-28 250-5-29

26.62 8.53
23.17

9.78
3.05 2.58

22.87 22.42 2.87 2.20


20.37 5.87 20.53 12.20

12.20

25.28

14.62 4.68 12.65

CAPITOLO 4.

PROVE COMPUTAZIONALI

105

Tabella 4.9: Istanze 500-5 di P.C. Chu e J.E. Beasley Istanza Tempo EC ( s ) card. distinte Tempo EC ( s ) card. non distinte 707.14 135.19 389.87

( = 0.25)
500-5-00 500-5-01 500-5-02 500-5-03 500-5-04 500-5-05 500-5-06 500-5-07 500-5-08 500-5-09 Istanza

563.31 127.20 233.25 192.61


220.92 559.56

407.37 171.37 482.61 261.00


Tempo EC ( s ) card. distinte

197.48 480.87
244.56 632.34 458.39 Tempo EC ( s ) card. non distinte 547.67 106.12 1617.36 801.17 71.75 523.08

545.15

( = 0.5)
500-5-10 500-5-11 500-5-12 500-5-13 500-5-14 500-5-15 500-5-16 500-5-17 500-5-18 500-5-19 Istanza

409.47 97.97 1347.89 781.12 65.22 215.22 188.05


212.41 488.12 125.87

116.02 200.30 417.98


Tempo EC ( s ) card. non distinte 43.83 403.53 105.64 231.31 327.09 207.97

340.61

Tempo EC ( s ) card. distinte

( = 0.75)
500-5-20 500-5-21 500-5-22 500-5-23 500-5-24 500-5-25 500-5-26 500-5-27 500-5-28 500-5-29

43.76 247.83 86.64 143.33 203.70 47.02


82.34 39.75

81.86
47.75

150.20
554.53

38.45 428.78
187.28

CAPITOLO 4.

PROVE COMPUTAZIONALI

106

Tabella 4.10: Istanze 100-10 di P.C. Chu e J.E. Beasley Istanza Tempo EC ( s ) card. distinte Tempo EC ( s ) card. non distinte

( = 0.25)
100-10-00 100-10-01 100-10-02 100-10-03 100-10-04 100-10-05 100-10-06 100-10-07 100-10-08 100-10-09 Istanza

83.11 24.14 175.56 89.84 7.76 13.42 63.23


Tempo EC ( s ) card. distinte 30.34 19.06

90.26

85.00
30.27

117.06

210.86

14.17
13.81 24.31 81.34

123.34

24.49

Tempo EC ( s ) card. non distinte

( = 0.5)
100-10-10 100-10-11 100-10-12 100-10-13 100-10-14 100-10-15 100-10-16 100-10-17 100-10-18 100-10-19 Istanza

72.42
21.06

106.37

39.62
24.25

20.12 79.94 21.14


140.32 101.76 30.83 92.55 223.75 Tempo EC ( s ) card. non distinte 47.02

82.66

112.14 96.20 28.19 81.09 113.43


Tempo EC ( s ) card. distinte 3.13

( = 0.75)
100-10-20 100-10-21 100-10-22 100-10-23 100-10-24 100-10-25 100-10-26 100-10-27 100-10-28 100-10-29

36.14 30.28
5.87

2.95

45.45 30.91

21.25
45.37 6.29 13.09

5.04

4.58 4.03

7.78

44.34 5.83 12.17


8.91

21.97

CAPITOLO 4.

PROVE COMPUTAZIONALI

107

Tabella 4.11: Sintesi dei risultati per le istanze 100.5, 250.5, 500.5 e 100.10 di P.C. Chu e J.E. Beasley Istanze 100.5 00-09 10-19 20-29 Tempo medio EC card. distinte( s ) 1.97 2.14 0.98 Tempo medio EC card. distinte( s ) Tempo medio EC card. non distinte( s )

( = 0.25) ( = 0.50) ( = 0.75)


250.5

1.50 1.65 0.92

Istanze

Tempo medio EC card. non distinte( s ) 32.12 41.55 14.99 Tempo medio EC card. non distinte( s ) 431.41 442.69 189.55 Tempo medio EC card. non distinte( s ) 72.46 84.32 18.11

00-09 10-19 20-29

( = 0.25) ( = 0.50) ( = 0.75)


500.5

24.72 31.92 13.10

Istanze

Tempo medio EC card. distinte( s )

00-09 10-19 20-29

( = 0.25) ( = 0.50) ( = 0.75)

321.93 393.11 159.90 59.60 69.48 17.41

Istanze 100.10 00-09 10-19 20-29

Tempo medio EC card. distinte( s )

( = 0.25) ( = 0.50) ( = 0.75)

CAPITOLO 4.

PROVE COMPUTAZIONALI

108

di vincoli la risoluzione di pi problemi distinti ognuno con il proprio vincolo di cardinalit permette in generale di ottenere delle prestazioni computazionali migliori. In pratica sia

un problema con

CARDmin

CARDmax

rispettivamente la cardi-

nalit minima e la cardinalit massima delle allocazioni da valutare. Sia inoltre l'algoritmo in grado di risolvere il problema in modo classico,

EC

ECk l'algoritmo che risolve il problema P applicando separatamente i CARDmax CARDmin + 1 vincoli di cardinalit e T una funzione per valutare il tempo di esecuzione degli algoritmi.
Per istanze con un numero di vincoli ridotto si ha, in generale, che:

CARDmax

T (EC (P )) >
k=CARDmin

T (ECk (P ))

(4.1)

Per problemi siatti il taglio sui costi ridotti estremamente ecace e permette di riformulare il problema in modo da ridurlo notevolmente in poche chiamate ricorsive. L'aggiunta di un ulteriore condizione stringente, quale il vincolo di cardinalit, al rilassato continuo, permette di generare costi ridotti in valore assoluto pi elevati parallelamente ad un upper bound (e di fatto al termine noto del vincolo RCC ) pi basso. Tutto questo raorza ulteriormente il vincolo RCC rendendo molto pi veloce l'applicazione dell'algoritmo ricorsivo per cardinalit prossime a quella ottima e quasi immediata per cardinalit distanti da essa. Questo spiega come sia possibile che la risoluzione di

CARDmax CARDmin + 1 problemi distinti sia pi rapida della

risoluzione di un unico problema. Lo stesso discorso pu essere applicato anche per le istanze 100.10 in quanto, sebbene il numero di vincoli sia maggiore, la dimensione del problema in termini di numero di variabili ancora piccola, ottenendo dei vincoli

RCC nuovamente raorzati se applicato il vincolo di cardinalit.

La situazione Per

cambia per le istanze pi complesse testate, a partire gi dalla classe 250.10.

questi problemi, l'aggiunta del vincolo di cardinalit non determina un raorzamento del taglio sui costi ridotti signicativo. Essendo questo taglio l'unica dierenza tra i vari problemi risolti da

ECk ,

applicare l'algoritmo basato sulla distinzione delle

cardinalit rischia di ridursi ad eseguire l'algoritmo su

CARDmax CARDmin + 1

problemi uguali, rendendo di fatto l'esecuzione complessiva molto pi lenta.

CAPITOLO 4.

PROVE COMPUTAZIONALI

109

4.2.4 Ordinamento delle variabili nell'enumerazione delle soluzioni in AAR


Un ultimo aspetto interessante da evidenziare relativo all'ordinamento delle variabili necessario per applicare i tagli all'albero di ricerca durante l'esecuzione dell'algoritmo AAR. Il nostro algoritmo prevede due tipologie di ordinamento delle variabili: per prezzi decrescenti e per beni crescenti. A seconda del problema e della cardinalit analizzata, la navigazione dell'albero di ricerca avviene pi velocemente considerando un tipo di ordinamento piuttosto che l'altro. Purtroppo non stato possibile

determinare a priori quali fattori entrano in gioco per determinare quale dei due ordinamenti preferibile applicare e di conseguenza ci siamo avvalsi di considerazioni empiriche. Abbiamo eseguito delle prove sulle istanze della classe 500.5 utilizzando diversi approcci e comparando i tempi ottenuti. Si deciso di ordinare le variabili a seconda del valore della cardinalit analizzata

in funzione del valor medio

kmedia

tra la cardinalit massima e quella minima. In tabella 4.12 sono riportati i tempi in secondi ottenuti utilizzando:

l'ordinamento per prezzi per tutte le cardinalit; l'ordinamento per beni per tutte le cardinalit; l'ordinamento per beni se l'ordinamento per beni se l'ordinamento per beni se l'ordinamento per beni se

k < kmedia , k kmedia , k kmedia , k > kmedia ,

altrimenti l'ordinamento per prezzi; altrimenti l'ordinamento per prezzi; altrimenti l'ordinamento per prezzi; altrimenti l'ordinamento per prezzi.

Dalle prove eettuate emerso che la strategia migliore quella di ordinare le variabili per beni crescenti qualora la cardinalit analizzata sia maggiore della cardinalit media, altrimenti le variabili devono essere ordinate per prezzi decrescenti. Tuttavia solo una considerazione empirica ottenuta mediando i tempi relativi esclusivamente a queste 30 istanze. Si consideri che, prendendo di volta in volta il tempo migliore in relazione alla singola istanza, si ottiene un tempo medio di risoluzione pari a 252 secondi, ossia del 15% pi basso del valore da noi trovato. Inoltre plausibile che un'ordinamento sia preferibile all'altro a prescindere dalla relazione tra la cardinalit analizzata e quella media ma in funzione di altri fattori. E' bene dunque eettuare

CAPITOLO 4.

PROVE COMPUTAZIONALI

110

Tabella 4.12: Tempi di risoluzione delle istanze 500.5 di P.C. Chu e J.E. Beasley per diversi ordinamenti delle variabili Istanza 500.5.00 500.5.01 500.5.02 500.5.03 500.5.04 500.5.05 500.5.06 500.5.07 500.5.08 500.5.09 500.5.10 500.5.11 500.5.12 500.5.13 500.5.14 500.5.15 500.5.16 500.5.17 500.5.18 500.5.19 500.5.20 500.5.21 500.5.22 500.5.23 500.5.24 500.5.25 500.5.26 500.5.27 500.5.28 500.5.29 media BENI 530 PREZZI 579 87 247 320 179

k < kmedia
559

k kmedia ,
535 98 159 304 185 371 369 181

k kmedia

140 178
230 399

141

86

523
135 165 183 220 391 582 151 448 243 582 96

k > kmedia
563 127 233 193 221 407 560 171 482 261 409 98 1348

220

149 441
235 606

573

356
206 553

367

170 362
362 201 544 254 411

312

387
61 1736

271

229
562 67 1548 840 73 308 123 178 191 496 40 356 74 198 231 113 30 37 125 650 306

505

1155
954 70 297 138 225 222 495 46 262 96 165 237 128 54 44 170 652 304

102

60
69

680
70 230

1697 685

1193 933 69 287 141 229 230 511 45 263 96 156 241 114 53 45 172 666 305

144 184
496 39 343 67 181 203

113

111 144 480 38 66 116 201 24 33


116 548 295 82 341 188

237

65 215
126 188 212 488

781

248
87 143 204 82 47 40 150

44

69
26 34

106 544
296

291

555

CAPITOLO 4.

PROVE COMPUTAZIONALI

111

ulteriori studi per stabilire se esiste una procedura che permetta di valutare di volta in volta la scelta di un ordinamento piuttosto che l'altro.

4.3

Algoritmo euristico

4.3.1 Valutazione dei problemi ridotti


Per problemi di grandi dimensioni, non possibile applicare fedelmente il nostro algoritmo in quanto il taglio sui costi ridotti non sucientemente forte da consentire una discesa ricorsiva rapida. In queste situazioni necessario adattare l'algoritmo

EC in modo da velocizzare la navigazione dello spazio delle soluzioni attraverso un


rilassamento delle condizioni di valutazione dei problemi ridotti. Questo da un lato consente un incremento delle prestazioni, dall'altro non permette di avere pi la garanzia che la soluzione trovata sia ottima. Come noto, applicando l'algoritmo RR vengono risolti dei problemi ridotti con l'obiettivo o di migliorare il lower bound del problema padre o di ssarne alcune variabili. Se il problema ridotto di dimensioni sucientemente piccole (n

V ARmax )

viene risolto tramite AAR, altrimenti si procede ricorsivamente ad applicare RR. L'algoritmo esatto non prevede alcun'altra condizione di valutazione oltre a questa e in entrambi i casi il problema ridotto viene risolto. La versione euristica del nostro algoritmo prevede semplicemente di introdurre una nuova condizione per la risoluzione del problema ridotto. ridotto, Sia

il problema il il

UB P

un suo upper bound ottenuto risolvendo il rilassato continuo e E' ovvio che se

lower bound calcolato nei passi ricorsivi precedenti. problema a

LB U B < LB

non viene risolto in quanto la soluzione ottima intera non sar mai uguale

LB .

Sfortunatamente questa condizione non si verica quasi mai ed necessario

rilassarla in questo modo:

UB

UB GAP

< LB

(4.2)

In pratica si decrementa l'upper bound di una quantit che dipende da esso. L'idea quella di non risolvere il problema se la dierenza tra

UB

LB

pi piccola di

una certa quantit ipotizzando che la soluzione ottima intera abbia un valore che si discosta da

UB

almeno di

UB . GAP

Ovviamente, pi basso il valore di

GAP

e pi

possibilit ci sono che la condizione (4.2) venga soddisfatta, evitando di risolvere il problema. Di fatto, per valori bassi di

GAP

molti problemi ridotti non vengono

CAPITOLO 4.

PROVE COMPUTAZIONALI

112

risolti e l'algoritmo molto prestante; tuttavia ci sono maggiori possibilit che venga tagliato parte dello spazio di ricerca in cui collocata la soluzione ottima. Aumentando il valore di

GAP ,

diminuisce il numero di problemi che vengono ignorati ma

aumenta la possibilit di trovare soluzioni di pi elevata qualit. Come vedremo, il valore di

GAP

non univoco ma dipende molto dall'istanza di

riferimento. Generalmente bene utilizzare valori bassi per problemi molto complessi per avere una prima buona soluzione in tempi comunque brevi. Successivamente possibile riapplicare l'algoritmo risolutivo con un

GAP

pi elevato. Questo dipende

anche dal tempo limite che viene ssato per la risoluzione di un certo problema. Nelle nostre prove abbiamo utilizzato diversi approcci per capire come valorizzare il parametro

GAP

e ne verr fatta menzione quando saranno presentati i risultati Per tutte le istanze risolte

per le istanze complesse di P.C. Chu e J.E. Beasley.

euristicamente, abbiamo utilizzato l'algoritmo EC senza distinzione delle cardinalit dei problemi durante la ricorsione.

4.3.2 Istanze di P.C. Chu e J.E. Beasley 500.10


In tabella 4.19 sono riportati i risultati ottenuti con un

GAP = 100.

Oltre al tempo di

elaborazione e alla miglior soluzione trovata, sono indicati anche la cardinalit della soluzione

e il miglior valore ottenuto dall'euristica di P.C. Chu e J.E. Beasley.

Si osserva come il nostro algoritmo trova una soluzione decisamente migliore rispetto a quella di Chu e Beasley su tutte le 30 istanze risolte, in tempi relativamente brevi mediamente sotto l'ora. Inoltre bene precisare che l'algoritmo EC stato

condotto a termine no a che il Core non poteva pi essere espanso, nonostante la soluzione riportata in tabella sia stata ricavata generalmente molto prima. Per fare un esempio il valore 219984 relativo al problema 500.10.17 stato trovato dopo soli 1500 secondi contro i 10421 dell'intera elaborazione. Chiaramente possibile partire con

GAP

pi bassi. Anche con

GAP = 50

ab-

biamo notato miglioramenti della soluzione in tempi dell'ordine dei minuti, anche se ovviamente non si raggiunge la qualit ottenuta con

GAP = 100.

Abbiamo di

seguito valutato il tempo impiegato per terminare l'algoritmo EC con per ripetere l'algoritmo con un nuovo valore di

GAP = 100

GAP .

L'idea quella di incrementare

il valore di poco quando il tempo di elaborazione gi piuttosto alto, mentre aumentarlo maggiormente sino a raddoppiarlo per istanze risolte in breve tempo. In tabella 4.14 sono riportati i nuovi valori della soluzione ottenuta con un

GAP

varia-

CAPITOLO 4.

PROVE COMPUTAZIONALI

113

Tabella 4.13: Risultati per le istanze 500.10 di P.C. Chu e J.E. Beasley con GAP = 100

Istanza 500.10.01 500.10.01 500.10.02 500.10.03 500.10.04 500.10.05 500.10.06 500.10.07 500.10.08 500.10.09 500.10.10 500.10.11 500.10.12 500.10.13 500.10.14 500.10.15 500.10.16 500.10.17 500.10.18 500.10.19 500.10.20 500.10.21 500.10.22 500.10.23 500.10.24 500.10.25 500.10.26 500.10.27 500.10.28 500.10.29

Risultato Chu e Beasley 117726 119139 119159 118802 116434 119454 119749 118288 117779 119125 217318 219022 217772 216802 213809 215013 217896 219949 214332 220833 304344 302332 302354 300743 304344 301730 304949 296437 301313 307014

Risultato

117790 119206 119215 118813 116509 119475 119790 118323 117781 119218 217377 219077 217797 216868 213846 215071 217931 219984 214382 220882 304387 302348 302416 300757 304357 301796 304952 296459 301357 307089

EC

K
134 136 136 137 135 137 139 135 136 137 256 259 256 259 256 256 260 257 257 254 379 380 380 378 380 376 377 379 379 378

GAP 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100

Tempo di elaborazione EC ( s ) 2445 1986 6744 2942 208 1343 9893 3786 201 1411 4243 1120 372 103 1543 964 213 10421 1032 3122 1534 524 1032 2653 4354 532 9321 3124 1033 212

CAPITOLO 4.

PROVE COMPUTAZIONALI

114

bile, dipendente dall'istanza. Come si osserva, in generale c' un incremento della soluzione rispetto al caso precedente, a scapito di un peggioramento computazionale considerato che il tempo medio di elaborazione passa da poco meno di un'ora a poco meno di tre ore.

4.3.3 Istanze di P.C. Chu e J.E. Beasley 500.30


Le istanze 500.30 rappresentano sicuramente la classe di problemi di pi dicile risoluzione tra tutti quelli proposti da P.C. Chu e J.E. Beasley e, pi in generale, presenti in letteratura per quanto riguarda il Multidimensional Knapsack Problem. Per queste istanze siamo partiti con un

GAP = 30

ottenendo buoni risultati in un

tempo medio per istanza pari a 1 ora. Abbiamo poi ristretto la condizione 4.2 con

GAP = 40

lasciando in esecuzione l'algoritmo per un tempo massimo di 8 ore.

risultati delle prove eseguite sono riportati in tabella 4.15. Anche in questo caso si nota la dierenza tra la qualit delle soluzioni trovate dal nostro algoritmo con quelle dell'euristica di P.C. Chu e J.E. Beasley. Inoltre i valori calcolati con

GAP = 40,

in

molti casi, sono stati ottenuti molto prima delle 8 ore di tempo massimo pressato.

4.3.4 Confronto con le migliori euristiche


E' interessante ora comparare i risultati appena presentati con quelli ottenuti dai migliori metodi risolutivi proposti in questi anni. Attualmente, le tecniche in grado di calcolare soluzioni di pi elevata qualit per le istanze di P.C. Chu e J.E. Beasley sono quelle basate su Tabu Search proposte da Vasquez e Hao in [38] e da Vasquez e Vimont in [39]. In tabella 5.1 sono riportati i risultati per le istanze 500.5, 500.10 e 500.30 di P.C. Chu e J.E. Beasley calcolati con i metodi [38], [39] e con il nostro algoritmo EC. Non stato possibile confrontare singolarmente i valori delle soluzioni per ogni istanza in quanto le metodologie prese in considerazione forniscono i risultati per set di 10 problemi, raggruppati per numero di vincoli, numero di variabili e coeciente

della funzione obiettivo.

Per quanto riguarda il nostro algoritmo, abbiamo chiaramente utilizzato i risultati del metodo esatto per quanto riguarda le istanze 500.5, mentre per le 500.10 e 500.30 abbiamo considerato valore della soluzione e tempistiche relativi al metodo con pi elevato tra quelli proposti in precedenza. Come si pu notare, non c' assolutamente paragone per le istanze 500.5 per le

GAP

CAPITOLO 4.

PROVE COMPUTAZIONALI

115

Tabella 4.14: Risultati per le istanze 500.10 di P.C. Chu e J.E. Beasley con GAP variabile Risultato EC GAP = 100 117790 Risultato EC GAP = gap

Istanza 500.10.01 500.10.01 500.10.02 500.10.03 500.10.04 500.10.05 500.10.06 500.10.07 500.10.08 500.10.09 500.10.10 500.10.11 500.10.12 500.10.13 500.10.14 500.10.15 500.10.16 500.10.17 500.10.18 500.10.19 500.10.20 500.10.21 500.10.22 500.10.23 500.10.24 500.10.25 500.10.26 500.10.27 500.10.28 500.10.29

gap
110 120 100 110 150 120 100 110 150 120 110 120 200 150 120 150 150 100 150 150 200 200 120 150 150 150 100 150 150 150

K
136 135 136 137 135 137 139 135 136 137 256 259 256 259 256 257 260 257 257 255 379 380 380 379 380 376 377 380 379 378

119215
118813 116509

119206

119790 118323 117781 217377 219077 216868


213846 217797 119218

119475

217931 219984 214382 304387 302416


300757 302348 220882

215071

301796 304952 301357 307089


296459

304357

117809 119217 119215 118825 116524 119481 119790 118323 117781 119228 217377 219077 217847 216868 213861 215086 217931 219984 214382 220899 304387 302379 302416 300784 304374 301796 304952 296472 301357 307089

Tempo EC ( s ) GAP = gap 10220 4372 6744 5710 19324 11450 9893 5420 6128 6023 6421 2645 2846 3784 8621 4439 9432 10421 15694 23123 11712 9173 3542 13339 20701 15434 9321 14379 21347 8531

CAPITOLO 4.

PROVE COMPUTAZIONALI

116

Tabella 4.15: Risultati per le istanze 500.30 di P.C. Chu e J.E. Beasley con GAP = 30 e GAP = 40 Risultato Chu e Beasley 115868 114667 116661 115237 116353 115604 113952 114199 115247 116947 217995 214534 215854 217836 215566 215762 215772 216336 217290 214624 301627 299985 304995 301935 304404 296894 303233 306944 303057 300460 Risultato EC GAP = 40 Risultato EC GAP = 30

Istanza 500.30.01 500.30.01 500.30.02 500.30.03 500.30.04 500.30.05 500.30.06 500.30.07 500.30.08 500.30.09 500.30.10 500.30.11 500.30.12 500.30.13 500.30.14 500.30.15 500.30.16 500.30.17 500.30.18 500.30.19 500.30.20 500.30.21 500.30.22 500.30.23 500.30.24 500.30.25 500.30.26 500.30.27 500.30.28 500.30.29

K
GAP = 40 128 128 128 129 128 131 128 129 128 128 251 251 250 252 251 254 252 253 253 252 375 374 375 375 376 373 374 376 375 376

115947 114780 116699 115244 116449 115734 114107 114311 115419 117030 218056 214626 215896 217848 215613 215867 215883 216450 217340 214701 301648 300055 305069 302001 304413 296953 303322 306961 303168 300532

115947
114701

115244 115734
114058 116399

116682

115419
117023

114246

214626 217848 215613 215867


215871 216444 217302 214655 301627 300016 215880

218033

302001 304413
296916 303299 306956

305045

300532

303162

CAPITOLO 4.

PROVE COMPUTAZIONALI

117

Tabella 4.16: Risultati comparativi per le istanze di P.C. Chu e J.E. Beasley 500.5, 500.10 e 500.30 [38] [39] EC

m
5

0.25 0.5 0.75

z
120 623 219 507 302 360 118 600 217 298 302 575 115 547 216 211 302 404

t [h]
5 5 5 9 9 9 12 12 12

z
120 628

t [h]
8.5 8.5 8.5 7.6 7.6 7.6 33 33 33

302 363 118 629 302 603 115 624 216 275 302 447
217 326

219 512

120 630 219 513 302 363 217 331


302 601 115 571 216 228 302 410 118 619

t [h]
0.1 0.1 0.1 2.5 2.5 3.5 8 8 8

10

0.25 0.5 0.75

30

0.25 0.5 0.75

quali neppure il metodo [39] in grado di trovare sempre l'ottimo pur con un tempo di elaborazione 100 volte superiore a quello impiegato dal nostro algoritmo. Per le istanze 500.10, i nostri risultati si avvicinano ai migliori noti ottenuti con [39] in un terzo del tempo. Inoltre per calcolata superiore. Per le istanze 500.30 la soluzione calcolata con [39] ha una qualit tale da non poter essere superata da quella ottenuta tramite il nostro algoritmo. Nonostante

= 0.5 il valore della soluzione ottima da noi

questo la qualit delle soluzioni da noi trovate superiore a tutti gli altri metodi presenti in letteratura, tranne appunto [39], con tempi decisamente inferiori. Inoltre possibile ottenere soluzioni di qualit ancora migliore semplicemente aumentando il valore di

GAP .

Per esempio, con

GAP = 50, abbiamo trovato per l'istanza 500.30.27

un valore di 306999 al posto di 306961 con un tempo di elaborazione di 12 ore. Per concludere, bene far notare come l'approccio euristico da noi utilizzato sia molto semplice e pu essere notevolmente migliorato attraverso nuovi studi. Nel

capitolo conclusivo entreremo maggiormente nel dettaglio relativamente a questo aspetto.

CAPITOLO 4.

PROVE COMPUTAZIONALI

118

4.3.5 Risultati per le istanze P.C. Chu e J.E. Beasley 250.10, 100.30, 250.30
Per completezza riportiamo i risultati per le rimanenti istanze di P.C. Chu e J.E. Beasley. Per le istanze 100.30 abbiamo applicato l'algoritmo EC con un Per le istanze 250.30 siamo partiti con

GAP = 30

per terminare con

GAP = 30. GAP = 40 no

ad un tempo di elaborazione massimo per istanza di 2 ore. Per le istanze 250.10 stato usato un

GAP = 100.

Si tenga presente che per queste ultime istanze noto

il valore ottimo, calcolato con il nostro algoritmo esatto. Di fatto si pu procedere ad un confronto pi oggettivo tra la soluzione ottima e quella trovata dalla nostra euristica. Si osserva dai risultati riportati in tabella 4.17 che per 28 delle 30 istanze elaborate l'algoritmo euristico trova la soluzione ottima (calcolata con il metodo esatto mediamente in 10 ore) in un tempo medio pari a 15 minuti.

CAPITOLO 4.

PROVE COMPUTAZIONALI

119

Tabella 4.17: Istanze 250.10 di P.C. Chu e J.E. Beasley Istanze Risultato EC GAP = 100 Tempo elaborazione EC - GAP = 100 ( s) 1181 3370 780 1910 6254 149 35 2550 888 1085 Tempo elaborazione EC - GAP = 100 ( s) 882 931 870 250 798 223 2240 701 363 334 Tempo elaborazione EC - GAP = 100 ( s) 314 1833 205 353 427 122 157 445 465 312

( = 0.25)
250.10.00 250.10.01 250.10.02 250.10.03 250.10.04 250.10.05 250.10.06 250.10.07 250.10.08 250.10.09 Istanze

Ottimo

59187 58781 58097 61000 58092 58824 58704 58936 59387 59208
Ottimo

59187 58781 58097 61000 58092 58824 58704 59387 59208


58930

Risultato EC GAP = 100

( = 0.5)
250.10.10 250.10.11 250.10.12 250.10.13 250.10.14 250.10.15 250.10.16 250.10.17 250.10.18 250.10.19 Istanze

110913 108717 108932 110086 108485 110845 106077 106686 109829 106723
Ottimo

108717 108932 110086 108485 110845 106077 106686 109829 106723


Risultato EC GAP = 100

110894

( = 0.75)
250.10.20 250.10.21 250.10.22 250.10.23 250.10.24 250.10.25 250.10.26 250.10.27 250.10.28 250.10.29

151809 148772 151909 151324 151966 152109 153131 153578 149160 149704

151809 148772 151909 151324 151966 152109 153131 153578 149160 149704

CAPITOLO 4.

PROVE COMPUTAZIONALI

120

Tabella 4.18: Risultati per le istanze 100.30 di P.C. Chu e J.E. Beasley con GAP = 30

Istanza 100.30.00 100.30.01 100.30.02 100.30.03 100.30.04 100.30.05 100.30.06 100.30.07 100.30.08 100.30.09 100.30.10 100.30.11 100.30.12 100.30.13 100.30.14 100.30.15 100.30.16 100.30.17 100.30.18 100.30.19 100.30.20 100.30.21 100.30.22 100.30.23 100.30.24 100.30.25 100.30.26 100.30.27 100.30.28 100.30.29

Risultato Chu e Beasley

Risultato

21946 21716 20754 21464


21814

22176 21799 21397 20983 40767


41304 22493

41041 40872 41058 41062 42719 42230 41700 57494 60027 58025 60776 58884 60011 58132 59064 58975 60603

41560

21946 21716 20754 21464 21844 22176 21799 21397 22525 20983 40767 41308 41630 41041 40872 41062 42719 42230 41700 57494 60027 58052 60776 58884 60011 58132 59064 58975 60603
41028

EC

k
24 25 24 24 24 24 25 24 24 24 49 49 50 50 49 49 49 49 49 49 73 73 74 74 74 74 74 74 74 73

GAP 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30

Tempo di elaborazione EC ( s ) 61.1 171.4 63.9 97.4 229.0 179.9 353.5 360.2 481.7 49.6 150.0 294.4 95.0 91.2 104.5 102.6 66.8 80.7 25.6 60.5 34.4 42.8 57.7 32.8 41.9 41.8 44.1 54.5 65.9 39.8

CAPITOLO 4.

PROVE COMPUTAZIONALI

121

Tabella 4.19: Risultati per le istanze 250.30 di P.C. Chu e J.E. Beasley con GAP = 30

Istanza 250.30.00 250.30.01 250.30.02 250.30.03 250.30.04 250.30.05 250.30.06 250.30.07 250.30.08 250.30.09 250.30.10 250.30.11 250.30.12 250.30.13 250.30.14 250.30.15 250.30.16 250.30.17 250.30.18 250.30.19 250.30.20 250.30.21 250.30.22 250.30.23 250.30.24 250.30.25 250.30.26 250.30.27 250.30.28 250.30.29

Risultato Chu e Beasley 56693 58318 56553 56863 56629 57119 56292

Risultato

57442
56447 107689 108338 106385 106796 107398 107246 106308 103993

56403

56824 58520 56572 56930 56629 57189 56303 56457 56447 107746 108379 106415 106855 107414 107271 106365 104013 106835 150138 149907 153007 153234 150287 148559 146477 152877 149570 149601
105733 57429

EC

k
63 65 63 63 63 63 63 63 63 63 125 124 124 124 125 126 125 124 123 125 187 186 187 186 186 186 186 186 186 186

GAP 40 30 30 40 40 30 30 30 30 40 30 30 30 40 40 40 40 40 40 40 30 30 40 30 40 40 40 30 40 30

Tempo di elaborazione EC ( s ) 7200 5640 3544 2832 7200 2002 7200 444 5630 1213 825 528 292 7200 804 2132 3125 7200 3561 7200 240 293 1856 398 895 7200 807 308 1104 485

105751
150083 149907 152993 153169 150287 148544 147471 152841 149568 149572

106835

Capitolo

Descrizione del Software


In questo capitolo verr descritta l'implementazione in Java 5.0 dell'algoritmo dettagliatamente presentato in precedenza. La prima parte del capitolo si soerma su una presentazione delle classi e dei packages che costituiscono gli elementi strutturali portanti di tutto il programma, utilizzando la notazione UML i cui diagrammi sono pensati a rappresentare formalmente software orientati agli oggetti. La seconda parte invece pi procedurale e verr proposto lo pseudocodice che descrive le parti pi signicative dell'algoritmo.

5.1

Il Packager mkp.*

I package java sono dei contenitori ttizi di classi, interfacce e altri packages, utili per rappresentare in modo gerarchico la struttura del software java. All'interno

di uno stesso package sono contenuti elementi con funzionalit ani, solitamente riconducibili al nome stesso del package. Per quanto concerne il nostro software ci siamo avvalsi della ripartizione delle classi schematizzata in gura 5.1. I packages sono rappresentati tramite dei rettangoli ombreggati. Ogni package contiene pi classi e in italico sono evidenziate le interfacce. La funzionalit di ogni package viene descritta in seguito:

mkp : il package radice di tutto il software e contiene le classi di avviamento


del programma e i parametri per personalizzarne l'esecuzione

122

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

123

Figura 5.1: Struttura gerachica delle classi che costituiscono il nostro software

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

124

mkp.solver : contiene i risolutori dei problemi che si preoccupano di correlare i


vari algoritmi con le strutture dati

mkp.solver.AAR : contiene le classi che implementano l'algoritmo AAR mkp.solver.RR : contiene le classi che implementano l'algoritmo RR mkp.problem : il package in cui sono inserite le classi che immagazzinano i
dati che descrivono il problema

mkp.problem.input : mette a disposizione un'interfaccia di acquisizione dei dati


da le e le relative implementazioni a seconda di come le informazioni relative al problema sono organizzate nel le stesso

mkp.core : fornisce le classi per la creazione e la manipolazione del problema


Core

mkp.euristic a:

mette a disposizione un interfaccia per la creazione di una

generica euristica per il problema

mkp.util : contiene classi di utilit generale, in particolar modo per l'ordinamento dei vettori che contengono i dati del problema (prezzi, beni, costi ridotti ecc.)

mkp.relax :

il package in cui sono contenute le classi per risolvere i vari

rilassamenti del problema tramite interfacciamento con CPLEX

mkp.cut : contiene i generatori di tagli da applicare ai vari rilassamenti mkp.cut.LCI : un package che fornisce le classi per implementare le Lifted Cover Inequalities, locali e globali

Sebbene, avendo denito l'algoritmo in modo rigoroso, sia possibile esplicitare concretamente gli elementi strutturali che lo compongono, si deciso di costruire una struttura dinamica facilmente estendibile per aumentare la essibilit e la robustezza del software, sopratutto in vista di modiche ed estensioni future. Le scelte

implementative adottate, ben supportate dall'utilizzo di un linguaggio orientato agli oggetti, sono indirizzate alla creazione di una struttura portante dell'algoritmo in cui l'inserimento di moduli aggiuntivi, implementati ad hoc dall'utente, sia semplicato il pi possibile. L'utilizzo di numerose interfacce permette ai vari componenti software

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

125

di accedere a servizi generici, i cui risultati dipendono dalle singole implementazioni. In particolare possibile:

creare una moltitudine di tagli semplicemente implementando l'interfaccia Cut-

Generator. Essa fornisce i metodi per istanziare un oggetto della classe Cut
che pu essere aggiunto a qualunque rilassamento tramite lo specico metodo

addTaglio().

creare diversi tipi di rilassamento, oltre a quello continuo utilizzato nel nostro algoritmo, implementando l'interfaccia MKPRilassamento.

implementare dierenti sistemi di acquisizione dei dati del problema a seconda di come questi sono organizzati all'interno del le tramite l'interfaccia

MKPInput.

sviluppare nuove euristiche, implementando l'interfaccia MKPEuristica, per calcolare lower bound ecaci per il problema

implementare diversi algoritmi di ordinamento dei vettori in cui sono contenuti i dati relativi al problema implementando l'interfaccia Ordinamento

creare nuovi enumeratori delle soluzioni tramite albero di ricerca, completamenti diversi dall'algoritmo AAR, implementando l'interfaccia Enumerator

Qualora si voglia continuare la ricerca iniziata con questo lavoro di tesi, l'aver utilizzato un linguaggio come Java rende decisamente semplice l'aspetto pratico dell'applicazione delle estensioni, in quanto si riduce ad una comprensione della collaborazione tra le classi. Se si seguono le poche linee guida dettate dal rispetto dei metodi offerti dalle varie interfacce, la quasi totalit del lavoro di sviluppo si focalizza sulla creazione di nuovi moduli, senza doversi preoccupare di come interfacciare queste nuove funzionalit all'interno del software preesistente.

5.2

Pseudocodice dell'algoritmo

Il capitolo 3 ore una descrizione formale degli aspetti algoritmici della metodologia di risoluzione proposta. Di seguito ci occuperemo di sintetizzare attraverso uno

pseudo-linguaggio di programmazione le modalit con cui le classi che costituiscono il

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

126

Figura 5.2: Diagramma delle Classi

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

127

Figura 5.3: Diagramma delle Classi

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

128

nostro software interagiscono per risolvere un problema seguendo la strategia dettata dall'algoritmo da noi proposto. L'idea quella di presentare solo i metodi che permettono alle classi di collaborare fra loro, evitando di formalizzare funzionalit e servizi di utilit varia la cui comprensione del tutto intuitiva anche senza una precisa descrizione. Questo stato fatto per evitare di non perdere il focus sul cuore dell'algoritmo considerando l'alto numero di classi di cui il software costituito. Qualora si voglia entrare maggiormente in dettaglio sugli aspetti puramente implementativi, il codice sorgente sviluppato durante questo lavoro di tesi stato scritto seguendo i principi di leggibilit della programmazione e commentato in modo approfondito. Lo pseudocodice riportato in seguito stato scritto seguendo alcuni criteri in modo da poter essere facilmente leggibile nel contesto del paradigma a oggetti, in cui spesso si ha a che fare con variabili e altri oggetti contenuti nella classe del metodo analizzato e non passati come argomenti al metodo stesso. In particolare, per ogni metodo, vengono specicati gli elementi esterni ai quali il metodo pu referenziarsi tramite la keyword Require. Con la parola chiave Ensure, si indicano tutte le strutture dati (semplici o complesse) che in qualche modo vengono modicate dal metodo. Inoltre, prima di procedere con i costrutti implementativi del metodo, vengono elencati tutti gli oggetti creati all'interno dal metodo con la relativa classe di appartenenza. Inne, i metodi invocati su questi oggetti, sono scritti in modo

enfatizzato rispetto alle altre strutture.

5.2.1 Avviamento del programma


Il software inizia con l'interpretare i dati contenuti all'interno di un le per inizializzare pi oggetti di tipo MKPProblem da risolvere in sequenza. Questa operazione viene eettuata dalle implementazioni speciche dell'interfaccia MKPInput, nel nostro caso dalla classe MKPInputBeasley. Viene fatto un primo controllo sulla dimensione del problema per scegliere la metodologia di risoluzione basata sulla distinzione delle cardinalit a livello RR o meno. Dopo aver istanziato l'opportuno risolutore (SolverCardDistinte o SolverCardNonDistinte ), a esso si demanda il compito di calcolare la soluzione ottima invocando il metodo solve(). Terminata l'elaborazione, si pu accedere al valore ottimo trovato tramite il metodo getOttimo() del risolutore (algoritmo 1)

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

129

Algorithm 1 MKP.main( String le )


1: 2: 3: 4:

MKPProblem problema Solver risolutore MKPInput input int ottimo


input new M KP InputBeasley(f ile) for i 1, input.getNumeroIstanze() do problema input.getMKPProblem(i) if problema.getNumeroVincoli() > 5 then if (problema.getNumeroVincoli() problema.getNumeroVariabili() 100) then risolutore new SolverCardDistinte(problema)

5: 6: 7: 8: 9:

10)

and

10: 11: 12: 13: 14: 15: 16: 17: 18: 19:

else

end if else end if end for

risolutore new SolverCardN onDistinte(problema)

risolutore new SolverCardDistinte(problema)

risolutore.solve() ottimo risolutore.getOttimo()

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

130

5.2.2 Inizializzazione del risolutore


Il metodo solve() del risolutore strutturato in modo diverso a seconda dell'implementazione dello stesso:

SolverCardNonDistinte : viene istanziato un oggetto CoreManager che si occupa di creare il core del problema ed espanderlo. Per far questo vengono passati come argomenti il problema da risolvere, il lower bound (che inizialmente uguale a 0), la cardinalit dell'allocazione (in questo caso 0 signica che devono essere analizzate tutte le cardinalit) e la dimensione del Core. Il risolutore

si occupa di iterare la chiamata del metodo continuaEsecuzione() dell'oggetto

CoreManager. Ad ogni chiamata del metodo, il CoreManager espande il Core


e risolve il problema riformulato calcolando un nuovo lower bound. Il risolutore aggiorna eventualmente il lower bound trovato e termina l'iterazione quando il core non pu essere pi espanso (algoritmo 2).

SolverCardDistinte : si calcola un lower bound iniziale istanziando un CoreManager e risolvendo il problema riformulato con core minimale. Il lower bound
trovato, attraverso le classi MinCardProblemRelax e MaxCardProblemRelax, permette di determinare la cardinalit minima e massima dell'allocazione ottima delle oerte. Si costruisce in seguito un vettore di istanze di CoreMan-

ager, ognuno inizializzato con la propria cardinalit, compresa tra minCard e maxCard, e il proprio ordinamento delle oerte. Ogni CoreManager risolve il
problema riformulato con core minimale: qualora non sia possibile costruire un core minimale in quanto il vincolo RCC viene violato, l'istanza non viene salvata nella lista e la cardinalit relativa viene scartata in quanto sicuramente non ottima. Una volta costruito il vettore, si esegue il metodo continuaEse-

cuzione() su ogni singolo CoreManager aggiornando eventualmente il lower


bound generale. Se tale metodo restituisce esito negativo, il relativo CoreM-

anager viene eliminato dal vettore in quanto il problema con cardinalit a lui
associato stato risolto. Il procedimento viene iterato no a quando non ci

sono pi elementi nel vettore dei CoreManager (algoritmi 3 e 4).

5.2.3 Creazione del Core


Dopo aver istanziato un oggetto CoreManager necessario invocare il suo metodo

init() per creare il Core. A sua volta questo metodo invoca il metodo interno create-

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

131

Algorithm 2 SolverCardNonDistinte.solve( MKPProblema problema ) Require:


1: 2:

DIM_CORE

int LB, ottimo CoreManager core


LB 0 core new CoreM anager(problema, DIM _CORE, 0, LB) core.init() core.processa() LB core.getLB()

3: 4: 5: 6: 7:

8: 9: 10: 11: 12: 13: 14: 15: 16:

repeat

core.setLB(LB) if core.continuaEsecuzione() =

break esci dal ciclo se il core non pu essere pi espanso end if if core.getLB() > LB then
LB core.getLB()
aggiorno il lower bound

false then

end if until *il core non pu essere pi espanso*


ottimo LB
il lower bound nale l'ottimo

17:

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

132

Algorithm 3 SolverCardDistinte.solve( MKPProblem problema ) - PARTE 1 Require: DIM_CORE 1: int LB, ottimo 2: CoreManager core 3: MinCardProblemRelax minCardRelax 4: MaxCardProblemRelax maxCardRelax 5: int ordine
6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:

LB 0 core new CoreM anager(problema, DIM _CORE, 0, LB) core.init() core.processa() LB core.getLB() minCardRelax new M inCardP roblemRelax(problema, LB) maxCardRelax new M axCardP roblemRelax(problema, LB) minCardRelax.solve() maxCardRelax.solve() int minCard minCardRelax.getValoreFunzioneObiettivo() int maxCard maxCardRelax.getValoreFunzioneObiettivo() int media (minCard + maxCard)/2 int card maxCard List solutori new List()

20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:

repeat
ordine ORDIN AM EN T O_P REZZI if card > media then ordine ORDIN AM EN T O_BEN I

end if

core new CoreM anager(problema, DIM _CORE, card, LB, ordine) core.init() if core.isStop() = false then core.processa() if core.getLB() > LB then LB core.getLB() aggiorno il lower bound

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

133

Algorithm 4 SolverCardDistinte.solve( MKPProblem problema ) - PARTE 2


31: 32: 33: 34: 35:

end if end if

solutori.aggiungi(core)

card card 1 until card < cardM in

ora ho una lista di tutti i problemi da risolvere

36: 37: 38: 39: 40: 41: 42: 43: 44: 45:

repeat for i 1, solutori.size() do

else

solutori.setLB(LB) if solutori[i].continuaEsecuzione() = solutori.remove(solutori[i]) LB solutori[i].getLB()

aggiorno il lower bound

false then

end if end for until solutori.size() = 0


ottimo LB

46:

il lower bound nale l'ottimo

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

134

OutCore() che accetta come parametri di ingresso il problema di partenza e la cardinalit. A livello implementativo viene creato un oggetto di tipo OutCore che contiene le strutture dati per le variabili esterne al Core. Si procede con la creazione di un oggetto MKPRilassamentoContinuo, implementazione dell'interfaccia MKPRilassa-

mento, a cui si aggiunge eventualmente il taglio di cardinalit attraverso il metodo addTaglio() qualora la cardinalit sia diversa da 0. Il metodo solve() di MKPRilassamento risolve il rilassato, il cui valore ottimo viene restituito tramite il metodo getValoreFunzioneObiettivo().
Quest'interfaccia dispone anche del metodo getCo-

stiRidotti() per avere il vettore dei costi ridotti delle variabili. I costi ridotti vengono
poi ordinati in ordine decrescente e vengono selezionati quelli pi alti in valore assoluto. Di quest'ultimi, vengono creati oggetti di tipo Variabile che memorizzano oltre all'indice della variabile, il prezzo e il costo ridotto. Tali oggetti vengono aggiunti ad

OutCore tramite l'apposito metodo addVarOutCore(). Il procedimento di aggiunta


delle variabili termina quando rimangono da valutare un numero di variabili pari a

DIM_CORE (algoritmo 5).

5.2.4 Risoluzione del problema con Core minimale


Il metodo processa() invocato sull'oggetto CoreManager risolve il problema ssando tutte le variabili presenti nell'oggetto OutCore. La classe MKPProblem ore un metodo chiamato creaProblemaVariabiliNonFissate() che, ricevuta in ingresso una lista di variabili da ssare, restituisce il problema ottenuto eliminando tali variabili dalla formulazione. Di questo problema si calcola il rilassamento continuo con l'eventuale vincolo di cardinalit memorizzando il valore risultante in UB. Il problema riformulato viene risolto attraverso il sistema di enumerazione oerto dall'interfaccia

Enumerator. Di questa interfaccia sono fornite due implementazioni, AAREnumerator e AAROneCardEnumerator, entrambe basate sull'algoritmo AAR. La prima
risolve il problema considerando tutte le cardinalit possibili per l'allocazione ottima, la seconda solo per la cardinalit in ingresso. Si osservi che la cardinalit del problema riformulato ottenuta sottraendo alla cardinalit di partenza il numero delle variabili settate a 1 nell'OutCore. Entrambe le classi necessitano in ingresso, oltre al problema, del lower bound, del termine noto del vincolo RCC e dei costi ridotti, tutte informazioni necessarie per l'applicazione dei tagli. AAROneCardEnu-

merator richiede inoltre la cardinalit di riferimento e la tipologia di ordinamento


delle variabili. L'interfaccia Enumerator mette a disposizione il metodo solve() per

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

135

Algorithm 5 CoreManager.createOutCore( MKPProblem problema, int card ) Ensure:


1: 2: 3: 4:

outCore, costiRidotti, indiciV ariabili

MKPRilassamento relax double[] costiRidotti int[] indiciV ariabili OutCore outCore


indiciV ariabili problema.getIndici() relax new M KP RilassamentoContinuo(problema) if card <> 0 then Cut taglioCard generaTaglioCardinalita(problema, card) relax.addTaglio(taglioCard)

5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:

end if

relax.solve() costiRidotti relax.getCostiRidotti()

ordinaCostiRidottiDecrescenti(costiRidotti,indiciVariabili)
outCore new OutCore() int cont1 1 int cont2 problema.getNumeroVariabili() int contV ar 0

18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:

repeat if costiRidotti[cont1] > costiRidotti[cont2] then


index cont1; cont1 cont + 1

else
index cont2; cont2 cont2 1 p problema.getPrezzoVariabile(indiciV ariabili[index]) Variabile var newV ariabile(indiciV ariabili[index], p, costiRidotti[index]) outCore.addVarOutCore(var) contV ar contV ar + 1 until problema.getNumeroVariabili() DIM _CORE < contV ar

end if

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

136

la risoluzione del problema e il metodo getOttimo() per ottenere l'ottimo trovato. Il lower bound iniziale LB del problema ottenuto sommando l'ottimo del problema riformulato con il prezzo delle variabili settate a 1 nell'OutCore, quest'ultimo calcolato grazie al suo metodo getPrezzo() (algoritmo 6).

5.2.5 Espansione del Core


La classe CoreManager dispone di un metodo chiamato continuaEsecuzione() che, invocato, permette di aggiungere al Core la variabile pi promettente risolvendo il nuovo problema riformulato. Viene invocato il metodo removeLastVar() dell'oggetto

OutCore che rimuove la variabile con costo ridotto in valore assoluto pi piccolo
tra tutte quelle escluse dal Core. Viene successivamente istanziato un oggetto di

tipo CoreRRManager passando come parametri di input il problema di partenza, l'OutCore, i costi ridotti, il lower bound, l'upper bound e l'eventuale cardinalit dell'allocazione ottima. La risoluzione del problema con il nuovo Core espanso,

viene eseguita invocando il metodo processa() di CoreRRManager. Il CoreManager valuta l'esito della risoluzione invocando il metodo getStato() del CoreRRManager. A seconda del valore restituito, il metodo continuaEsecuzione() aggiorna il lower bound e restituisce true, se al core si possono aggiungere ulteriori variabili, false se l'espansione del Core da considerarsi terminata (algoritmo 7).

5.2.6 Risoluzione del problema con Core espanso


Il CoreRRManager, tramite il metodo processa(), risolve il problema in ingresso applicando l'algoritmo RR. Per prima cosa vengono ssate al problema le variabili contenute nell'OutCore, creando in seguito il problema ottenuto eliminado tali variabili dalla formulazione. Tra le variabili rimanenti viene selezionata quella con costo ridotto in valore assoluto pi grande, vale a dire l'ultima variabile che stata inserita nel Core (o eliminata dall'OutCore ). Se il costo ridotto di tale variabile ha un valore tale da violare il vincolo RCC, la variabile di classe stato viene settata al valore ES-

PANSIONE_CORE_TERMINATA . In caso contrario l'oerta viene settata a 1 se


il costo ridotto negativo, a 0 se positivo e si verifca la possibilit di ssare altre variabili tramite il metodo xAltreVariabili(). Le variabili ssate sono salvate nella lista

varFissate che viene passata in ingresso, insieme al problema riformulato, al metodo isFixable(). Tale metodo restituisce true o false a seconda se la variabile pu essere

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

137

Algorithm 6 CoreManager.processa() Require: problema, outCore, card Ensure: LB


1: 2: 3: 4:

MKPRilassamento relax Enumerator e MKPProblem rif ormulato int LB List varOutCore outCore.getVarOutCore()
rif ormulato problema.creaProblemaVariabiliNonFissate(varOutCore) if card <> 0 then Cut taglioCard generaTaglioCardinalita(problema, card) relax.addTaglio(taglioCard)

5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:

end if

relax.solve() LB 0 double U B relax.getValoreFunzioneObiettivo() double termineN otoRCC U B LB int nuovaCard card outCore.getVarCrPositivo()

16: 17:

if

18: 19:

else

card <> 0 then e new AAROneCardEnumerator(rif ormulato, LB, relax.getCostiRidotti(), range, nuovaCard, EN U M ERAZION E _BEN I) e new AAREnumerator(rif ormulato, relax.getCostiRidotti(), range) LB,

20:

end if

21: 22:

e.solve() LB e.getOttimo() + outCore.getPrezzo()


il lower bound iniziale dato dall'ottimo del problema core e dalle variabili settate a 1 dell'outcore

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

138

Algorithm 7 CoreManager.continuaEsecuzione() Require:


problema, LB, outCore, costiRidotti, indiciV ariabili, card, U B, LB, ordine

1:

CoreRRManager rcc return false end if if


outCore.getNumeroVariabili() = 0

2: 3: 4: 5:

then

outCore.removeLastVar() problema.setLB(LB) rcc new CoreRRM anager(costiRidotti, indiciV ariabili, U B, LB, problema, card, ordine, outCore) rcc.processa()
espansione del core

6: 7:

8:

9: 10: 11: 12: 13: 14: 15: 16:

if

return true else if rcc.getStato() = ESP AN SION E _CORE _T ERM IN AT A then return false else return true end if

rcc.getStato() = LB _M IGLIORAT O LB rcc.getLB()

applica la riduzione RCC

then

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

139

Algorithm 8 CoreRRManager.xIndiretto() Require: problema, backupCard, termineN otoRCC, M AV _V AR Ensure: stato, LB


1: 2: 3: 4: 5:

MKPProblem rif ormulato double[] costiRidotti int[] indiciV ariabili int stato, var List varF issate

6: 7: 8: 9: 10: 11: 12: 13: 14: 15:

ordinaCostiRidottiDecrescenti(costiRidotti,indiciVariabili)
card backupCard if costiRidotti[1] > costiRidotti[problema.getNumeroVariabili()] if costiRidotti[1] > termineN otoRCC then stato ESP AN SION E _CORE _T ERM IN AT A

then

exit end if
var indiciV ariabili[cont1]

interrompi esecuzione

else if then

costiRidotti[problema.getNumeroVariabili()] < termineN otoRCC stato ESP AN SION E _CORE _T ERM IN AT A

16: 17: 18: 19: 20: 21:

exit end if end if

interrompi esecuzione

var indiciV ariabili[problema.getNumeroVariabili()]

22: 23: 24: 25: 26: 27:

varF issate fixAltreVariabili(var, rif ormulato, costiRidotti, indiciV ariabili) if isFixable(varF issate, rif ormulato) = true then stato LB _N ON _M IGLIORAT O

else

LB *aggiorno il lower bound* stato LB _M IGLIORAT O

end if

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

140

ssata al valore opposto a quello a cui stata temporaneamente settata. Nel contesto del CoreRRManager, se la variabile viene ssata signica che il lower bound del problema non migliorato, e si ssa la variabile stato a LB_NON_MIGLIORATO. Viceversa, se la variabile pu essere ssata, il lower bound migliorato e di fatto la variabile stato viene valorizzata a LB_MIGLIORATO. La variabile stato viene restituita tramite il metodo getStato() che lo stesso invocato dal CoreManager per vericare l'esito dell'espansione del Core (algoritmo 8).

5.2.7 Applicazione dell'algoritmo RR


La classe RRManager risolve un problema di tipo MKPProblem applicando rigorosamente l'algoritmo RR tramite il metodo processa(). La prima operazione eseguita da questo metodo ssare tutte le variabili i cui costi ridotti violano il taglio RCC. Di questo si occupa il metodo x() il quale eettua una scansione intelligente del vettore dei costi ridotti e ssa la variabile a 1, se il corrispondente costo ridotto pi grande del termine noto del vincolo RCC, e a 0 se invece pi piccolo. Il termine noto del vincolo RCC memorizzato nella variabile di classe termineNotoRCC e calcolato come dierenza tra UB e LB in ingresso a RRManager. Inoltre il metodo

xDiretto() tiene traccia sia del numero di variabili settate (variabiliFissate ) sia della
nuova cardinalit di analisi del problema (backupCard ) (algoritmo 9). Successivamente viente invocato il metodo xIndiretto() la cui implementazione dierisce da quella della classe CoreRRManager. In questo caso, infatti, l'idea Di

quella di cercare di ssare pi variabili e non solo l'ultima inserita nel Core.

volta in volta viene selezionata la variabile con costo ridotto in valore assoluto pi elevato e salvata temporaneamente in var. Se non ci sono pi variabili con costo

ridotto positivo si setta neCrPos a true ; analogamente se non ci sono pi variabili con costo ridotto negativo si setta neCrNeg a true. Selezionata la variabile, viene chiamato il metodo xAltreVariabili() a cui si passano come argomenti la variabile stessa, il problema, i costi ridotti con i relativi indici delle variabili e i vettori xed,

varFissate e varFissateTemp.

xed permette di vericare in modo diretto se una

determinata variabile stata gi settata ad un valore senza scandire alcuna lista,

varFissate contiene tutte le variabili che sicuramente sono ssate o a 0 o a 1 mentre


in varFissateTemp, inizialmente vuoto, ci sono solo le variabili che sono state settate temporaneamente per non violare il vincolo RCC in seguito al settaggio della variabile var (algoritmo 10).

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

141

Algorithm 9 RRManager.xDiretto() Require: problema, costiRidotti, indiciV ariabili, backupCard, termineN otoRCC Ensure: variabiliF issate, backupCard
1:

int variabiliF issate 0 for i = 1, costiRidotti.size(), i i + 1 do if costiRidotti[i] > termineN otoRCC then
problema.fix(indiciV ariabili[i], 1) backupCard backupCard 1 variabiliF issate variabiliF issate + 1

2: 3: 4: 5: 6: 7: 8: 9: 10:

else break end if end for for i = costiRidotti.size(), 1, i i 1 do if costiRidotti[i] > termineN otoRCC then
problema.fix(indiciV ariabili[i], 1) variabiliF issate variabiliF issate + 1

esci dal ciclo

11: 12: 13: 14: 15: 16: 17: 18:

else break end if end for

esci dal ciclo

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

142

Algorithm 10 RRManager.xIndiretto() - PARTE 1 Require: problema, backupCard, termineN otoRCC, variabiliF issate Ensure: stato, LB, backupCard
1: 2: 3: 4: 5: 6:

MKPProblem rif ormulato double[] costiRidotti int[] indiciV ariabili int stato, var, card, cont List varF issate, varF issateT emp boolean f ineCrP os false f ineCrN eg false

7: 8: 9: 10: 11: 12: 13:

ordinaCostiRidottiDecrescenti(costiRidotti,indiciVariabili)
int cont1 1 int cont2 problema.getNumeroVariabili() repeat

14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:

card backupCard boolean esegui true if (costiRidotti[cont1] > costiRidotti[cont2] f ineCrN eg = true then cont cont1 var indiciV ariabili[cont1] if costiRidotti[cont1] <= 0 then esegui false f ineCrP os true

and f ineCrP os = false) or

end if else

end if end if

cont cont2 var indiciV ariabili[cont2] if costiRidotti[cont2] >= 0 then esegui false f ineCrN eg true

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

143

Algorithm 11 RRManager.xIndiretto() - PARTE 2


esegui = true then 29: card fixAltreVariabili(var, rif ormulato, costiRidotti, indiciV ariabili, f ixed, varF issate, varF issateT emp) 30: if isFixable(varF issateT emp, rif ormulato) = true then 31: if costiRidotti[cont] > 0 then 32: varF issate.add(newV ariabile(var, 1)) 33: backupCard backupCard 1 34: f ixed[var] true 35: cont1 cont1 + 1
28: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47:

if

else

varF issate.add(newV ariabile(var, 0)) f ixed[var] false cont2 cont2 1

end if
variabiliF issate variabiliF issate + 1

= true) problema.getNumeroVariabili() M AX _V AR

else *gestione variabili non ssate* *aggiornamento lower bound* end if end if until (f ineCrP os = true and f ineCrN eg

or

variabiliF issate >

48: 49: 50: 51:

for i = 1, varF issate.size() do ssa le variabili al problema padre int indiceP adre rif ormulato.getIndicePadre(varF issate[i].indice) end for
problema.fix(indiceP adre, varF issate[i].valore)

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

144

Il metodo xAltreVariabili() restituisce la nuova cardinalit del problema dopo il settaggio temporaneo delle variabili. Per vericare se la variabile var pu essere ssata ad un certo valore, si invoca il metodo isFixable(), passando come argomento, oltre al problema, il vettore varFis-

sateTemp. Se l'esito positivo, la variabile var viene ssata a 1 qualora il suo costo
ridotto sia positivo, a 0 se il costo ridotto negativo. In entrambi i casi viene aggiunta nella lista varFissate, si aggiorna il vettore xed e si incrementa il valore di

variabiliFissate di uno. Se l'esito negativo, signica che stato trovato un lower


bound migliore di quello attuale e viene memorizzato. Inoltre la variabile var viene aggiunta in un'apposita lista e valutata qualora ci siano ulteriori miglioramenti del lower bound grazie ai quali il suo ssaggio pu avvenire senza problemi. Il procedimento viene iterato no a quanto sia neCrPos che neCrNeg sono posti a true oppure no a quando il valore di variabiliFissate supera il numero di variabili del problema diminuito di MAX_VAR. Al termine delle iterazioni tutte le variabili contenute in varFissate vengono effettivamente ssate nel problema invocando il metodo x() della classe MKPProblem passando appunto l'indice della variabile e il valore a cui deve essere posta (algoritmo 11).

xAltreVariabili:

questo metodo ssa la variabile var in ingresso a 1 se il suo

costo ridotto negativo e a 0 se positivo, aggiungendola al vettore varFissateTemp e aggiornando il termineNotoRCC ora salvato in nuovoTermineNotoRCC. Viene eseguita una scansione intelligente del vettore costiRidotti e vengono ssate a 1 tutte le variabili con costo ridotto superiore a nuovoTermineNotoRCC e a 0 quella con costo ridotto inferiore a nuovoTermineNotoRCC cambiato di segno. In entrambi i casi il ssaggio viene eseguito per non violare il vincolo RCC e si realizza semplicemente aggiungendo le variabili interessate nel vettore varFissateTemp. Inne in questa lista vengono anche aggiunte tutte le variabili sicuramente ssate, contenute in varFissate (algoritmo 12).

isFixable:

questo metodo verica la possibilit di ssare denitivamente il valore

della variabile var selezionata all'interno di xIndiretto(). Il prezzo complessivo delle variabili contenute in varFissateTemp e valorizzate a 1 viene salvato in valoreFissato. Si costruisce il problema ottenuto eliminando le variabili presenti in varFissateTemp dalla sua formulazione. Il lower bound del nuovo problema cos ottenuto uguale

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

145

Algorithm 12
varFissateTemp )

RRManager.xAltreVariabili(int var, int[] indiciVariabili,

MKPProblem riformulato, List varFissate, List

double[] costiRidotti,

boolean[] xed,

Require: termineN otoRCC, card Ensure: varF issateT emp, card


1: 2:

double nuovoT ermineN otoRCC int cont1, cont2


nuovoT ermineN otoRCC termineN otoRCC abs(costiRidotti[var]) int cont1 1 int cont2 rif ormulato.getNumeroVariabili() if costiRidotti[var] > 0 then sso temporaneamente la variabile varF issateT emp.add(newV ariabile(indiciV ariabili[var], 0))

3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:

else

varF issateT emp.add(newV ariabile(indiciV ariabili[var], 1)) card card 1

end if

f ixed[indiciV ariabili[var]] true while costiRidotti[cont1] > nuovoT ermineN otoRCC do if cont1 <> var and f ixed[indiciV ariabili[cont1]] = false then varF issateT emp.add(newV ariabile(indiciV ariabili[cont1], 1))

end if

cont1 cont1 + 1

end while while costiRidotti[cont2] < nuovoT ermineN otoRCC do if cont2 <> var and f ixed[indiciV ariabili[cont2]] = false then varF issateT emp.add(newV ariabile(indiciV ariabili[cont2], 0)) end if
cont2 cont2 1

end while for i = 1, varF issate.size() do


denitivamente

aggiungo anche le variabili ssate

26: 27:

end for

varF issateT emp.add(varF issate[i])

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

146

Algorithm 13 RRManager.isFixable( List varFissateTemp, MKPProblem riformulato ) - PARTE 1

Require:
1: 2: 3:

card, cardDistinte, GAP, M AX _V AR

int LB, valoreF issato MKPProblem ridotto MKPRilassamento relax


LB rif ormulato.getLB()

4:

5: 6: 7: 8: 9: 10:

for i = 0, varF issateT emp.size() do if varF issaT emp[i].valore = 1 then end if end for
valoreF issato valoreF issato + rif ormulato.getPrezzoVariabile(varF issateT emp[i].indice)

11: 12: 13: 14:

LB LB valoreF issato ridotto rif ormulato.creaProblemaVariabiliNonFissate(varF issateT emp) ridotto.setLB(LB) relax newM KP RilassamentoContinuo(ridotto)

15: 16: 17: 18: 19:

if

end if

cardDistinte = true then Cut taglioCard generaTaglioCardinalita(ridotto, card) relax.addTaglio(taglioCard)

relax.solve()

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

147

Algorithm 14 RRManager.isFixable( List varFissateTemp, MKPProblem riformulato ) - PARTE 2


20: 21: 22:

if

return true end if if

relax.getValoreFunzioneObiettivo() GAP < LB

then

23: 24: 25: 26: 27: 28: 29: 30: 31:

*aggiorno il lower bound* return false else return true end if end if

ridotto.getNumeroVariabili() <= M AX _V AR then esito risolviConAAR(relax, ridotto, LB, card) if esito = LB _M IGLIORAT O then

sso la variabile

32: 33: 34: 35: 36: 37: 38:

esito risolviConRR(relax, ridotto, LB, card) if esito = LB _M IGLIORAT O then

*aggiorno il lower bound* return false else return true end if

sso la variabile

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

148

al lower bound del problema di partenza diminuito di valoreFissato. Di questo problema si calcola il rilassamento continuo, con eventuale vincolo di cardinalit, nel consueto modo. Viene poi vericata la condizione di rilassamento per la valutazione del problema in cui entra in gioco il parametro GAP. Se la condizione non vericata il problema deve essere risolto. Qualora il numero di variabili sia minore

a MAX_VAR, si invoca il metodo risolviConAAR(), in caso contrario il metodo

risolviConRR().

Entrambi i metodi accettano come input il rilassato continuo, il

problema, il suo lower bound e l'eventuale cardinalit da analizzare. Se l'esito del metodo coincide con LB_MIGLIORATO, si aggiorna il lower bound e il metodo is-

Fixable() restituisce false. In caso contrario viene ritornato il valore true (algoritmi
13 e 14).

risolviConAAR:

questo metodo avvia la risoluzione del problema in ingresso

tramite l'applicazione dell'algoritmo AAR. Per prima cosa in base al valore dell'upper bound e del lower bound viene calcolato il valore di nuovoTermineNotoRCC che, se negativo, evita di risolvere il problema. In seguito vengono fatte alcune valutazioni sulla cardinalit da analizzare. Se la variabile di classe cardDistinte, valorizzata in fase di istanziazione di RRManager, posta a true, signica che stato adottato un approccio che prevede la risoluzione di tanti problemi distinti, uno con la propria cardinalit. Questa cardinalit salvata in card, anch'essa input del metodo. Ovviamente il valore di card deve essere superiore al numero di variabili del problema. Si istanzia un oggetto Enumerator, in particolare AAREnumerator se cardDistinte uguale a false o AAROneCardEnumerator altrimenti. In quest'ultimo caso, necessario che il valore di card sia compreso tra la cardinalit minima e quella massima dell'allocazione ottima, ottenute invocando rispettivamente i metodi getCardMin() e getCardMax() dell'oggetto Enumerator. Si risolve il problema invocando il metodo solve() di Enumerator e si ottiene il valore ottimo tramite getOttimo(). Se quest'ultimo superiore al lower bound corrente, si aggiorna il valore di LB. In tutti i casi la risoluzione del problema non garantisce un ottimo superiore al lower bound, il metodo restituisce LB_NON_MIGLIORATO. (algoritmo 15).

risolviConRR:

questo metodo avvia la risoluzione del problema in ingresso tramite

l'applicazione dell'algoritmo RR e costituisce il punto in cui avviene di fatto l'esecuzione ricorsiva dell'algoritmo stesso. Quello che viene eseguito semplicemente

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

149

Algorithm 15 Require:
1: 2:

RRManager.risolviConAAR( MKPRilassamento relax, MKPProb-

lem ridotto, int LB, int card )

cardDistinte, ordine

double nuovoT ermineN otoRCC Enumerator e


nuovoT ermineN otoRCC relax.getValoreFunzioneObiettivo() LB if nuovoT ermineN otoRCC < 0 then return LB _N ON _M IGLIORAT O

3: 4: 5: 6: 7: 8: 9: 10: 11:

end if if cardDistinte = true and card > ridotto.getNumeroVariabili() then return LB _N ON _M IGLIORAT O end if if cardDistinte = true then e new AAROneCardEnumerator(ridotto, LB,
relax.getCostiRidotti(), nuovoT ermineN otoRCC, card, ordine)

12: 13:

else

e new AAREnumerator(ridotto, LB, relax.getCostiRidotti(), nuovoT ermineN otoRCC)

14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:

end if if e.getCardMin() > e.getCardMax() then return LB _N ON _M IGLIORAT O end if if cardDistinte = true then if e.getCardMin()> card or e.getCardMax()< card then return LB _N ON _M IGLIORAT O end if end if
e.processa() if e.getOttimo() < LB then return LB _N ON _M IGLIORAT O

else *aggiorno il lower bound* end if

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

150

Algorithm 16 RRManager.risolviConRR( MKPRilassamento relax, MKPProblem


problema, int LB, int card )

Require:
1: 2: 3: 4:

cardDistinte, ordine

RRManager rcc MKPProblem ridotto MKPRilassamento ridottoRelax int ridottoLB, ridottoCard


LB problema.getLB() if cardDistinte = false then card 0

5: 6: 7: 8: 9:

end if

10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26:

rcc new RRM anager(relax.getCostiRidotti(), relax.getValoreFunzioneObiettivo(), LB, problema, card, ordine) rcc.processa() RCC ssa alcune variabili al problema ridotto problema.creaProblemaVariabiliNonFissate() ridottoRelax new M KP RilassamentoContino(ridotto) if cardDistinte = true then Cut taglioCard generaTaglioCardinalita(ridotto, card) ridottoRelax.addTaglio(taglioCard)

end if

ridottoRelax.solve() ridottoLB LB problema.getPrezzoVariabiliFissate() ridottoCard rcc.getCard() esito risolviConAAR(ridottoRelax, ridotto, ridottoLB, ridottoCard) if esito = LB _M IGLIORAT O then

*aggiorno il lower bound* return false else return true end if

sso la variabile

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

151

istanziare un nuovo oggetto di tipo RRManager, relativo al problema ridotto dopo il settaggio, anche temporaneo, di alcune variabili. Se cardDistinte uguale a false, il valore di card viene posto a 0 in modo che anche nel livello ricorsivo pi basso il problema possa essere trattato in tutte le sue cardinalit. Invocando il metodo processa() del nuovo oggetto RRManager, il problema viene ridotto ulteriormente ad una dimensione massima di MAX_VAR variabili. Questo nuovo problema ora pu essere tranquillamente risolto con AAR tramite il metodo risolviConAAR() (algoritmo 16).

5.2.8 Applicazione dell'algoritmo AAR


Il metodo processa() dell'interfaccia Enumerator si comporta in modo diverso a seconda della specica implementazione considerata. Nel caso di AAREnumerator viene prima calcolata la cardinalit minima e massima dell'allocazione ottima attraverso i metodi calcolaCardMin() e calcolaCardMax() e successivamente si valuta se enumerare le soluzioni ordinando le oerte per prezzi decrescenti o per beni crescenti a seconda della cardinalit analizzata. In entrambi i casi vengono inizializzate le

strutture dati necessarie per applicare i tagli tramiti i metodi initProcessaPrezzi() e initProcessaBeni() per poi iniziare con l'enumerazione vera e propria tramite i metodi processaPrezzi() e processaBeni(). Nel caso di AAROneCardEnumerator suciente scegliere una delle due modalit di enumerazione delle soluzioni in base alla variabile di classe ordine. Analizziamo ora come strutturato l'algoritmo di enumerazione delle soluzioni per ordinamento decrescenti dei prezzi delle variabili, tenendo presente che quello per beni crescenti del tutto analogo. un'allocazione x di card oerte. L'intero algoritmo ha il compito di creare

Il contenuto di

x [cont]

corrisponde all'oerta al-

locata nella posizione cont. Si inizia con la chiamata del metodo iteraPrezzi() che accetta come parametri cont, card e inizio, corrispondente all'indice dell'oerta, nel vettore ordinato, che si vuole cercare di allocare (inizialmente sar la prima oerta, di indice 0). Questo metodo aggiorna il vettore x no ad ottenere un'allocazione, anche parziale, che soddisfa tutti i vincoli e che abbia un valore migliore del lower bound corrente. Inoltre restituisce la posizione della prossima oerta da allocare in

x, salvandolo in cont. Se card uguale a cont, l'allocazione x full, si aggiorna la


cardinalit ottima e si salva la soluzione associata, altrimenti si aggiorna solo il lower bound per le iterazioni seguenti. Si verica che dall'allocazione corrente x possa

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

152

Algorithm 17 AAREnumerator.processaPrezzi( int card ) Require: problema, LB, x Ensure: cardOttima, LB, ottimo
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:

int cont iteraPrezzi(cont,card,0) int num problema.getNumeroVariabili()1 int tempCont cont repeat
ottimo storicoP rezzoP arziale[card] LB ottimo if card = cont then cardOttima card

*copia soluzione ottima* end if if x[0] > problema.getNumeroVariabili()card then break nessuna allocazione futura end if
cont cont 1; dif f card cont; dif f T emp 0 if cont = card 1 then dif f 0

end if while true do if num x[cont] >= dif f then break end if
dif f dif f + 1; cont cont 1

esci dal ciclo

end while
xT emp x[cont] for i = cont, tempCont x[i] 0

do

end for

cont iteraPrezzi(cont, card, xT emp + 1) tempCont cont

until *non esistono allocazioni valide*

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

153

Algorithm 18 AAREnumerator.iteraPrezzi( int cont, int card, int inizio ) - PARTE


1

Require:
1:

problema, storicoP rezzoP arziale, prezzi

for i = inizio, problema.getNumeroVariabili() do if break end if


cont = card

2: 3: 4: 5:

then
allocazione full

storicoP rezziP arziali[cont + 1] storicoP rezziP arziali[cont] + prezzi[i]

6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:

if taglioPrezzi(card, cont, i) = true then int dif f erenza 2 while true do break end if if temp i > dif f erenza then break else if temp i = 2 then
dif f erenza 1

temp i; cont cont 1; i x[cont] if cont = 0 then


allocazione svuotata

trovata allocazione di partenza

end if end if end while *passa all'iterazione successiva* end if


storicoBeniP arziali[cont + 1] beni[indiceP rezzi[i]] storicoBeniP arziali[cont] +

23:

24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:

if taglioBeni(card, cont, i) = true then

else break end if end while *passa all'iterazione successiva* end if

temp i while i < problema.getNumeroVariabili()1 do if beni[indiceP rezzi[i + 1] > beni[indiceP rezzi[temp] ii+1

then

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

154

Algorithm 19 AAREnumerator.iteraPrezzi( int cont, int card, int inizio ) - PARTE


2
35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46:

if

costiRidotti[indiceP rezzi[i]] <= 0 then temp rangeT ermineN otoRCC[cont] + costiRidotti[indiceP rezzi[i]] if temp < 0 then

*passa all'iterazione successiva* end if if taglioRCC(i, temp) = true then *passa all'iterazione successiva* end if

else

rangeT ermineN otoRCC[cont + 1] temp rangeT ermineN otoRCC[cont + 1] rangeT ermineN otoRCC[cont]

end if

47: 48: 49:

50:

then

sommaV incoli[j][cont + 1] sommaV incoli[j][cont]+ problema.getPesoVariabileVincolo(j, indiceP rezzi[i]) if sommaV incoli[j][cont + 1] > problema.getCapacitaVincolo(j)

boolean ok true for j = 0, problema.getNumeroVincoli() do

51: 52: 53: 54: 55: 56: 57:

break end if end for if ok = false then *passa all'iterazione successiva* end if if taglioVincoli(card, cont, i) = true then *passa all'iterazione successiva* end if end for
x[cont] i; cont cont + 1

ok false

esce dal ciclo for

58: 59: 60:

61: 62:

63:

return cont

ritorna la posizione in X della prossima oerta da allocare

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

155

essere generata una nuova allocazione, altrimenti il metodo termina l'esecuzione in quanto tutte le allocazioni con quella cardinalit sono state analizzate. Viene in seguito calcolata la nuova allocazione parziale da cui partire aggiornando sia il valore di cont che il valore di inizio, coincidente con

x [cont] + 1.

Viene quindi

chiamato nuovamente il metodo iteraPrezzi(), questa volta sui nuovi valori aggiornati. L'intero procedimento viene iterato no a quando le allocazioni da analizzare sono terminate (algoritmo 17). Il metodo iteraPrezzi() costruisce l'allocazione vera e propria aggiornando il vettore x. All'interno di un ciclo con indici dinamici avviene al pi l'allocazione di una singola oerta per ogni iterazione, con il calcolo dei nuovi valori di cont e inizio. L'indice i del ciclo corrisponde all'indice dell'oerta che deve essere allocata. Se

questa oerta viene allocata si passa all'iterazione successiva aggiungendo l'oerta

i in x nella posizione cont e incrementando di uno il valore di cont. Se non viene


allocata signica che uno dei tagli implementati risultato ecace. L'implemen-

tazione dei tagli non viene riportata in quanto descritta in dettaglio nel Capitolo 3. I metodi taglioPrezzi(), taglioBeni(), taglioRCC() e taglioVincoli() accettano come parametri card, cont e i e restituiscono true se il taglio risultato ecace. In questo caso vengono calcolati i nuovi valori di card e inizio terminando l'iterazione corrente (senza aggiungere l'oerta nell'allocazione) e passando a quella successiva. E' in questo punto che l'indice del ciclo viene modicato all'interno del suo corpo. Il metodo termina l'esecuzione o quando si raggiunta un'allocazione full o quando sono state valutate, per la posizione cont, tutte le oerte rimanenti, ossia quando l'indice del ciclo settato all'ultima variabile (algoritmi 18 e 19).

5.2.9 Altre note implementative


MKPFactory:
vero e proprio. lo pseudocodice riportato in questo capitolo non una trasposizione completamente fedele dei costrutti java utilizzati per la stesura del codice Infatti alcune parti sono state volutamente semplicate in quanto avrebbero richiesto una maggior comprensione delle tecniche di programmazione legate al paradigma a oggetti. Una semplicazione, non riportata nello pseudocodice, riguarda l'utilizzo della classe MKPFactory. Si tratta di un interfaccia che mette a disposizione i metodi per la creazione degli oggetti maggiormente utilizzati all'interno dell'algoritmo e che trova una sua implementazione nella classe MKPTesiFactory.

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

156

In particolar modo vengono forniti i seguenti metodi, ognuno con i propri parametri di ingresso:

creaAlgoritmoOrdinamento() : crea l'istanza di una classe che implementa l'interfaccia Ordinamento

creaEnumerator() : Enumerator

crea l'istanza di una classe che implementa l'interfaccia

creaInput() : crea l'istanza di una classe che implementa l'interfaccia MKPInput creaEuristica() : crea l'istanza di una classe che implementa l'interfaccia MKPEuristica

creaRilassamentoContinuo() : crea l'istanza di una classe che implementa l'interfaccia MKPRilassamento

A seconda dell'implementazione di MKPFactory, i relativi metodi istanziano e restituiscono oggetti di classi dierenti, le quali rappresentano diverse implementazioni della stessa interfaccia. Per fare un esempio, nell'mplementazione utilizzata concretamente (MKPTesiFactory ) il metodo creaInput() restituisce un istanza di MKPIn-

putBeasley e il metodo creaAlgoritmoOrdinamento() un istanza di Heap. All'implementazione specica di MKPFactory, tutte le classi del software accedono tramite la classe statica MKPRepository che fornisce un metodo getFactory(). Ogni qualvolta uno degli oggetti sopra elencati deve essere istanziato, la creazione non avviene direttamente nella classe che lo utilizza ma viene demandata alla factory. La comunicazione avviene tramite dei servizi (i metodi dell'interfaccia) a prescindere dall'implementazione degli oggetti. Il vantaggio palese in quanto la modica del tipo di algoritmo di ordinamento utilizzato, o del gestore del le di input del problema, o ancora dell'algoritmo che enumera le soluzioni localizzata in un unico punto ed suciente creare una dierente implementazione di MKPFactory per fare in modo che vengano istanziati oggetti dierenti. Tutto ci rende il software essibile e robusto a cambiamenti, aspetto questo a cui si dato peso sin dalla sua progettazione. Tecnicamente sono stati utilizzati alcuni design pattern tipici della progettazione di software a oggetti, in particolare del Factory Pattern e del Singleton Pattern.

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

157

ordinamento delle oerte:

l'algoritmo di ordinamento utilizzato nel nostro

software heap sort [47] di complessit

n log (n)

rispetto a

n2

del pi classico

insertion sort. La relativa classe di supporto Heap, implementazione dell'interfaccia Ordinamento. L'ordinamento, indipendentemente dall'algoritmo specico utilizzato,
prevede di modicare sempre l'ordine degli elementi di due vettori distinti. Il primo vettore specico e contiene gli elementi veri e propri da ordinare (prezzi, beni, costi ridotti ecc.). Il secondo invece contiene gli indici delle variabili, i cui elementi vanno permutati in modo speculare a quelli contenuti nel primo vettore, in modo da non perdere mai il riferimento tra la quantit da ordinare e l'oerta ad essa associata.

riferimenti delle variabili tra i problemi:

l'intero algoritmo si basa sull'ese-

cuzione ricorsiva del problema. Ogni problema da risolvere in realt ottenuto da una riformulazione di un problema padre a sua volta ottenuto dalla riformulazione del problema al livello ricorsivo precedente e via discorrendo. E' necessario di fatto mantenere le associazioni tra gli indici delle variabili di un problema delle relative variabili del problema padre

Pn

e gli indici

P n1 .

Tale associazione viene garantita

attraverso un vettore nella classe MKPProblem chiamato indiciPadre. In pratica, se

indiciP adre [3] = 11, signica che la variabile di indice 3 del problema P n la stessa n1 variabile che nel problema padre P ha indice 11. Il vettore nomi, sempre presente n in MKPProblem, lega invece le variabili del problema P con quelle del problema di partenza P, in modo del tutto analogo al caso di indiciPadre. Queste associazioni
sono importanti in quanto il miglioramento della soluzione ottima localizzato generalmente in livelli ricorsivi pi bassi della radice, quando il problema numero di variabili decisamente pi ridotto del problema di partenza queste variabili deve essere ssato nel problema padre

Pn

ha un

P.

Il valore di

n1

, il quale contiene altre

variabili, precedentemente ssate. Questo ssaggio, eseguito tramite il metodo x-

VariabiliProblemaPadre() della classe MKPProblem, avviene a ritroso utilizzando le


informazioni contenute in indiciPadre da a

P n a P n1 ,

da

P n1

P n2

no ad arrivare

P.

Fissate le variabili del problema di partenza, si ottiene la soluzione ottima vera

e propria aggiornata.

aggiornamento del lower bound:


problema bound

l'aggiornamento del lower bound un oper-

azione ricorsiva a ritroso identica alla creazione della soluzione ottima. Quando un

P n ha un valore ottimo della funzione obiettivo maggiore del suo LBn , anche il problema P n1 avr un lower bound LBn1 migliore

lower e pi

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

158

precisamente pari alla somma di nel problema

LBn

e del prezzo di tutte le variabili ssate a 1

n1

. In modo analogo si calcola il lower bound

LBn2

di

P n2

no

all'aggiornamento del lower bound del problema di partenza. Questa operazione di aggiornamento del valore del lower bound tra glio e padre avviene ogni volta che negli algoritmi di cui proposto lo pseudocodice si utilizzata l'istruzione *aggiorno

il lower bound*.

MKPRepository:

si tratta di una classe statica, i cui elementi e metodi di utilit

possono essere utilizzati da tutti gli oggetti istanziati durante l'esecuzione dell'interno algoritmo. Tra i pi signicativi si evidenziano:

GAP : contiene il valore del gap da utilizzare per rilassare la condizione di


valutazione dei sottoproblemi generati durante la ricorsione

LOG : se posto a true l'esecuzione dell'algoritmo genera informazioni aggiuntive


quali l'aggiornamento intermedio del lower bound, la variabile entrata nel Core che si sta valutando ecc.

DIM_CORE : indica la dimensione che deve avere il Core iniziale PERCENTUALE_VARIABILI_DA_VALUTARE : indica la percentuale, rispetto al numero di variabili del problema di partenza, delle variabili che si vogliono aggiungere nel Core. Si pu infatti pensare di non voler aggiungere nel Core le variabili con valore assoluto pi elevato in quanto euristicamente ritenute gi ssate al loro valore ottimo senza necessit di dimostrarlo tramite la risoluzione del nuovo Core espanso. E' un modo per velocizzare l'algoritmo euristico.

TEMPO_LIMITE : il tempo massimo, in secondi, di elaborazione dell'algoritmo. Se posto uguale a 0, non viene ssato alcun limite temporale di

esecuzione.

5.3

Diagrammi UML delle interazioni

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

159

Figura 5.4: Funzionamento del software ad alto livello

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

160

Figura 5.5: Funzionamento del risolutore senza distinzione di cardinalit

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

161

Figura 5.6: Funzionamento del risolutore con distizione di cardinalit

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

162

Figura 5.7: Funzionamento di CoreRRManager

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

163

Figura 5.8: Funzionamento di RRManager - PARTE 1

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

164

Figura 5.9: Funzionamento di RRManager - PARTE 2

CAPITOLO 5.

DESCRIZIONE DEL SOFTW ARE

165

Figura 5.10: Funzionamento di RRManager - PARTE 3

Capitolo

Conclusione
6.1 Riepilogo del lavoro di tesi

Nel presente lavoro di tesi stato proposto un algoritmo in grado di risolvere sia in modo esatto che in modo euristico il Multidimensional Knapsack Problem, un problema noto essere NP-Hard Strong. Le maggiori dicolt nel risolvere questo tipo di problema sono dovute principalmente all'assenza di informazioni fornite dal modello le quali non sono sucientemente rilevanti per l'elaborazione di algoritmi ecienti ed ecaci. Lo studio da noi condotto ha permesso di sfrutture al massimo le potenzialit e le informazioni intrinseche nei coecienti di costo ridotto derivati dal rilassamento continuo del problema, permettendo di sviluppare tramite discesa ricorsiva un robusto sistema di determinazione del valore delle variabili. L'idea su cui si fonda l'intero algoritmo quella di focalizzare l'attenzione su un problema ridotto chiamato Core contenente le variabili che tra tutte risultano quelle pi dicili da settare al valore ottimo e valutarne il comportamento aggiungendo di volta in volta variabili secondo una precisa funzione di ecacia basata sui costi ridotti. La risoluzione del problema derivato dall'espansione dinamica del Core facilitata grazie all'utilizzo di un taglio che, se applicato in modo ricorsivo, in grado di ssare teoricamente tutte le variabili con costo ridotto non nullo in tempi dipendenti essenzialmente dal numero di vincoli del problema. I tempi di elaborazione ottenuti sono particolarmente incoraggianti. Allo stato dell'arte attuale nessun algoritmo presente in letteratura in grado di reggere il confronto con il nostro per quanto riguarda la risoluzione di problemi correlati con

166

CAPITOLO 6.

CONCLUSIONE

167

pochi vincoli e un numero elevato di variabili, sia dal punto di vista della qualit della soluzione trovata, da noi garantita ottima, sia dell'ecienza computazionale. Per le istanze pi complesse tra quelle proposte da P.C. Chu e J.E. Beasley [9] la variante euristica del nostro algoritmo consente di ottenere soluzioni molto buone in tempi ragionevoli, posizionandosi al secondo posto in assoluto per quanto riguarda la qualit delle soluzioni trovate. Rispetto alla metodologia che occupa la prima

posizione in questa particolare classica, il nostro approccio decisamente pi eciente, avendo dei tempi di elaborazione quattro volte inferiori. Inoltre la possibilit di applicare una serie di migliorie all'euristica sviluppata, unitamente al fatto che possibile procedere con l'esecuzione dell'algoritmo ben oltre il tempo limite da noi imposto, ci rende duciosi sul fatto che si possano trovare soluzioni almeno pari a quelle migliori note in tempi del tutto simili, se non inferiori, alla strategia risolutiva attualmente pi ecace.

6.2

Sviluppi futuri

Abbiamo deciso di concludere questa trattazione segnalando una serie di accorgimenti e migliorie che possono essere applicate all'algoritmo attuale in modo da incrementarne l'ecienza nella risoluzione delle istanze complesse di P.C. Chu e J.E. Beasley. In realt le possibilit di modicare il nostro algoritmo in modo euristico sono molte e solo la mancanza di tempo non ci ha permesso di vericarne gli eetti su tutte le istanze di prova a nostra disposizione. Tuttavia, essendo ora l'algoritmo ben denito nella sua struttura portante, non escluso che si possa iniziare uno studio mirato alla ricerca di nuove strade per rendere la variante euristica dell'algoritmo sempre pi eciente. Di seguito elenchiamo alcuni aspetti che secondo noi utile approfondire :

Come noto, uno dei tagli applicati durante l'analisi dell'albero di ricerca binario quello dei costi ridotti. Qualora il problema abbia un numero di

vincoli limitato, questo taglio decisamente ecace e accelera notevolmente l'esecuzione dell'algoritmo. Per problemi con un numero di vincoli elevato Si prendano in considerazione le istanze di Un problema per essere risolto tramite

le cose cambiano radicalmente. P.C. Chu e J.E. Beasley con

m = 30.

1 nessuno dei suggerimenti e alternative qui proposte stato applicato all'algoritmo utilizzato
per produrre i risultati presentati nel Capitolo 4.

CAPITOLO 6.

CONCLUSIONE

168

AAR deve avere un numero di variabili pari a


abbiamo settato proprio a 30.

V ARmax

che nelle nostre prove

Ora, a meno di qualche variabile di slack in

base, la maggior parte delle 30 variabili del problema sono tutte in base e di conseguenza il costo ridotto ad esse associate nullo. Di fatto il taglio sui costi ridotti, essendo questi quasi tutti nulli, risulta essere completamente inecace e pu essere benissimo eliminato. Si osservato che l'eliminazione di questo taglio per istanze a 30 vincoli migliora le prestazioni dell'algoritmo di almeno il 20%.

Abbiamo osservato, analizzando la soluzione ottima calcolata per le istanze risolte in modo esatto, che i vincoli non sono mai soddisfatti all'uguaglianza. In altre parole, all'ottimo, non tutti i beni vengono assegnati; anzi, per alcune tipologie di beni, il numero di beni non assegnato rimane elevato. E' dunque possibile utilizzare questa informazione empirica per raorzare notevolmente il taglio sui beni che, ricordiamo, si appoggia sulla quantit totale dei beni messi a disposizione dal banditore d'astra. Questo pu essere fatto settando questa quantit alla somma delle capacit dei vincoli diminuita di una certa quantit dipendente anche dall'istanza considerata. Anche qui, diminuendo

di 10000 la quantit di beni totale per istanze a 30 vincoli si osservato un incremento di circa il 40% dei tempi computazionali senza che la soluzione migliore precedentemente trovata venga tagliata.

E' consigliabile procedere ad una traduzione rigorosa dell'algoritmo in un linguaggio compilabile come il C. Una versione ottimizzata dell'algoritmo in C pu portare ad un incremento delle prestazioni di almeno il 100% rispetto alla versione interpretata.

Si pu evitare di far entrare nel Core tutte le variabili del problema anche quando il criterio di terminazione dell'espansione del Core non soddisfatto. Dalle prove da noi condotte per una qualunque istanza 500.30 tale condizione non viene mai soddisfatta ed necessario valutare l'inserimento di tutte le variabili nel Core. In realt abbiamo notato che quasi sempre la miglior soluzione calcolata stata trovata prima dell'inserimento della variabile in posizione 150 nell'ordinamento basato sui costi ridotti. istanze 500.10 e 500.5. E tale valore scende ancora per le

In altre parole, una volta ordinate le variabili per il

CAPITOLO 6.

CONCLUSIONE

169

valore assoluto crescente dei costi ridotti, le ultime 350 variabili possono essere ssate a priori, evitando ulteriori calcoli.

Sarebbe opportuno condurre uno studio approfondito sul legame sussistente tra la struttura del problema e il tipo di ordinamento delle variabili da applicare nell'algoritmo AAR, in quanto abbiamo notato che la preferenza dell'ordinamento per beni rispetto a quella per prezzi del tutto relativa alla singola istanza presa in considerazione. Inoltre possibile valutare l'ecacia di al-

tre forme di ordinamento, come quella basata sui pesi delle oerte in uno dei vincoli del problema, magari quello che a priori pu risultare il pi violabile.

La variante euristica dell'algoritmo stata costruita rilassando la condizione di valutazione dei sottoproblemi in modo banale. E' consigliabile studiare sistemi alternativi per tagliare lo spazio di ricerca. Per esempio si possono ssare a

priori certe variabili in tutti i livelli ricorsivi, oppure su valutarne solo i primi

n sottoproblemi ridotti

k che hanno il valore U BLB pi grande, o ancora si pu

pensare di valorizzare il parametro gap in modo dinamico, dipendentemente dal livello ricorsivo o dal sottoproblema analizzato.

Bibliograa

[1] E. Balas - E. Zemel. An algorithm for large zero-one knapsack problems.

Operations Research, 28:1130-1154, 1980


[2] E. Balas - C.H. Martin. Pivot and complement: a heuristic for 0-1 programming.

management science, 26:86-96, 1980


[3] E. Balas. Facets of the knapsack polytope. Math. Program., 8:146-164, 1975 [4] S. Balev - N. Yanev - A. Freville - R. Andonov. A dynamic programming based reduction procedure for the multidimensional 0-1 knapsack problem. technical

report, university of valenciennes, 2001


[5] R. Battiti - G. Tecchiolli. The Reactive Tabu Search,

ORSA Journal on

Computing, 6:126-140, 1994


[6] R. Battiti - G. Tecchiolli. Parallel biased search for combinatorial optmization: Genetic algorithms and tabu search. Microprocessors and Microsystems, 16:351367, 1993 [7] D. Bertsimas - R. Demir. An approximate dynamic programming approach to multidimensional knapsack problem. Management Science, 48:550-565, 2002. [8] K. L. Brown - Y. Shonam - M. Tennenholtz. An algorithm for multi-unit combinatorial auctions. Americans Association for Articial Intelligence, 2000 [9] P.C. Chu - J.E. Beasley. A genetic algorithm for the multidimensional knapsack problem. Journal of Heuristics, 86:63-86, 1998.

170

BIBLIOGRAFIA

171

[10] F. Dammayer - S. Voss. Application of tabu search strategies for solving multiconstraint zero-one knapsack problems. Working paper, Technische Hochschule

Darmstadt, 1991
[11] F. Dammayer S. Voss. Dynamic tabu list management using Reverse

Elimination Method. Annals of Operations Research, 31-46, 1993 [12] G. Dobson: Worst-case analysis of greedy heuristics for integer programming with non-negative data. mathematics of operations research, 7:515-531, 1982. [13] A. Drexl. A simulated annealing approach to the multiconstraint zero-one knapsack problem, Computing, 40:1-8 [14] G. Dueck - T. Scheuer. Threshold accepting: a general purpose optimization algorithm. Journal of computational Physics, 90:161-175 [15] A. Freville - G. Plateau. An ecient preprocessing procedure for the multidimensional 0-1 knapsack problem. Discrete Applied Mathematics, 49:189-212, 1994. [16] B. Gavish - H. Pirkul. Ecient algorithms for solving multiconstraint zero-one knapsack problems to optimality. Mathematical Programming, 31:78-105, 1985 [17] F. Glover - G.A. Kochenberger. Critical event tabu search for multidimensional knapsack problems. Metaheuristics: The Theory and Applications, 407-427, 1996 [18] F. Glover - Tabu Search :Part I. ORSA Journal on Computing , 3:190-206,1989 [19] F. Glover - Tabu Search:Part II. ORSA Journal on Computing, 1:4-32,1990 [20] R. Gonen - D. Lehmann. Linear programming helps solving large multi-unit combinatorial auctions, Aprile 2001 [21] Z. Gu - G.L. Nemhauser - M.W.P. Savelsbergh. Cover inequalities for 0-1 linear programs: computation. INFORMS J. on Computing, 10:427-437, 1998 [22] S.R. Gupta - R.L. Buln - J.S. Smith. Lifting Cover Inequalities for the Binary Knapsack Polytope

BIBLIOGRAFIA

172

[23] S. Hana - A. Freville. Extension of reverse elimination method through a dyamic management of the tabu list, RAIRO Operations Research, 35:251-267, 2001 [24] K. Kaparis - A.N. Letchford. Local and Global Lifted Cover Inequalities for the 0-1 Multidimensional Knapsack Problem. Department of Management Science,

Lancaster University, Inghilterra


[25] H. Kellerer - U. Pferschy - D. Pisinger. Knapsack Problems. Springer, 2004. [26] M. Ohlsenn - C. Peterson - B. Soderberg. Neural Networks for optimization problems with inequality constraints: the knapsack problem. Neural

Computation, 5:331-339, 1993


[27] C. Oliva - P. Michelon - C. Artigues. Constraint adn linear programming: Using reduced cost for solving the zero/one multiple knapsack problem, 2001. [28] M.A. Osorio - F. Glover - P.L. Hammer. Cutting and surrogate constraint analysis for improved multidimensional knapsack solutions. Techinal Report

HCES-08-00, Hearin Center for Enterprise Science, University of Mississippi,


2000. [29] R. Mansini - M.G. Speranza. Combinatorial Auctions: an exact approach, Pro-

ceedings of the 5th International Conference in Electronic Commerce Research (ICECR-5), Montreal ( Canada ), 23-27 ottobre 2002
[30] H. Pirkul - S. Narasimhan. Ecient algorithms for the multiconstraint general knapsack problem. IEEE transactions, 18:195-203,1986. [31] H. Pirkul. A heuristic solution procedure for the multiconstraint zero-one knapsack problem. Naval Research Logistics, 34:161-172, 1987. [32] D. Pisinger. An expanding-core algorithm for the exact 0-1 knapsack problem.

European Journal of Operational Research, 87:175-187, 1995.


[33] J. Puchinger - G. Raid - U. Pferschy. The Core Concept for the Multidimensional Knapsack Problem, 2006

BIBLIOGRAFIA

173

[34] J. Puchinger - G.R. Raidl - M. Gruber. Cooperating Memetic and Branch-andCut Algorithms for Solving the Multidimensional Knapsack Problem. The 6th

Metaheuristics International Conference, Vienna, agosto 2005


[35] M. Rossetti. Modelli e algoritmi su Aste Combinatorie per l'Assegnazione di Frequenze di Trasmissione. Universit degli Studi di Brescia, Facolt di Ingegneria,

Dipartimento di Elettronica per l'Automazione, anno accademico 2002/2003.


[36] S. Senju - Y. Toyoda. An approach to linear programming with 0-1 variables.

Management Science, 15:196-207, 1968.


[37] W. Shin. A branch and bound method for the multiconstraint zero-one knapsack problem. journal of the operational research society. 30:369-378, 1979 [38] M. Vasquez - J.K. Hao. A Hybrid Approach for the 0-1 Multidimensional Knapsack Problem. Proceedings of the Int. Joint Conference on Articial Intelligence, 328-333, 2001 [39] M. Vasquez - Y. Vimont. Improved results on the 0-1 multidimensional knapsack problem. European Journal of Operational Research, 70-81, 165 [40] L.A. Wolsey. Faces for linear inequalities in 0-1 variables. Math. Program., 8:165178, 1975 [41] E. Zemel. Easily computable facets of the knapsack polytope. Math. Oper. Res., 14:760-765, 1989 [42] Ilog Cplex 10.0 user's guide, 2005: http://www.ilog.com/products/cplex [43] http://java.sun.com [44] http://www.bea.com/ [45] http://wireless.fcc.gov/auctions/about/index.html [46] http://hces.bus.olemiss.edu/tools.html [47] Algoritmi di ordinamento - lucidi della professoressa M. Zanella per il corso di Algoritmi e Strutture Dati

You might also like