Κ Σ Ι Ενδεικτικές Λύσεις 1ου Σετ Ασκήσεων Παναγιώτα Παναγοπούλου Άσκηση 1. Υποθέστε ότι οι διεργασίες ενός σύγχρονου κατανεμημένου συστήματος έχουν μοναδικές ταυτότητες (UIDs), γνωρίζουν ότι είναι συνδεδεμένες σε τοπολογία κατευθυνόμενου δακτυλίου και η κάθε μία γνωρίζει τον εισερχόμενο και τον εξερχόμενο γείτονά της. Το μέγεθος του δακτυλίου n δεν είναι γνωστό στις διεργασίες. Κάθε διεργασία i έχει ως είσοδο έναν αριθμό a i R. Να περιγράψετε έναν κατανεμημένο αλγόριθμο υπολογισμού του μέσου όρου a = i a i/n (δηλαδή στο τέλος του αλγορίθμου κάθε διεργασία πρέπει να έχει υπολογίσει την τιμή a). Να δώσετε τον ψευδοκώδικα του αλγορίθμου, να επιχειρηματολογήσετε ως προς την ορθότητά του και να αναλύσετε τη χρονική πολυπλοκότητα και την πολυπλοκότητα επικοινωνίας του. Λύση. Κάθε κόμβος i κρατάει τοπικά δύο μεταβλητές counter με αρχική τιμή 1 και sum με αρχική τιμή a i. Κάθε κόμβος i στέλνει στο δεξιόστροφο γείτονά του ένα μήνυμα που περιέχει το UID του και τον αριθμό a i. Κάθε κόμβος που λαμβάνει ένα μήνυμα με ένα UID u k και έναν αριθμό a k, συγκρίνει το UID που έλαβε με το δικό του. Αν είναι διαφορετικό, αυξάνει την τοπική μεταβλητή counter κατά 1 και τη sum κατά a k και προωθεί στο δεξιόστροφο γείτονα το μήνυμα που έλαβε. Αν το UID που έλαβε ισούται με το δικό του UID, τότε η τιμές των counter και sum του ισούνται με το συνολικό πλήθος κόμβων του δικτύου και το συνολικό άθροισμα a αντίστοιχα, επομένως υπολογίζει το μέσο όρο και τερματίζει. Ακολουθεί ο ψευδοκώδικας του παραπάνω αλγορίθμου. Το αλφάβητο των μηνυμάτων M αποτελείται από ζεύγη της μορφής < u, a >, όπου u είναι UID και a ένας πραγματικός αριθμός. states i //(σύνολο καταστάσεων διεργασίας/κόμβου i) u, ένα UID, αρχικά το UID u i της i a i, ένας πραγματικός αριθμός (η είσοδος του αλγορίθμου) sum, ένας πραγματικός αριθμός, αρχικά a i counter, ένας ακέραιος, αρχικά 1 a, ένας πραγματικός αριθμός (η έξοδος του αλγορίθμου) send, ένα μήνυμα < u, a > ή NULL, αρχικά το < u i, a i > msgs i //(γεννήτρια εξερχόμενων μηνυμάτων της i) 1
στείλε την τρέχουσα τιμή του send στο δεξιόστροφο γείτονα (διεργασία i + 1) trans i //(συνάρτηση αλλαγής κατάστασης της i) if το εισερχόμενο μήνυμα είναι < v, a v > then if v u then send :=< v, a v >; counter := counter + 1; sum = sum + a v ; else a := sum/counter ; send := NULL Για να αποδείξουμε την ορθότητα του αλγορίθμου, παρατηρούμε ότι η μεταβλητή counter έχει αρχική τιμή 1 και αυξάνεται κατά 1 κάθε φορά που ένας κόμβος λαμβάνει μήνυμα από ένα UID διαφορετικό από το δικό του. Επίσης, κάθε μήνυμα ταξιδεύει δεξιόστροφα σε όλο το δίκτυο και περνάει από κάθε κόμβο ακριβώς μία φορά, καταλήγοντας στον κόμβο από όπου ξεκίνησε. Άρα η μεταβλητή counter περιέχει το σωστό πλήθος των κόμβων του δικτύου όταν υπολογίζεται το a. Αντίστοιχα, η μεταβλητή sum έχει αρχική τιμή a i και αυξάνεται κατά a v κάθε φορά που ένας κόμβος λαμβάνει έναν αριθμό a v από έναν κόμβο με UID διαφορετικό από το δικό του. Άρα η μεταβλητή sum περιέχει το σωστό άθροισμα των τιμών εισόδου όταν υπολογίζεται το a, άρα στο τέλος η a περιέχει τη σωστή τιμή του μέσου όρου. Για τη χρονική πολυπλοκότητα, παρατηρούμε ότι η μεταβλητή counter έχει αρχική τιμή 1 και αυξάνεται σε κάθε γύρο (εκτός από τον τελευταίο), άρα μετράει το συνολικό πλήθος των γύρων που εκτελούνται. Άρα, επειδή στο τέλος counter = n, απαιτούνται n γύροι για να τερματίσει ο αλγόριθμος. Για την πολυπλοκότητα επικοινωνίας του αλγορίθμου, παρατηρούμε ότι, σε κάθε γύρο, κάθε κόμβος στέλνει ακριβώς 1 μήνυμα (στο δεξιόστροφο γείτονά του). Άρα συνολικά απαιτούνται n 2 μηνύματα. Άσκηση 2. Θεωρήστε ένα σύγχρονο, κατευθυνόμενο δακτύλιο με n > 3 διεργασίες. Το n δεν είναι γνωστό στις διεργασίες, είναι όμως γνωστό ότι δεν είναι πολλαπλάσιο του 3 (δηλαδή n mod 3 0). Τρεις από τις διεργασίες έχουν ταυτότητα 1 και οι υπόλοιπες n 3 διεργασίες έχουν ταυτότητα 0 (οι θέσεις των διεργασιών με ταυτότητα 1 δεν είναι γνωστές και δεν είναι απαραίτητα διαδοχικές). Να περιγράψετε αναλυτικά (αλλά όχι απαραίτητα με ψευδοκώδικα) έναν κατανεμημένο αλγόριθμο εκλογής αρχηγού και να αναλύσετε τη χρονική πολυπλοκότητα και την πολυπλοκότητα επικοινωνίας του. Λύση. Θα βρούμε πρώτα έναν (κεντρικοποιημένο) τρόπο να ξεχωρίσουμε έναν από τους τρεις κόμβους με ID ίσο με 1 ώστε να τον επιλέξουμε ως αρχηγό. Η επιλογή θα γίνει με βάση τη θέση του στο δίκτυο. Εφόσον βρούμε έναν τρόπο να ξεχωρίσουμε έναν κόμβο, αρκεί να σχεδιάσουμε έναν κατανεμημένο αλγόριθμο που θα επιτρέπει σε κάθε διεργασία να μάθει τις θέσεις των 1 στο δίκτυο, ώστε να μπορεί στη συνέχεια να αποφασίσει αν θε είναι αρχηγός ή όχι. Αριθμούμε αυθαίρετα τους κόμβους ενός τέτοιου δικτύου με τη σειρά 0, 1, 2,..., n, έτσι ώστε ο i να συνδέεται με τον i+1( mod n). Έστω ότι οι κόμβοι με ID 1 βρίσκονται στις θέσεις i, j και k, με i < j < k. Έστω a ij η απόσταση των i και j στο δίκτυο. Αντίστοιχα ορίζουμε τις αποστάσεις a jk και a ki. Θεωρούμε τη μέγιστη από αυτές τις αποστάσεις. Χωρίς βλάβη της γενικότητας, έστω ότι αυτή είναι είναι η a ij. Επειδή n mod 3 0, αποκλείεται να ισχύει a ij = a jk = a ki. Άρα διακρίνουμε τις παρακάτω περιπτώσεις: 2
Έστω a ij > a jk και a ij > a ki. Τότε επιλέγουμε ως αρχηγό τον k. Έστω a ij = a jk > a ki. Τότε επιλέγουμε ως αρχηγό τον j. Έστω a ij = a ki > a jk. Τότε επιλέγουμε ως αρχηγό τον i. Επομένως, αν κατασκευάσουμε έναν κατανεμημένο αλγόριθμο που θα επιτρέπει σε κάθε διεργασία με ID 1 να υπολογίσει τις αποστάσεις τις από τις άλλες διεργασίες με ID 1, τότε η διεργασία θα είναι σε θέση να εφαρμόσει τον παραπάνω κανόνα και να αποφασίσει αν θα είναι αρχηγός ή όχι. Εφόσον οι διεργασίες θα έχουν τη σωστή πληροφορία σχετικά με τη θέση τους στο δίκτυο και εφαρμόσουν όλες τον ίδιο κανόνα, ο οποίος σε κάθε περίπτωση ορίζει μόνο έναν αρχηγό, τότε στο τέλος το πρόβλημα εκλογής αρχηγού θα έχει λυθεί. Ο αλγόριθμος περιγράφεται συνοπτικά ως εξής: Κάθε διεργασία με ID ίσο 0 θέτει τον εαυτό της ως όχι αρχηγός. Αν λάβει κάποιο μήνυμα, απλά το προωθεί στο γείτονά της. Κάθε διεργασία i με ID ίσο με 1 κρατάει τρεις τοπικές μεταβλητές dist 1, dist 2 και counter με αρχικές τιμές 0. Η counter θα μετρά τις διεργασίες με ID 1, και στόχος είναι η dist 1 να ισούται στο τέλος με την απόσταση που έχει από τη διεργασία i η αμέσως προηγούμενη διεργασία με ID 1 (έστω k), και η dist 2 να κρατάει την απόσταση που έχει από την i η άλλη (δηλαδή η αμέσως επόμενη) διεργασία με ID 1 (έστω j). Επομένως η dist 1 θα ισούται με το πλήθος των hops που απαιτούνται ώστε από τη διεργασία στη θέση k να φτάσουμε στη διεργασία στη θέση i. Αντίστοιχα, η dist 2 θα ισούται με το πλήθος των hops που απαιτούνται ώστε από τη διεργασία στη θέση j να φτάσουμε στη διεργασία στη θέση i. Προσέξτε εδώ ότι τα i, j, k είναι τοπικά ονόματα που χρησιμοποιούνται από κάθε διεργασία, και αναφέρονται αντίστοιχα στον εαυτό της, στον αμέσως επόμενο κόμβο με ID 1 και στον αμέσως προηγούμενο κόμβο με ID 1. Σε κάθε γύρο, μια τέταρτη μεταβλητή rounds (με αρχική τιμή 0) αυξάνεται κατά 1. Κάθε διεργασία i με ID ίσο με 1 στέλνει ένα μήνυμα < 1 > στο γείτονά της. Αν σε κάποιο γύρο λάβει κάποιο μήνυμα, αυξάνει την τιμή του counter. Αν το counter γίνει ίσο με 1, τότε εντοπίστηκε ο αμέσως προηγούμενος κόμβος με ID ίσο με 1, επομένως θέτει dist 1 = rounds (τόσοι γύροι απαιτήθηκαν ώστε να φτάσει το μήνυμα από τον αμέσως προηγούμενο κόμβο με ID 1, άρα το dist 1 υπολογίζεται σωστά). Αντίστοιχα, αν το counter γίνει ίσο με 2, τότε εντοπίστηκε ο αμέσως επόμενος κόμβος με ID ίσο με 1, επομένως θέτει dist 2 = rounds. Αν το counter γίνει ίσο με 3, τότε η διεργασία έλαβε το μήνυμα που έστειλε η ίδια, άρα μπορεί να υπολογίσει το πλήθος των κόμβων του δικτύου (n = rounds). Επομένως, μετά το τέλος του γύρου n, κάθε διεργασία i έχει όλη την πληροφορία που χρειάζεται σχετικά με το δίκτυο ώστε να μπορεί να υπολογίσει τις αποστάσεις a ij, a jk, a ki. Συγκεκριμένα, a ij = n dist 2, a jk = dist 2 dist 1, a ki = dist 1. Αν το a jk είναι το μοναδικό μέγιστο, τότε αποφασίζει ότι είναι αρχηγός. Αν a ij = a ki > a jk τότε και πάλι αποφασίζει ότι είναι αρχηγός. Διαφορετικά αποφασίζει ότι δεν είναι αρχηγός. Η χρονική πολυπλοκότητα του αλγορίθμου είναι ακριβώς n γύροι. Κάθε διεργασία με ID 1 στέλνει 1 μήνυμα που ταξιδεύει σε όλο το δακτύλιο, άρα η πολυπλοκότητα επικοινωνίας είναι 3n = O(n). Άσκηση 3. Να αποδείξετε την ορθότητα του αλγορίθμου SynchBFS. (Υπόδειξη: δείξτε με επαγωγή ότι, μετά από r γύρους, κάθε διεργασία σε απόσταση d από τη ρίζα, όπου 1 d r, έχει ορίσει το γονέα της, ο οποίος βρίσκεται σε απόσταση d 1 από τη ρίζα.) 3
Λύση. Επαγωγική βάση: Μετά από r = 1 γύρους, κάθε διεργασία σε απόσταση d = 1 από τη ρίζα (δηλαδή οι άμεσοι γείτονες της ρίζας) έχουν ορίσει το γονέα τους, που είναι η ρίζα, η οποία βρίσκεται σε απόσταση d 1 = 0 από τη ρίζα, επομένως για r = 1 ισχύει. Επαγωγική υπόθεση: Έστω ότι, μετά από r = k γύρους, κάθε διεργασία σε απόσταση d από τη ρίζα, όπου 1 d k, έχει ορίσει το γονέα της, ο οποίος βρίσκεται σε απόσταση d 1 από τη ρίζα. Επαγωγικό βήμα: Μετά από r = k + 1 γύρους, κάθε διεργασία σε απόσταση 1 d k από τη ρίζα έχει ορίσει το γονέα της, ο οποίος βρίσκεται σε απόσταση d 1 από τη ρίζα (ισχύει από την επαγωγική υπόθεση). Μένει να εξετάσουμε τις διεργασίες σε απόσταση ακριβώς k + 1 από τη ρίζα. Κάθε τέτοια διεργασία v έχει τουλάχιστον ένα γείτονα u σε απόσταση k από τη ρίζα. Άρα, από την επαγωγική υπόθεση, μετά από k γύρους κάθε τέτοια κορυφή u έχει ορίσει το γονέα της στο δέντρο. Άρα στο γύρο k + 1 κάθε γειτονική κορυφή u της v σε απόσταση k από τη ρίζα στέλνει μήνυμα αναζήτησης στους γείτονές της, άρα και στη v, και τότε η v θέτει ως γονέα της μία από αυτές τις κορυφές u, που βρίσκεται σε απόσταση d 1 = k από τη ρίζα. Άσκηση 4. Υποθέστε ότι οι διεργασίες ενός σύγχρονου κατανεμημένου συστήματος είναι συνδεδεμένες σε συνεκτικό μη κατευθυνόμενο δίκτυο. Οι διεργασίες δεν γνωρίζουν τίποτα για το δίκτυο εκτός από τους γείτονές τους (δηλαδή δε γνωρίζουν το μέγεθος n, τη διάμετρο, ή κάτι άλλο σχετικά με την τοπολογία του δικτύου) και έχουν UIDs. Μια διακεκριμένη διεργασία i 0 επιθυμεί να στείλει ένα μήνυμα σε κάθε άλλη διεργασία του δικτύου, και να λάβει κάποια διαβεβαίωση (acknowledgement) ότι όλες οι διεργασίες έλαβαν το μήνυμα. Να περιγράψετε έναν κατανεμημένο αλγόριθμο (όσο πιο αποδοτικό μπορείτε) για το πρόβλημα, να δώσετε τον ψευδοκώδικα, και να αναλύσετε τη χρονική πολυπλοκότητα και την πολυπλοκότητα επικοινωνίας του. Λύση. Η διεργασία i 0 ξεκινάει έναν αλγόριθμο SynchBFS με ρίζα τον εαυτό της. Ουσιαστικά εδώ το μήνυμα αναζήτησης (που χρησιμοποιεί ο SynchBFS) είναι το μήνυμα που επιθυμεί να στείλει η i 0. Αφού κατασκευαστεί το δένδρο BFS, ξεκινώντας από τα φύλλα, κάθε διεργασία στέλνει στο γονέα της ένα μήνυμα διαβεβαίωσης (ACK). Κάθε διεργασία, όταν λάβει ACK από όλα τα παιδιά της, στέλνει ACK στο γονέα της. Έτσι όταν η ρίζα λάβει ACK από όλα τα παιδιά της γνωρίζει ότι το μήνυμα έχει φτάσει σε κάθε άλλη διεργασία του δικτύου. Ο αλγόριθμος απαιτεί τόσους γύρους όση η ακτίνα της i 0 επί δύο (για να σταλεί και το μήνυμα και το ACK), άρα η χρονική πολυπλοκότητα είναι O(diam), όπου diam είναι η διάμετρος του δικτύου. Ο αλγόριθμος SynchBFS απαιτεί O(m) μηνύματα (όπου m είναι το πλήθος των πλευρών του δικτύου), ενώ στέλνονται επιπλέον n 1 μηνύματα ACK (ένα για κάθε πλευρά του δένδρου), άρα η πολυπλοκότητα επικοινωνίας είναι O(n + m). Για τον ψευδοκώδικα του αλγορίθμου, έστω m M το μήνυμα που θέλει να στείλει η i 0. Χρησιμοποιούμε τη δυαδική μεταβλητή mode, η οποία γίνεται 1 μόνο όταν μια διεργασία είναι έτοιμη να στείλει acknowledgement στο γονέα της (άρα έχει λάβει acknowledgements από όλα τα παιδιά της). 4
Το αλφάβητο των μηνυμάτων αποτελείται από δυάδες < uid, m > και από τα μηνύματα ACK, CHILD. states i msgs i trans i parent, ένα UID, αρχικά NULL. Αν i = i 0 (η ρίζα) τότε, αρχικά, parent := u. marked, boolean, αρχικά false. Aν i = i 0 τότε, αρχικά, marked := true. first_time_marked, boolean, αρχικά false. send, ένα UID ή NULL, αρχικά NULL. Aν i = i 0 τότε, αρχικά, send := u. children, ένας ακέραιος, αρχικά 0 acks, ένας ακέραιος, αρχικά 0 mode {0, 1}, αρχικά 0 στείλε το send σε κάθε γείτονα if first_time_marked = true then στείλε CHILD στον parent if mode = 1 then στείλε ACK στον parent send := NULL mode := 0 if marked = false and το σύνολο των εισερχόμενων μηνυμάτων είναι < u i, m > για i U, ένα υποσύνολο UIDs, then επίλεξε τυχαία ένα v U και θέσε parent = v marked := true f irst_time_marked := true send :=< u, m > else if first_time_marked = true f irst_time_marked := false if έλαβες k εισερχόμενα μηνύματα CHILD then children = k if children = 0 then mode := 1 else if έλαβες k εισερχόμενα μηνύματα ACK then acks := acks + k if acks = children then mode := 1 5
Άσκηση 5. Για τον αλγόριθμο RandomAttack, να αποδείξετε ότι: Λύση. Αν κάποια διεργασία έχει αρχική τιμή 0, τότε το 0 είναι η μόνη δυνατή απόφαση. Αν το πολύ ένα μήνυμα χάνεται, τότε η πιθανότητα συντονισμένης επίθεσης (δηλαδή όλες οι διεργασίες να αποφασίσουν 1) είναι τουλάχιστον r 1 r (όπου r είναι ο γύρος στο τέλος του oποίου αποφασίζουν οι διεργασίες). Έστω ότι υπάρχει διεργασία i που αποφασίζει 1. Αυτό συμβαίνει αν και μόνο αν το επίπεδο πληροφόρησης της i είναι level i key και γνωρίζει ότι όλες οι αρχικές τιμές είναι 1. Εφόσον όμως υπάρχει διεργασία j με αρχική τιμή 0, η τελευταία συνθήκη δεν μπορεί να ισχύει. Άρα όλες οι διεργασίες αποφασίζουν 0. Εξετάζουμε την περίπτωση όπου όλες οι τιμές εισόδου είναι 1 (διαφορετικά η μόνη δυνατή απόφαση είναι το 0). Αν δεν χαθεί κάποιο μήνυμα, τότε (από τη 2η συνθήκη εγκυρότητας του RandomAttack) όλες οι διεργασίες αποφασίζουν 1. Έστω τώρα ότι χάνεται ένα ακριβώς μήνυμα. Πιο συγκεκριμένα, υποθέτουμε ότι στο γύρο s r χάνεται το μήνυμα από τη διεργασία i προς τη διεργασία j. Μέχρι και το τέλος του γύρου s 1 τα επίπεδα πληροφόρησης όλων των διεργασιών είναι ακριβώς s 1 (αφού δεν έχει χαθεί κάποιο μήνυμα). Στο τέλος του γύρου s τα επίπεδα πληροφόρησης όλων των διεργασιών εκτός της j είναι s, ενώ το επίπεδο πληροφόρησης της j παραμένει s 1. Αν s < r 1 τότε, στο γύρο s+1 < r (όπου δεν θα χαθεί κανένα μήνυμα), τα επίπεδα πληροφόρησης όλων των διεργασιών εκτός της j παραμένουν s, ενώ το επίπεδο πληροφόρησης της j γίνεται s + 1. Στον επόμενο γύρο s + 2 τα επίπεδα πληροφόρησης των διεργασιών γίνονται s + 1, και συνεχίζουν να αυξάνονται σε κάθε επόμενο γύρο μέχρι τον τελευταίο. Άρα στο τέλος θα είναι όλα ίσα με r 1. Στην περίπτωση αυτή δεν υπάρχει πιθανότητα διαφωνίας. Σύμφωνα με τον κανόνα απόφασης του αλγορίθμου, μια διεργασία αποφασίζει 1 αν και μόνο αν γνωρίζει ότι όλες οι αρχικές τιμές είναι 1 και το επίπεδό της είναι τουλάχιστον όσο το key. Άρα, εφόσον όλα τα επίπεδα είναι ίσα, όλες οι διεργασίες θα αποφασίσουν την ίδια τιμή (1 αν key r 1 και 0 διαφορετικά). Άρα η πιθανότητα να αποφασίσουν όλες 0 είναι η πιθανότητα το key να είναι μεγαλύτερο από r 1, άρα ίση με την πιθανότητα το key να είναι ακριβώς ίσο με r (το key είναι τυχαία μεταβλητή, ομοιόμορφα κατανεμημένη στο {1, 2,..., r}). Αν s = r 1 τότε, στο γύρο s+1 = r (όπου δεν θα χαθεί κανένα μήνυμα), τα επίπεδα πληροφόρησης όλων των διεργασιών εκτός της j παραμένουν s = r 1, ενώ το επίπεδο πληροφόρησης της j γίνεται r. Άρα στο τέλος τα επίπεδα πληροφόρησης όλων των διεργασιών εκτός της j θα είναι r 1 ενώ της j θα είναι r. Απομένει η περίπτωση s = r. Τότε, στο τέλος του αλγορίθμου, τα επίπεδα πληροφόρησης όλων των διεργασιών εκτός της j είναι r, ενώ το επίπεδο πληροφόρησης της j είναι r 1. Στις τελευταίες δύο περιπτώσεις, κάθε διεργασία έχει επίπεδο πληροφόρησης είτε r είτε r 1 (και υπάρχει πάντα τουλάχιστον μία διεργασία από κάθε κατηγορία!). Σύμφωνα με τον κανόνα απόφασης 6
του αλγορίθμου, όσες διεργασίες έχουν επίπεδο r θα αποφασίσουν 1 (αφού το key είναι το πολύ r). Η πιθανότητα να υπάρχει διεργασία που να αποφασίζει 0 ισούται με την πιθανότητα μια διεργασία με επίπεδο r 1 να αποφασίσει 0, δηλαδή με την πιθανότητα key > r 1, δηλαδή είναι και πάλι ίση με την πιθανότητα το key να είναι ίσο με r. Επομένως σε κάθε περίπτωση, η μόνη δυνατή τιμή για το key που μπορεί να οδηγήσει μια διεργασία να αποφασίσει 0 είναι η key = r. Άρα Pr{υπάρχει διεργασία που αποφασίζει 0} = Pr{key > r 1} = Pr{key = r} = 1 r. Επομένως Pr{ όλες οι διεργασίες αποφασίζουν 1} = 1 Pr{υπάρχει διεργασία που αποφασίζει 0} = 1 1 r = r 1 r. 7