Università degli Studi di Padova DIPARTIMENTO DI MATEMATICA

CORSO DI LAUREA IN INFORMATICA

Implementazione di algoritmi per la determinazione di bipartizioni domatiche di grafi con vincoli di cardinalità

Tesi di laurea triennale

Relatore

Prof. Luigi De Giovanni

Laureando

Filippo Rampado, 1047774

ANNO ACCADEMICO 2014-2015

Filippo Rampado: Implementazione di algoritmi per la determinazione di bipartizioni domatiche di grafi con vincoli di cardinalità, Tesi di laurea triennale, © Set 2015 Sommario

Il presente documento descrive il lavoro svolto dal laureando Filippo Rampado durante il periodo di stage, presso il Dipartimento di Matematica dell’Università di Padova.

Lo scopo principale dello stage è l’implementazione di algoritmi per un problema di partizionamento di grafi, a supporto di ricerche condotte dal gruppo di Ricerca Operativa del Dipartimento di Matematica, in collaborazione con il Dipartimento di Informatica dell’Università di Udine.

È quindi richiesta una implementazione in linguaggio ++ di un algoritmo già esistente nel linguaggio Mathematica rivolto agli alberi, al fine di agevolarne l’integrazione e l’estendibilità dello stesso in un algoritmo più generale rivolto ai grafi.

Successivamente è richiesta l’analisi e l’implementazione di tecniche euristiche basate sulla costruzione di opportuni alberi ricoprenti, e il confronto delle prestazioni con tecniche esatte, che comportano l’implementazione di modelli di programmazione lineare.

Indice

1. Introduzione ...... 1

1.1. Il problema ...... 1 1.2. Stato del Dominio ...... 1 1.3. Scopo dello stage ...... 2 1.4. Il progetto in breve ...... 2 1.5. Organizzazione del testo ...... 6

2. Strumenti e tecnologie utilizzate ...... 7

2.1. C/C++...... 7 2.2. Librerie ...... 7 2.3. GCC ...... 7 2.4. Visual Studio 2013 ...... 8 2.5. Mathematica ...... 8 2.6. AMPL ...... 8 2.7. CPLEX ...... 9 2.8. Astah ...... 9

3. Analisi dei requisiti ...... 10

3.1. Requisiti obbligatori ...... 10 3.2. Requisiti desiderabili ...... 10 3.3. Requisiti opzionali...... 11

4. La teoria ...... 12

4.1. Il problema CDBP ...... 12 4.2. Modello di programmazione lineare intera ...... 13 4.3. Il caso degli alberi ...... 14 4.4. Complessità computazionale ...... 16 4.5. Grafi generici ed euristiche ...... 17 4.6. Il caso pesato ...... 18

5. Software CDBP-Algo ...... 19

5.1. L’algoritmo per gli alberi ...... 19 5.2. L’algoritmo per i grafi ...... 20 5.3. Euristiche ...... 22 5.3.1. Tipo A ...... 23 5.3.2. Tipo B ...... 25 5.3.3. Tipo C ...... 27 5.4. Il caso pesato ...... 30

6. Progettazione e codifica ...... 31 6.1. Vincoli di sviluppo ...... 31 6.2. Progettazione dei moduli ...... 31 6.2.1. Algoritmo per gli alberi ...... 32 6.2.2. Algoritmo per i grafi ...... 34 6.3. Codifica ...... 36 6.3.1. Algoritmo per gli alberi ...... 36 6.3.2. Algoritmo per i grafi ...... 37 6.3.3. Modello in AMPL ...... 38

7. Verifica e Test ...... 39

7.1. Ambiente di test ...... 39 7.2. Piano dei test ...... 39 7.3. Test di unità ...... 40 7.4. Test di integrazione ...... 40 7.5. Test di sistema ...... 40 7.6. Collaudo prestazionale ...... 41 7.7. Analisi dei risultati ...... 44

8. Consuntivo ...... 47

8.1. Difficolta rilevate ...... 47 8.2. Consuntivo finale ...... 47 8.3. Raggiungimento degli obiettivi ...... 49 8.3.1. Requisiti obbligatori ...... 49 8.3.2. Requisiti desiderabili ...... 50 8.3.3. Requisiti opzionali ...... 50

9. Conclusioni ...... 51

9.1. Note per possibili sviluppi futuri ...... 51 9.2. Conoscenze pregresse e acquisite ...... 51 9.3. Valutazione personale ...... 52

A. CDBP-Algo: Manuale utente ...... 53

A.1. Requisiti di sistema ...... 53 A.2. Parametri in ingresso ...... 53 A.3. Esecuzioni previste ...... 55

B. Risultati dei benchmark ...... 57

B.1. Singola esecuzione ...... 57 B.2. Esecuzione con 10 alberi ricoprenti ...... 63

Glossario ...... 70

Bibliografia ...... 72

Elenco delle tabelle

Tabella 1: Attività previste per lo svolgimento dello stage ...... 3

Tabella 2: Schema dell'algoritmo per gli alberi ...... 15

Tabella 3: Problemi e relative complessità computazionali ...... 18

Tabella 4: Tipi di euristica sviluppati ...... 23

Tabella 5: Differenza ore consuntivo-preventivo ...... 48

Tabella 6: Risultati dei test con un albero ricoprente ...... 63

Tabella 7: Risultati dei test con 10 alberi ricoprenti ...... 69

Elenco delle figure

Figura 1: Diagramma di Gantt delle attività del progetto ...... 5

Figura 2: Partizione domatica di un grafo ...... 12

Figura 3: Modello di programmazione lineare intera per il problema CDBP ...... 13

Figura 4: Esempio di bipartizione domatica ...... 14

Figura 5: Diagramma di attività dell'algoritmo per grafi ...... 21

Figura 6: Esempio di grafo ...... 23

Figura 7: Risultato euristica A ...... 24

Figura 8: Risultato euristica B ...... 25

Figura 9: Risultato euristica B - 80% ...... 26

Figura 10: Risultato euristica C ...... 28

Figura 11: Risultato euristica C- 50% ...... 29

Figura 12: Architettura algoritmo per gli alberi ...... 33

Figura 13: Architettura algoritmo per gli alberi ...... 35

Figura 14: Grafico p-tempo per risoluzione del modello in AMPL ...... 42 Introduzione

1. Introduzione

In questo capitolo viene data una descrizione sintetica del problema e del progetto oggetto dello stage. I contenuti saranno dettagliati nei successivi capitoli.

1.1. Il problema

Il progetto proposto ha il fine di supportare le ricerche condotte dal gruppo di Ricerca Operativa del Dipartimento di Matematica, in collaborazione con il Dipartimento di Informatica dell’Università di Udine in merito a un problema di partizionamento di grafi.

Il problema in analisi è noto come Constrained Domatic BiPartition (CDBP) di un grafo (Bipartizione Domatica con vincoli di cardinalità): dato un grafo, si vuole determinare una bipartizione dei suoi nodi in insiemi dominanti di cui uno di cardinalità p data (e l’altro di cardinalità n – p, dove n è il numero di nodi). Si ricorda che un (sotto)insieme di nodi di un grafo è dominante se ogni nodo del grafo appartiene a questo (sotto)insieme o è adiacente a un nodo del (sotto)insieme stesso.

È noto dalla letteratura che il problema senza vincoli di cardinalità è risolvibile in tempo polinomiale, mentre il problema nella versione vincolata è NP-completo su grafo generico, polinomiale nel caso il grafo sia un albero [1, 2].

In particolare, le ricerche in parola hanno messo a punto un algoritmo polinomiale in grado di determinare, per un dato albero e una data cardinalità p dell’insieme dominante, se una tale CDBP esiste e, in questo caso, fornirne una. Nell’ambito delle ricerche in corso, sono stati concepiti degli algoritmi euristici che sfruttano l’algoritmo noto per la soluzione del problema sugli alberi per fornire una soluzione ammissibile per un grafo generico.

1.2. Stato del Dominio

Le ricerche in corso hanno messo a punto un modello di programmazione lineare intera per la soluzione del problema CDBP su un grafo generico [1]. Le stesse ricerche hanno evidenziato la possibilità di ottenere una bipartizione domatica vincolata di un grafo generico sfruttando come core l’algoritmo messo a punto per gli alberi.

L’osservazione di base è che una bipartizione domatica di cardinalità p di un qualsiasi albero ricoprente del grafo è anche una bipartizione domatica del grafo stesso.

1 di 72 Introduzione

È disponibile un’implementazione in Mathematica dell’algoritmo di bipartizione domatica di un albero, in grado di determinare simultaneamente, per tutti i valori di p compresi tra 1 e n- 1, se esiste una bipartizione domatica vincolata, e, nel caso, di esibirne una. Facciamo notare che l’implementazione è a uno stato prototipale e non è adatta a estensioni o integrazioni in altro codice.

A partire dall’algoritmo per alberi disponibile, lo schema di principio dell’algoritmo per la soluzione del problema su grafo generico G con vincoli di cardinalità p è quindi il seguente:

1. Estrai da G un opportuno albero ricoprente T

2. Applica l’algoritmo per gli alberi a T ottenendo l’insieme P delle cardinalità per cui esiste una bipartizione domatica di T

3. Se p ∈ P, la soluzione trovata può essere estesa a G

Lo schema può essere iterato per diversi alberi ricoprenti T da scegliere opportunamente.

1.3. Scopo dello stage

Lo scopo dello stage è quello di fornire supporto al gruppo di ricerca per l’implementazione degli algoritmi di soluzione del problema CDBP su grafo generico.

Due sono gli elementi chiave da considerare:

Il primo è il porting dell’algoritmo attualmente implementato in Mathematica [4] in un linguaggio di programmazione di maggiore diffusione e che permette l’integrazione e l’estensione dell’algoritmo stesso (nel nostro caso è stato utilizzato C++ [5]).

Il secondo è l’implementazione e il test delle performance di diversi criteri di selezione degli spigoli per la costruzione degli alberi ricoprenti di cui alla precedente sezione.

1.4. Il progetto in breve

Come dettagliato nel Capitolo 3, gli obiettivi preliminari dello stage sono l’apprendimento della letteratura di base sul problema CDBP, lo studio dell’algoritmo rivolto agli alberi e della sua implementazione in Mathematica. Dopodiché, è previsto il porting dell’algoritmo in C++ e la sua estensione a grafi generici, andando ad integrare in modo incrementale tecniche euristiche iterative.

2 di 72 Introduzione

È desiderabile l’implementazione di criteri euristici alternativi e l’analisi delle performance. È opzionale l’implementazione con AMPL del modello di programmazione lineare intera analizzando le prestazioni per confronto con le tecniche esatte.

Dopo aver analizzato gli obiettivi dello stage, sono state definite le fasi principali e le tempistiche del progetto, le quali vengono descritte nella seguente tabella.

Tabella 1: Attività previste per lo svolgimento dello stage

3 di 72 Introduzione

Analisi dello stato dell’arte: in questa fase è previsto lo studio e l’assimilazione della teoria riguardante il problema CDBP e l’algoritmo rivolto agli alberi.

Implementazione dell’algoritmo su alberi: questa fase prevede lo studio dell’implementazione preesistente in Mathematica dell’algoritmo per gli alberi, e la sua conversione in C++.

Implementazione di un euristica per CDBP su grafo generico: in questa fase è previsto lo studio e l’implementazione di metodi euristici per la generazione guidata di alberi ricoprenti.

Integrazione di diversi criteri di selezione degli spigoli: questa fase prevede l’analisi e l’implementazione di criteri alternativi di selezione degli spigoli, con relative analisi di performance.

Confronto con tecniche esatte: in questa fase è prevista l’implementazione del modello di programmazione lineare intera in AMPL e il confronto dei risultati con le tecniche esatte.

Verifica e testing: in questa fase oltre alla correttezza del codice, sarà valutato il corretto funzionamento degli algoritmi.

Produzione di documenti, manuali e relazioni: in questa fase verrà finalizzata tutta la documentazione richiesta e la relazione finale.

Si fa notare che, durante lo svolgimento dello stage, le ricerche in corso hanno considerato l'estensione del problema al caso pesato e hanno individuato la possibilità di ottenere un algoritmo pseudo-polinomiale come semplice estensione dell'algoritmo per il caso non pesato.

È stato quindi aggiunto in corso d'opera un ulteriore obiettivo opzionale, che prevede la ricerca e l’integrazione di modifiche agli algoritmi per la risoluzione dei grafi pesati. Le osservazioni e le modifiche verranno spiegate in dettaglio nel capitolo 5.4.

Segue il diagramma di Gantt previsto per il progetto.

4 di 72 Introduzione

Figura 1: Diagramma di Gantt delle attività del progetto

5 di 72 Introduzione

1.5. Organizzazione del testo

Di seguito viene descritta la struttura del presente documento:

Il secondo capitolo descrive gli strumenti informatici utilizzati.

Il terzo capitolo descrive i requisiti del progetto.

Il quarto capitolo illustra brevemente le teorie alla base di questo progetto.

Il quinto capitolo descrive in dettaglio l’algoritmo oggetto di questo progetto.

Il sesto capitolo approfondisce il funzionamento del software CDBP-Algo a livello progettuale e di codice.

Il settimo capitolo illustra l’attività di test e verifica prestazionale svolta e commenta le tabelle con i risultati.

L’ottavo capitolo espone le differenze tra il lavoro svolto rispetto a quanto preventivato.

Il nono capitolo contiene i commenti finali e le note per eventuali sviluppi futuri.

L’Appendice A contiene un manuale d’uso per l’esecuzione del software CDBP-Algo e indicazioni su come fornire i dati in input.

L’Appendice B contiene i risultati dei test prestazionali eseguiti, in forma tabellare.

Il glossario contiene termini tecnici ed i termini non di uso comune, gli acronimi e le abbreviazioni usati in questo documento.

La bibliografia contiene i riferimenti bibliografici utilizzati a supporto del progetto. Verranno riferiti nel testo tramite il numero identificativo tra parentesi quadre (ad esempio [1]).

6 di 72 Strumenti e tecnologie utilizzate

2. Strumenti e tecnologie utilizzate

In questo capitolo vengono illustrati gli strumenti e le metodologie utilizzate per lo svolgimento del progetto.

2.1. C/C++

Il C++ è un linguaggio di programmazione orientato agli oggetti, con tipizzazione statica. Sviluppato nel 1983 da Bjarne Stroustrup, allora ricercatore presso AT&T, il C++ è tra i primi 5 linguaggi più utilizzati al mondo. Il software CDBP-Algo è stato scritto in C++, anche se si tratta fondamentalmente di codice C, visto che non si sfrutta il paradigma ad oggetti; tuttavia, vengono utilizzate alcune librerie ed alcune caratteristiche che appartengono al linguaggio C++. Il software usa essenzialmente funzionalità dello standard C++98, ma è stato scelto di usare comunque C++11 per semplificare notevolmente la scrittura degli input.

Per l’implementazione degli algoritmi è stato scelto di utilizzare il linguaggio C++ al posto di Java principalmente per le performance migliori che si ottengono. In secondo luogo gli algoritmi seguono il paradigma procedurale, uno stile molto più consono al linguaggio C/C++ che a Java, essendo quest’ultimo un linguaggio puramente ad oggetti.

2.2. Librerie

Il software CDBP-Algo fa largo uso delle librerie standard del C++. In particolare vengono ampiamente utilizzate le strutture dati , e . Vengono inoltre usate delle funzioni messe a disposizione dalla libreria per le operazioni di ricerca e unione di insiemi, funzioni delle librerie e per la generazione di numeri casuali, e le funzioni di scrittura su file della libreria per l’output su file.

2.3. GCC

GCC (GNU Compiler Collection, in origine GNU C Compiler) è un compilatore multi-target creato da Richard Matthew Stallman, fondatore della Free Software Foundation, come parte

7 di 72 Strumenti e tecnologie utilizzate

del Progetto GNU. Inizialmente destinato al linguaggio C, dispone oggi di vari front end per altri linguaggi.

Si è scelto GCC sia perché si tratta di uno dei compilatori più usati, che per la conoscenza pregressa di questo compilatore da parte del laureando avendolo già usato in altri progetti.

2.4. Visual Studio 2013

Visual Studio è un ambiente di sviluppo integrato (Integrated Development Environment o IDE) multipiattaforma sviluppato da Microsoft, che supporta attualmente diversi tipi di linguaggio, quali C, C++, C#, F#, Visual Basic .Net e ASP .Net, e che permette la realizzazione di applicazioni, siti web, applicazioni web e servizi web.

Visual Studio è stato utilizzato per la scrittura, esecuzione e test del codice. Si è scelto questo IDE per gli enormi vantaggi derivati dai suoi tool integrati, tra cui debug molto semplice, analisi statica in tempo reale e formattazione automatica del codice.

2.5. Mathematica

Mathematica [4] è un ambiente di calcolo simbolico e numerico multipiattaforma, ideato da Stephen Wolfram e successivamente sviluppato da un team di matematici e programmatori. È anche un potente linguaggio di programmazione interpretato che permette di realizzare algoritmi complessi.

Mathematica è stato utilizzato per la stesura dell’algoritmo CDBP rivolto agli alberi [3], dal quale si è fatto il porting nel linguaggio C++. È stato utilizzato inoltre per testare la correttezza dell’algoritmo sviluppato nel corso dello stage, confrontando i risultati ottenuti a parità di input con la versione in Mathematica.

2.6. AMPL

AMPL [6], acronimo di A Mathematical Programming Language Linguaggio di programmazione matematica), è un linguaggio ad alto livello, sviluppato dai laboratori Bell, per descrivere e risolvere grossi e complicati problemi di programmazione matematica. La sintassi del linguaggio è molto simile alla notazione matematica dei problemi di ottimizzazione, e ciò ne consente una definizione molto concisa e leggibile. AMPL supporta

8 di 72 Strumenti e tecnologie utilizzate

decine di risolutori, tra cui CPLEX, CBC, FortMP, , MINOS, IPOPT, SNOPT, KNITRO e LGO.

AMPL è stato utilizzato per l’implementazione del modello di programmazione lineare intera associato al problema CDBP, potendo così avere una tecnica esatta di soluzione con cui confrontare i risultati degli algoritmi.

2.7. CPLEX

