Pre/Post Condition Logic 03/06/2013
Agenda Hoare’s Logic Overview Application to Pre/Post Conditions
Hoare Logic Prove partial correctness of computer programs Prove termination separately Hoare triple {P} C {Q} P and Q are assertions P = precondition Q = postcondition C is a command When P holds a state before C is executed, then Q will hold after (or C does not terminate)
Hoare Logic Partially correct Assuming precondition is true before function executes Postcondition is true after function executes Totally correct Precondition is true Function guaranteed to terminate Postcondition is true Total correctness = Partial correctness + termination
Hoare Logic Rules Empty statement {P} skip {P} Skip statement doesn’t change program state Assignment {x = 5} x := x * 2 {x > 0} Clearly correct, but not precise x > 5 && x < 20 is better as a postcondition { ∃ x, y. (y > 0) ∧ (n = x y )} n := n * (n + 1) { ∃ x, y. (n = x y )} With quantifiers To me, seems to be basic predicate logic as applied to programming constructs
Hoare Logic Example r := 1; i := 0; while i < m do r := r * n; i := i + 1
Hoare Logic Example r := 1; i := 0; while i < m do r := r * n; i := i + 1 Prove that function computes nth power of m, and leaves result in r
Hoare Logic Postcondition definition r := 1; i := 0; while i < m do r := r * n; i := i + 1 Postcondition: r = n m
Hoare Logic Defining pre- and postconditions r := 1; i := 0; while i < m do r := r * n; i := i + 1 Determine precondition(s) Must have m >= 0 No provision for dividing by n 0 0 Precondition: m >= 0 && n > 0 Determine precondition(s) Must have m >= 0 No provision for dividing by n 0 0 Precondition: m >= 0 && n > 0
Hoare Logic Next step would be to generate a proof to ensure specification is correct Get into SAT solvers, etc.
Application Based on Hoare’s logic syntax, the sorting algorithms had pre/postconditions added void call_sort(struct Sorter* sorter_) { if (sorter_->sort_fn != NULL) { sorter_->sort_fn(sorter_->numbers_, 0, SIZE-1); } Composing in wrapper
Application Based on Hoare’s logic syntax, the sorting algorithms had pre/postconditions added // preconditions: sorter_ != NULL // preconditions: sorter_.numbers_ = array of integers // preconditions: sorter_.sort_fn != NULL // postconditions: sorter_.numbers_[0] <=... <= // sorter_.numbers_[SIZE-1] void call_sort(struct Sorter* sorter_) { if (sorter_->sort_fn != NULL) { sorter_->sort_fn(sorter_->numbers_, 0, SIZE-1); }
Application Based on Hoare’s logic syntax, the sorting algorithms had pre/postconditions added // preconditions: sorter_ != NULL // preconditions: sorter_.numbers_ = array of integers // preconditions: sorter_.sort_fn != NULL // postconditions: sorter_.numbers_[0] <=... <= // sorter_.numbers_[SIZE-1] void call_sort(struct Sorter* sorter_) { if (sorter_->sort_fn != NULL) { sorter_->sort_fn(sorter_->numbers_, 0, SIZE-1); } Ensure incoming array is not unassigned
Application Based on Hoare’s logic syntax, the sorting algorithms had pre/postconditions added Array type // preconditions: sorter_ != NULL // preconditions: sorter_.numbers_ = array of integers // preconditions: sorter_.sort_fn != NULL // postconditions: sorter_.numbers_[0] <=... <= // sorter_.numbers_[SIZE-1] void call_sort(struct Sorter* sorter_) { if (sorter_->sort_fn != NULL) { sorter_->sort_fn(sorter_->numbers_, 0, SIZE-1); }
Application Based on Hoare’s logic syntax, the sorting algorithms had pre/postconditions added Precondition that function pointer must be active // preconditions: sorter_ != NULL // preconditions: sorter_.numbers_ = array of integers // preconditions: sorter_.sort_fn != NULL // postconditions: sorter_.numbers_[0] <=... <= // sorter_.numbers_[SIZE-1] void call_sort(struct Sorter* sorter_) { if (sorter_->sort_fn != NULL) { sorter_->sort_fn(sorter_->numbers_, 0, SIZE-1); }
Application Based on Hoare’s logic syntax, the sorting algorithms had pre/postconditions added Postcondition that the array must be sorted in ascending order // preconditions: sorter_ != NULL // preconditions: sorter_.numbers_ = array of integers // preconditions: sorter_.sort_fn != NULL // postconditions: sorter_.numbers_[0] <=... <= // sorter_.numbers_[SIZE-1] void call_sort(struct Sorter* sorter_) { if (sorter_->sort_fn != NULL) { sorter_->sort_fn(sorter_->numbers_, 0, SIZE-1); }
Application Based on Hoare’s logic syntax, the sorting algorithms had pre/postconditions added No postcondition for what type of array…. // preconditions: sorter_ != NULL // preconditions: sorter_.numbers_ = array of integers // preconditions: sorter_.sort_fn != NULL // postconditions: sorter_.numbers_[0] <=... <= // sorter_.numbers_[SIZE-1] void call_sort(struct Sorter* sorter_) { if (sorter_->sort_fn != NULL) { sorter_->sort_fn(sorter_->numbers_, 0, SIZE-1); }
Application The majority of the other examples boiled down to the same thing Incoming array Outgoing sorted array
Thoughts Tool could be written in Python to automatically parse pre/postconditions Easy to use for text parsing Also pull out method signature Format and send output/objects to Puppy for use in algorithm Initial pass could verify overall correctness of logical syntax Could be called as an entry point into the developed tool (We could also leverage some of the STL/Boost libraries as well if the preference is to stick with a single language)
References Hoare, Charles Antony Richard. "An axiomatic basis for computer programming." Communications of the ACM (1969): hoare-notes.pdf pdf