Κεφάλαιο 5 Αξιωματική Σημασιολογία και Απόδειξη Ορθότητας Προγραμμάτων Προπτυχιακό μάθημα Αρχές Γλωσσών Προγραμματισμού Π. Ροντογιάννης 1
Εισαγωγή Τα προγράμματα μιας (κλασικής) γλώσσας προγραμματισμού αποτελούνται από εντολές (ανάθεσης, επανάληψης κλπ) Βασικός σκοπός του κεφαλαίου αυτού είναι η μελέτη της τεχνικής των Floyd- Hoare για απόδειξη ορθότητας τέτοιων προγραμμάτων. 2
Κανόνες Το συντακτικό που θα εξετασθεί είναι το: C ::= skip ( C ) i := E C o ; C 1 while B do C if B then C o else C 1 3
Τεχνική Floyd - Hoare Ο C.A.R. Hoare εισήγαγε τον συμβολισμό για τον καθορισμό του τι κάνει ένα πρόγραμμα: {P} C {Q} όπου C είναι το πρόγραμμα της γλώσσας που μελετάται και P και Q συνθήκες, που σχετίζονται με μεταβλητές που χρησιμοποιεί το C 4
Συνθήκη Αποτελεί έκφραση μιας απλής λογικής γλώσσας Περιέχει μεταβλητές του προγράμματος, σταθερές, λογικούς τελεστές κλπ Όταν προηγείται μιας εντολής περιγράφει περιορισμούς για μεταβλητές του προγράμματος σε εκείνο το σημείο Όταν ακολουθεί εντολή περιγράφει τους νέους περιορισμούς για τις μεταβλητές, μετά την εκτέλεση της εντολής Εκφράσεις της μορφής {P} C {Q} ονομάζονται προδιαγραφές (specifications) 5
Ορισμός 5.1 Μία προδιαγραφή {P} C {Q} είναι αληθής εάν όταν το C εκτελείται σε μία κατάσταση που ικανοποιεί τη συνθήκη P και αν η εκτέλεση του C τερματίζει, τότε στην κατάσταση στην οποία καταλήγει το πρόγραμμα, ικανοποιείται η συνθήκη Q 6
Ορισμός 5.1 Οι προδιαγραφές ονομάζονται και τύποι μερικής ορθότητας διότι η απόδειξη του ότι ένα πρόγραμμα τερματίζει θεωρείται ξεχωριστή διαδικασία, που πρέπει να εξετάσει ο προγραμματιστής, για να είναι βέβαιος για την ορθότητα του προγράμματος του. 7
Παράδειγμα 5.1 Η προδιαγραφή: { Χ = 1 } Χ:= Χ + 1{ Χ = 2 } είναι αληθής. Το σύμβολο = είναι η γνωστή μας μαθηματική ισότητα. 8
Παράδειγμα 5.2 Η προδιαγραφή: { Χ = 1 } Y:= Χ { Y = 1 } είναι αληθής. 9
Παράδειγμα 5.3 Η προδιαγραφή: { Χ = 1 } Y:= Χ + 1{ X = 2 } είναι ψευδής. 10
Παράδειγμα 5.4 Η προδιαγραφή: { Χ = x Y = y} R:= Χ ; X := Y ; Y:= R{ X = y Y = x } είναι αληθής. Οι μεταβλητές x και y, που εμφανίζονται στις συνθήκες, αλλά όχι στην εντολή, ονομάζονται βοηθητικές μεταβλητές. Σκοπός τους είναι να δώσουν όνομα στις αρχικές τιμές των Χ και Υ αντίστοιχα. 11
Παράδειγμα 5.5 Η προδιαγραφή: { true}c{q} Είναι αληθής, εάν όταν το πρόγραμμα C τερματίζει, ισχύει η συνθήκη Q. 12
Παράδειγμα 5.6 Η προδιαγραφή: {P} C {true} είναι πάντα αληθής για κάθε αρχική συνθήκη Ρ και κάθε εντολή C. 13
Τεχνική Floyd-Hoare Δημιουργία τυπικών αποδείξεων για προδιαγραφές προγραμμάτων Χρήση αξιωμάτων και κανόνων εξαγωγής συμπερασμάτων, που υποστηρίζει η τεχνική θεωρημάτων κλασσικών μαθηματικών 14
Διαφορά Αξιωμάτων και Κανόνων Αξίωμα είναι μία λογική πρόταση για την οποία υποθέτουμε ότι είναι αληθής Κανόνας εξαγωγής συμπερασμάτων είναι μία μέθοδος, που χρησιμοποιείται για να δείξουμε ότι μία προδιαγραφή είναι αληθής με την υπόθεση ότι άλλες προδιαγραφές είναι αληθείς 15
Αξίωμα του skip Η εντολή skip δε μεταβάλλει οποιαδήποτε συνθήκη ισχύει πριν από την εκτέλεση της {P} skip {P} 16
Κανόνας των παρενθέσεων Εάν ισχύει το {P} C {R} τότε μπορούμε να εξάγουμε ως συμπέρασμα και το {P} (C) {R} 17
Αξίωμα Εντολής Ανάθεσης Αναπαριστά το γεγονός ότι η τιμή μιας μεταβλητής V μετά από την εκτέλεση της εντολής ανάθεσης V:=E ισούται με την τιμή της έκφρασης Ε στην κατάσταση πριν την εκτέλεση της εντολής. 18
Αξίωμα Εντολής Ανάθεσης Το αξίωμα είναι: {Ρ[Ε/V]} V := E {P} Όπου V μεταβλητή, Ε έκφραση, Ρ συνθήκη και Ρ[Ε/V] το αποτέλεσμα της αντικατάστασης όλων των εμφανίσεων της μεταβλητής V στην Ρ με Ε. 19
Παράδειγμα 5.7 Εφαρμογή του αξιώματος της Εντολής Ανάθεσης {Χ+1 = n+1} X := X+1 {X = n+1} Όπως και {Ε=Ε} Χ:= Ε {Χ=Ε} αν το Χ δεν εμφανίζεται στο Ε 20
Μορφή Μία συχνή παρανόηση είναι ότι το αξίωμα Ανάθεσης θα έπρεπε να είναι: {Ρ}V:=E{P[Ε/V]} Είναι όμως λανθασμένο, γιατί θα έδινε προδιαγραφές: {X=0}X:=1{1=0} Το (σωστό) αξίωμα Ανάθεσης δεν ισχύει (σε αυτή τη μορφή) για πιο πολύπλοκες προστακτικές γλώσσες προγραμματισμού. 21
Κανόνας Ενδυνάμωσης της Προσυνθήκης Εάν ισχύει το P R καθώς και το {R}C{Q} τότε μπορούμε να εξάγουμε ως συμπέρασμα και το {Ρ}C{Q} 22
Παράδειγμα 5.8 {Χ+1 = n+1} X := X+1{X = n+1} Επίσης και (Χ+1= n+1) (X=n) Επομένως με βάση τον Κανόνα της Ενδυνάμωσης της Προσυνθήκης, εξάγουμε ως συμπέρασμα {Χ= n} X := X+1{X = n+1} Η n είναι η βοηθητική μεταβλητή για συσχετισμό τιμών στην κατάσταση πριν και μετά την εκτέλεση εντολής 23
Κανόνας Αποδυνάμωσης της Μετασυνθήκης Εάν ισχύει το {Ρ}C{R} καθώς και το R Q τότε μπορούμε να εξάγουμε ως συμπέρασμα και το {Ρ}C{Q} 24
Παράδειγμα 5.9 Με χρήση του αξιώματος της Εντολής Ανάθεσης έχουμε: {R=X 0=0}Q:=0{R=X Q=0} Από τα κλασσικά μαθηματικά γνωρίζουμε (R=X) (R=X 0=0) Με χρήση του κανόνα Ενδυνάμωσης της Προσυνθήκης έχουμε {R=X}Q:=0{R=X Q=0) 25
Παράδειγμα 5.9 Με χρήση πάλι απλών μαθηματικών έχουμε (R=X Q=0) (R=X+ΥⅹQ) Με χρήση του κανόνα Αποδυνάμωσης της Μετασυνθήκης έχουμε {R=X}Q:=0{R=X+ΥⅹQ) Οι κανόνες Ενδυνάμωσης και Αποδυνάμωσης ονομάζονται και κανόνες Συνεπαγωγής 26
Κανόνες Σύζευξης και Διάζευξης Εάν ισχύει το {Ρ 1 }C{Q 1 } καθώς και το {Ρ 2 }C{Q 2 } τότε μπορούμε να εξάγουμε ως συμπέρασμα και το {Ρ 1 P 2 }C{Q 1 Q 2 } Εάν ισχύει το {Ρ 1 }C{Q 1 } καθώς και το {Ρ 2 }C{Q 2 } τότε μπορούμε να εξάγουμε ως συμπέρασμα και το {Ρ 1 P 2 }C{Q 1 Q 2 } 27
Κανόνας Σύνθετων Εντολών Αφορά εντολές της μορφής C 1 ;C 2 Εάν ισχύουν τα {P} C 1 {Q} και {Q} C 2 {R} μπορούμε να εξάγουμε το συμπέρασμα {P} C 1 ; C 2 {R} 28
Παράδειγμα 5.10 Με χρήση του αξιώματος της εντολής ανάθεσης μπορούμε να εξάγουμε ότι ισχύουν τα ακόλουθα: { Χ = x Y = y } R:= Χ { R = x Y = y } { R = x Y = y } X:= Y { R = x X = y } { R = x X = y } Y:= R { Y = x X = y } 29
Παράδειγμα 5.10 Από τα δύο πρώτα και με βάση τον κανόνα των Σύνθετων Εντολών μπορούμε να εξάγουμε ότι ισχύουν τα ακόλουθα: {Χ = x Y = y} R:= Χ ; X:=Y {R = x X = y} Τα παραπάνω δίνουν {Χ = x Y = y} R:= X; X:=Y ; Y:=R {Y = x X = y} 30
Κανόνας του if Εάν ισχύει {P S} C 1 {Q} καθώς και {P not S} C 2 {Q} τότε μπορούμε να εξάγουμε ως συμπέρασμα το {P} if S then C 1 else C 2 {Q} 31
Παράδειγμα 5.11 Με χρήση του κανόνα του if καθώς και άλλους προηγούμενους κανόνες και αξιώματα η προδιαγραφή {y>1} if (x>0) then (y:= y-1) else (y := y+1) {y>0} είναι αληθής 32
Κανόνας του while Αν γνωρίζουμε ότι {P S} C {P} τότε μπορούμε να εξάγουμε ως συμπέρασμα ότι {P} while S do C{P not S} Η συνθήκη P ονομάζεται αμετάβλητη συνθήκη διότι εξακολουθεί και ισχύει και μετά το τέλος της εκτέλεσης της εντολής while. 33
Κανόνας του while - 2 Ο κανόνας του while λέει ότι εάν P είναι μία αμετάβλητη συνθήκη του σώματος μιας εντολής while (όταν ισχύει και η συνθήκη S) τότε η P είναι μία αμετάβλητη συνθήκη ολόκληρης της εντολής while. 34
Παράδειγμα 5.12 Έστω ότι θέλουμε να αποδείξουμε: {true} R:=X; Q:=0; while (Y<= R) do (R:=R-Y; Q:=Q+1) {R<Y X=R+(YⅹQ)} Ο αλγόριθμος υπολογίζει το πηλίκο Y και το υπόλοιπο R της διαίρεσης του Χ με το Y 35
Παράδειγμα 5.12 Απόδειξη Πρώτα θα δείξουμε ότι: {true}r:=x; Q:=0{X=R+YⅹQ)} και μετά {X=R+(YⅹQ)} while Y<=R do (R:=R-Y;Q:=Q+1) {X=R+ (YⅹQ) not (Y R)} 36
Παράδειγμα 5.12 Η πρώτη αποδεικνύεται εύκολα. Για τη δεύτερη θα δείξουμε πρώτα ότι: {X=R+(YⅹQ)}R:=R-Y;Q:=Q+1{X=R+ (YⅹQ)} Με βάση το Αξίωμα Εντολής Ανάθεσης {X=(R-Υ)+Υ+(YⅹQ)}R:=R-Y{X=R+Υ+ (YⅹQ)} Και επίσης με βάση το ίδιο αξίωμα: {X=R+(Yⅹ(Q+1))}Q:=Q+1{X=R+ (YⅹQ)} Με χρήση του Κανόνα Σύνθετων Εντολών {X=R+(YⅹQ)}R:=R-Y;Q:=Q+1{X=R+ (YⅹQ)} 37
Παράδειγμα 5.12 Με χρήση του Κανόνα Ενδυνάμωσης της Προσυνθήκης {(X=R+(YⅹQ)) (Υ R)}R:=R-Y;Q:=Q+1{X=R+ (YⅹQ)} Με εφαρμογή του Κανόνα του While θα πάρουμε το ζητούμενο αποτέλεσμα 38
Παράδειγμα Έστω το πρόγραμμα: j=0; i=k; while (i<n); j :=j+1; i :=i+1; end P 39
Παράδειγμα Βρείτε μια invariant για το while loop i k k+1 k+2 j 0 1 2 40
Λύση Προφανώς i-j=k είναι μία invariant. Για να το δείξουμε τυπικά, αρκεί να δείξουμε ότι: {(i-j=k) (i<n)} j:=j+1; i:=i+1{i-j=k} Αρχίζοντας από το τέλος: {i+1-j=k} i:=i+1{i-j=k} {i+1-j-1=k} j:=j+1 {i+1-j=k} i-j=k Επομένως το i-j=k είναι μία invariant 41
Παράδειγμα Κ:=Ν; s:=1; while (K>0) do s:= A * s; K:=K-1; end P Θέλουμε να δείξουμε ότι: {Ν>0 and A 0} P { s=a N } 42
Λύση Πως βρίσκουμε τις αμετάβλητες συνθήκες; Δοκιμάζουμε τον κώδικα για μικρούς αριθμούς πχ Α=2, Ν=5 Κ 5 4 3 2 1 0 s 1 2 4 8 16 32 sa K 32 32 32 32 32 32 43
Λύση Μία αμετάβλητη συνθήκη, που θα μπορούσαμε να χρησιμοποιήσουμε είναι η: s * A K = A N Βλέπουμε επίσης ότι μία άλλη αμετάβλητη συνθήκη φαίνεται να είναι η: Κ 0, διότι {(Κ 0) (Κ>0)}s = A * s, K:=K-1{Κ 0} Επομένως διαλέγουμε ως invariant τη συνθήκη: (s * A K = A N ) (Κ 0) 44
Λύση Δείχνουμε καταρχήν ότι: {(s * A K = A N ) (Κ 0) (Κ>0)}s:=A * s; K:=K-1{(s * A K = A N ) (Κ 0)} Ή ισοδύναμα {(s * A K = A N ) (Κ>0)}s:=A * s; K:=K-1{(s * A K = A N ) (Κ 0)} Έχουμε: {(s * A K-1 = A N ) (Κ -1 0)}κ:=K-1{(s * A K = A N ) (Κ 0)} 45
Επίσης Λύση {(Α * s * A K-1 = A N ) (Κ-1 0)}s:=A * s; {(s * A K-1 = A N ) (Κ-1 0)} Δηλαδή {(s * A K = A N ) (Κ>0)}s:=A * s; K:=K-1{(s * A K = A N ) (Κ 0)} Επομένως θα έχουμε για όλο το WHILE: {(s * A K = A N ) (Κ 0)} WHILE.END{(s * A K = A N ) (Κ 0) (K>0)} {(s * A K = A N ) (Κ =0)} Όμως: {(s * A K = A N ) (Κ =0)} s = A N 46
Λύση Με αποδυνάμωση της μετασυνθήκης έχουμε: {(s * A K = A N ) (Κ 0)} WHILE.END{(s = A N )} Μας μένει να δείξουμε ότι: {Ν>0 Α 0)} Κ:=Ν; s:=1 {(s * A K = A N ) (Κ 0)} Ξεκινώντας από το δεύτερο έχουμε: {(A K = A N ) (Κ 0)} s:=1{(s * A K = A N ) (Κ 0)} Το πρώτο δίνει: {(A Ν = A N ) (Ν 0)} κ:=ν{(a K = A N ) (Κ 0)} TRUE 47
Λύση Όμως: (Ν>0 Α 0) Ν 0 Επομένως το ζητούμενο ισχύει. 48
Παράδειγμα Έστω το πρόγραμμα: count :=n; fact :=1; while (count!=0) do fact :=fact * count; count := count 1; end Θέλουμε να δείξουμε ότι: {n 0} P {fact =n!} P 49
Λύση Δοκιμάζουμε μερικές τιμές: count n n-1 n-2 n-3 fact 1 n (n-1) * n (n-2) * (n-1) * n Γενικά count! * fact = n! 50
Λύση Το παραπάνω όταν τελειώσει το loop δίνει 0! * fact = n! που είναι αυτό, που θέλουμε. Διαλέγουμε λοιπόν ως invariant το: (count! * fact = n!) (count 0) Μένει να εξετάσουμε αν είναι invariant 51
Λύση {(count! * fact = n!) (count 0) (count 0)} fact = fact * count; count=count 1; {(count! * fact = n!) (count 0)} count >0 Μπορούμε να το εξετάσουμε αρχίζοντας από το τέλος προς την αρχή 52
Λύση {(count-1)! * (fact = n!) (count 1)} count:=count-1{(count! * fact = n!) (count 0)} (count! * fact = n!)^(count >0) {((count-1)! * count * fact = n!) (count 1)} fact:=fact * count{((count-1)! * fact = n!) (count 1)} Επομένως μπορούμε να εξάγουμε το συμπέρασμα ότι: fact = n! {(count! * fact = n!) (count 0)}WHILE END{{(count! * fact = n!) (count 0) (count=0)} 53
Λύση Το μόνο, που μένει είναι να δείξουμε: { n 0} count :=n; fact:=1 ; {(count! * fact=n!) (count 0)} Το οποίο είναι απλό: {(count! =n!) (count 0)}fact:=1{(count! * fact=n!) (count 0)} {(n!=n!) (n 0)}count:=n{(count!=n!) (count 0)} 54