CPLEX [9], è un pacchetto software sviluppato dalla IBM per la risoluzione esatta di problemi di programmazione lineare e di programmazione lineare mista intera. Consente la soluzione di problemi lineari, anche di notevoli dimensioni (migliaia di variabili e vincoli), mediante l’utilizzo dell’algoritmo del simplesso e delle sue varianti. I metodi di risoluzione implementati per la programmazione intera si basano su tecniche di tipo , dynamic search, piani di taglio ed euristiche. CPLEX permette inoltre all’utente di modificare le tecniche di risoluzione tramite diversi parametri che definiscono le scelte e strategie da applicare.

CPLEX è stato utilizzato come risolutore in AMPL per il modello di Programmazione Lineare Intera implementato.

2.8. Astah

Astah [10], conosciuto formalmente come JUDE (Java and UML Developers' Environment), è uno strumento di modellazione UML creato dalla compagnia giapponese Change Vision. Permette di creare una vasta gamma di diagrammi UML, tra cui diagrammi delle classi, diagrammi di attività, diagrammi di sequenza ecc.

Astah è stato utilizzato per la produzione dei diagrammi presenti in questo documento.

9 di 72 Analisi dei requisiti

3. Analisi dei requisiti

In questo capitolo vengono illustrati i requisiti del progetto, divisi in obbligatori, desiderabili ed opzionali.

3.1. Requisiti obbligatori

Ob1: Assimilazione dei concetti di base del problema CDBP e dell’algoritmo per alberi.

Ob2: Assimilazione dell’implementazione esistente in Mathematica dell’algoritmo per alberi.

Ob3: Porting dell’algoritmo per alberi in un linguaggio di programmazione.

Ob4: Assimilazione dei criteri di selezione degli spigoli per la costruzione di opportuni alberi ricoprenti.

Ob5: Implementazione dell’algoritmo per la costruzione di alberi ricoprenti.

Ob6: Integrazione dell’algoritmo per la soluzione di CDBP su alberi e dell’algoritmo di costruzione degli alberi ricoprenti in un’euristica iterativa per la soluzione del problema CDBP su grafo generico.

Ob7: Produzione di documentazione sui moduli sviluppati.

Ob8: Produzione di un manuale di utilizzo dei moduli sviluppati.

3.2. Requisiti desiderabili

De1: Analisi prestazionale dei diversi criteri di selezione su benchmark standard.

De2: Studio di ulteriori criteri di selezione per la costruzione degli alberi ricoprenti.

10 di 72 Analisi dei requisiti

3.3. Requisiti opzionali

Op1: Implementazione con AMPL del modello di programmazione lineare intera per la soluzione esatta del problema CDBP.

Op2: Estensione dell’analisi prestazionale per confronto, dove possibile, con i risultati del modello esatto.

Op3: Implementazione di un algoritmo per la risoluzione di grafi pesati.

Si fa notare che Op3 non era previsto inizialmente, ma, durante lo svolgimento dello stage, le ricerche in corso hanno considerato l'estensione del problema al caso pesato e hanno individuato la possibilità di ottenere un algoritmo pseudo-polinomiale come semplice estensione dell'algoritmo per il caso non pesato.

11 di 72 La teoria

4. La teoria

In questo capitolo vengono presentate brevemente le teorie su cui si basa questo progetto, tratte da [1, 2].

4.1. Il problema CDBP

Dato un grafo non orientato G = (V, E), un sottoinsieme di nodi è dominante se ogni nodo di G o fa parte del sottoinsieme o è adiacente a qualche nodo nel sottoinsieme. Una partizione domatica consiste quindi nel partizionale i in k insiemi disgiunti tali che ogni insieme sia un insieme dominante per G (il grafo in Figura 2 è partizionato in tre insiemi dominati, rappresentati da tre colori deversi). Il domatic number rappresenta la massima dimensione di una partizione domatica, ovvero il massimo numero di insiemi dominanti disgiunti (il grafo in Figura 2 possiede domatic number pari a 3).

Figura 2: Partizione domatica di un grafo

Trovare una bipartizione domatica di un grafo è sempre possibile assumendo che G non abbia nodi isolati. Il domatic numer per gli alberi infatti è 2 e per i grafi in generale è sufficiente considerare un albero di copertura per ogni componente connessa: ogni albero è connesso e bipartito e le due parti di un grafo connesso bipartito corrispondono a due insiemi dominanti.

Dato un grafo non orientato, il Constrained Domatic Bipartition Problem (CDBP), ovvero bipartizione domatica con vincoli di cardinalità, è un problema che consiste nel determinare una bipartizione, se esiste, dei nodi in due insiemi dominanti, con il vincolo aggiuntivo che uno dei due sottoinsiemi abbia cardinalità data.

È noto dalla letteratura che il problema senza vincoli di cardinalità è risolvibile in tempo polinomiale, mentre il problema con vincoli di cardinalità è NP-Completo. Per gli alberi invece esiste un algoritmo polinomiale che lo risolve, con complessità O(n3) dove n è il numero di nodi.

12 di 72 La teoria

4.2. Modello di programmazione lineare intera

Risolvere il problema CDBP consiste essenzialmente nel cercare un modo di colorare i nodi di un grafo con due colori diversi, b (black - nero) e w (white - bianco), tali che ogni nodo è adiacente ad almeno un nodo di colore diverso, e la cardinalità dell’insieme di nodi neri è uguale a un valore p dato. Questo problema può essere formulato tramite un modello di Programmazione Lineare Intera (PLI).

Consideriamo un generico grafo connesso G = (V, E), e senza perdita di generalità assumiamo n = |V| ≥ 2. Associamo quindi una variabile decisionale binaria xi ad ogni nodo i di V, con xi = 1 se i è colorato di nero, 0 altrimenti. Definiamo S(i) la stella in G centrata in i (che include anche il nodo i) e d(i) il grado di i in G.

Dato un intero p, il seguente PLI rappresenta tutte le possibili soluzioni al problema CDBP:

Figura 3: Modello di programmazione lineare intera per il problema CDBP

Le disuguaglianze di sinistra di (1) impongono che, per ogni stella, almeno un nodo deve essere nero. Le disuguaglianze di destra invece impongono che non tutti i nodi della stella possono essere neri. Le prime disuguaglianze impongono quindi vincoli sulle stelle, le disuguaglianze (2) e (3) forzano il vettore x = (x1, x2, … , xn) a essere binario, mentre (4) è il vincolo di cardinalità.

Poniamo P(G) ∈ ℝn il politopo associato alle diseguaglianze (1) e (2), che quindi non considera il vincolo di cardinalità e il vincolo di interezza. Il sistema di disuguaglianze stella (1) può essere riformulato in forma matriciale come

1 ≤ Sx ≤ d

Notare che S = A + I dove A è la matrice di adiacenza e I è la matrice identità, per cui S è simmetrica.

Definiamo il poliedro che rappresenta tutte le bipartizioni domatiche come

13 di 72 La teoria

P = { x : 1 ≤ Sx ≤ d, 0 ≤ x ≤ 1 }

La cosa interessante è che, nel caso degli alberi, sebbene S non sia totalmente unimodulare, tutti i vertici di P hanno componenti intere e corrispondono quindi a bipartizioni domatiche. Questo ci permette di trovare la bipartizione domatica con minore cardinalità di V’ semplicemente risolvendo il problema di programmazione lineare. Tuttavia se imponiamo il vincolo di cardinalità |V’| = p per un generico valore di p, il risultante politopo non ha più, in generale, vertici interi. Quindi la programmazione lineare non può essere usata per risolvere il problema CDBP per un generico valore di p.

4.3. Il caso degli alberi

Nell’ambito delle ricerche in corso, è stato sviluppato un algoritmo rivolto agli alberi che risolve il problema CDBP in tempo polinomiale. L’algoritmo risolve il problema simultaneamente per tutti i valori 1 ≤ p ≤ n, determinando quindi se esiste una bipartizione domatica vincolata in cardinalità, e in caso positivo, fornisce quella partizione.

Senza perdita di generalità si può assumere che l’insieme dominante più piccolo sia composto da nodi colorati di nero, di cardinalità 1 ≤ p ≤ ⎿n/2⏌, mentre il più grande, ricavato per complementarietà, contenga nodi bianchi. Poniamo quindi Ñ = {1, 2, … , ⎿n/2⏌}.

Inoltre diciamo che un nodo è “coperto” se almeno un nodo adiacente ad esso è di colore diverso. Per ogni insieme di nodi S, una colorazione k-ammissibile è una mappa che assegna ad ogni nodo in S un colore (bianco o nero) tale che il numero di nodi neri in S è k, e ogni nodo in S è coperto. In Figura 4 si può notare una colorazione 3-ammissibile, in cui ogni nodo è coperto da un nodo adiacente: il nodo 1 è coperto dal nodo 2, il nodo 3 è coperto dai nodi 4 e 5 e così via.

Figura 4: Esempio di bipartizione domatica

14 di 72 La teoria

L’algoritmo procede analizzando in sequenza ogni nodo dell’albero i cui figli sono già stati esaminati, partendo quindi dalle foglie e arrivando fino alla radice. Per ogni nodo v vengono calcolati i seguenti insiemi:

K: è l’insieme di valori k ∈ Ñ tali che esiste una colorazione k-ammissibile dell’albero con radice v assumendo un certo colore di v. Notare che v deve essere coperto da almeno uno dei suoi figli.

K+: è l’insieme dei valori k ∈ Ñ tali che esiste una colorazione k-ammissibile sapendo il colore di v e anche del padre di v. Notare che i valori K sono contenuti in K+.

K-: è l’insieme di valori k ∈ Ñ tali che tutti i figli di v hanno lo stesso colore di v, ed esiste una colorazione (k-1)-ammissibile per l’albero con radice in v, escluso v stesso.

Inoltre per ogni valore di questi insiemi sono associati altri insiemi, rispettivamente S, S+ ed S-, che indicano l’insieme di nodi da colorare di nero corrispondente al specifico valore di k.

Lo schema dell’algoritmo è quindi il seguente:

1. Imposta struttura dati 2. Inizializzazione 3. - Ripeti 4. Seleziona nodo da esaminare 5. Esegui Procedura 1 6. - Ripeti 7. Seleziona figlio di v 8. Esegui Procedura 2 9. - Per ogni figlio diverso dal primo del nodo 10. Esegui Procedura 3 11. Dichiara v esaminato 12. - Fino ad arrivare alla radice 13. Esegui Procedura 4 14. Dichiara radice esaminata 15. Raccogli soluzioni

Tabella 2: Schema dell'algoritmo per gli alberi

Mentre l’inizializzazione riguarda solamente la valutazione dei possibili colori delle foglie dell’albero, le 4 procedure dell’algoritmo consistono nel valutare i possibili valori di k per cui esiste una colorazione ammissibile tenendo conto di tutte le combinazioni di colori possibili dei nodi.

In particolare:

La Procedura 1 valuta le combinazioni tra il nodo in esame e solamente il primo figlio

La Procedura 2 valuta le combinazioni tra il nodo in esame e i primi l nodi figli.

15 di 72 La teoria

La Procedura 3 valuta le combinazioni tra il nodo in esame, tutti i figli e anche il nodo padre.

La Procedura 4 valuta le combinazioni del nodo radice.

Una volta esaminate anche le combinazioni della radice, vengono raccolte le combinazioni unendo le soluzioni con radice nera Kb e radice bianca Kw, ottenendo tutte le possibili cardinalità dell’insieme V’. L’insieme V può quindi essere partizionato in due insiemi dominanti V’ e V’’ di cardinalità p e n-p (p ≤ n – p) se e solo se p ∈ Kb ∪ Kw. Se p è presente in uno dei due insiemi, l’insieme di nodi da colorare di nero per avere una colorazione p- ammissibile è direttamente fornita dallo stesso algoritmo nell’insieme S del nodo radice.

Si fa notare che per determinare le combinazioni di colori ammissibili, viene definito un particolare operatore di somma tra insiemi, chiamato “setsum”, e definito come segue:

per ogni A, B ⊆ Ñ, A ⊕ B = { a + b | a ∊ A, b ∊ B, a + b ≤ n / 2 } ⊆ Ñ

È già disponibile un’implementazione nel linguaggio Mathematica [3] dell’algoritmo schematizzato in Tabella 2.

4.4. Complessità computazionale

L’algoritmo per gli alberi parte dalle foglie e visita uno a uno tutti i nodi quando tutti i figli di un nodo sono stati esaminati. Quando un nodo è visitato, tutti gli archi discendenti sono processati, per cui n-1 archi sono processati una sola volta.

Le operazioni che vengono eseguite per ogni nodo sono essenzialmente due:

Combinazioni dei valori k-ammissibili tra un nodo e un altro: richiede nel peggiore dei casi n2 somme, quindi la complessità è O(n2).

Unione di insiemi: costa O(n) e deve essere eseguita al più n volte, ovvero per ogni valore possibile di k.

Per cui la complessità totale dell’algoritmo è O(n3), ovvero polinomiale.

16 di 72 La teoria

4.5. Grafi generici ed euristiche

È stato dimostrato in [1] che il problema CDBP è polinomiale per gli alberi, mentre è NP-Hard per i grafi generici. Le ricerche in corso riguardano quindi un algoritmo euristico per grafi generici, che permetta di risolvere il problema CDBP in tempi ragionevoli.

Le tecniche di risoluzione basate su modelli di programmazione lineare, cercano di risolvere il problema senza fermarsi prima di essere arrivati a una soluzione esatta. Questo approccio può risultare particolarmente dispendioso in termini di tempo computazionale, e non sempre si necessita di una soluzione esatta, ma ci si può accontentare di una approssimazione.

Infatti se si prova a risolvere il problema su un grafo sufficientemente grande utilizzando un apposito risolutore (ad esempio il software CPLEX in AMPL), si può notare che con il vincolo di cardinalità imposto, che rende il problema NP-Hard, il risolutore può impiegare diverso tempo per fornire la risposta per alcuni valori di p. Questo accade perché il risolutore, per risolvere un modello di programmazione lineare intera, usa metodi di tipo branch and bound che hanno complessità computazionale NP-Hard.

Per poter risolvere il problema può essere utile usare delle euristiche. Gli algoritmi euristici non sempre forniscono la soluzione ottima, ma riescono a ricavare una soluzione in tempi ragionevoli, e possono, se ben progettati, arrivare a fornire delle soluzioni di buona qualità. Solitamente vengono effettuate alcune osservazioni sui dati in input che permettono di seguire alcune strade più promettenti, e evitarne altre, riducendo il tempo computazionale e arrivando velocemente a una stima della soluzione.

Nel caso CDBP, l’approccio che si intende seguire consiste nello scegliere opportunamente degli alberi ricoprenti del grafo in ingresso, osservando che una soluzione ottenuta su un albero ricoprente è valida anche per il grafo originale. A partire dall’algoritmo per alberi disponibile, lo schema dell’algoritmo per la soluzione del problema su grafo generico G con vincolo di cardinalità p è quindi il seguente:

1. Estrai da G un opportuno albero ricoprente T

2. Applica l’algoritmo per gli alberi a T ottenendo l’insieme P delle cardinalità per cui esiste una bipartizione domatica di T

3. Se p ∈ P, la soluzione trovata può essere estesa a G

Lo schema può essere iterato per diversi alberi ricoprenti, applicando scelte euristiche nella selezione degli alberi. Facciamo notare che un tale algoritmo euristico può trovare una soluzione per alcuni valori di p, ma non è in grado di garantire che, per i valori di p non trovati, il problema non abbia soluzione.

17 di 72 La teoria

4.6. Il caso pesato

Una possibile estensione del problema CDBP discussa in [1] è il Weight-Constrained Domatic Bipartition Problem, ovvero problema di bipartizione domatica con vincoli di peso su un grafo pesato. Formalmente, considerando un grafo G = (V, E) con pesi w(v) su ogni nodo v, ci si chiede se V può essere partizionato in due insiemi dominanti disgiunti V’ e V’’ tali che la somma dei pesi dei nodi in V’ è uguale a un valore W dato.

Come dimostrato in [1], il problema è NP-Hard, anche per gli alberi. Si fa notare che CDBP è un caso speciale polinomiale con w(v) = 1 per ogni nodo v.

Le ricerche in corso hanno evidenziato come l'algoritmo per il caso non pesato possa essere facilmente esteso al caso pesato, ottenendo un algoritmo più generale applicabile agli alberi con complessità pseudo-polinomiale.

Segue una tabella riassuntiva dei problemi descritti e relative complessità computazionali.

Problema Complessità

Domatic Bipartition Problem per grafi Polinomiale

Constrained Domatic Bipartition Problem (CDBP) per grafi NP-Hard

Constrained Domatic Bipartition Problem (CDBP) per alberi Polinomiale O(n3)

Weighted Domatic Bipartition Problem per grafi NP-Hard

Weighted Domatic Bipartition Problem per alberi NP-Hard (in senso debole)

Tabella 3: Problemi e relative complessità computazionali

18 di 72 Software CDBP-Algo

5. Software CDBP-Algo

In questo capitolo viene descritto lo scopo e il funzionamento del software CDBP-Algo realizzato per la soluzione del problema della Constrained Domatic Bipartition su alberi e su grafi generici.

5.1. L’algoritmo per gli alberi

Il software CDBP-Algo è stato realizzato in due step: il primo riguarda la parte relativa agli alberi, il secondo usa ripetutamente il codice sviluppato per gli alberi su diversi alberi ricoprenti per cercare le soluzioni su un grafo. È evidente che l’algoritmo per gli alberi, essendo usato come core dell’algoritmo finale, deve essere il più veloce possibile. Si è cercato quindi di porre particolare attenzione all’efficienza dell’algoritmo per gli alberi, effettuando anche test di performance per cercare possibili ottimizzazioni del codice implementato.

Come previsto dal piano di lavoro, il primo step, riguardante gli alberi, è stato essenzialmente un lavoro di porting in C++ dell’algoritmo implementato in Mathematica [3]. L’implementazione di partenza rispecchia fedelmente l’ordine di istruzioni dell’algoritmo descritto in [1], anche se presenta alcune funzioni e dettagli implementativi propri del linguaggio Mathematica. Si è cercato quindi di creare delle funzioni di supporto per cercare di rendere più simile possibile le due implementazioni, al fine di agevolare il debug e la comprensione dello stesso algoritmo.

Il software accetta gli stessi parametri in input della controparte in Mathematica:

printLevel: si tratta di un flag che indica quale livello di log si desidera. Si rivela utile per il debug del codice o per comprendere il procedimento effettuato.

N: si tratta di un intero che indica la cardinalità dell’insieme dei nodi dell’albero.

tree: si tratta di un insieme di archi di dimensione N-1, composti a loro volta di coppie di nodi padre e figlio la cui unione costituisce l’albero specificato.

Il software permette anche la generazione casuale dell’albero data la cardinalità, in modo da poter testare performance su alberi di grande dimensione senza dover immettere manualmente tutti gli archi.

L’implementazione si compone delle seguenti 5 fasi sequenziali:

19 di 72 Software CDBP-Algo

1. Impostazione struttura dati: a partire dai dati in input, il software crea strutture di supporto alla risoluzione, come le mappature padre-figlio, l’insieme di foglie, quali nodi sono già stati visitati, ma anche gli insiemi K, K+, K-, S, S+ ed S-, come previsto dall’algoritmo teorico.

2. Inizializzazione: in questa fase vengono determinati i valori degli insiemi per tutti i nodi foglia, che verranno usati come base per il calcolo degli insiemi associati agli altri nodi.

3. Ciclo principale: l’algoritmo qui entra in un ciclo che termina solo quando tutti i nodi sono stati esaminati, analizzando in ordine i nodi i cui figli sono già stati visitati. Un ciclo corrisponde quindi all’esame di un singolo nodo, guardando le combinazioni di possibili valori k-ammissibili tra il nodo stesso e il primo figlio, poi il nodo e tutti i figli, e infine il nodo e il padre.

4. Step finale: in questa fase vengono composte le soluzioni per l’albero complessivo, selezionate tra le soluzioni del nodo radice nei due colori nero e bianco.

5. Rivelazione soluzioni: in questa ultima fase vengono unite le soluzioni trovate e calcolare le soluzioni complementari, dal momento che l’algoritmo trova le soluzioni

1 ≤ p ≤ ⎿n/2⏌

Alla fine dell’esecuzione dell’algoritmo si ottengono quindi tutte le soluzioni trovate con i relativi insiemi di nodi da colorare di nero per ottenere la bipartizione.

5.2. L’algoritmo per i grafi

Se si volesse risolvere il problema CDBP per un grafo generico l’algoritmo per gli alberi non sarebbe più adatto. Lo scopo di questo progetto è infatti sviluppare un algoritmo che trovi una CDBP anche per grafi generici.

L’osservazione di base è che una soluzione trovata su un albero ricoprente di una grafo è anche una soluzione per il grafo, si può quindi cercare di risolvere il problema iterando la risoluzione di diversi alberi ricoprenti del grafo, fino a trovare una soluzione con la cardinalità richiesta. L’algoritmo completo prevede l’utilizzo dell’algoritmo per gli alberi come core, applicandolo ciclicamente ad alberi diversi.

Il software sviluppato per grafi generici prevede i seguenti parametri in input:

printLevel: si tratta di un flag che indica quale livello di log si desidera. Si rivela utile per il debug del codice o per comprendere il procedimento effettuato.

20 di 72 Software CDBP-Algo

N: in questo casa si tratta della cardinalità dell’insieme dei nodi del grafo.

graph: si tratta di un insieme di archi di dimensione N-1, composti a loro volta di coppie di nodi padre e figlio, la cui unione costituisce il grafo voluto. Notare che in questo caso sono permessi cicli.

p: come nell’algoritmo teorico, indica la cardinalità di uno degli insiemi della bipartizione.

Lo schema dell’algoritmo viene descritto dal seguente diagramma di attività:

Figura 5: Diagramma di attività dell'algoritmo per grafi

21 di 72 Software CDBP-Algo

Le fasi principali sono:

1. Impostazione struttura dati: qui viene generata una mappatura dei link del grafo e la relativa matrice di adiacenza per agevolare l’esecuzione dell’algoritmo.

2. Impostazione albero di partenza: qui viene generato un primo albero ricoprente del grafo, secondo una tecnica a scelta.

3. Ciclo principale: consiste nell’iterare la risoluzione degli alberi ricoprenti, cambiando di volta in volta l’albero fino a quando si trova la soluzione prefissata oppure si raggiunge un numero massimo di tentativi impostato.

4. Rivelazione soluzione: in questo ultimo passo vengono unite tutte le soluzioni trovate, e mostrato l’insieme di nodi neri della bipartizione richiesta se questa viene trovata.

Si fa notare che data la complessità NP-Hard del problema, all’algoritmo viene imposto un limite massimo di iterazioni, ovvero di cambi di albero ricoprente. Questo comporta che si potrebbe arrivare alla fine dell’esecuzione dell’algoritmo senza trovare la cardinalità richiesta tra le soluzioni trovate dagli alberi esaminati, anche se in realtà tale soluzione esiste.

5.3. Euristiche

Dal momento che gli alberi ricoprenti sono in numero esponenziale, appare evidente che la parte critica dell’algoritmo sta nello scegliere opportunamente gli alberi ricoprenti: diversi tipi di configurazioni di alberi ricoprenti corrispondono a insiemi di soluzioni diverse. Si deve cercare quindi un modo per generare gli alberi che sia adatto al tipo di soluzione che vogliamo.

A tal scopo è necessario implementare delle tecniche euristiche che partendo da delle osservazioni sui dati in ingresso, cerchino di far convergere le soluzioni ottenute verso quella richiesta. Euristiche migliori comportano un numero di iterazioni minore per arrivare alla soluzione, oppure in caso di grafi molto grandi, alcune euristiche riescono ad arrivare velocemente alla soluzione, altre invece richiederebbero troppe iterazioni per risolvere il problema, e quindi un eccessivo tempo di calcolo.

Nel caso del software CDBP-Algo ci sono due punti di applicazione delle euristiche: la selezione del primo albero ricoprente e il cambio di albero ad ogni iterazione. Appare evidente che partire già con un albero configurato in modo da ottenere molte soluzioni o soluzioni vicine a quella prefissata permette di risparmiare iterazioni.

Sono state sviluppate tre tipi di euristiche descritte nelle successive sezioni, che, per brevità, verranno riferite coi nomi A, B e C. La Tabella 4 chiarisce l’associazione tra il tipo di euristica e la relativa lettera.

22 di 72 Software CDBP-Algo

Tipo euristica Descrizione

A I nodi vengono selezionati in modo casuale

B Vengono selezionati per primi i nodi di indice minore

C Vengono selezionati per primi i nodi collegati al maggior numeri di nodi di grado minore

Tabella 4: Tipi di euristica sviluppati

Di seguito verrà fatto riferimento alla Figura 6 per aiutare la comprensione dei procedimenti.

Figura 6: Esempio di grafo

5.3.1. Tipo A

Il primo tipo di euristica consiste nel generare in modo casuale gli alberi. Lo schema dell’algoritmo è molto semplice e viene descritto in seguito:

1. Scelta radice: seleziona un nodo casuale come radice dell’albero e nodo corrente.

2. Aggiunta figlio: viene connesso il nodo corrente con uno scelto a caso tra quelli connessi non già selezionati.

3. Cambio nodo corrente: se il figlio selezionato al passo 2 possiede almeno un nodo collegato ad esso non già selezionato, viene impostato come nodo corrente. Altrimenti si risale la gerarchia fino a trovare un nodo che abbia almeno un figlio selezionabile.

23 di 72 Software CDBP-Algo

4. Controllo dimensione: se l’albero ha tutti i nodi connessi, l’algoritmo termina, altrimenti torna al passo 2.

Un esempio di esecuzione relativo alla Figura 6 è il seguente:

Seleziona il nodo 1 come radice. Unisce il nodo 1 al nodo 2 (scelto a caso) e imposta 2 come nodo corrente. Unisce il nodo 2 al nodo 4 e imposta 4 come nodo corrente. Unisce il nodo 4 al nodo 5 e imposta 4 come nodo corrente. Unisce il nodo 5 al nodo 3 e non al nodo 1 perché 1 è già selezionato e termina perché tutti i nodi sono stati selezionati

Il risultato è raffigurato nella Figura 7:

Figura 7: Risultato euristica A

Una particolarità di questo schema è che tende a generare alberi molto profondi e poco larghi, ovvero tende a creare cammini mediamente più lunghi tra i nodi rispetto ad altre euristiche. Questo è dovuto al fatto che una volta selezionato un nodo, si va a scegliere il successivo tra i suoi figli, aumentando così la profondità dell’albero. Di fatto questo si traduce in valori di p più alti, quindi anche se molto veloce come algoritmo, non è adatto a cercare valori estremi di p.

Data la natura casuale della generazione degli alberi, questo tipo di euristica piò essere utilizzato sia per la generazione del primo albero, che come strategia di cambio albero.

24 di 72 Software CDBP-Algo

5.3.2. Tipo B

Il secondo tipo di euristica consiste nel generare gli alberi connettendo per primi i nodi di indice minore. Lo schema dell’algoritmo è abbastanza semplice e viene descritto in seguito:

1. Seleziona il nodo di indice minore come radice e nodo corrente.

2. Connetti al nodo corrente tutti i nodi a lui connesso non già selezionati.

3. Finché tutti i nodi non sono stati selezionati, cambia nodo impostandolo come corrente scegliendo il nodo di indice successivo. Torna al passo 2.

Un esempio di esecuzione relativo alla Figura 6 è il seguente:

Seleziona il nodo 1 (nodo di indice inferiore) come radice. Unisce il nodo 1 al nodo 2 (nodo di indice inferiore non selezionato). Unisce il nodo 1 al nodo 3. Unisce il nodo 1 al nodo 5. Imposta il nodo 2 come nodo corrente perché è il nodo successivo all’1. Unisce il nodo 2 al nodo 4. Termina perché tutti i nodi sono stati selezionati.

Il risultato è raffigurato nella Figura 8:

Figura 8: Risultato euristica B

Questo schema a differenza di quello casuale, tende a generare alberi abbastanza equilibrati tra profondità e larghezza. L’algoritmo infatti tende a creare un buon numero di stelle connesse tra loro in un percorso. Nell’esempio di esecuzione le stelle sono i nodi 1 e 2.

25 di 72 Software CDBP-Algo

Di fatto questo si traduce in valori di p abbastanza equilibrati, quindi si ottengono buoni risultati, sufficiente eterogenei, con un algoritmo piuttosto semplice.

Questo tipo di euristica però mancando di elementi casuali, genera lo stesso tipo di albero ad ogni esecuzione, per cui è adatta solo come generazione del primo albero e non per il cambio albero. Si può ovviare a questo problema inserendo una componente casuale in selezione dei nodi, in modo da ridurre la probabilità di avere due alberi uguali dopo due esecuzioni della stessa euristica.

Introduciamo quindi un parametro a questa euristica che chiamiamo probabilità, che consiste nella percentuale di possibilità di scegliere un figlio di un nodo. In questo modo, tanto più bassa è la probabilità, tanto meno probabile sarà scegliere un figlio di un nodo e tanto meno probabile sarà ottenere due alberi uguali da due esecuzioni diverse. Chiaramente il caso senza il parametro di probabilità è equivalente a probabilità = 100%.

Un esempio di esecuzione con probabilità = 80% può essere la seguente:

Seleziona il nodo 1 (nodo di indice inferiore) come radice. Unisce il nodo 1 al nodo 2 (nodo di indice inferiore non selezionato) perché si genera un numero casuale che rientra nel 80%. NON unisce il nodo 1 al nodo 3 perché si genera un numero casuale che NON rientra nel 80%. Unisce il nodo 1 al nodo 5 perché si genera un numero casuale che rientra nel 80%. Imposta il nodo 2 come nodo corrente perché è il nodo successivo all’1. Unisce il nodo 2 al nodo 4 perché si genera un numero casuale che rientra nel 80%. Imposta il nodo 3 come nodo corrente perché è il nodo successivo all’2. Unisce il nodo 3 al nodo 5 perché si genera un numero casuale che rientra nel 80%. Termina perché tutti i nodi sono stati selezionati.

Il risultato è raffigurato nella Figura 9:

Figura 9: Risultato euristica B - 80%

26 di 72 Software CDBP-Algo

Con questa variazione si può provare a iterare questa euristica andando a generare alberi diversi, fissando un numero massimo di iterazioni.

5.3.3. Tipo C

Il terzo tipo di euristica consiste nel generare gli alberi connettendo per primi i nodi aventi il massimo numero di nodi di grado minore. In questo modo si vanno a collegare per primi i nodi che hanno meno probabilità di essere collegati (grado minore = meno collegamenti con altri nodi), e si vanno a creare poche grandi strutture a stella.

Il problema più grande di questa euristica sta nel modo in cui un nodo dovrebbe essere scelto a scapito di un altro. Bisogna infatti cerca di:

Massimizzare il numero di nodi a loro connessi Minimizzare il grado dei nodi connessi

Bisogna cercare un modo quindi di assegnare un “peso” ai nodi, ovvero un valore che indichi se un nodo è migliore o meno di un altro. Sono state effettuate diverse prove con diverse formule di calcolo del peso, e quella più efficace si è rivelata essere la seguente:

Dove v indica il nodo in esame, s(v) indica l’insieme di nodi adiacenti al nodo v, e d(i) indica il grado del nodo i.

Il risultato di quella formula dunque aumenta se il nodo in esame possiede tanti nodi adiacenti, ma cresce più velocemente se i nodi adiacenti hanno grado basso.

Prendendo il grafo in Figura 6:

Il nodo 1 avrà peso 1000/(23) + 1000/(23) + 1000/(33) = 287 Il nodo 2 avrà peso 1000/(23) + 1000/(33) = 162 Il nodo 3 avrà peso 1000/(33) + 1000/(33) = 74 Il nodo 4 avrà peso 1000/(23) + 1000/(33) = 162 Il nodo 5 avrà peso 1000/(33) + 1000/(23) + 1000/(23) = 287

Si nota che per questa euristica il nodo meno adatto a fare da centro di una stella è il nodo 3, avente il peso minore, mentre i più adatti sono il nodo 1 e il nodo 5.

Il calcolo del peso deve tener conto solo dei nodi collegabili, quindi se alcuni nodi adiacenti sono già stati selezionati, questi non devono apparire nella formula del peso, per non falsificare il peso totale con nodi non raggiungibili.

27 di 72 Software CDBP-Algo

Lo schema dell’algoritmo è quindi il seguente:

1. Seleziona il nodo avente peso maggiore tra tutti i nodi, impostalo come radice e nodo corrente.

2. Connetti al nodo corrente tutti i nodi adiacenti non già selezionati.

3. Finché tutti i nodi non sono selezionati, cerca il figlio del nodo corrente avente peso maggiore, non considerando i nodi già selezionati. Se non esistono nodi figli, risali la gerarchia.

4. Imposta il nodo trovato come nodo corrente, e torna al passo 2.

Una possibile esecuzione di questa euristica è quindi la seguente:

Seleziona il nodo 5 (oppure il 1) come radice e come centro della stella perché possiede il maggior peso tra gli altri nodi. Connetti al nodo 5 tutti i nodi adiacenti ad esso, quindi al 1, 3 e 4. Seleziona il nodo 1 (oppure il 4) come centro della stella perché possiede il maggior peso (in egual misura a 4, essendo il nodo 2 l’unico non ancora non selezionato) Connetti il nodo 1 al nodo 2. Termina perché tutti i nodi sono stati selezionati

Il risultato è raffigurato nella Figura 10:

Figura 10: Risultato euristica C

Questa euristica cerca quindi di generare poche stelle ma di alto grado, risultando quindi in alberi poco profondi e molto larghi. Nell’esempio di esecuzione le stelle sono i nodi 5 e 1. Di fatto questo si traduce in valori di p molto eterogenei, spaziando dai valori più bassi ai valori

28 di 72 Software CDBP-Algo

più alti. Può risultare utile quindi se ci cercano dei valori “estremi” ovvero vicini ai valori limite per la cardinalità della bipartizione.

Inoltre questa euristica, come quella di tipo B, manca di elementi casuali, per cui genera lo stesso tipo di albero ad ogni esecuzione, risultando adatta solo come generazione del primo albero e non per il cambio albero. Si può ovviare a questo problema inserendo una componente casuale in selezione dei nodi, in modo da ridurre la probabilità di avere due alberi uguali dopo due esecuzioni della stessa euristica.

Introducendo lo stesso parametro probabilità, come nell’euristica B, abbiamo una percentuale di possibilità di scegliere un nodo migliore di un altro come centro della stella. In questo modo le stelle dell’albero che ne determinano la forma, vengono scelte in modo casuale, con una probabilità indicata nel parametro. Come prima, il caso senza il parametro di probabilità è equivalente a probabilità = 100%.

Un esempio di esecuzione con probabilità = 50% può essere la seguente:

Seleziona il nodo 4 come radice e come centro della stella perché è tra quelli di peso maggiore e rientra dell’50% di probabilità di essere scelto, mentre i nodi 1 e 5 non rientrano nel 50%. Connetti al nodo 4 tutti i nodi adiacenti ad esso, quindi al 2 e 5. Seleziona il nodo 5 come centro della stella perché possiede il maggior peso tra i nodi figli di 4 (5 e 2) e rientra nel 50% di probabilità. Connetti il nodo 5 al nodo 1 e 3. Termina perché tutti i nodi sono stati selezionati

Il risultato è raffigurato nella Figura 11:

Figura 11: Risultato euristica C- 50%

Con questa variazione si può provare a iterare questa euristica andando a generare alberi fino a quando se ne trova uno non già generato, fissando un numero massimo di iterazioni.

29 di 72 Software CDBP-Algo

5.4. Il caso pesato

Il problema CDBP pesato prevede dei pesi sui nodi del grafo e la soluzione consiste nel trovare una bipartizione domatica in cui la somma dei pesi dei nodi colorati di nero (o bianco) sia uguale a un certo valore p fissato.

Le ricerche in corso hanno evidenziato come l'algoritmo proposto per gli alberi possa essere adattato abbastanza facilmente al caso del CDBP pesato, sempre su alberi. L’osservazione di base è che il caso non pesato equivale al caso pesato con tutti pesi pari a 1.

Il nuovo algoritmo deve tenere conto quindi non solo delle combinazioni di nodi da colorare o meno, ma delle combinazioni di somme di pesi che si vanno a generare colorando un nodo o meno. Di conseguenza l’algoritmo deve cercare tutte le combinazioni

1 ≤ p ≤ ⎿totalWeight/2⏌ dove totalWeight è la somma di tutti i pesi del grafo.

Le modifiche effettuate all’algoritmo per gli alberi sono le seguenti:

Impostazione struttura dati: Gli insiemi S, S+ ed S- sono stati ridimensionati per permettere il salvataggio di tutti i valori 1 ≤ p ≤ ⎿totalWeight/2⏌. Inoltre è stata predisposta una mappatura che dato un nodo restituisca il relativo peso.

Inizializzazione: i valori di default delle foglie nel caso di nodo colorato ora tengono conto del peso del relativo nodo al posto del valore di default 1.

Ciclo principale: l’ordine di esecuzione rimane invariato, le modifiche attuate si applicano al calcolo delle combinazioni di valori k-ammissibili. Quando si calcolano le combinazioni di k-ammissibili, se si aggiunge un nodo da colorare, si considera il peso del nodo invece che del valore di default 1. Come per i valori p, i k-ammissibili devono soddisfare 1 ≤ k ≤ ⎿totalWeight/2⏌.

Rivelazione soluzioni: le soluzioni complementari calcolate tengono conto della somma di pesi del grafo invece che del numero di nodi.

Una volta riadattata la parte degli alberi, l’algoritmo per i grafi non ha richiesto modifiche, perché si limita ad usare l’algoritmo per gli alberi come una funzione che restituisce tutti i valori p-ammissibili. Nemmeno le euristiche hanno richiesto modifiche perché si limitano a costruire alberi secondo certe caratteristiche degli archi, e non considerano il peso dei nodi.

30 di 72 Progettazione e codifica

6. Progettazione e codifica

In questo capitolo vengono tratte le tematiche riguardanti la progettazione e la codifica dei moduli del software CDBP-Algo.

6.1. Vincoli di sviluppo

Il vincolo principale da tener presente per lo sviluppo dei moduli è che devono produrre un software più veloce possibile. Per questo si è scelto di usare C++, che essendo un linguaggio compilato ed ottimizzato garantisce un miglior livello di performance rispetto a linguaggi interpretati come Java. Si fa notare che trattandosi di programmazione procedurale, il software usa essenzialmente i costrutti del linguaggio C, evitando l’overhead causato dall’uso di classi e oggetti definiti dal programmatore disponibili in C++, tipici della programmazione ad oggetti. Vengono comunque usati alcuni costrutti e oggetti esclusivi del C++ per semplificare e rendere più comprensibile il codice, come ad esempio le operazioni di input e output, oppure le strutture dati vector, map e set della libreria standard del linguaggio.

Inoltre per l’algoritmo degli alberi, trattandosi di un porting da un’implementazione già esistente nel linguaggio Mathematica [3], si è cercato di mantenere lo stesso ordine di istruzioni e modalità di stampa dei log per semplificare le attività di debug controllando i risultati delle esecuzioni dei due software.

Infine si è scelto di scrivere tutto il codice, commenti compresi, in inglese, al fine di internazionalizzare il software, che dovrà essere reso disponibile sul web a un'utenza internazionale.

6.2. Progettazione dei moduli

Vista la struttura iterativa dell’algoritmo per i grafi, si è cercato di mantenere separata l’implementazione dei due algoritmi, trattando l’algoritmo per gli alberi come una funzione di libreria da utilizzare passandogli i parametri necessari, che ritorna la soluzione trovata, senza interferenze dall’esterno. Le sezioni successive chiariscono le scelte progettuali per entrambi gli algoritmi, e per l’implementazione del modello di programmazione lineare intera in AMPL.

31 di 72 Progettazione e codifica

6.2.1. Algoritmo per gli alberi

Per quanto riguarda l’algoritmo per gli alberi, trattandosi di un porting di codice già esistente, si è cercato di mantenere la medesima struttura, sia per rendere più immediata la comprensione del codice che per agevolare le attività di debug.

Il codice in Mathematica è già suddiviso in procedure, che in buona parte coincidono con la suddivisione logica in procedure dell’algoritmo descritto in [1]. Si è deciso quindi di mantenere la stessa suddivisione, che consiste essenzialmente in:

SetDataStructure(): questo modulo si occupa di allocare e inizializzare le strutture dati di supporto all’esecuzione. Inizialize(): questo modulo si occupa di impostare i valori di default delle foglie dell’albero. Step0(): questo modulo si occupa di scegliere il prossimo nodo da esaminare. Step1(): questo modulo si occupa di analizzare le combinazioni k-ammissibili tra il nodo e il primo figlio Step2(): questo modulo si occupa di analizzare le combinazioni k-ammissibili tra il nodo e i primi l figli. Step3(): questo modulo si occupa di analizzare le combinazioni k-ammissibili della radice FinalStep(): questo modulo si occupa di esaminare le combinazioni complessive dell’albero unendo quelle della radice. CollectSolution(): questo modulo calcola tutte le soluzioni ammissibili, tenendo conto delle soluzioni complementari.

32 di 72 Progettazione e codifica

Segue un diagramma di attività che chiarisce graficamente le relazioni tra i moduli.

Figura 12: Architettura algoritmo per gli alberi

33 di 72 Progettazione e codifica

Tutte le struttura dati necessarie all’algoritmo vengono gestite dal modulo DataStructure. L’ordine di esecuzione dell’algoritmo complessivo è gestito dal modulo CDBPTree, mentre il modulo TreeCore gestisce l’ordine della MainIteration.

Per quanto riguarda funzioni di supporto e funzioni proprie del linguaggio Mathematica, se particolarmente complesse in termini di codice sorgente, sono implementate in un apposito modulo, chiamato TreeUtils. In particolare in questo modulo sono contenute le operazioni di stampa degli insiemi, le procedure di generazione di elementi casuali, e l’operazione di somma di insiemi con vincolo di valore massimo, corrispondente all’operazione setsum dell’algoritmo in [1].

6.2.2. Algoritmo per i grafi

Lo schema generale dell’algoritmo per i grafi era già stato proposto, e costituisce l’idea che sta alla base di tutto il progetto. Il punto focale dello schema è l’iterazione controllata di risoluzione degli alberi ricoprenti di un grafo in input, fino a trovare la soluzione o raggiungere un massimo numero di iterazioni fissato.

L’algoritmo per gli alberi è usato modalità black box, ovvero viene eseguito senza sapere come funziona, semplicemente passandogli l’albero ricoprente in input e ricevendo i valori k- ammissibili in output.

Le parti principali dell’algoritmo sono quindi:

SetGraphStructure(): in questo modulo vengono create e inizializzate le strutture dati di supporto all’algoritmo.

SetStartingTree(): in questo modulo viene generato il primo albero ricoprente del grafo in ingresso sulla base di una tecnica euristica definita dall’utente.

SolveTree(): questo modulo corrisponde all’algoritmo per gli alberi. Qui viene passato l’albero all’algoritmo apposito e vengono ricevuti i relativi valori k-ammissibili.

ChangeTree(): in questo modulo viene cambiato l’albero ricoprente, tenendo conto di quelli già esaminati, secondo una tecnica euristica definita dall’utente.

GetKFounded(): questo modulo si occupa di organizzare e restituire i valori di k trovati durante tutte le iterazioni.

34 di 72 Progettazione e codifica

Segue un diagramma di attività che chiarisce graficamente le relazioni tra i moduli.

Figura 13: Architettura algoritmo per gli alberi

Tutte le struttura dati necessarie all’algoritmo vengono gestite dal modulo GraphData. L’ordine di esecuzione dell’algoritmo complessivo è gestito dal modulo CDBPTree, mentre il modulo GraphCore gestisce la selezione delle tecniche euristiche. Le tecniche euristiche sono implementate nel modulo Strategy, mentre le funzioni supporto sono implementate nel modulo GraphUtils.

35 di 72 Progettazione e codifica

6.3. Codifica

L’attività di codifica è coincisa nella pratica con l’implementazione dei moduli progettati in C++. L’ambiente di sviluppo Visual Studio ha favorito questa attività, grazie all’analisi statica integrata del codice, e del potente strumento di debug offerto. Esso permette di eseguire passo dopo passo il codice visualizzando dinamicamente il contenuto delle variabili, inserendo dei breakpoint in prossimità di istruzioni potenzialmente errate, in modo da verificare a fondo l’esecuzione effettiva.

Il codice è stato commentato nei punti chiave o in prossimità di parametri di input o output, al fine di chiarire il comportamento del codice. A volte sono presenti delle sezioni marcate come opzionali, che possono essere commentate e decommentate a piacere, a seconda che si voglia o meno l’esecuzione di tali istruzioni. Si tratta tipicamente di operazioni di stampa, che chiariscono l’esecuzione dell’algoritmo.

Di seguito viene precisata tale attività per ognuno dei tre software prodotti.

6.3.1. Algoritmo per gli alberi

La codifica dell’algoritmo in C++ è stata per certi versi semplice dal momento che si aveva già l’ordine di istruzioni di codice da seguire, ma anche difficile a causa dei costrutti e funzioni proprie del linguaggio Mathematica da convertire. È stata necessaria infatti una documentazione approfondita del loro funzionamento tramite l’apposito sito [4].

Per quanto riguarda la struttura dati, sono stati utilizzati in gran parte i vector, oggetti della libreria standard C++, che incapsulano un array rendendo disponibili alcune operazioni aggiuntive su di esso e semplificandone l’utilizzo. Sono stati utilizzati spesso anche vector multidimensionali, in particolare per il salvataggio degli insiemi K, K+, K-, S, S+ ed S-, in cui serve avere un insieme di interi per ogni nodo, per ogni combinazione di colore padre-figlio dove prevista, e per ogni valore k-ammissibile nel caso degli insiemi S, S+ ed S-.

Dal momento che è richiesta un’alta velocità di accesso ai membri delle strutture dati, sono stati scelti i vector che permettono l’accesso diretto tramite indicizzazione, a differenza di altre strutture. Le strutture Map e Set sono state comunque utilizzate nei casi in cui la velocità di accesso non è rilevante, mentre sono ben più importanti gli altri benefici ottenuti da queste strutture, come l’unicità dei membri.

È stata posta particolare attenzione nell’implementazione dell’operazione “setsum”, perché si tratta di un operazione ripetuta moltissime volte: un implementazione poco efficiente della stessa avrebbe forti ripercussioni sul tempo computazionale richiesto dal software. Sono stati utilizzati due vector di interi corrispondenti agli insiemi da sommare in modo da avere un

36 di 72 Progettazione e codifica

accesso diretto ai valori. Un altro vector di valori booleani di lunghezza N/2 è stato utilizzato per indicare se la somma era ammissibile o meno; si è scelto ancora il vector per avere efficienza massima in accesso ai valori. Dal momento che le somme dei valori devono essere minori di N/2, si è cercato di ottimizzare questa operazione scartando alcune somme che sicuramente non sono accettabili. Sommando i valori del primo insieme con quelli del secondo sequenzialmente, tramite due cicli annidati, appena si arriva a una somma che non rispetta il vincolo imposto, si sa per certo che le somme con valori superiori a quelli correnti non saranno ammissibili, per cui si può passare direttamente al ciclo successivo.

6.3.2. Algoritmo per i grafi

Anche per l’implementazione dell’algoritmo per i grafi valgono le osservazioni sulla struttura dati dell’algoritmo per gli alberi.

L’input dell’algoritmo consiste essenzialmente nel grafo da risolvere, gli eventuali pesi sui nodi, la cardinalità N dei nodi del grafo, e il valore p, ovvero il vincolo di cardinalità. Tutti i parametri di input sono gestiti nel file Main.cpp, per cui è necessario modificare il codice sorgente di questo file per cambiare i parametri. È stata presa questa scelta per semplificare enormemente le operazioni di input dei dati agevolando l’utente nella scrittura degli stessi, a fronte della richiesta di compilazione ad ogni modifica di input.

Inoltre sono presenti diversi livelli di log, che permettono di visualizzare con più o meno dettaglio che passi sta eseguendo l’algoritmo. È stata predisposta anche una procedura di generazione automatica del file CDBP.dat contenente i dati già formattati correttamente del grafo attualmente in risoluzione, al fine di confrontare agevolmente i risultati col modello in AMPL. Tale procedura è opzionale e può essere abilitata o disabilitata.

Una descrizione approfondita di tutti i parametri è presente nel manuale d’uso in appendice.

È stato realizzato inoltre un secondo file Main, denominato BenchmarkMain.cpp, che contiene le istruzioni necessarie a:

generare vari tipi di grafo e i relativi file .dat da passare in input ad AMPL;

leggere in input i grafi dai file .dat risolti da AMPL con il relativo numero di soluzioni trovate dal modello;

testare la risoluzione dei grafi letti in input tramite le varie euristiche;

stampare a video e su file (benchmark.txt) i risultati dei test.

37 di 72 Progettazione e codifica

6.3.3. Modello in AMPL

Il modello di programmazione lineare intera è stato implementato in AMPL, per avere un metodo esatto con cui confrontare i risultati ottenuti dal software CDBP-Algo realizzato. Come previsto dalla prassi di AMPL, il codice è stato suddiviso in tre file:

CDBP.mod: questo file contiene il modello vero e proprio, ovvero la definizione degli insiemi e parametri del problema, le variabili in gioco, i vincoli sulle variabili e i domini.

CDBP.dat: questo file contiene i dati di input del problema, dichiarati nel modello. Per effettuare i test, è stato generato un file di questo tipo per ogni tipologia di grafo, variando il numero di nodi e la densità degli archi.

CDBP.run: questo file serve ad automatizzare l’esecuzione, impostando i dati dal file .dat al modello, avviando l’esecuzione e mostrando i dati in output. Si tratta quindi del file che si deve eseguire per avviare la risoluzione.

Si fa notare che è stato implementato il modello tenendo conto anche del caso pesato, quindi nel file CDBP.dat è possibile inserire in input l’insieme di pesi corrispondenti ai nodi del grafo. In caso non si volesse il caso pesato, si possono inserire tutti i pesi pari a 1 per avere una risoluzione per il caso non pesato.

Per effettuare i test prestazionali, il file CDBP.run è stato integrato successivamente con uno script che avvia iterativamente la risoluzione del modello per tutti i valori possibili di p. È possibile inoltre specificare un insieme di grafi diversi in input tramite più file .dat, avviando la risoluzione per ognuno di essi.

38 di 72 Verifica e Test

7. Verifica e Test

In questo capitolo vengono esposti i test eseguiti e i risultati finali.

7.1. Ambiente di test

Tutti i test sono stati eseguiti nel medesimo ambiente di lavoro. In particolare è stato utilizzato:

Processore Intel i5 2500k, 3,30 GHz, Quad Core.

RAM 8 GB.

Sistema operativo Windows 10 Pro 64bit.

Compilatore GCC della suite MinGW con flag -std=c++11.

7.2. Piano dei test

Per la verifica e la validazione dei moduli sviluppati, è stato previsto il seguente piano dei test:

1. Test di unità sui nuovi moduli implementati.

2. Test di integrazione tra i nuovi moduli ed il software esistente.

3. Test di sistema.

4. Collaudo prestazionale.

5. Benchmark standard.

39 di 72 Verifica e Test

7.3. Test di unità

Dopo una iniziale fase di Walkthrough del codice (lettura critica ad ampio spettro, senza l’assunzione di presupposti), ci si è focalizzati sul test di unità dei moduli.

Per l’esecuzione dei test di unità ci si è avvalsi del framework “C++ Unit Test” (Microsoft.VisualStudio.TestTools.CppUnitTestFramework) di Visual Studio 2013. Questi test hanno permesso di identificare e risolvere alcuni problemi presenti nei moduli inizialmente sviluppati che avrebbero portato un sostanzioso dispendio di tempo nel cercare l’errore successivamente.

7.4. Test di integrazione

Terminata la fase dei test di unità, sono stati eseguiti i test di integrazione dei moduli sviluppati con il codice preesistente. Anche in questo caso ci si è avvalsi dello strumento “C++ Unit Test” di Visual Studio 2013: il test si è svolto a coppie, verificando inizialmente il corretto funzionamento di due moduli per volta, ed integrando via via i restanti moduli. Non sono stati rilevati problemi.

7.5. Test di sistema

I test di sistema si sono svolti in due modalità:

1. La prima fase si è svolta secondo la modalità white box, che prevede la conoscenza diretta del software. Per questa fase, il codice prodotto è stato arricchito di istruzioni di controllo a run-time che facilitassero la scoperta di eventuali errori, ed in particolare è stato controllato che non si accedesse a indici non validi di array per evitare eccezioni.

2. La seconda fase invece è stata effettuata con la tecnica black box, e cioè è stato eseguito il software su istanze conosciute, valutando che le soluzioni trovate coincidessero. Dal momento che parte fondamentale del codice sta nella logica di esecuzione, questa fase ha assicurato che il software fornisse soluzioni esatte rispetto a soluzioni note, calcolate manualmente oppure tramite confronto con il modello di programmazione lineare in AMPL.

40 di 72 Verifica e Test

I test hanno confermato la correttezza logica dell’algoritmo, evidenziando invece problemi di natura implementativa, tra cui il fallimento di generazione di numeri casuali, problema che è stato risolto tramite una versione migliore con le librerie standard C++.

7.6. Collaudo prestazionale

Una volta verificato che i risultati del software fossero quelli attesi, si è proceduto con i test prestazionali. Questi test valutano sia l’efficacia delle euristiche proposte in termini di soluzioni trovate, che l’efficienza in termini di tempo computazionale richiesto.

Per avere una stima della bontà dell’algoritmo sviluppato, si sono confrontati i risultati ottenuti con quelli forniti dal modello di programmazione lineare intera implementato in AMPL. Per fare ciò, è stato creato uno script che avvia la risoluzione del modello iterativamente per tutti i valori p possibili, ovvero da 1 a N-1, dove N è il numero di nodi del grafo. Il caso p = N non è considerato perché implicherebbe di dover aver tutti i nodi colorati di nero, il che non è possibile dal momento che c’è bisogno di almeno un nodo bianco per avere una bipartizione.

Provando ad eseguire lo script su grafi sufficientemente grandi, ci si è resi conto che il modello riesce a risolvere il problema molto velocemente per valori di p ammissibili nella parte centrale dell’intervallo, e per valori di p sufficientemente lontani dagli estremi dell’intervallo. Per valori di p vicini agli estremi dell’intervallo invece il modello può impiegare molto tempo per fornire la risposta, che sia affermativa o negativa. Per grafi sufficientemente grandi, ciò può portare all’impossibilità di sapere se la soluzione è ammissibile o meno. La Figura 14 chiarisce graficamente l’andamento del tempo di esecuzione richiesto per i valori di p.

41 di 72 Verifica e Test

Figura 14: Grafico p-tempo per risoluzione del modello in AMPL

Le soluzioni con valori di p vicini agli estremi sono quelle più improbabili perché sono possibili con un numero molto piccolo di combinazioni di colorazioni dei nodi. Questo comporta che il modello, cercando di fissare le variabili della funzione obiettivo, abbia meno soluzioni disponibili, e quindi richiede più iterazioni e più tempo di elaborazione.

Per ovviare a questo problema, nei test è stato introdotto un limite di tempo al risolutore del modello: se la soluzione non viene fornita entro un certo tempo stabilito, si considera quel valore di p non ammissibile. In questo modo si garantisce un’esecuzione sufficientemente veloce, perdendo tuttavia la garanzia che la soluzione esista o meno. Si fa notare che lo scopo del test è calcolare il numero di valori p-ammissibili relativi a un certo grafo, che si estendono per tutto l’intervallo centrale di valori indicato in Figura 14, per cui il fatto di trascurare il calcolo di pochi valori vicini agli estremi non è particolarmente rilevante.

Sono stati condotti diversi test per cercare un valore ottimale di limite di tempo, in modo da lasciare tempo sufficiente al risolutore di fornire una risposta. Si è notato che lasciando tempi limite superiori ad 1 secondo, il modello non forniva un maggior numero di soluzioni, per cui si è scelto questo come limite di tempo.

Lo script, implementato nel file CDBP.run, è stato poi migliorato per eseguire il calcolo del numero di p-ammissibili per tutti i grafi generati, iterando sui file .dat presenti.

La procedura di test prestazionali è stata quindi la seguente:

1. Sono stati generati grafi con numero di nodi da 10 a 80, e densità degli archi 25%, 50% e 75%, per un totale di 24 tipi di grafo diversi.

42 di 72 Verifica e Test

2. Sono stati generati 24 file .dat corrispondenti ai grafi del punto precedente, e passati in input al modello in AMPL. 3. Il modello ha risolto tutti i grafi determinando il numero di soluzioni p-ammissibili per ciascuno. 4. Sono stati letti i grafi dai file .dat generati, e il numero di soluzioni per ciascuno fornite da AMPL. 5. Per ogni grafo sono state eseguite tutte le euristiche per determinare un unico albero ricoprente, confrontando i risultati con quelli del modello. 6. Sono state eseguite le euristiche cambiando 10 volte l’albero ricoprente e confrontando i risultati col punto precedente.

Per ogni test sono stati valutati i seguenti parametri:

Numero di soluzioni p-ammissibili trovate rispetto al totale ricavato dal modello in AMPL. Più alta è questa percentuale, maggiore è l’efficacia dell’euristica.

Soluzione minima p-ammissibile, che costituisce il valore estremo dell’insieme dei valori p-ammissibili. Si fa notare che il valore minimo corrisponde anche al valore massimo di questo insieme, perché sono complementari da p = N - p.

Tempi minimo, massimo e medio di esecuzione di ciascuna istanza, calcolati sulla base di 10 prove. Chiaramente più bassi sono i tempi, più efficiente è il modello.

Si precisa che i test sono stati svolti con p=0, volutamente non ammissibile, in modo da non far fermare l’algoritmo anticipatamente per la scoperta di una soluzione ammissibile. Inoltre per questi test non si è considerato il caso pesato, che è evidentemente più complesso sia da testare che da comprendere e che non fa parte degli obiettivi di questo stage.

Si fa notare che i test prestazionali sono stati eseguiti solamente su un grafo per ogni combinazione di numero di nodi e densità. Questi test sono serviti quindi come collaudo, per far emergere eventuali criticità, prima della fase successiva prevista, dove si sarebbero valutati diversi grafi per tipologia secondo benchmark standard. Per mancanza di tempo dovuto alle difficoltà incontrate nell’implementazione dei test non si è riusciti a completare la seconda fase di test. Tuttavia gli script di automazione dei test sono già a buon livello di implementazione, per cui un test completo non sarebbe particolarmente oneroso.

I risultati dei test sono riportati in appendice B del presente documento e sono raggruppati prima per tipo di euristica, poi per probabilità associata all’euristica, e infine per numero di nodi del grafo. Le euristiche eseguite sono indicate dai relativi codici descritti nel manuale in appendice A.2 del presente documento.

43 di 72 Verifica e Test

7.7. Analisi dei risultati

I test sono stati svolti risolvendo i grafi secondo due modalità: prima generando un unico albero ricoprente, e successivamente generando 10 alberi ricoprenti. Si precisa che per ogni euristica, ogni albero ricoprente generato è diverso da quelli già esaminati.

Per quanto riguarda l’esecuzione singola si può osservare che:

L'euristica di tipo A tende a generare alberi con un numero di p-ammissibili quasi costante, indipendentemente dal numero di nodi e dalla densità. Si tratta di un valore vicino al 33%, ovvero un terzo di tutti i valori ammissibili con una sola iterazione. Tuttavia il valore di p minimo trovato non è altrettanto soddisfacente, risultando mediamente più alto, e quindi peggiore, dei risultati ottenuti con le altre euristiche. Per cui il tipo A è adatto a trovare subito un buon numero di soluzioni, che si trovano però nella parte centrale dell'intervallo di soluzioni ammissibili.

L'euristica di tipo B non casuale, ovvero con probabilità pari al 100%, trova un numero di soluzioni fortemente dipendente dalla densità del grafo: a densità minori corrisponde un maggior numero di soluzioni trovate, e viceversa. Anche il valore di p minimo dipende dalla densità: più alta è la densità, minore (e quindi migliore) è il valore minimo di p trovato. Si nota quindi che c'è una sorta di equilibrio tra numero di soluzioni trovate e valore minimo di p, che dipende dalla densità.

L'euristica di tipo B casuale, è stata testata con le probabilità del 50%, 60%, 70%, 80%, e 90% su tutti i grafi. Dai risultati si più notare che valori più bassi di probabilità corrispondono a risultati più bilanciati, indipendentemente dalla densità del grafo: si ottengono un buon numero di soluzioni, che cresce con la dimensione del grafo (dal 40% al 60%) e dei buoni valori di p minimo. Aumentando la probabilità invece ci si avvicina alla situazione del caso precedente.

L'euristica di tipo C non casuale, ovvero con probabilità pari al 100%, risulta essere una versione estremizzata del tipo B non casuale: basse densità corrispondono a moltissime soluzioni trovate (da 45% a 75%) e buoni valori minimi di p, mentre alte densità corrispondono a poche soluzioni trovate (sotto il 10%) ma valori minimi di p migliori di qualsiasi altra euristica. Si tratta quindi dell'euristica migliore per trovare gli estremi dell'intervallo di valori di p.

L'euristica di tipo C casuale è stata testata con le probabilità del 50%, 60%, 70%, 80%, e 90% su tutti i grafi. I risultati ottenuti con questo tipo di euristica sono molto simili alla versione non casuale, per qualunque valore di probabilità. Questo probabilmente è dovuto al fatto che la scelta casuale dei nodi stella avviene sempre tra i nodi con miglior peso, per cui la struttura dell'albero risultante non varia di molto. Si nota comunque un leggero aumento del numero di soluzioni trovate a scapito del valore minimo trovato.

44 di 72 Verifica e Test

Tutte le euristiche si sono rivelate molto performanti per grafi sotto gli 80 nodi, risolvendoli al massimo entro 20 millisecondi.

Per quanto riguarda la seconda modalità con 10 alberi ricoprenti si può notare che:

L'euristica di tipo A non vede particolari miglioramenti aumentando il numero di alberi esaminati: la percentuale di soluzioni trovate e il valore di p minimo trovato rimangono praticamente inalterate. Probabilmente questo è dovuto alla struttura pressoché uguale degli alberi ricoprenti generati, caratterizzati da una elevata profondità e scarsa larghezza. Questo tipo di euristica non è adatto quindi ad essere iterato perché non si riscontrano particolari benefici.

L'euristica di tipo B non casuale prevede l'esecuzione di una probabilità del 100% la prima volta, e del 90% per le successive per poter trovare alberi ricoprenti diversi. Questa euristica, a differenza della precedente, vede un notevole miglioramento nel numero di soluzioni trovate (tra il 50% e l'80%) e un discreto miglioramento per il valore minimo di p. Si nota anche che il valore di densità per cui l'euristica trova più soluzioni (dal 65% al 85%) è il 50%, mentre con una singola esecuzione era il 25%. Questo tipo di euristica è adatta ad essere iterata, e risulta particolarmente efficace per grafi mediamente connessi.

L'euristica di tipo B casuale vede anch'essa un notevole miglioramento complessivo. Si nota inoltre che percentuali più alte di probabilità portano a soluzioni trovate più numerose a discapito della qualità del valore minimo di p trovato. Si può variare quindi la probabilità scegliendo il bilanciamento della qualità dei risultati trovati.

L'euristica di tipo C non casuale prevede l'esecuzione di una probabilità del 100% la prima volta, e del 80% per le successive. Per questa euristica non si notano particolari miglioramenti iterandola più volte, se non per grafi con densità del 50% per i quali la percentuale di valori p trovati cresce molto. Questa euristica risulta quindi particolarmente efficace per la scoperta di valori estremi di p, mentre per la numerosità delle soluzioni, a meno di grafi poco densi, è preferibile utilizzare l'euristica di tipo B.

L'euristica di tipo C casuale vede un andamento simile alla versione non casuale, per cui valgono le stesse considerazioni. La variazione di probabilità non influisce in modo rilevante sulle soluzioni trovate.

I tempi di esecuzione sono molto simili per tutte le euristiche, risultando direttamente proporzionali al numero di alberi ricoprenti generati. Si tratta di tempi di esecuzione molto buoni: per 10 alberi ricoprenti su un albero di 80 nodi vengono impiegati circa 160 millisecondi.

In conclusione si può quindi ipotizzare che la strategia migliore per massimizzare il numero di p trovati, trovando anche valori estremi, sia una combinazione delle euristiche B e C. In particolare si potrebbe procedere nel seguente modo:

45 di 72 Verifica e Test

1. Eseguire una prima volta l’euristica di tipo C non casuale per trovare valori estremi di p.

2. Eseguire 2-3 volte l’euristica di tipo C casuale per trovare altri valori estremi di p non trovati nella precedente esecuzione.

3. Per i successivi tentativi eseguire l’euristica di tipo B casuale variando la probabilità associata, in modo da avere un insieme di soluzioni più eterogeneo. Un esempio può essere eseguire l’euristica ciclicamente ripetendo i valori di probabilità 50%, 60%, 70%, 80% e 90%.

Questo tipo di euristica non è stato implementato per mancanza di tempo, ma può essere un’idea per un futuro miglioramento dell’algoritmo.

46 di 72 Consuntivo

8. Consuntivo

In questo capitolo viene confrontato quanto eseguito rispetto al preventivato, analizzando le difficoltà rilevate.

8.1. Difficolta rilevate

Vengono elencate di seguito le principali difficoltà rilevate:

L’algoritmo in Mathematica in [3] di cui è stato effettuato il porting in C++ rispecchia fedelmente l’ordine di istruzioni dell’algoritmo descritto in [1], anche se presenta alcune funzioni e dettagli implementativi propri del linguaggio Mathematica. È stata necessaria quindi un’analisi approfondita nella documentazione del linguaggio delle funzioni usate, al fine di comprendere esattamente il funzionamento del codice.

L’automazione dell’esecuzione dei test prestazionali in AMPL è stata più difficile del previsto, a causa dell’inesperienza in scripting in questo linguaggio. Ciò ha richiesto una documentazione aggiuntiva sull’argomento risultando in un numero di ore maggiore rispetto a quanto prefissato.

Il risolutore CPLEX mostra difficoltà a riconoscere l'inammissibilità per alcuni valori di p. Questo è stato scoperto con notevole dispendio di tempo perché in un primo momento di pensava a un errore di implementazione del modello.

Parte della sintassi C/C++ per la suddivisione e integrazione dei file sorgenti non era mai stata utilizzata, richiedendo quindi una documentazione preliminare da [5].

8.2. Consuntivo finale

Le tempistiche preventivate sono state rispettate, ad eccezione della seconda fase, relativa all’implementazione dell’algoritmo per gli alberi. Il codice dell’algoritmo implementato in Mathematica si è rivelato infatti essere più tecnico del previsto, il che ha richiesto diverse ore di analisi aggiuntive non preventivate.

Inoltre sono state necessarie più ore per il l’analisi prestazionale dei risultati delle euristiche a causa della difficoltà incontrate nella procedura di automazione dei test.

47 di 72 Consuntivo

Le altre attività invece sono state tutte grossomodo entro i tempi prefissati, con alcune attività invece che sono state particolarmente veloci e che hanno ammortizzato le ore aggiuntive richieste. In particolare l’attività di studio della letteratura sul problema CDBP si è rivelata molto più veloce, probabilmente a causa di una discussione preliminare con il proponente dello stage che ha chiarito subito molti concetti. Inoltre anche l’integrazione delle euristiche si è rivelata essere più veloce del previsto, a causa dell’esperienza maturata nella codifica.

La seguente tabella riassume la differenza di ore effettive rispetto a quelle preventivate.

Attività Ore prev. Ore. cons. Differenza Analisi dello stato dell'arte

Studio della letteratura di base sul problema CDBP 35 26 -9 Studio dell'algoritmo per CDBP su alberi 20 18 -2 Implementazione dell'algoritmo su alberi

Studio preliminare dell'implementazione in Mathematica 10 15 5 Progettazione dei moduli 15 21 6 Implementazione 35 42 7 Implementazione di un'euristica per CDBP su grafo generico

Studio dei criteri di selezione degli spigoli 5 6 1 Progettazione dei moduli 10 9 -1 Implem. dell'algoritmo per la costruzione guidata di alberi ric. 20 15 -5 Integrazione in un'euristica iterativa per CDBP 35 28 -7 Integrazione di diversi criteri di selezione degli spigoli

Analisi dei criteri alternativi 10 8 -2 Implementazione dei criteri 15 20 5 Confronto con tecniche esatte

Studio dei modelli di letteratura 5 4 -1 Implementazione del modello in AMPL 20 15 -5 Confronto con i risultati dell'euristica e analisi delle prestazioni 20 25 5 Verifica e testing 20 23 3 Produzione di documenti, manuali e relazioni 40 40 0 315 315

Tabella 5: Differenza ore consuntivo-preventivo

48 di 72 Consuntivo

8.3. Raggiungimento degli obiettivi

8.3.1. Requisiti obbligatori

Ob1: Assimilazione dei concetti di base del problema CDBP e dell’algoritmo per alberi.

Requisito soddisfatto grazie allo studio testi riportati in bibliografia, in particolare di [1].

Ob2: Assimilazione dell’implementazione esistente in Mathematica dell’algoritmo per alberi.

Requisito soddisfatto grazie allo studio preliminare dell’algoritmo in [1] e del codice in [3] anche tramite test.

Ob3: Porting dell’algoritmo per alberi in un linguaggio di programmazione.

Requisito soddisfatto come da capitolo 5.1 del presente documento.

Ob4: Assimilazione dei criteri di selezione degli spigoli per la costruzione di opportuni alberi ricoprenti.

Requisito soddisfatto grazie a riunioni con il proponente (prof. De Giovanni).

Ob5: Implementazione dell’algoritmo per la costruzione di alberi ricoprenti.

Requisito soddisfatto come da capitolo 5.2 del presente documento.

Ob6: Integrazione dell’algoritmo per la soluzione di CDBP su alberi e dell’algoritmo di costruzione degli alberi ricoprenti in un’euristica iterativa per la soluzione del problema CDBP su grafo generico.

Requisito soddisfatto come da capitolo 5.2 e 5.3 del presente documento.

Ob7: Produzione di documentazione sui moduli sviluppati.

Requisito soddisfatto in fase di commento del codice.

Ob8: Produzione di un manuale di utilizzo dei moduli sviluppati.

Requisito soddisfatto, si veda in appendice A del presente documento.

49 di 72 Consuntivo

8.3.2. Requisiti desiderabili

De1: Analisi prestazionale dei diversi criteri di selezione su benchmark standard.

Requisito parzialmente soddisfatto come da capitolo 7.7 del presente documento. Al momento sono stati effettuati solo dei test di collaudo per evidenziare eventuali criticità, ma si ricorda che gli strumenti per effettuare i test completi sono già stati implementati.

De2: Studio di ulteriori criteri di selezione per la costruzione degli alberi ricoprenti.

Requisito soddisfatto come da capitolo 5.3 del presente documento.

8.3.3. Requisiti opzionali

Op1: Implementazione con AMPL del modello di programmazione lineare intera per la soluzione esatta del problema CDBP.

Requisito soddisfatto come da capitolo 6.3.3 del presente documento.

Op2: Estensione dell’analisi prestazionale per confronto, dove possibile, con i risultati del modello esatto.

Requisito parzialmente soddisfatto come da capitolo 7.7 del presente documento. Come per De1, si ricorda che gli strumenti per effettuare i test completi sono già stati implementati.

Op3: Implementazione di un algoritmo per la risoluzione di grafi pesati.

Requisito soddisfatto come da capitolo 5.4 del presente documento.

Si fa notare che tutti requisiti sono stati soddisfatti, sia quelli preventivati, sia l'ulteriore requisito Op3 emerso in fase di svolgimento dello stage.

50 di 72 Conclusioni

9. Conclusioni

9.1. Note per possibili sviluppi futuri

Sarebbe stato interessante continuare con lo sviluppo dello stage andando a cercare di migliorare il codice prodotto o le euristiche, o implementare nuove funzionalità. Vengono elencate di seguito delle possibili estensioni o migliorie che potrebbero essere implementate in futuro.

Euristiche che considerino il peso dei nodi: tutte le euristiche prodotte non considerano il peso dei nodi. Sarebbe interessante quindi cercare di capire se esiste una correlazione tra il peso dei nodi e la loro distribuzione nella struttura dell’albero ricoprente.

Fattorizzazione del codice: In diversi punti il codice è ripetitivo, ovvero le istruzioni eseguite sono molto simili, ma non si è trovato un modo efficace di fattorizzarle mantenendo un buon livello di leggibilità. Sarebbe interessante trovare un metodo che le raggruppi e fattorizzi, favorendo la manutenibilità del codice.

Implementazione di euristiche ibride, che prevedano un mix di euristiche per combinare tutti i loro punti di forza in poche iterazioni, arrivando quindi a molte soluzioni trovate con anche valori estremi.

9.2. Conoscenze pregresse e acquisite

Durante l’attività di stage, mi sono trovato a mettere in pratica molte conoscenze acquisite durante il corso di studi. In particolare, mi sono stati utili gli insegnamenti erogati durante il corso di ricerca operativa e matematica discreta, che mi hanno permesso una veloce comprensione del tema affrontato.

Molto importanti sono state anche le conoscenze acquisite durante i corsi di programmazione 1 e 2, per la conoscenza del linguaggio C++, ed il corso di algoritmi e strutture di dati, per l’analisi e la conoscenza degli stessi.

Di fondamentale importanza è stato il corso (ed il relativo progetto) di ingegneria del software, dove ho appreso la metodologia per l’analisi, la progettazione, lo sviluppo, la verifica del software e la gestione di un progetto nelle sue fasi.

51 di 72 Conclusioni

Nel complesso ho acquisito nuove conoscenze soprattutto relativamente a tecniche euristiche ed ottimizzazione combinatoria, ma anche in programmazione dei linguaggi C++, Mathematica ed AMPL.

In particolare ho acquisito competenze di livello avanzato per il linguaggio di modellazione AMPL, soprattutto per le operazioni di scripting e sul funzionamento del risolutore CPLEX. Ho raggiunto una buona padronanza del linguaggio C++, conoscendo nel dettaglio alcuni suoi punti deboli e di forza. Inoltre avendo lavorato con un algoritmo implementato in Mathematica, ho potuto apprendere le basi di questo linguaggio, a me sconosciuto prima dello stage.

Infine il fatto di lavorare ad un progetto che coinvolgesse più discipline, mi ha permesso di dare un senso più completo a ciò che ho studiato in questi tre anni mettendolo in pratica.

9.3. Valutazione personale

La mia valutazione personale delle attività svolte durante questo stage è senz’altro positiva. In particolare, vorrei qui ringraziare il prof. De Giovanni per l’aiuto ed il supporto fornitomi durante tutto il periodo di stage.

Mi ha fatto molto piacere dal punto di vista personale acquisire nuove conoscenze riguardanti le tecniche euristiche. Mi piacerebbe approfondire l’argomento, e integrarlo tramite lo studio di modelli evolutivi o di tecniche di intelligenza artificiale, quali reti neurali.

Inoltre sto valutando la possibilità per i prossimi anni di continuare gli studi con la laurea magistrale di informatica, seguendo appunto il percorso di intelligenza artificiale.

52 di 72 CDBP-Algo: Manuale utente

A. CDBP-Algo: Manuale utente

In questa appendice viene spiegato come poter utilizzare il software CDBP-Algo al fine di agevolare usi e sviluppi futuri.

A.1. Requisiti di sistema

Il software CDBP-Algo non richiede particolari risorse hardware oltre a quelle di un normale PC. Ovviamente hardware più potenti permettono di ottenere tempi di esecuzione più rapidi.

Il software CDBP-Algo può essere compilato ed eseguito su qualunque sistema operativo, assicurandosi che il compilatore GCC (GNU Compiler Collection) sia correttamente installato sul proprio dispositivo insieme alle librerie standard di C/C++.

Dopodiché basta posizionarsi nella cartella con i file del codice ed eseguire il comando:

make

Dopo aver compilato il programma, è sufficiente avviare l’eseguibile prodotto CDBP.exe, sia da linea di comando che tramite interfaccia grafica.

A.2. Parametri in ingresso

Dal momento che il software accetta grafi di qualsiasi dimensione, si è deciso di lasciare l’input direttamente dai file sorgenti, al fine di agevolare la scrittura e correzioni degli stessi. L’input viene gestito nel file Main.cpp, e deve essere inserito nelle sezioni indicate secondo convenzioni ben definite. L’immissione di dati non aspettati o incongruenti può pregiudicare la corretta esecuzione del programma.

Nel file Main.cpp i parametri di default sono inizializzati in alto, circoscritti nella sezione “Default values”. L’input può essere immesso manualmente nella sezione successiva, “Manual input here”.

In particolare possono essere specificati:

53 di 72 CDBP-Algo: Manuale utente

printLevel: si tratta di un flag che indica quale livello di log si desidera. I possibili valori sono:

o 0 = nessuna stampa oltre a quelle strettamente necessarie. È utile in caso di grafi grandi per non rallentare l’esecuzione con le stampe a video dei dettagli. o 1 = stampe dettagliate sulla risoluzione degli alberi. È utile se si vuole sapere in dettaglio come vengono aggiornati i registri K, K+, K-, S, S+ ed S-. o 2 = stampe dettagliate sulla risoluzione del grafo. È utile se si vuole sapere in dettaglio come vengono scelti gli alberi ricoprenti e le soluzioni ottenute. o 3 = stampe complete sia dei grafi che degli alberi. È utile per capire a fondo il procedimento dell’algoritmo.

outputFile: si tratta di un flag che indica se si vuole la generazione del file .dat da utilizzare in AMPL (CDBP.dat) e un file di testo contenente l’albero in forma testuale per poterlo inserire in input all’algoritmo in Mathematica (Mathematica.txt). Entrambi i file vengono creati nella cartella corrente. Può assumere due valori:

o 0 = non viene generato nessun file o 1 = vengono generati entrambi i file

N: si tratta di un intero che indica la cardinalità dell’insieme dei nodi del grafo. In caso di incoerenza con il numero di archi, il programma fallirà l’esecuzione.

p: si tratta di un intero che indica la cardinalità dell’insieme di nodi che si vuole colorare di nero (o bianco) nella bipartizione. Nel caso pesato sarà la somma dei pesi dei nodi.

tries: si tratta di un intero che indica quanti tentativi al massimo si vogliono effettuare per cercare la soluzione prima di fermarsi.

graph: si tratta di un vector di dimensione a piacere di archi, composti a loro volta di un vector di dimensione due contenente i nodi padre e figlio. La sintassi è del tipo: {{padre, figlio}, {padre, figlio}, ….}. In caso di incoerenza con il numero N, il programma fallirà l’esecuzione.

weights: si tratta di un vector di dimensione a piacere contenente i pesi dei nodi indicati in ordine. La sintassi è del tipo: {pesoNodo1, pesoNodo2, …..}. In caso di incoerenza con il numero N, il programma fallirà l’esecuzione.

strategy: si tratta di un vector di dimensione 3 che indica quali strategie euristiche si vogliono eseguire nella scelta degli alberi ricoprenti. È composto da tre valori:

o Il primo è come il primo albero deve essere generato o Il secondo è come si vuole che vengano cambiati gli alberi o Il terzo è un valore intero da 1 a 100 che serve come probabilità per alcuni tipi di euristica

54 di 72 CDBP-Algo: Manuale utente

Il primo può assumere i seguenti valori:

o -1: albero generato casualmente (euristica A) o -2: vengono selezionati per primi i nodi di indice inferiore (euristica B) o -3: vengono selezionati per primi i nodi di indice inferiore con una certa probabilità, specificata dal terzo parametro (euristica B - random) o -4: vengono selezionati i nodi aventi il maggior numero di nodi di grado basso (euristica C) o -5: vengono selezionati i nodi aventi il maggior numero di nodi di grado basso con una certa probabilità, specificata dal terzo parametro (euristica C - random)

Il secondo può assumere i seguenti valori:

o 1: albero generato casualmente (euristica A) o 2: vengono selezionati per primi i nodi di indice inferiore con una certa probabilità, specificata dal terzo parametro (euristica B - random) o 3: vengono selezionati i nodi aventi il maggior numero di nodi di grado basso con una certa probabilità, specificata dal terzo parametro (euristica C - random)

Dopo questa sezione sono presenti inoltre due procedure di stampa opzionali, che è sufficiente decommentare all’occorrenza. La prima, printGraph(graph) stampa a video il grafico in input, la seconda printWeights(weights) stampa a video i pesi del grafo. Sono utili nel caso di generazione casuale del grafo.

A.3. Esecuzioni previste

Il programma può terminare nei seguenti modi:

La soluzione specificata in p viene trovata in una delle iterazioni: vengono stampati i nodi relativi a quella soluzione e la soluzione complementare con n-p (o somma dei pesi – p nel caso pesato). Vengono inoltre mostrati gli altri valori di p trovati durante le iterazioni.

La soluzione specificata in p non viene trovata in nessuna delle iterazioni: vengono mostrate solo le altre soluzioni trovate nelle iterazioni. In questo caso può essere utile o aumentare il numero di iterazioni o cambiare strategia tramite il parametro strategy.

Viene mostrato un messaggio di errore dove si dice che non si riesce a generare un albero ricoprente in un certo numero di tentativi: in questo caso con la strategia selezionata non si riesce a generare un albero ricoprente che non sia già stato esaminato, entro un certo numero di tentativi. Può essere utile cambiare strategia tramite il parametro strategy.

55 di 72 CDBP-Algo: Manuale utente

Il programma resta apparentemente bloccato: per grandi dimensioni dei grafi in input (maggiori di 100), l’algoritmo può rivelarsi molto lento in esecuzione a causa della grande mole di calcoli necessari. Può essere utile l’interruzione del programma (CTRL+C).

Eccezione o arresto anomalo con messaggio di sforamento dei limiti di un vector: è dovuto a dati in ingresso non coerenti. Occorre verificare la dimensione e la correttezza del grafo in input, dei pesi e del numero di nodi.

56 di 72 Risultati dei benchmark

B. Risultati dei benchmark

B.1. Singola esecuzione

Only one spanning tree

First Change Prob. N Density TimeMin TimeMax TimeMed p-Cover p-Min ------1 1 100 10 25 0 1 0.5 30.0% 4 -1 1 100 10 50 0 1 0.8 40.0% 3 -1 1 100 10 75 0 1 0.5 35.0% 3 -1 1 100 20 25 1 2 1.5 35.0% 7 -1 1 100 20 50 1 2 1.8 35.0% 7 -1 1 100 20 75 1 2 1.5 35.0% 7 -1 1 100 30 25 3 3 3.0 31.7% 10 -1 1 100 30 50 2 4 2.8 31.7% 10 -1 1 100 30 75 3 3 3.0 36.7% 10 -1 1 100 40 25 4 5 4.8 32.5% 14 -1 1 100 40 50 5 5 5.0 35.0% 13 -1 1 100 40 75 5 6 5.5 33.8% 13 -1 1 100 50 25 6 8 7.0 34.0% 17 -1 1 100 50 50 7 8 7.5 34.0% 17 -1 1 100 50 75 8 9 8.5 34.0% 17 -1 1 100 60 25 9 10 9.8 34.2% 20 -1 1 100 60 50 10 12 11.0 33.3% 20 -1 1 100 60 75 11 12 11.5 34.2% 20 -1 1 100 70 25 13 15 14.3 34.3% 23 -1 1 100 70 50 14 16 14.8 33.6% 23 -1 1 100 70 75 16 18 16.8 33.6% 23 -1 1 100 80 25 14 17 16.0 33.8% 27 -1 1 100 80 50 15 32 23.5 33.8% 27 -1 1 100 80 75 15 32 19.5 33.8% 27

First Change Prob. N Density TimeMin TimeMax TimeMed p-Cover p-Min ------2 1 100 10 25 0 0 0.0 30.0% 4 -2 1 100 10 50 0 0 0.0 30.0% 2 -2 1 100 10 75 0 0 0.0 20.0% 2 -2 1 100 20 25 0 0 0.0 15.0% 7 -2 1 100 20 50 0 16 4.0 40.0% 5 -2 1 100 20 75 0 0 0.0 20.0% 2 -2 1 100 30 25 0 15 3.8 50.0% 8 -2 1 100 30 50 0 16 4.0 26.7% 5 -2 1 100 30 75 0 15 3.8 40.0% 5

57 di 72 Risultati dei benchmark

-2 1 100 40 25 0 16 4.0 52.5% 10 -2 1 100 40 50 0 16 4.0 57.5% 5 -2 1 100 40 75 0 16 4.0 10.0% 4 -2 1 100 50 25 0 16 7.8 58.0% 11 -2 1 100 50 50 0 16 7.8 74.0% 7 -2 1 100 50 75 0 16 8.0 16.0% 3 -2 1 100 60 25 0 16 11.8 65.0% 11 -2 1 100 60 50 0 16 7.8 26.7% 4 -2 1 100 60 75 0 16 8.0 26.7% 4 -2 1 100 70 25 15 16 15.5 70.0% 11 -2 1 100 70 50 0 16 11.8 28.6% 7 -2 1 100 70 75 0 16 11.8 11.4% 4 -2 1 100 80 25 15 31 19.5 68.8% 13 -2 1 100 80 50 15 16 15.5 15.0% 6 -2 1 100 80 75 15 16 15.8 10.0% 4

First Change Prob. N Density TimeMin TimeMax TimeMed p-Cover p-Min ------3 1 50 10 25 0 0 0.0 32.5% 3 -3 1 50 10 50 0 0 0.0 30.0% 2 -3 1 50 10 75 0 0 0.0 27.5% 2 -3 1 50 20 25 0 0 0.0 30.0% 7 -3 1 50 20 50 0 0 0.0 31.3% 7 -3 1 50 20 75 0 16 4.0 41.3% 3 -3 1 50 30 25 0 15 3.8 36.7% 9 -3 1 50 30 50 0 16 4.0 40.0% 8 -3 1 50 30 75 0 0 0.0 50.8% 7 -3 1 50 40 25 0 16 4.0 43.8% 11 -3 1 50 40 50 0 16 4.0 47.5% 10 -3 1 50 40 75 4 16 8.0 45.6% 7 -3 1 50 50 25 6 7 6.5 41.0% 15 -3 1 50 50 50 7 8 7.3 57.0% 9 -3 1 50 50 75 7 10 8.3 46.0% 6 -3 1 50 60 25 9 10 9.8 45.8% 15 -3 1 50 60 50 0 16 10.3 64.2% 9 -3 1 50 60 75 0 16 11.8 58.3% 7 -3 1 50 70 25 0 16 11.8 52.9% 16 -3 1 50 70 50 0 16 11.5 67.1% 11 -3 1 50 70 75 0 31 15.8 62.5% 8 -3 1 50 80 25 15 16 15.5 54.4% 17 -3 1 50 80 50 15 16 15.5 67.5% 11 -3 1 50 80 75 15 31 19.5 70.0% 8 -3 1 60 10 25 0 0 0.0 30.0% 4 -3 1 60 10 50 0 0 0.0 35.0% 3 -3 1 60 10 75 0 0 0.0 30.0% 3 -3 1 60 20 25 0 0 0.0 30.0% 7 -3 1 60 20 50 0 15 3.8 45.0% 5 -3 1 60 20 75 0 0 0.0 38.8% 3 -3 1 60 30 25 0 16 4.0 38.3% 9 -3 1 60 30 50 3 14 5.8 41.7% 6 -3 1 60 30 75 2 4 3.0 55.8% 5

58 di 72 Risultati dei benchmark

-3 1 60 40 25 4 5 4.3 42.5% 11 -3 1 60 40 50 5 5 5.0 51.3% 6 -3 1 60 40 75 5 6 5.3 43.1% 6 -3 1 60 50 25 6 7 6.8 41.0% 15 -3 1 60 50 50 7 8 7.5 60.0% 9 -3 1 60 50 75 0 8 4.3 34.0% 5 -3 1 60 60 25 0 16 7.8 47.5% 16 -3 1 60 60 50 0 16 11.8 60.4% 8 -3 1 60 60 75 0 16 11.8 62.5% 6 -3 1 60 70 25 0 16 11.8 55.7% 15 -3 1 60 70 50 15 16 15.8 66.4% 8 -3 1 60 70 75 15 16 15.5 46.8% 6 -3 1 60 80 25 15 16 15.8 60.0% 14 -3 1 60 80 50 15 16 15.8 65.3% 9 -3 1 60 80 75 15 31 19.5 51.9% 7 -3 1 70 10 25 0 0 0.0 32.5% 3 -3 1 70 10 50 0 0 0.0 35.0% 2 -3 1 70 10 75 0 15 4.0 40.0% 2 -3 1 70 20 25 1 2 1.5 30.0% 7 -3 1 70 20 50 1 2 1.3 42.5% 5 -3 1 70 20 75 1 2 1.5 31.3% 3 -3 1 70 30 25 2 3 2.8 40.0% 9 -3 1 70 30 50 3 3 3.0 44.2% 5 -3 1 70 30 75 3 3 3.0 35.8% 6 -3 1 70 40 25 4 5 4.3 45.0% 10 -3 1 70 40 50 5 6 5.3 65.0% 7 -3 1 70 40 75 5 6 5.3 44.4% 4 -3 1 70 50 25 6 7 6.5 43.0% 13 -3 1 70 50 50 7 8 7.5 65.0% 8 -3 1 70 50 75 7 8 7.3 23.5% 4 -3 1 70 60 25 9 11 10.0 55.8% 12 -3 1 70 60 50 0 10 7.0 43.3% 7 -3 1 70 60 75 0 16 7.8 40.0% 5 -3 1 70 70 25 0 16 11.8 58.6% 12 -3 1 70 70 50 15 16 15.8 71.1% 9 -3 1 70 70 75 15 16 15.5 32.9% 5 -3 1 70 80 25 15 16 15.8 61.3% 14 -3 1 70 80 50 15 16 15.8 51.3% 7 -3 1 70 80 75 15 31 19.5 41.3% 5 -3 1 80 10 25 0 16 4.0 30.0% 4 -3 1 80 10 50 0 0 0.0 35.0% 2 -3 1 80 10 75 0 0 0.0 30.0% 2 -3 1 80 20 25 0 15 3.8 28.8% 6 -3 1 80 20 50 0 0 0.0 50.0% 5 -3 1 80 20 75 0 16 4.0 20.0% 2 -3 1 80 30 25 0 0 0.0 45.0% 8 -3 1 80 30 50 2 18 6.5 36.7% 6 -3 1 80 30 75 3 4 3.3 58.3% 5 -3 1 80 40 25 4 5 4.3 41.9% 10 -3 1 80 40 50 4 6 5.0 59.4% 6 -3 1 80 40 75 5 5 5.0 27.5% 4

59 di 72 Risultati dei benchmark

-3 1 80 50 25 6 7 6.8 53.0% 11 -3 1 80 50 50 7 8 7.3 55.5% 8 -3 1 80 50 75 0 16 6.8 20.0% 3 -3 1 80 60 25 0 16 7.8 56.7% 13 -3 1 80 60 50 0 16 11.8 58.8% 6 -3 1 80 60 75 0 16 11.8 25.0% 5 -3 1 80 70 25 0 16 11.8 60.0% 13 -3 1 80 70 50 0 16 11.5 71.4% 8 -3 1 80 70 75 0 16 11.8 31.4% 5 -3 1 80 80 25 15 16 15.5 63.1% 15 -3 1 80 80 50 15 31 19.5 40.0% 6 -3 1 80 80 75 15 16 15.8 20.0% 5 -3 1 90 10 25 0 15 3.8 30.0% 4 -3 1 90 10 50 0 0 0.0 35.0% 2 -3 1 90 10 75 0 0 0.0 30.0% 2 -3 1 90 20 25 0 16 4.0 22.5% 6 -3 1 90 20 50 0 0 0.0 43.8% 5 -3 1 90 20 75 0 16 4.0 20.0% 2 -3 1 90 30 25 2 6 3.5 43.3% 8 -3 1 90 30 50 2 3 2.8 30.0% 5 -3 1 90 30 75 3 4 3.3 47.5% 5 -3 1 90 40 25 4 5 4.3 51.3% 10 -3 1 90 40 50 4 5 4.8 40.6% 5 -3 1 90 40 75 4 5 4.8 17.5% 4 -3 1 90 50 25 6 7 6.8 53.0% 11 -3 1 90 50 50 7 8 7.8 64.5% 7 -3 1 90 50 75 7 8 7.3 20.0% 3 -3 1 90 60 25 9 10 9.5 59.2% 12 -3 1 90 60 50 9 10 9.5 25.0% 4 -3 1 90 60 75 1 16 9.5 26.7% 4 -3 1 90 70 25 0 16 11.8 67.1% 11 -3 1 90 70 50 0 16 11.8 60.7% 7 -3 1 90 70 75 15 16 15.8 17.1% 4 -3 1 90 80 25 15 16 15.5 62.5% 13 -3 1 90 80 50 15 16 15.5 46.6% 6 -3 1 90 80 75 15 31 19.5 17.5% 4

First Change Prob. N Density TimeMin TimeMax TimeMed p-Cover p-Min ------4 1 100 10 25 0 0 0.0 40.0% 3 -4 1 100 10 50 0 16 4.0 40.0% 2 -4 1 100 10 75 0 0 0.0 20.0% 1 -4 1 100 20 25 0 9 3.0 55.0% 5 -4 1 100 20 50 1 2 1.5 30.0% 3 -4 1 100 20 75 1 2 1.5 10.0% 1 -4 1 100 30 25 2 3 2.5 46.7% 5 -4 1 100 30 50 2 3 2.5 26.7% 3 -4 1 100 30 75 2 3 2.8 13.3% 2 -4 1 100 40 25 4 5 4.5 67.5% 7 -4 1 100 40 50 4 5 4.3 20.0% 4 -4 1 100 40 75 4 5 4.3 10.0% 2

60 di 72 Risultati dei benchmark

-4 1 100 50 25 6 6 6.0 70.0% 6 -4 1 100 50 50 6 7 6.3 16.0% 3 -4 1 100 50 75 6 7 6.8 8.0 % 2 -4 1 100 60 25 8 9 8.3 71.7% 6 -4 1 100 60 50 9 9 9.0 13.3% 3 -4 1 100 60 75 8 10 9.0 6.7 % 2 -4 1 100 70 25 0 16 11.8 78.6% 7 -4 1 100 70 50 0 16 11.8 11.4% 3 -4 1 100 70 75 15 16 15.5 5.7 % 2 -4 1 100 80 25 15 16 15.8 78.8% 8 -4 1 100 80 50 15 16 15.5 20.0% 4 -4 1 100 80 75 15 16 15.8 5.0 % 3

First Change Prob. N Density TimeMin TimeMax TimeMed p-Cover p-Min ------5 1 50 10 25 0 16 4.0 40.0% 3 -5 1 50 10 50 0 0 0.0 40.0% 2 -5 1 50 10 75 0 0 0.0 20.0% 1 -5 1 50 20 25 0 15 3.8 41.3% 5 -5 1 50 20 50 0 5 2.0 32.5% 3 -5 1 50 20 75 1 2 1.3 10.0% 1 -5 1 50 30 25 2 3 2.5 46.7% 5 -5 1 50 30 50 2 3 2.5 25.8% 3 -5 1 50 30 75 2 3 2.5 13.3% 2 -5 1 50 40 25 4 5 4.5 66.3% 7 -5 1 50 40 50 4 5 4.3 20.0% 3 -5 1 50 40 75 4 5 4.5 10.0% 2 -5 1 50 50 25 6 7 6.3 68.0% 8 -5 1 50 50 50 6 7 6.3 16.0% 3 -5 1 50 50 75 6 7 6.8 8.0 % 2 -5 1 50 60 25 8 9 8.8 67.9% 7 -5 1 50 60 50 8 9 8.8 13.3% 3 -5 1 50 60 75 9 10 9.8 6.7 % 2 -5 1 50 70 25 12 12 12.0 60.0% 6 -5 1 50 70 50 0 16 11.8 17.1% 3 -5 1 50 70 75 0 16 11.5 7.1 % 2 -5 1 50 80 25 0 31 11.8 69.7% 7 -5 1 50 80 50 15 16 15.5 20.0% 4 -5 1 50 80 75 15 16 15.8 5.0 % 2 -5 1 60 10 25 0 0 0.0 37.5% 3 -5 1 60 10 50 0 0 0.0 40.0% 2 -5 1 60 10 75 0 0 0.0 20.0% 1 -5 1 60 20 25 0 0 0.0 46.3% 5 -5 1 60 20 50 0 16 4.0 40.0% 3 -5 1 60 20 75 0 0 0.0 15.0% 1 -5 1 60 30 25 0 15 3.8 42.5% 5 -5 1 60 30 50 0 16 4.0 26.7% 3 -5 1 60 30 75 0 16 4.0 13.3% 2 -5 1 60 40 25 0 15 3.8 65.0% 7 -5 1 60 40 50 0 16 4.0 20.0% 4 -5 1 60 40 75 0 15 3.8 10.0% 2

61 di 72 Risultati dei benchmark

-5 1 60 50 25 0 16 4.0 63.5% 6 -5 1 60 50 50 0 16 4.0 20.0% 3 -5 1 60 50 75 6 7 6.8 8.0 % 2 -5 1 60 60 25 8 10 9.3 70.4% 7 -5 1 60 60 50 9 9 9.0 20.0% 3 -5 1 60 60 75 9 10 9.5 6.7 % 2 -5 1 60 70 25 0 16 10.5 59.6% 6 -5 1 60 70 50 0 16 11.8 17.1% 3 -5 1 60 70 75 0 16 11.8 5.7 % 2 -5 1 60 80 25 15 16 15.8 72.2% 7 -5 1 60 80 50 15 16 15.8 20.0% 4 -5 1 60 80 75 15 16 15.5 5.0 % 2 -5 1 70 10 25 0 16 4.0 40.0% 3 -5 1 70 10 50 0 0 0.0 40.0% 2 -5 1 70 10 75 0 0 0.0 20.0% 1 -5 1 70 20 25 0 15 3.8 53.8% 5 -5 1 70 20 50 0 0 0.0 35.0% 3 -5 1 70 20 75 0 16 4.0 10.0% 1 -5 1 70 30 25 0 0 0.0 43.3% 5 -5 1 70 30 50 0 0 0.0 26.7% 3 -5 1 70 30 75 0 15 3.8 13.3% 2 -5 1 70 40 25 4 15 7.0 57.5% 7 -5 1 70 40 50 4 5 4.5 20.0% 3 -5 1 70 40 75 5 6 5.3 10.0% 2 -5 1 70 50 25 6 7 6.3 62.0% 6 -5 1 70 50 50 6 7 6.3 16.0% 3 -5 1 70 50 75 7 7 7.0 8.0 % 2 -5 1 70 60 25 9 10 9.3 72.5% 7 -5 1 70 60 50 9 9 9.0 13.3% 3 -5 1 70 60 75 9 10 9.5 6.7 % 2 -5 1 70 70 25 11 12 11.8 61.1% 6 -5 1 70 70 50 0 16 10.3 11.4% 3 -5 1 70 70 75 0 16 11.8 5.7 % 2 -5 1 70 80 25 0 16 11.8 75.6% 7 -5 1 70 80 50 15 16 15.5 20.0% 4 -5 1 70 80 75 16 23 18.3 5.0 % 3 -5 1 80 10 25 0 4 1.5 40.0% 3 -5 1 80 10 50 0 1 0.5 40.0% 2 -5 1 80 10 75 0 1 0.5 20.0% 1 -5 1 80 20 25 1 2 1.3 55.0% 5 -5 1 80 20 50 1 2 1.5 30.0% 3 -5 1 80 20 75 1 2 1.3 10.0% 1 -5 1 80 30 25 2 3 2.8 46.7% 5 -5 1 80 30 50 2 3 2.8 26.7% 3 -5 1 80 30 75 2 3 2.8 13.3% 2 -5 1 80 40 25 4 5 4.5 65.0% 7 -5 1 80 40 50 4 5 4.3 20.0% 3 -5 1 80 40 75 4 5 4.5 10.0% 2 -5 1 80 50 25 6 7 6.3 66.5% 6 -5 1 80 50 50 6 7 6.5 16.0% 3 -5 1 80 50 75 6 7 6.8 8.0 % 2

62 di 72 Risultati dei benchmark

-5 1 80 60 25 8 10 8.8 69.6% 6 -5 1 80 60 50 8 9 8.8 13.3% 3 -5 1 80 60 75 9 10 9.5 6.7 % 2 -5 1 80 70 25 11 13 12.0 61.4% 6 -5 1 80 70 50 11 13 12.0 11.4% 3 -5 1 80 70 75 12 13 12.8 5.7 % 2 -5 1 80 80 25 14 16 15.3 65.0% 7 -5 1 80 80 50 15 16 15.3 20.0% 4 -5 1 80 80 75 16 16 16.0 5.0 % 2 -5 1 90 10 25 0 0 0.0 40.0% 3 -5 1 90 10 50 0 0 0.0 40.0% 2 -5 1 90 10 75 0 12 3.3 20.0% 1 -5 1 90 20 25 1 2 1.3 52.5% 5 -5 1 90 20 50 1 2 1.3 33.8% 3 -5 1 90 20 75 1 2 1.3 10.0% 1 -5 1 90 30 25 2 3 2.5 43.3% 5 -5 1 90 30 50 2 3 2.8 26.7% 3 -5 1 90 30 75 2 3 2.5 15.0% 2 -5 1 90 40 25 4 5 4.3 66.3% 7 -5 1 90 40 50 4 5 4.3 20.0% 3 -5 1 90 40 75 4 5 4.5 10.0% 2 -5 1 90 50 25 6 7 6.3 68.0% 6 -5 1 90 50 50 6 7 6.3 16.0% 3 -5 1 90 50 75 6 7 6.8 8.0 % 2 -5 1 90 60 25 8 9 8.5 69.2% 6 -5 1 90 60 50 9 9 9.0 13.3% 3 -5 1 90 60 75 0 16 7.8 6.7 % 2 -5 1 90 70 25 12 18 15.5 75.7% 7 -5 1 90 70 50 13 13 13.0 14.3% 3 -5 1 90 70 75 13 14 13.3 5.7 % 3 -5 1 90 80 25 15 17 16.0 71.9% 7 -5 1 90 80 50 15 17 16.0 20.0% 4 -5 1 90 80 75 17 17 17.0 5.0 % 3

Tabella 6: Risultati dei test con un albero ricoprente

B.2. Esecuzione con 10 alberi ricoprenti

Executing with 10 spanning tree

First Change Prob. N Density TimeMin TimeMax TimeMed p-Cover p-Min ------1 1 100 10 25 4 8 5.3 30.0% 4 -1 1 100 10 50 4 5 4.5 50.0% 3 -1 1 100 10 75 4 5 4.8 50.0% 3 -1 1 100 20 25 12 15 13.3 37.5% 6

63 di 72 Risultati dei benchmark

-1 1 100 20 50 13 14 13.5 35.0% 7 -1 1 100 20 75 13 14 13.5 35.0% 7 -1 1 100 30 25 25 26 25.5 38.3% 9 -1 1 100 30 50 25 27 26.0 36.7% 10 -1 1 100 30 75 26 27 26.5 36.7% 10 -1 1 100 40 25 42 46 44.0 37.5% 13 -1 1 100 40 50 45 46 45.3 36.3% 13 -1 1 100 40 75 45 48 46.3 37.5% 13 -1 1 100 50 25 66 66 66.0 37.0% 16 -1 1 100 50 50 68 70 69.0 35.0% 16 -1 1 100 50 75 68 72 69.5 34.0% 17 -1 1 100 60 25 95 97 95.5 35.0% 20 -1 1 100 60 50 92 95 93.3 35.0% 20 -1 1 100 60 75 95 100 98.0 35.0% 20 -1 1 100 70 25 125 134 130.3 35.7% 23 -1 1 100 70 50 129 133 131.8 35.7% 23 -1 1 100 70 75 125 135 129.8 35.7% 23 -1 1 100 80 25 160 176 168.5 36.3% 26 -1 1 100 80 50 165 177 169.8 35.6% 26 -1 1 100 80 75 170 177 172.8 33.8% 27

First Change Prob. N Density TimeMin TimeMax TimeMed p-Cover p-Min ------2 2 100 10 25 5 11 7.3 50.0% 3 -2 2 100 10 50 4 5 4.3 70.0% 2 -2 2 100 10 75 4 5 4.5 65.0% 2 -2 2 100 20 25 11 12 11.8 40.0% 6 -2 2 100 20 50 12 13 12.8 55.0% 5 -2 2 100 20 75 11 12 11.8 67.5% 2 -2 2 100 30 25 25 26 25.3 50.0% 8 -2 2 100 30 50 23 25 24.0 64.2% 5 -2 2 100 30 75 24 25 24.3 66.7% 5 -2 2 100 40 25 37 39 37.8 52.5% 10 -2 2 100 40 50 41 41 41.0 77.5% 5 -2 2 100 40 75 37 37 37.0 59.4% 4 -2 2 100 50 25 63 67 65.5 58.0% 11 -2 2 100 50 50 69 74 70.8 74.0% 7 -2 2 100 50 75 55 62 58.8 50.0% 3 -2 2 100 60 25 95 99 96.0 65.0% 11 -2 2 100 60 50 84 89 87.0 82.5% 4 -2 2 100 60 75 86 89 87.3 66.7% 4 -2 2 100 70 25 121 128 124.3 70.0% 11 -2 2 100 70 50 114 120 116.5 81.4% 7 -2 2 100 70 75 100 102 101.3 55.7% 4 -2 2 100 80 25 158 170 163.8 69.4% 12 -2 2 100 80 50 136 148 142.5 85.6% 6 -2 2 100 80 75 131 139 135.8 51.3% 4

First Change Prob. N Density TimeMin TimeMax TimeMed p-Cover p-Min ------3 2 50 10 25 5 9 6.0 40.0% 3

64 di 72 Risultati dei benchmark

-3 2 50 10 50 4 5 4.5 60.0% 2 -3 2 50 10 75 4 5 4.5 50.0% 3 -3 2 50 20 25 12 14 13.0 35.0% 7 -3 2 50 20 50 13 14 13.5 52.5% 5 -3 2 50 20 75 12 15 13.3 70.0% 3 -3 2 50 30 25 25 28 26.5 43.3% 9 -3 2 50 30 50 25 27 26.3 58.3% 6 -3 2 50 30 75 25 27 26.3 63.3% 5 -3 2 50 40 25 40 42 40.8 43.8% 11 -3 2 50 40 50 45 48 46.3 62.5% 7 -3 2 50 40 75 45 46 45.5 68.8% 6 -3 2 50 50 25 63 65 64.3 45.0% 13 -3 2 50 50 50 64 69 66.5 64.0% 8 -3 2 50 50 75 67 73 70.0 80.0% 5 -3 2 50 60 25 91 99 94.8 55.0% 12 -3 2 50 60 50 89 96 92.5 70.8% 9 -3 2 50 60 75 94 98 96.3 77.5% 6 -3 2 50 70 25 118 126 121.3 57.1% 15 -3 2 50 70 50 128 133 130.0 72.1% 10 -3 2 50 70 75 132 134 132.8 81.4% 6 -3 2 50 80 25 169 170 169.5 60.0% 15 -3 2 50 80 50 166 176 171.0 76.3% 9 -3 2 50 80 75 173 181 175.3 83.8% 6 -3 2 60 10 25 4 9 5.8 40.0% 3 -3 2 60 10 50 4 5 4.8 60.0% 2 -3 2 60 10 75 4 5 4.5 62.5% 2 -3 2 60 20 25 12 13 12.8 42.5% 6 -3 2 60 20 50 13 14 13.3 55.0% 5 -3 2 60 20 75 12 13 12.8 77.5% 2 -3 2 60 30 25 25 28 26.8 46.7% 8 -3 2 60 30 50 25 27 26.0 61.7% 6 -3 2 60 30 75 25 28 26.8 65.0% 5 -3 2 60 40 25 40 42 41.3 50.0% 10 -3 2 60 40 50 45 47 46.0 65.0% 7 -3 2 60 40 75 42 47 44.3 76.3% 5 -3 2 60 50 25 62 64 63.0 51.0% 11 -3 2 60 50 50 64 67 65.5 67.0% 8 -3 2 60 50 75 61 66 64.0 82.0% 5 -3 2 60 60 25 91 96 94.3 58.3% 13 -3 2 60 60 50 89 94 92.5 75.8% 7 -3 2 60 60 75 95 102 97.0 82.5% 5 -3 2 60 70 25 122 133 128.0 60.7% 13 -3 2 60 70 50 129 131 129.8 73.6% 8 -3 2 60 70 75 117 126 122.0 82.9% 6 -3 2 60 80 25 164 171 167.0 63.1% 15 -3 2 60 80 50 159 167 164.0 81.3% 7 -3 2 60 80 75 151 162 156.3 85.6% 6 -3 2 70 10 25 4 9 5.5 50.0% 3 -3 2 70 10 50 4 5 4.3 65.0% 2 -3 2 70 10 75 4 5 4.3 70.0% 2 -3 2 70 20 25 11 12 11.8 37.5% 6

65 di 72 Risultati dei benchmark

-3 2 70 20 50 12 13 12.5 55.0% 5 -3 2 70 20 75 11 12 11.8 82.5% 2 -3 2 70 30 25 25 26 25.3 45.0% 8 -3 2 70 30 50 24 26 25.0 66.7% 5 -3 2 70 30 75 24 25 24.5 70.0% 5 -3 2 70 40 25 38 40 39.3 51.3% 10 -3 2 70 40 50 41 43 42.3 70.0% 6 -3 2 70 40 75 40 41 40.5 82.5% 4 -3 2 70 50 25 62 65 63.3 54.0% 11 -3 2 70 50 50 64 65 64.5 70.0% 8 -3 2 70 50 75 57 60 59.0 84.0% 3 -3 2 70 60 25 85 91 88.0 61.7% 11 -3 2 70 60 50 89 93 90.5 80.8% 6 -3 2 70 60 75 85 88 87.0 85.8% 4 -3 2 70 70 25 116 125 119.0 64.3% 12 -3 2 70 70 50 119 124 121.5 80.0% 7 -3 2 70 70 75 114 119 115.8 85.7% 4 -3 2 70 80 25 166 169 167.3 66.3% 13 -3 2 70 80 50 157 163 158.8 83.8% 6 -3 2 70 80 75 146 154 150.0 84.4% 5 -3 2 80 10 25 5 9 6.3 45.0% 3 -3 2 80 10 50 4 5 4.5 70.0% 2 -3 2 80 10 75 4 5 4.3 67.5% 2 -3 2 80 20 25 12 13 12.3 45.0% 6 -3 2 80 20 50 12 13 12.5 55.0% 5 -3 2 80 20 75 11 12 11.8 78.8% 2 -3 2 80 30 25 27 28 27.3 50.0% 8 -3 2 80 30 50 24 28 25.8 70.0% 5 -3 2 80 30 75 25 28 26.8 70.0% 5 -3 2 80 40 25 42 43 42.3 52.5% 10 -3 2 80 40 50 45 46 45.3 73.8% 5 -3 2 80 40 75 42 44 42.8 80.0% 4 -3 2 80 50 25 68 70 68.8 58.0% 11 -3 2 80 50 50 69 71 70.0 72.0% 7 -3 2 80 50 75 61 63 61.5 72.0% 3 -3 2 80 60 25 94 99 96.3 63.3% 11 -3 2 80 60 50 90 95 92.5 83.3% 5 -3 2 80 60 75 86 93 89.3 83.3% 4 -3 2 80 70 25 128 134 131.0 67.9% 11 -3 2 80 70 50 128 131 129.0 80.7% 7 -3 2 80 70 75 112 118 114.5 77.9% 4 -3 2 80 80 25 177 183 179.5 68.8% 13 -3 2 80 80 50 163 170 165.3 85.6% 6 -3 2 80 80 75 141 149 145.3 73.8% 4 -3 2 90 10 25 6 11 7.8 50.0% 3 -3 2 90 10 50 4 5 4.5 70.0% 2 -3 2 90 10 75 4 5 4.5 62.5% 2 -3 2 90 20 25 12 13 12.3 40.0% 6 -3 2 90 20 50 12 15 13.0 55.0% 5 -3 2 90 20 75 12 13 12.3 70.0% 2 -3 2 90 30 25 27 27 27.0 50.0% 8

66 di 72 Risultati dei benchmark

-3 2 90 30 50 25 27 26.0 65.8% 5 -3 2 90 30 75 25 27 26.0 68.3% 5 -3 2 90 40 25 40 42 41.0 52.5% 10 -3 2 90 40 50 44 46 45.0 77.5% 5 -3 2 90 40 75 39 43 41.0 60.0% 4 -3 2 90 50 25 68 69 68.8 60.0% 10 -3 2 90 50 50 70 72 71.0 74.0% 7 -3 2 90 50 75 58 63 60.0 50.0% 3 -3 2 90 60 25 91 98 94.5 65.0% 11 -3 2 90 60 50 84 92 86.8 80.0% 4 -3 2 90 60 75 85 87 86.0 69.2% 4 -3 2 90 70 25 123 127 124.5 70.0% 11 -3 2 90 70 50 124 128 125.5 78.6% 7 -3 2 90 70 75 106 109 107.0 47.9% 4 -3 2 90 80 25 174 177 175.0 70.0% 12 -3 2 90 80 50 150 160 153.3 84.4% 6 -3 2 90 80 75 136 142 139.5 55.0% 4

First Change Prob. N Density TimeMin TimeMax TimeMed p-Cover p-Min ------4 3 100 10 25 3 11 5.8 50.0% 3 -4 3 100 10 50 6 8 6.8 67.5% 2 -4 3 100 10 75 4 8 6.3 40.0% 1 -4 3 100 20 25 12 15 13.3 57.5% 4 -4 3 100 20 50 13 16 13.8 71.3% 3 -4 3 100 20 75 10 20 15.8 40.0% 1 -4 3 100 30 25 23 27 25.0 70.0% 5 -4 3 100 30 50 25 29 26.5 70.8% 3 -4 3 100 30 75 28 48 38.0 30.0% 2 -4 3 100 40 25 43 45 44.3 67.5% 7 -4 3 100 40 50 38 48 42.0 53.8% 3 -4 3 100 40 75 44 55 49.5 23.8% 2 -4 3 100 50 25 58 63 61.3 78.0% 6 -4 3 100 50 50 59 68 63.5 51.0% 3 -4 3 100 50 75 66 107 81.8 12.0% 2 -4 3 100 60 25 83 87 85.0 81.7% 6 -4 3 100 60 50 81 92 85.5 49.2% 3 -4 3 100 60 75 121 127 123.8 19.2% 2 -4 3 100 70 25 114 120 116.3 84.3% 6 -4 3 100 70 50 112 121 115.5 60.7% 3 -4 3 100 70 75 121 142 135.0 14.3% 2 -4 3 100 80 25 144 151 147.5 83.8% 7 -4 3 100 80 50 135 145 139.0 55.6% 4 -4 3 100 80 75 147 174 158.8 10.0% 2

First Change Prob. N Density TimeMin TimeMax TimeMed p-Cover p-Min ------5 3 50 10 25 4 11 6.3 50.0% 3 -5 3 50 10 50 4 6 4.8 67.5% 2 -5 3 50 10 75 4 5 4.3 55.0% 1 -5 3 50 20 25 12 14 12.8 60.0% 4

67 di 72 Risultati dei benchmark

-5 3 50 20 50 12 14 13.0 71.3% 3 -5 3 50 20 75 13 14 13.3 42.5% 1 -5 3 50 30 25 24 26 25.3 70.0% 5 -5 3 50 30 50 23 25 24.0 80.8% 3 -5 3 50 30 75 23 24 23.8 43.3% 2 -5 3 50 40 25 42 44 42.5 68.8% 6 -5 3 50 40 50 37 39 38.0 62.5% 3 -5 3 50 40 75 38 39 38.8 28.8% 2 -5 3 50 50 25 59 64 62.0 77.0% 6 -5 3 50 50 50 54 57 55.3 56.0% 3 -5 3 50 50 75 54 58 56.3 15.0% 2 -5 3 50 60 25 82 88 85.8 80.8% 6 -5 3 50 60 50 76 77 76.3 60.8% 3 -5 3 50 60 75 77 81 78.8 20.0% 2 -5 3 50 70 25 112 114 113.0 84.3% 6 -5 3 50 70 50 99 102 101.3 68.6% 3 -5 3 50 70 75 100 103 102.0 16.4% 2 -5 3 50 80 25 143 147 145.3 83.8% 7 -5 3 50 80 50 130 133 131.5 60.0% 4 -5 3 50 80 75 129 137 132.3 10.0% 2 -5 3 60 10 25 5 9 6.5 50.0% 3 -5 3 60 10 50 4 5 4.5 62.5% 2 -5 3 60 10 75 5 7 5.5 50.0% 1 -5 3 60 20 25 12 14 12.5 57.5% 4 -5 3 60 20 50 12 15 12.8 73.8% 3 -5 3 60 20 75 13 15 14.0 42.5% 1 -5 3 60 30 25 24 26 24.8 70.0% 5 -5 3 60 30 50 23 26 24.8 74.2% 3 -5 3 60 30 75 23 26 24.5 40.0% 2 -5 3 60 40 25 41 43 42.3 68.8% 6 -5 3 60 40 50 37 39 38.3 58.8% 3 -5 3 60 40 75 39 41 39.8 26.3% 2 -5 3 60 50 25 60 63 61.5 78.0% 6 -5 3 60 50 50 55 57 56.0 49.0% 3 -5 3 60 50 75 55 59 57.0 15.0% 2 -5 3 60 60 25 84 91 86.3 80.8% 6 -5 3 60 60 50 76 78 77.0 55.8% 3 -5 3 60 60 75 76 80 78.3 19.2% 2 -5 3 60 70 25 112 116 114.3 83.6% 6 -5 3 60 70 50 102 105 103.5 61.4% 3 -5 3 60 70 75 103 109 105.5 15.7% 2 -5 3 60 80 25 142 145 144.0 83.8% 7 -5 3 60 80 50 129 139 134.0 53.8% 4 -5 3 60 80 75 127 144 134.5 10.6% 2 -5 3 70 10 25 4 10 7.0 50.0% 3 -5 3 70 10 50 5 5 5.0 62.5% 2 -5 3 70 10 75 5 8 6.3 55.0% 1 -5 3 70 20 25 13 14 13.3 57.5% 4 -5 3 70 20 50 12 14 12.8 71.3% 3 -5 3 70 20 75 16 21 18.0 40.0% 1 -5 3 70 30 25 24 27 25.5 70.0% 5

68 di 72 Risultati dei benchmark

-5 3 70 30 50 23 25 24.0 74.2% 3 -5 3 70 30 75 22 27 25.3 38.3% 2 -5 3 70 40 25 43 45 44.3 67.5% 7 -5 3 70 40 50 38 42 39.5 61.3% 3 -5 3 70 40 75 42 50 45.8 25.0% 2 -5 3 70 50 25 59 64 61.3 78.0% 6 -5 3 70 50 50 56 62 58.0 45.0% 3 -5 3 70 50 75 60 71 65.8 13.0% 2 -5 3 70 60 25 84 86 85.0 81.7% 6 -5 3 70 60 50 78 83 80.8 48.3% 3 -5 3 70 60 75 81 88 85.0 18.3% 2 -5 3 70 70 25 109 115 113.0 83.6% 6 -5 3 70 70 50 106 111 107.8 61.4% 3 -5 3 70 70 75 111 132 117.3 14.3% 2 -5 3 70 80 25 143 147 145.5 83.8% 7 -5 3 70 80 50 132 134 133.3 54.4% 4 -5 3 70 80 75 135 147 140.8 10.0% 2 -5 3 80 10 25 4 9 6.5 50.0% 3 -5 3 80 10 50 6 7 6.5 62.5% 2 -5 3 80 10 75 5 10 7.3 50.0% 1 -5 3 80 20 25 13 16 13.8 57.5% 4 -5 3 80 20 50 12 15 13.8 71.3% 3 -5 3 80 20 75 15 22 18.5 35.0% 1 -5 3 80 30 25 24 27 25.5 70.0% 5 -5 3 80 30 50 24 27 26.3 74.2% 3 -5 3 80 30 75 27 39 34.8 30.0% 2 -5 3 80 40 25 43 45 43.8 70.0% 6 -5 3 80 40 50 38 44 41.0 57.5% 3 -5 3 80 40 75 47 57 53.0 27.5% 2 -5 3 80 50 25 58 61 59.5 78.0% 6 -5 3 80 50 50 55 65 60.3 43.0% 3 -5 3 80 50 75 71 94 80.3 12.0% 2 -5 3 80 60 25 83 88 85.3 81.7% 6 -5 3 80 60 50 79 89 85.5 53.3% 3 -5 3 80 60 75 103 148 125.5 20.0% 2 -5 3 80 70 25 112 115 113.3 83.6% 6 -5 3 80 70 50 106 119 112.0 64.3% 3 -5 3 80 70 75 121 147 134.3 13.6% 2 -5 3 80 80 25 141 148 144.0 83.8% 7 -5 3 80 80 50 137 142 139.5 54.4% 4 -5 3 80 80 75 137 166 149.3 10.0% 2

Tabella 7: Risultati dei test con 10 alberi ricoprenti

69 di 72 Glossario

Glossario

Albero: nella teoria dei grafi un albero è un grafo non orientato nel quale due vertici qualsiasi sono connessi da uno e un solo cammino (grafo non orientato, connesso e privo di cicli) [11].

Branch and bound: è una tecnica generale per la risoluzione di problemi di ottimizzazione combinatoria basato sulla scomposizione del problema originale in sottoproblemi più semplici da risolvere, ovvero si “provano", almeno implicitamente, tutte le soluzioni possibili fino a trovare quella ottima (o quella corretta) scartandone alcune dimostrando a priori la loro non ottimalità [11].

Cardinalità: nella teoria degli insiemi per cardinalità (o numerosità o potenza) di un insieme finito si intende il numero dei suoi elementi [11].

Core: nel presente contesto, il core di un algoritmo è un insieme di istruzioni che stanno al fulcro dell’algoritmo stesso, ovvero costituiscono la parte fondamentale su cui si basa tutto l’algoritmo [11].

Debug: l'attività che consiste nell'individuazione da parte del programmatore della porzione di software affetta da errore (bug) rilevata nei software a seguito dell'utilizzo del programma [11].

Grafo: è un insieme di elementi detti nodi o vertici che possono essere collegati fra loro da linee chiamate archi o lati o spigoli [11].

Grafo pesato: si tratta di un grafo in cui ad ogni nodo (o vertice) è associato un valore, detto peso [1].

Euristiche: algoritmi che mirano a fornire una soluzione del problema in tempi ridotti. La soluzione fornita non è dimostrabilmente quella ottima (per problemi di ottimizzazione), ma ne rappresenta un'approssimazione. Gli algoritmi euristici sono spesso una strada obbligata per fornire una soluzione a problemi molto difficili (ad esempio quelli NP-Hard).

Matrice totalmente unimodulare: è una matrice (non necessariamente quadrata) per la quale anche ogni minore non singolare è unimodulare. Ne consegue che ogni suo elemento vale 0, +1 o -1. Un programma intero nel quale la matrice dei vincoli è totalmente unimodulare può essere risolto efficientemente, in quanto il suo rilassamento lineare (ottenuto eliminando il vincolo di interezza) porta a soluzioni intere se risolto con opportune tecniche, come ad esempio il simplesso [11].

70 di 72 Glossario

NP: è una classe di problemi comprende tutti quei problemi decisionali che, per trovare una soluzione su una macchina di Turing non deterministica, impiegano un tempo polinomiale. La classe NP prende il suo nome dall'abbreviazione di Nondeterministic Polynomial Time [11].

NP-Completo: i problemi NP-completi sono i più difficili problemi nella classe NP (problemi non deterministici in tempo polinomiale) nel senso che, se si trovasse un algoritmo in grado di risolvere in tempo polinomiale un qualsiasi problema NP- completo, allora si potrebbe usarlo per risolvere velocemente ogni problema in NP [11].

NP-Hard: da Nondetermistic Polynomial-time hard, (ovvero difficile nondeterministico in tempo polinomiale) sono una classe di problemi che può essere definita informalmente come la classe dei problemi almeno difficili come i più difficili problemi delle classi di complessità P e NP [11].

P: conosciuta anche come PTIME (Polinomial TIME), è una classe di complessità che contiene tutti i problemi decisionali che possono essere risolti da una macchina di Turing deterministica usando una quantità polinomiale di tempo di computazione [11].

PLI o ILP: sta per Programmazione Lineare Intera, ovvero problemi di ottimizzazione o ammissibilità nei quali le variabili possono assumere solo valori interi e funzione obiettivo e vincoli sono espressioni lineare delle stesse variabili. La programmazione lineare intera è in generale NP-hard [11].

Porting: in informatica, indica un processo di trasposizione, a volte anche con modifiche, di un componente software, volto a consentirne l'uso in un ambiente di esecuzione diverso da quello originale [11].

Programmazione lineare (PL oppure LP): è quella branca della ricerca operativa che si occupa di studiare algoritmi di risoluzione per problemi di ottimizzazione lineari. Un problema è detto lineare se sia la funzione obiettivo sia i vincoli sono funzioni lineari delle variabili decisionali [11].

71 di 72 Bibliografia

Bibliografia

[1] G. Andreatta, C. De Francesco, L. De Giovanni, P. Serafini, Constrained Domatic Bipartition of a Tree, Working paper (2015)

[2] G. Andreatta, C. De Francesco, L. De Giovanni, P. Serafini, Constrained Domatic Bipartitions and Star Partitions, Working Paper (2015).

[3] P. Serafini, http://www.math.unipd.it/~luigi/manuscripts/CDBP-tree-algorithm/CDBP-tree- algorithm.nb (2015)

[4] Documentazione sulla programmazione funzionale nel linguaggio Mathematica https://reference.wolfram.com/language/guide/FunctionalProgramming.html

[5] Documentazione sul linguaggio C++ http://www.cplusplus.com/reference/

[6] Sito web di AMPL http://ampl.com/

[7] Documentazione sui comandi di AMPL http://ampl.com/BOOK/CHAPTERS/14- command.pdf

[8] Documentazione sullo scripting in AMPL http://ampl.com/BOOK/CHAPTERS/16- script.pdf

[9] Sito web di CPLEX http://www-01.ibm.com/software/commerce/optimization/cplex- optimizer/

[10] Sito web di Astah http://astah.net/

[11] Sito web di Wikipedia https://it.wikipedia.org/

72 di 72