Πέμπτη, Νοεμβρίου 29, 2007

Αλγόριθμοι και υπολογιστές

Αφού πήρα την άδεια του κ. Γυφτοδήμου για το c(λ)opyright, ανεβάζω μερικές πολύ ενδιαφέρουσες απαντήσεις σε εξίσου ενδιαφέρουσες ερωτήσεις (της Κατερίνας). Λόγω όγκου, θα ανεβούν σε δόσεις. Ακολουθεί σεντόνι...


1. Τι εννοούμε λέγοντας αλγοριθμική επεξεργασία;

Αλγόριθμος είναι η επίλυση ενός προβλήματος, με τρόπο ώστε να την πετυχαίνουμε ακολουθώντας συγκεκριμένα βήματα υπολογισμών (τουλάχιστον ένα) που είναι βέβαιο πως είναι δυνατό να εκτελεστούν. Δηλαδή, ένας αλγόριθμος αποτελείται από διαδοχικά βήματα, κατά τα οποία εφαρμόζουμε συγκεκριμένες πράξεις ή/και δράσεις πάνω στα δεδομένα (πράξεις και δράσεις που δεν είναι τίποτα άλλο από στοιχειώδεις αλγόριθμοι).

Με άλλα λόγια, είναι ένας προκαθορισμένος τρόπος (μέθοδος, διαδικασία) που κατά την εκτέλεσή του δέχεται κάποια δεδομένα (είσοδος) και υπολογίζει βήμα – προς – βήμα το ή τα ζητούμενα αποτελέσματα (έξοδος). Η επεξεργασία των δεδομένων εισόδου από αλγόριθμο είναι η αλγοριθμική επεξεργασία. Αυτές οι πράξεις και δράσεις μετασχηματίζουν, αποθηκεύουν, μεταφέρουν δεδομένα ή παράγουν άλλα, κατά τη διάρκεια της εκτέλεσης του αλγόριθμου. Τα βήματα πρέπει να είναι πεπερασμένου πλήθους, και ο αλγόριθμος είναι ορθός όταν η εκτέλεση τερματίζεται με τελικό βήμα αυτό που ολοκληρώνει αυτό που θεωρούμε ως λύση στο πρόβλημα.

Συνθετικά, αξιοποιούμε πολύ τη δυνατότητα να δίνει ένας αλγόριθμος την έξοδό του ως είσοδο σε άλλον αλγόριθμο. Μπορούμε έτσι να σχηματίζουμε αλγόριθμους που έχουν τη μορφή αλυσίδας αλγόριθμων, ή ακόμα συνθετότερα, αν έχουμε αλγόριθμους με περισσότερες εισόδους, να σχηματίζουμε αλγόριθμους που έχουν τη μορφή δένδρου, με υπολογισμό που αρχίζει από τα φύλλα - δεδομένα, προχωρά ανεβαίνοντας κλάδους προς τη ρίζα – τελικό ζητούμενο, ακολουθώντας μια πορεία που καθορίζεται από τον τρόπο διασύνδεσης (τι δίνει τι, σε ποιόν, και με ποια διαδοχή).

Πολλά πλεονεκτήματα μας δίνει το να διαθέτουμε αλγόριθμο επίλυσης για κάποιο πρόβλημα: Βασικό είναι η επαναχρησιμοποίηση του αλγόριθμου σε ίδιο πρόβλημα με εκτέλεση πάνω σε άλλα δεδομένα. Επίσης, επαναχρησιμοποίηση στα πλαίσια άλλων αλγόριθμων, ευρύτερα από την κατασκευή αλυσίδων ή δένδρων: αν έχουμε ένα σύνολο αλγόριθμων που λύνουν βασικά προβλήματα, μπορούμε να τους χρησιμοποιούμε και ως προκατασκευασμένα τμήματα (στοιχειοποιημένα, όπως λέγονται) για να σχηματίσουμε συνθετότερους αλγόριθμους (όπως τους προετοιμασμένους τοίχους σε μια "προκάτ" οικοδομή: χρησιμοποιούνται οι στοιχειώδεις αλγόριθμοι "πρόσοψη", "πλαϊνός_τοίχος", "πίσω_τοίχος", "ταβάνι" για την κατασκευή των τμημάτων, και το συνολικό σχέδιο της οικοδομής είναι ο σύνθετος αλγόριθμος "σπίτι" που συνθέτεται από τα βήματα που χρησιμοποιούν και συνδέουν τα τμήματα που παράγουν οι στοιχειώδεις αλγόριθμοι. Η εκτέλεση του αλγόριθμου "σπίτι" καλεί για εκτέλεση τον κατάλληλο στοιχειώδη αλγόριθμο όποτε χρειαστεί το αντίστοιχο τμήμα).

