Lezione n°5
Algoritmi Avanzati
a.a.2015/2016
Prof.ssa Rossella Petreschi
Sequenze pulite
Una sequenza binaria si dice pulita se è composta interamente da 0 o da 1.
Se S è bitonica almeno una delle due sottosequenze bitoniche m(S) e M(S) è pulita
(diretta conseguenza del fatto che la cardinalità di {0,1} è due).
In figura è presentato un circuito di ordinamento, di profondità logaritmica, per
sequenze 0/1 bitoniche (ad ogni passo rendiamo pulita metà della sequenza).
0
0
1
1
1
0
0
0
0
0
0
0
1
0
1
1
0
0
0
0
1
0
1
1
0
0
0
0
0
1
1
1
Circuito di fusione
Il circuito di fusione fonde due sequenze ordinate costruite sullo stesso alfabeto
sfruttando il fatto che, date due sequenze ordinate entrambe crescenti (o decrescenti) x
e y, la sequenza che si ottiene concatenando x con z=“y rovesciata” è bitonica
(l’inversione della stringa y si realizza semplicemente variando le connessioni).
0
0
0
1
0
0
1
1
0
0
0
0
1
0
1
1
0
0
0
0
1
0
1
1
0
0
0
0
0
1
1
1
La profondità del circuito è logaritmica e il numero di comparatori ad ogni passo è n/2.
Circuito di ordinamento
In figura è riportato un circuito di ordinamento che realizza l’ordinamento connettendo
iterativamente diversi circuiti di fusione (la base di questa costruzione sta nel fatto che
ogni sequenza di due elementi è bitonica).
1
0
0
0
0
1
1
0
0
1
0
0
0
1
0
1
0
0
1
0
0
0
1
1
0
0
0
1
0
0
1
1
0
0
0
0
1
0
1
1
0
0
0
0
1
0
1
1
0
0
0
0
0
1
1
1
Poiché concateniamo un numero logaritmico di circuiti di fusione, otteniamo una
profondità del circuito O(log2 n).
Applicando il teorema di Brent
Il circuito di ordinamento, O, è un circuito combinatorico di
profondità d = O(log2 n), di dimensione pari al numero di
comparatori c = O(nlog2n), fan in e fan out limitati. Per il
Teorema di Brent, l’algoritmo di ordinamento che lavora su O
può essere simulato da una algoritmo che lavora su una PRAM
EREW con p processori in tempo O(c / p + d),
ovvero O((n log2 n) / p + log2 n).
Quando p = O(n) si ha che la complessità temporale
dell'ordinamento su una PRAM EREW è
O(log2 n) e il costo O(n log2 n).
Ricordiamo che:
Trasportabilità fra P-RAM con diverso numero
di processori
Teorema (p' < p): ogni algoritmo A che lavora in tempo parallelo O(t) su
una PRAM con p processori può essere simulato da un algoritmo A' che
lavora su una PRAM con p' processori (p' < p) in tempo O(t p / p').
Dimostrazione: durante ognuno dei t passi dell’esecuzione di A, i p
processori lavorano parallelamente in tempo O(1). Durante ogni passo
della esecuzione di A', ciascuno dei p'<p processori eseguirà un blocco
seriale di p/p' operazioni in tempo O(p/p'). Pertanto il tempo parallelo
relativo alla esecuzione di A' sarà O(tp/p').
Il costo dei due algoritmi A e A' rimane pari a O(tp).
Numero di processori limitato (1)
Vogliamo sommare n numeri, con la tecnica della prima metà, avendo a disposizione un
numero fissato a priori di p processori (p < n).
Ricordiamo come si lavora con n processori
Begin
for i = 1 to log n do
for j = 0 to n/2i -1 pardo
Pj: A[ j ] = A[ j ] + A[ j+n/2i ]
return A[ 0 ]
end
P1 P 2 P3 P4
4 2 7 4 1 6 3 8
5 8 10 12
15 20
35
Numero di processori limitato (2)
p = 2 P1 P2
Vediamo cosa cambia con p <n processori
Begin
for i = 1 to log n do
for s = 0 to (n/2i) / p -1 do
for j = 0 to min(n/2i, p) -1 pardo
if (j+s*p < n/2i) then
Pj: A[ j+s*p ] = A[ j+s*p ] + A[ j+s*p +n/2i ]
return A[ 0 ]
end
i=1
4 2 7 4 1 6 3 8
s=0
5 8 7 4 1 6 3 8
s=1
i=2 5 8 10 12
s=0
i=3 15 20
s=0
35
La tecnica del
Accelerated Cascading
Dato un problema P di dimensione n, siano A1 e A2 due algoritmi per
risolvere il problema P che operano rispettivamente in tempo T1e T2 (T1>
T2), si costruisce un nuovo algoritmo A nel seguente modo:
1.
si applica a P l’algoritmo A1(A1lavora per fasi) fintanto che l’output delle
fasi non produca una istanza P’ di P di dimensione minore di una soglia
prefissata;
2.
si applica a P’ l’algoritmo A2
E’ da notare che invece di un solo algoritmo di riduzione A1 si potrebbe
avere una catena di algoritmi di questo tipo. In tal caso si considera la
catena di algoritmi di riduzione ordinata dall’algoritmo più lento al più
veloce e si costruisce il nuovo algoritmo sostituendo il passo1 con
l’applicazione a P della catena così ordinata.
Somma con la tecnica dell’accelerated
cascading
L’algoritmo di somma parallelo con la tecnica della prima metà non è ottimo
perché costa O(n log n) (ovvero n processori per log n tempo),mentre il miglior
algoritmo sequenziale richiede tempo O(n). La tecnica dell’accelerated cascading
ci permette di ridurre il costo dell’algoritmo parallelo a O(n) e quindi a
raggiungere valore dell’efficienza uguale ad 1.
La tecnica consiste nel dividere l’algoritmo in due fasi:
1° fase: si applica l’algoritmo sequenziale su k sotto-istanze del problema di piccola
dimensione h in modo da ridurre la dimensione totale dello intero problema. Tempo
parallelo O(h).
2° fase: si applica l’algoritmo parallelo con p processori sui k risultati del passo
precedente. Tempo parallelo O(log k)
Costo = O(p (h + log k))
Algoritmo per la somma con la tecnica
dell’Accelerated Cascading
Si adoperano p processori
SommaAC(A, n)
begin
k=p
h = n/k
for i = 0 to k-1 pardo
Pi: bi = i * h
for j = 1 to h -1 do
if bi + j < n then A[ bi ] = A[ bi ] + A[ bi + j ]
B[ i ] = A[ bi ]
Somma(B, k)
end
// algoritmo di somma parallela standard
Tempo parallelo O(h + log k)
Esempio di somma con la tecnica
dell’Accelerated Cascading
n = 12
P0
P=4
P1
size = 3
P2
P3
24 32 10 11 7 16 9 45 2 19 31 5
1° fase
sequenziale
2° fase
parallela
24
11
9
19
56
18
54
50
66
34
56
55
122
89
211
Analisi dell’algoritmo SommaAC
Per ottenere costo Cp=O(n) e quindi Eff=1, dobbiamo scegliere O(n/log n)
processori, assegnando a ciascuno O(log n) elementi da sommare
sequenzialmente.
La 1° fase pertanto richiede tempo paralello O(log n) per generare
O(n/log n) elementi. Con O(n/log n) processori si opera con l’algoritmo di
somma parallelo su gli O(n/log n) elementi, impiegando un tempo
parallelo pari a:
log (n/log n) = log n – log log n = O(log n)
Costo totale = O(n/log n (log n + log n)) = O(n)
Somme prefisse con
Accellerated Cascading
Si adoperano k processori
Per semplicità assumiamo n multiplo di k: n = h·k
begin
for i = 0 to k-1 pardo
Pi:
bi = i * h
// inizio blocco i-esimo
for j = 1 to h -1 do
A[ bi + j ] = A[ bi + j ] + A[ bi + j-1 ]
B[ i ] = A[ bi + h-1 ]
// l’ultimo del blocco
PrefixSum(B, k)
for i = 1 to k-1 pardo
Pi:
for j = 0 to h -1 do
A[ bi + j ] = A[ bi + j ] + B[ i-1 ]
end
Tempo parallelo O(h + log k)