Algoritmi Avanzati a.a.2014/2015 Prof.ssa Rossella Petreschi Lezione n°14 Algoritmi Avanzati a.a.2014/2015 Prof.ssa Rossella Petreschi 1
Individuazione del minimo albero ricoprente in un contesto distribuito Si provede in modo analogo al caso parallelo, ovvero si prende come base l’algoritmo di Sollin. Si procede formando frammenti (frammento = meganodo) e collegandoli fra loro individuando, per ogni frammento, l’arco uscente di costo minimo. La correttezza di questa strategia dipende dalle 2 proprietà fondamentali, già precedentemente enunciate: Dato un sottoalbero T’ di un qualche albero di copertura T di costo minimo e un arco e uscente da T’ di costo minimo, allora T’ U {e} è ancora un sottoalbero di qualche albero di copertura di costo minimo (non serve l’unicità dei pesi in questo caso). Se tutti gli archi di un grafo G hanno pesi differenti, allora esiste un unico albero di copertura di G di costo minimo.
Cosa si deve fare nel distribuito Ad ogni frammento si associa un livello di appartenenza e un identificativo: inizialmente i frammenti sono a livello 0 e sono costituiti da un solo nodo il cui identificativo coincide con quello del frammento e lo spigolo “portante” è lo spigolo di costo minimo incidente nel nodo; a livello k, l’identificativo di un frammento è dato da uno dei due nodi estremi dello spigolo portante della parte di MST propria del frammento; il livello si incrementa di 1, ogni volta che si esegue una unione per combinazione. Come si uniscono i frammenti: per combinazione di frammenti allo stesso livello k con lo stesso spigolo di costo minimo che diviene spigolo portante. In tal caso si crea un nuovo frammento di livello k+1; per assorbimento di un frammento di livello minore con uno di livello maggiore; in questo caso il livello non viene incrementato.
Cosa si deve evitare nel distribuito Che i frammenti non coordinino le loro azioni: ogni nodo deve riconoscere a quale frammento appartiene e questa informazione la deve ricevere in modo coordinato con gli altri nodi dello stesso frammento; fra tutti gli spigoli uscenti dal frammento, va trovato lo spigolo di costo minimo relativo al frammento stesso; Che l’unione dei frammenti non implichi un numero di messaggi da trasmettere troppo elevato: evitare l’unione di frammenti grandi con vertici isolati: questo potrebbe portare a trasmettere un numero quadratico di messaggi.
Ordinamento fra frammenti Consideriamo un ordinamento fra i frammenti determinato da livello di appartenenza e dal costo del minimo arco uscente. Chiamiamo fl un frammento a livello l 0 ed el il suo spigolo uscente di costo minimo c(el). fl < fl’ se l < l’ se, l = l’, c(el) < c(el’). fl ≈ fl’ se, l = l’, el = el’.
Unione di frammenti Si ha: combinazione di frammenti quando fl ≈ fl’. Si crea un nuovo frammento di livello l+1 il cui spigolo portante è lo spigolo che ha unito i due frammenti a livello l (l = l’, el = el’). assorbimento di fl in fl’ se fl < fl’. Il frammento di livello minore è assorbito da quello di livello maggiore che si trasforma in nuovo frammento mantenendo stesso livello e stesso spigolo portante (l < l’ oppure l = l’e c(el) < c(el’)); nessuna operazione quando fl > fl’ ,ovvero fl’ risponderà alla richiesta di fl mettendolo in attesa. La richiesta di fl verrà servita non appena si verificheranno le condizioni per una combinazione o un assorbimento.
Schema dell’algoritmo Si uniscono i frammenti. Il minimo arco uscente dai frammenti che si combinano diventa l’arco portante della componente risultante. Quindi al termine di una combinazione, gli estremi del nuovo arco portante aggiornano la componente contestualmente alla richiesta di ricerca del nuovo minimo arco uscente, causando l’aggiornamento delle relazioni padre/figli. Ad ogni incremento di livello, le richieste lasciate in attesa devono essere nuovamente analizzate per verificare se possono essere servite. L’algoritmo termina quando un frammento non è in grado di individuare il suo arco uscente di costo minimo tutti gli archi vengono scartati perché non esterni in quanto il frammento copre l’intero grafo G.
Esempio 10 c m l 16 15 9 7 8 11 a f g 6 17 2 i 1 3 5 4 12 b d e h 18 14 13 Inizialmente ogni nodo è un frammento di livello 0 a b c d e f g h i l m Identificazione dell’arco uscente di peso minimo 1 1 2 2 3 3 4 5 6 7 9 b a d c f e e g g g f Combinazione a b c d e f liv 1 liv 1 liv 1 e f Assorbimento liv 1 g m
Esempio Identificazione dell’arco uscente di peso minimo a b c d g e f h i l 16 14 5 5 6 7 c e h g g g Combinazione (niente) g e f m Assorbimento h i l liv 1 Identificazione dell’arco uscente di peso minimo a b c d h g e f m 16 14 i 14 l c e d f m 4 combinazioni successive c d e g h liv 2 l i Assorbimento (niente)
Esempio f m Identificazione dell’arco uscente di peso minimo a b c d e g h 16 16 l i c a liv 1 liv 2 f m Assorbimento b a c d e g h liv 2 l i
Spigolo di costo minimo del frammento Quando due frammenti si combinano (o quando uno viene assorbito in un altro) bisogna che tutti i nodi del nuovo frammento aggiornino le loro variabili e che l’intero frammento identifichi il proprio arco uscente di costo minimo. Tutto avviene tramite una operazione di broadcast con eco così suddivisa: si propagano le nuove informazioni a tutti i nodi; ciascun nodo v individua l’arco (v,u) di costo minimo tra quelli ad esso adiacenti uscenti dal frammento; tramite l’eco si trasmettono al nodo identificatore del frammento i minimi parziali; il nodo identificatore individua il minimo assoluto (x,y). Tale valore sarà poi ritrasmesso a tutti i nodi del frammento; in questo modo, il nodo x potrà mandare una richiesta di connessione al frammento ad esso adiacente.
Risposta alle richieste Il destinatario v di un messaggio di richiesta di informazioni, verifica identificativo e livello del richiedente. Se l’identificativo corrisponde a quello del frammento di v, v invia ad u un messaggio di rifiuto e l’arco viene scartato da entrambi i nodi. Un nodo u, che riceve un rifiuto, procede verificando il successivo arco non classificato di costo minimo. In caso contrario, si controlla il livello: Se il livello del frammento di u è minore o uguale a quello di v, v accetta la richiesta di u. Se il livello del frammento di u è maggiore del livello del frammento di v, la richiesta di u viene messa in attesa, e verrà servita quando una delle condizioni precedenti sarà verificata.
Possiamo avere stallo? Verifichiamo che le attese per ottenere risposta a richieste di informazioni su un arco o a richieste di combinazione non possano portare allo stallo. Consideriamo un qualunque istante dell’esecuzione dell’algoritmo e consideriamo un frammento fl minimo secondo la nostra relazione di ordine. Qualunque frammento fl’ avrà livello almeno pari a l, pertanto tutte le richieste di informazione sugli archi provenienti da fl verranno servite immediatamente. Quindi fl individuerà il suo minimo arco uscente e ed effettuerà un richiesta di aggregazione. Poiché fl è minimo, all’altro estremo di e potrà trovarsi o un frammento fl’ ≈ fl (quindi combinazione di fl’ e fl ), o un frammento di livello maggiore che assorbirà fl . Ogni altra ipotesi porterebbe ad una contraddizione nella definizione della relazione di ordine fra i frammenti. Poiché l’istante considerato è arbitrario, in qualunque momento dell’esecuzione dopo tempo finito avremo che un frammento incrementa il suo livello e la sua dimensione, il che garantisce la terminazione.
Le variabili Per ogni nodo p: Fram(p) nome del frammento a cui p appartiene. Liv(p) valore del livello del frammento a cui p appartiene. Per ogni arco (p, q): Statop(q) accettato se è stato inserito nel MST. Per ogni frammento f: w(f) minimo fra i costi degli archi uscenti da f (è sufficiente ad identificare univocamente l’arco perché assumiamo costi distinti).
Algoritmo per il MST distribuito begin // inizialmente init = V Piinit: inizializza tutte le variabili trova l’arco (i,y) di costo minimo poni statoi(y) = accettato send ad y richiesta di connessione repeat Pi: receive messaggio M dal mittente q if M è una richiesta di connessione then if liv(q) > liv(i) then non fare nulla else if liv(q) < liv(i) then assorbi fram(q) in fram(i) send a q richiesta di ridefinizione R{liv(i), fram(i)} else if q = y e liv(q) = liv(i) e w(fram(i))=w(fram(q)) then combina fram(q) con fram(i) send a q richiesta di ridefinizione R{liv(i)+1, min(q,i)} else if M è una richiesta di ridefinizione then aggiorna tutte le variabili relative a i con i valori ricevuti da R send R a tutti gli appartenenti al vecchio frammento di i trova lo arco (x,y) di costo minimo uscente dal nuovo frammento if i = x then poni statoi(y) = accettato // solo il nodo x contatta y until rimane un solo frammento end
Complessità temporale Lemma: Il livello di un frammento non eccede mai O(log n) Dim: Per l > 0, un frammento di livello l si forma soltanto quando due frammenti di livello l-1 si fondono, quindi un frammento di livello l contiene almeno 2l nodi, ne consegue l’asserto, dato che n 2l, per ogni l. Come conseguenza del Lemma e del fatto che le operazioni ad ogni livello richiedono tempo O(n) si ha: Teorema: l’algoritmo per la determinazione del MST in un sistema distribuito richiede complessità temporale O(n log n)
Complessità di comunicazione Teorema: l’algoritmo per la determinazione del MST in un sistema distribuito richiede complessità di comunicazione O(n log n + m). Dim: ad ogni livello O(n) messaggi in totale sono inviati lungo gli spigoli dell’albero. Ci sono inoltre O(m) messaggi addizionali in fase di inizializzazione, necessari affinchè ogni nodo possa conoscere quali sono gli identificativi dei propri vicini e scegliere lo spigolo di costo minimo.