Παράδειγμα κατ' αναλογία: Μια μηχανή που φτιάχνει κονσέρβες λειτουργεί ενεργοποιώντας διάφορες επί μέρους διαδικασίες συνθετικά (μια κεντρική, κύρια διαδικασία παίρνει αυτά που χρειάζεται από άλλες, ενεργοποιώντας την εκτέλεσή τους την κατάλληλη στιγμή ώστε να τα έχουν ήδη παράγει όταν χρειαστούν, που σημαίνει κλήση προς εκτέλεση των υπο-αλγόριθμων στα κατάλληλα βήματα του κύριου αλγόριθμου) .

Για να έχουμε αλγοριθμική επεξεργασία πρέπει βέβαια να διαθέτουμε κατάλληλο αλγόριθμο, αλλιώς οφείλουμε να τον κατασκευάσουμε. Όταν διαθέτουμε τα δεδομένα και ξέρουμε τι ζητάμε (δηλ. όταν έχουμε θέσει το πρόβλημα) αλλά δεν έχουμε ακόμα σαφή επίγνωση του τρόπου υπολογισμού των ζητουμένων (δηλ. δεν έχουμε βρει ακόμα την επίλυση), προσπαθούμε να εντοπίσουμε ένα κατάλληλο αλγόριθμο. Μερικές φορές εργαζόμαστε απλά "βλέποντας και κάνοντας", κατασκευάζοντας αρχικά ένα -συνήθως ατελή- αλγόριθμο, και προσθέτουμε ή διορθώνουμε στοιχεία του προς το ορθότερο, το καλύτερο, το πληρέστερο για το σκοπό που έχουμε, μέχρι να πετύχουμε ένα ικανοποιητικό αποτέλεσμα. Άλλοτε, ακολουθούμε μια πιο αυστηρή πορεία, όπως να αναλύουμε το πρόβλημα σε μέρη απλούστερα (από το ζητούμενο, προς τις απαιτήσεις που θέτει, κοκ. μέχρι τα προφανή) και μετά, με οδηγό αυτή την ανάλυση, να ακολουθούμε συνθετικά την αντίστροφη πορεία για να κατασκευάσουμε τον αλγόριθμο: αρχίζοντας από τα δεδομένα και συνθέτοντάς τα κατά βήματα, να καταλήγουμε στο ζητούμενο.Σημαντικό είναι ότι, κάποιες φορές, έχοντας κατασκευάσει ένα αλγόριθμο, παρατηρώντας εκ των υστέρων το αποτέλεσμα όπως και ολόκληρη την πορεία υπολογισμού του, ανακαλύπτουμε πως θα μπορούσαμε να εξάγουμε και άλλα αποτελέσματα, αξιοποιώντας καλύτερα τα δεδομένα μας ή χρησιμοποιώντας και άλλα που γνωρίζαμε αλλά δεν είχαμε σκεφτεί πως θα ήταν χρήσιμα. Τότε προχωράμε σε μια εξελικτική αναδιαμόρφωση του αλγόριθμου. Η εξελικτική προγραμματιστική προσέγγιση ενσωματώνει στην αναζήτηση της λύσης του προβλήματος και την προοπτική να αναδιαμορφώνουμε (γενικεύουμε, διευρύνουμε...) και το ζητούμενο, ανάλογα με το τι βλέπουμε από την εκτέλεση τού μέχρι στιγμής ανεπτυγμένου κώδικα.

