Sie sind auf Seite 1von 2

Parallelverarbeitung Übungszettel 6

Anton Pirogov (616847) Denis-Michael Lux (617286)

Aufgabe 6.3

Gegeben sei ein Baum als Adjazenzliste mit n Knoten. Wir legen ein Array A der Größe 3n an, wobei jeder Knoten i die 3 Positionen im Array 3i, 3i + 1, 3i + 2 erhält. Nun verpointern

wir die Knoten i ∈ {0,

Blatt ist, setzen wir A[3i] = 3i + 1, A[3i + 1] = 3i + 2. Falls der Knoten i ein innerer Knoten

mit m log(n) Kindern ist, auf die man mit nthChild(i, j), 1 j m zugreifen kann, setzen wir analog zur Übung:

A[3i] = 3 · nthChild(i, 1) A[3 · nthChild(i, n) + 2] = 3i + 2 A[3 · nthChild(i, n/2) + 2] = 3i + 1 A[3i + 1] = 3 · nthChild(i, n/2 + 1) A[3 · nthChild(i, j) + 2] = 3 · nthChild(i, j + 1) für alle j ∈ {1,

Nun erzeugen wir in O(log(n)) ein List-Ranking B von den 3n Elementen der Liste A. Wir ordnen sie nun in A entsprechend dem Ranking in O(1) um (einschließlich dem umbiegen der Pointer) und setzen C[j] = i/3 und D[j] = i mod 3, wobei i die alte Position in B ist und j die neue (entsprechend dem Ranking). Im Array C steht also zu welchem Knoten des Baumes der eintrag gehört und in D steht ob es die erste, zweite oder dritte Kopie ist (welche entsprechend in Pre-/In- und Post-Order besucht werden).

Für k ∈ {0, 1, 2} erzeugen wir uns zunächst ein Array E k , setzen E k [i] = 0 falls D[i] = k und sonst E k [i] = 1 und lassen darauf in O(log(n)) eine Präfixsumme darauf laufen, wobei wir am Ende wieder E k [i] = 0 für D[i] = k setzen. Dann werden die Eintrage von C[i] für die E k [i] = 0 ist mit Offset von k · n an die entsprechende Position in ein Ergebnisarray geschrieben.

Am Ende stehen die Knotennummern der Pre-, In- und Post-Order Traversierungen nachein- ander in dem Ergebnisarray.

Die Laufszeit ist O(log(n)) und die Arbeit O(n), was aus dem beschriebenen Ablauf ersichtlich ist.

, n 1} im Array parallel in O(1) folgendermaßen: Falls Knoten i ein

, n} \ {n/2}.

Aufgabe 6.4

1

#include<stdio.h> #include<stdlib.h> #define hmask 0xffffffff00000000 #define lmask 0x00000000ffffffff

6

void parallel_implementation(int* array, int n, int p) { if (p<2) p=2; // 1 kern ist so extrem langsam, das wird einfach verboten unsigned long *sr = calloc(n,sizeof(unsigned long)); int* sr2 = (int*)sr; #pragma omp parallel for num_threads(p)

11

 

for (int i=0; i<n; i++) if (array[i] != -1) { sr2[(i<<1)|1] = array[i]; sr2[(i<<1)] = 1; } else

16

 

sr2[(i<<1)|1] = i;

 

#pragma omp parallel for num_threads(p) schedule(dynamic,1000) for (int i=0; i<n; i++) { //pointer jumping while (((sr[i] ^ sr[sr[i]>>32])&hmask) != 0) {

21

 

sr[i] = sr[sr[i]>>32] + (sr[i]&lmask);

 

}

}

#pragma omp parallel for num_threads(p)

26

for (int i=0; i<n; i++) array[i] = sr2[i<<1];

}

lr_bench_par.c

1 / 2

Parallelverarbeitung Übungszettel 6

Anton Pirogov (616847) Denis-Michael Lux (617286)

Mit einer Implementierung des Repeated-Suspend-Algorithmus hatten wir keinen Erfolg, da das Färben zu lange dauert. Die Pointer-Jumping-basierte Variante hier erreicht wenigstens Speedups 0.55-0.6, was zwar auch nicht gut ist, aber besser als unsere anderen Versuche.

Aufgabe 6.5

Wie im Hinweis angemerkt, kann man bei gegebenem Graph und zwei Knoten s und t einfach t als seinen eigenen Nachfolger festlegen und ein Pointer-Jumping durchführen. Dabei wird es nach log(n) Runden abgebrochen um eine Endlosschleife zu verhindern (in den anderen Ringen wird ja quasi weiter im Kreis gesprungen). Das reicht für den worst case, falls alle n Knoten im gleichen Ring sind. Falls am Ende der Zeiger von s auf t zeigt, müssen sie im selben Kreis liegen. Die Zeit ist O(log(n)) und die Arbeit O(n log(n)).

Wenn man statt reinem Pointer-Jumping den AC-List-Ranking Algorithmus verwendet, kann man die Zeit O(log(n) log log(n)) und Arbeit O(n) erreichen, wobei man für die R[i] alles auf

0 setzt außer wenn A[i] = t, also wird nur für den Vorgänger vom Ziel die Kante auf den Wert

1 gesetzt. Wir verwenden erneut unser garantiert terminierendes Pointer-Jumping welches nun

aber um den Faktor log(n) weniger Arbeit hat. Nur können wir feststellen, ob s im gleichen Ring wie t ist, falls der Rang von s am Ende auch 1 ist (wie am Ende bei allen Knoten im Ring). In allen anderen Ringen gibt es nämlich nur 0-Kanten, sodass alle den Rang 0 behalten werden.

2 / 2