Επίσης, μπορούμε να χρησιμοποιήσουμε ένα αλγόριθμο ως βασική ιδέα για την κατασκευή άλλου αλγόριθμου, για να λύσουμε πρόβλημα που "κάπως μοιάζει". Εδώ παίζει ρόλο η εμπειρία μας και η διαίσθηση, ακριβώς όπως παίζει ρόλο να έχουμε λύσει πολλά προβλήματα Γεωμετρίας για να λύσουμε ένα νέο. Η λεγόμενη "δοκιμή και σφάλμα" (trial and error) πορεία ανάπτυξης βοηθά πολύ στην ανάπτυξη του κώδικα, διότι το σφάλμα δείχνει όχι μόνο ότι κάτι φταίει, αλλά και τι φταίει.

Αν κατά την εξελικτική ανάπτυξη του προγράμματος πετυχαίνουμε και την εισαγωγή κώδικα κατά τη διάρκεια της εκτέλεσης (δηλ. χωρίς να περιμένουμε τερματισμό της εκτέλεσης για να περάσουμε στον editor του πηγαίου κώδικα, οπότε χρειάζεται και επανεκκίνηση από την αρχική κατάσταση) έχουμε τη δυναμική εξέλιξη. Αυτό σημαίνει:

Η εκτέλεση ξεκινά από μια κατάσταση Α για το χώρο αληθειών του προγράμματος, και τα βήματα (δυνητικά) μεταβάλλουν αυτή την κατάσταση. Αν σε κάποια φάση της εκτέλεσης έχει δημιουργηθεί η κατάσταση Β και τότε γίνει η επέμβαση εισαγωγής κώδικα που προκαλεί μεταβολή της Β στην κατάσταση Γ, να συνεχιστεί μετά η εκτέλεση από την κατάσταση Γ. Αυτού του είδους η λειτουργικότητα προγράμματος ακολουθεί, μοιάζει με, τον τρόπο που συνήθως κάτι λειτουργεί και εξελίσσεται στην πραγματικότητα, εξέλιξη που προκαλεί είτε η ίδια του τη λειτουργία ή κάποια εξωτερική επέμβαση.


2. Τι εννοούμε λέγοντας αλγόριθμοι που επεξεργάζονται δομές;

Οι αλγόριθμοι δεν επεξεργάζονται μόνον απλά δεδομένα, πχ. 3 , 3.14 , "Μαρία" , "Κώστας" (ως strings) αλλά και σύνθετα, όπως η δομή της λίστας, πχ. (1 2 3), ((1 2) (2 3)), η δομή της κλάσης, πχ. "αυτοκίνητο" που έχει "εργοστάσιο" , "τύπο", "κυβισμό", "ιπποδύναμη", το ειδικό αντικείμενο "αυτοκίνητο του Γιάννη" που επί πλέον από τα χαρακτηριστικά τύπου αυτοκινήτου έχει "ιδιοκτήτη", "αριθμό κυκλοφορίας". Για να είναι δυνατή η επεξεργασία κάποιου σύνθετου δεδομένου πρέπει αυτό να είναι εκφρασμένο στη μορφή (καλούπι) κάποιας συγκεκριμένης δομής, ώστε ο αλγόριθμος που θα επεξεργαστεί το εν λόγω δεδομένο να μπορεί να την αναγνωρίσει, με σκοπό να μπορεί να επεξεργάζεται και άλλα δεδομένα που έχουν την ίδια δομή. Έτσι θα μπορεί να αναγνωρίζει τα επί μέρους στοιχεία - δεδομένα, είτε σύμφωνα με τη θέση που έχουν στη δομή (πχ. "το τρίτο στοιχείο λίστας", είτε σύμφωνα με τη συσχέτιση που έχουν με άλλα στοιχεία της δομής (πχ. να αποδώσουμε τη δομή "αυτοκίνητο" ως "σύμβολο με ιδιότητες" και το όνομα του ιδιοκτήτη να ακολουθεί την ιδιότητα "ιδιοκτήτης") .

Μια δομή δεν εκφράζει μόνο μια τυπική σύνθετη μορφή ώστε να είναι επεξεργάσιμη, αλλά παριστά και κάποια πραγματική κατάσταση, και σ' αυτό παίζει διπλό ρόλο: να το αναγνωρίζει ο υπολογιστής, και να το αναγνωρίζει ο άνθρωπος. Σ' αυτό μπορούμε να βασίσουμε την νοηματική επικοινωνία ανθρώπου – μηχανής.


3. Τι σημαίνει συμπεριφορά οντοτήτων;

Κατά την κατασκευή προγράμματος μπορούμε εννοιολογικά να προσδιορίσουμε κάποια στοιχεία ως οντότητες: το στοιχείο "Γιάννης" είναι σκόπιμο να το θεωρούμε ως οντότητα, διότι σημασιολογικά είναι κάτι ιδιαίτερο και αυτόνομο που έχει, αποκτά ή χάνει συνδέσεις με άλλες οντότητες (πχ. έχει αυτοκίνητο τάδε, είναι παντρεμένος με τη Μαίρη, κλπ.). Το αυτοκίνητο του Γιάννη επίσης είναι οντότητα (έχει μηχανή τέτοια, ζάντες τάδε, λάστιχα τάδε...), αλλά δεν έχει νόημα οντότητας ο "κυβισμός του αυτοκινήτου", που είναι απλά ένα κοινό χαρακτηριστικό. Δεν έχουμε κάτι το φορμαλιστικό που να ξεχωρίζει "τι είναι οντότητα και τι όχι".

Αν έχουμε ένα αλγόριθμο (συνάρτηση) που δέχεται ως είσοδο μια ή περισσότερες οντότητες, και τις επεξεργάζεται με τρόπο ώστε, ανάλογα με τις συνδέσεις που έχουν και τα χαρακτηριστικά τους, κατά την εκτέλεση να προκαλεί αποτελέσματα που φαινομενικά να δείχνουν πως προέρχονται από τις οντότητες, τότε έχουμε αυτό που μπορούμε να ονομάσουμε "συμπεριφορά των οντοτήτων". Πχ, το ρομπότ – σκυλάκι της Sony που "του μιλάς και γαβγίζει", ή "το χαϊδεύεις και κουνά την ουρά του", είναι μια "οντότητα με συμπεριφορά". Γενικά, μια σύνθετη οντότητα η οποία κατά την ένταξή της (ως τιμή εισόδου) σε κάποια λειτουργία (δηλ. εκτέλεση αλγόριθμου) παρουσιάζει εξειδικευμένη προς τη λειτουργία αντίδραση, προκαλεί αποτελέσματα που τα χαρακτηρίζουμε ως "συμπεριφορά" διότι έρχονται ως συγκεκριμένη αντίδραση σε συγκεκριμένα ερεθίσματα (με την προϋπόθεση ότι εμείς το αναγνωρίζουμε αυτό ως άμεση σχέση αιτίου – αποτελέσματος).


4. Τι είναι compiler της γλώσσας;

Εδώ φταίει το ότι δεν αρχίσαμε το μάθημα από το πρώτο τεύχος, το θεώρησα ήδη γνωστό αφού έχετε περάσει το αντίστοιχο μάθημα στην εισαγωγή σας στο Τμήμα.

Μια αλγοριθμική γλώσσα είναι μια γλώσσα ικανή για να εκφράσει κανείς οποιονδήποτε αλγόριθμο. Τυπικά, αλγόριθμος είναι αυτό που μπορεί να αποδοθεί ως όρος σε μια από τις (ισοδύναμες) θεωρίες αλγόριθμων. Μια τέτοια θεωρία, που έκανε πάταγο όταν προτάθηκε από τον Turing πριν 60 χρόνια, είναι η λεγόμενη "μηχανή Turing" (το θεωρητικό μαθηματικο-μηχανικό ανάλογο του υπολογιστή) όπου τελικά δέχτηκε ο Turing ότι αλγόριθμος είναι είτε μια μηχανή Turing είτε η Αφηρημένη Μηχανή Turing (βρήκε ότι κάτι έλειπε από την απλή μηχανή Turing…). Μια -κατά τη γνώμη μου- πιο οργανωμένη πρακτικά και θεωρητικά προσέγγιση της έννοιας αλγόριθμος είναι η έννοια της λ-έκφρασης, σύμφωνα με τη θεωρία του λ-λογισμού (στοιχεία σχετικά βρίσκονται στο τέλος των σημειώσεων για τη Scheme).

Γλώσσα μηχανής είναι η αλγοριθμική γλώσσα που έχει οργανώσει ο κατασκευαστής κάθε τύπου επεξεργαστή (η καρδιά του υπολογιστή), και είναι η μόνη γλώσσα που ο υπολογιστής "καταλαβαίνει". Στη γλώσσα αυτή τα πάντα είναι πεπερασμένες ακολουθίες από μονάδες και μηδενικά, και είναι ακατανόητη για τον άνθρωπο (εκτός βέβαια αν είναι ειδικός). Οτιδήποτε εκφράζουμε προς τον υπολογιστή πρέπει να "μεταφραστεί" στη γλώσσα αυτή, και αυτό το αναλαμβάνουν οι γλώσσες προγραμματισμού.

Μια αλγοριθμική γλώσσα προγραμματισμού (διότι έχουμε και μη αλγοριθμικές γλώσσες προγραμματισμού: η Prolog, που θα δούμε στο β' εξάμηνο, για όποιον αντέχει την Πληροφορική...) είναι μια γλώσσα που εκτός από γλώσσα έκφρασης αναλαμβάνει και το να "μεταφράσει" τον αλγόριθμο που γράφουμε, σε γλώσσα μηχανής. Η "μετάφραση" αυτή λέγεται μεταγλώττιση (compilation), για να διακρίνεται από τη συνήθη έννοια του όρου μετάφραση, που είναι η μεταφορά από μια γλώσσα έκφρασης σε άλλη, ενώ η γλώσσα μηχανής δεν χρησιμοποιείται ως γλώσσα έκφρασης από τον άνθρωπο. Τη μεταγλώττιση την αναλαμβάνει ένας μηχανισμός (που είναι επίσης αλγόριθμος) που λέγεται compiler, εξειδικευμένος για το συγκεκριμένο τύπο επεξεργαστή και το χρησιμοποιούμενο λειτουργικό σύστημα. Ο compiler παίρνει ως είσοδο το πρόγραμμά μας (πηγαίο κώδικα) και δίνει έξοδο το μεταφρασμένο σε γλώσσα μηχανής, το λεγόμενο "δυαδικό κώδικα", που είναι εκτελέσιμο από τη γλώσσα μηχανής.

Ο υπολογιστής "γνωρίζει" τη γλώσσα μηχανής (ως ενσωματωμένο ηλεκτρονικό κύκλωμα) αλλά δεν αρκεί αυτό για τη λειτουργία, χρειάζεται και το λειτουργικό σύστημα, που είναι ένα σύνολο προγραμμάτων σε δυαδικό κώδικα με τα οποία αποκτά συγκεκριμένες λειτουργικές ικανότητες (για να αποφύγουμε τη λέξη "μαθαίνει"...) όπως: από ποια μονάδα διαβάζει δεδομένα, σε ποια βασική μορφή πρέπει να είναι καταχωρημένα, σε ποια μονάδα γράφει, κλπ.

Ο δυαδικός; κώδικας του προγράμματός μας εκτελείται από το σύστημα (υπολογιστής + λειτουργικό σύστημα) όταν ζητηθεί αυτό.

Ο compiler κάνει επίσης έλεγχο σφαλμάτων σύνταξης του αλγόριθμου, ενώ με την εκτέλεση γίνεται έλεγχος των λογικών σφαλμάτων.


Γ. Γυφτοδήμος

Δεν υπάρχουν σχόλια: