450 likes | 606 Views
A reminder. Programming Fundamentals 21 Feliks Klu ź niak. Operational thinking is no good: there are too many paths. Operational thinking is no good: there are too many paths. The usefulness of testing is limited, for the same reasons.
E N D
A reminder Programming Fundamentals 21 Feliks Kluźniak A reminder
Operational thinking is no good: there are too many paths. A reminder
Operational thinking is no good: there are too many paths. The usefulness of testing is limited, for the same reasons. A reminder
Operational thinking is no good: there are too many paths. The usefulness of testing is limited, for the same reasons. “Testing can show the presence of errors, but not their absence.” E. W. Dijkstra A reminder
Operational thinking is no good: there are too many paths. The usefulness of testing is limited, for the same reasons. So we must be able to reason about programs as static entities. A reminder
Operational thinking is no good: there are too many paths. The usefulness of testing is limited, for the same reasons. So we must be able to reason about programs as static entities. The way to do this is to use assertions, which characterize the set of states in which the program must be at a given point. A reminder
Operational thinking is no good: there are too many paths. The usefulness of testing is limited, for the same reasons. So we must be able to reason about programs as static entities. The way to do this is to use assertions, which characterize the set of states in which the program must be at a given point. This allows us to “dispose of history”: we don’t care how the program got here, we only care about what must be true when the program is here. A reminder
Operational thinking is no good: there are too many paths. The usefulness of testing is limited, for the same reasons. So we must be able to reason about programs as static entities. The way to do this is to use assertions, which characterize the set of states in which the program must be at a given point. This allows us to “dispose of history”: we don’t care how the program got here, we only care about what must be true when the program is here. Of course, at any given (reachable) point there is an infinite number of correct assertions: we are interested only in those that have something to do with our purpose! A reminder
Operational thinking is no good: there are too many paths. The usefulness of testing is limited, for the same reasons. So we must be able to reason about programs as static entities. The way to do this is to use assertions, which characterize the set of states in which the program must be at a given point. The effective and precise way to characterize a set of state is to use predicate calculus. A reminder
Operational thinking is no good: there are too many paths. The usefulness of testing is limited, for the same reasons. So we must be able to reason about programs as static entities. The way to do this is to use assertions, which characterize the set of states in which the program must be at a given point. The effective and precise way to characterize a set of state is to use predicate calculus. You may use English as well, but it is much harder to make it sufficiently precise and concise, so in the lectures I must use predicates. A reminder
Operational thinking is no good: there are too many paths. The usefulness of testing is limited, for the same reasons. So we must be able to reason about programs as static entities. The way to do this is to use assertions, which characterize the set of states in which the program must be at a given point. The effective and precise way to characterize a set of state is to use predicate calculus. You may use English as well, but it is much harder to make it sufficiently precise and concise, so in the lectures I must use predicates. You will find that even elementary knowledge of predicate calculus (i.e., “mathematical logic”) is useful in all walks of life. A reminder
Operational thinking is no good: there are too many paths. • The usefulness of testing is limited, for the same reasons. • So we must be able to reason about programs as static entities. • The way to do this is to use assertions, which characterize the set of states in which the program must be at a given point. • The effective and precise way to characterize a set of state is to use predicate calculus. • Assertions about loops are a special case: consider “unrolling” the loop • while B do • S • od • say, three times: • S % P0 • S % P1 • S % P2 A reminder
Operational thinking is no good: there are too many paths. • The usefulness of testing is limited, for the same reasons. • So we must be able to reason about programs as static entities. • The way to do this is to use assertions, which characterize the set of states in which the program must be at a given point. • The effective and precise way to characterize a set of state is to use predicate calculus. • Assertions about loops are a special case: consider “unrolling” the loop • while B do • S • od • say, three times: • S % P0 • S % P1 • S % P2 The assertions P0, P1 and P2 had better have something in common: otherwise we would have to carry out a separate reasoning for each possible unrolling of the loop (i.e., each possible number of repetitions of S. A reminder
Operational thinking is no good: there are too many paths. • The usefulness of testing is limited, for the same reasons. • So we must be able to reason about programs as static entities. • The way to do this is to use assertions, which characterize the set of states in which the program must be at a given point. • The effective and precise way to characterize a set of state is to use predicate calculus. • Assertions about loops are a special case: consider “unrolling” the loop • while B do • S • od • say, three times: • S % P0 • S % P1 • S % P2 The assertions P0, P1 and P2 had better have something in common: otherwise we would have to carry out a separate reasoning for each possible unrolling of the loop (i.e., each possible number of repetitions of S. Hence the idea of an invariant: an assertion that always holds before and after S. A reminder
Operational thinking is no good: there are too many paths. • The usefulness of testing is limited, for the same reasons. • So we must be able to reason about programs as static entities. • The way to do this is to use assertions, which characterize the set of states in which the program must be at a given point. • The effective and precise way to characterize a set of state is to use predicate calculus. • Assertions about loops are a special case: consider “unrolling” the loop • while B do • S • od • say, three times: • S % P0 • S % P1 • S % P2 The assertions P0, P1 and P2 had better have something in common: otherwise we would have to carry out a separate reasoning for each possible unrolling of the loop (i.e., each possible number of repetitions of S. Hence the idea of an invariant: an assertion that always holds before and after S. Again, there is an infinite number of these: we are interested in one that is relevant to our purpose. A reminder
The fundamental invariance theorem for the iterative construct • (aka The main theorem of Computing Science) • Let P be an invariant of the statement S. • IfPis true just before the loop • while B do • S • od • thennot B and Pwill be true just after the loop, provided the loop terminates. A reminder
The fundamental invariance theorem for the iterative construct • (aka The main theorem of Computing Science) • Let P be an invariant of the statement S. • IfPis true just before the loop • while B do • S • od • thennot B and Pwill be true just after the loop, • provided the loop terminates. • We have seen that in general this is our only tool for reasoning about loops. Remember the black and white balls? A reminder
The fundamental invariance theorem for the iterative construct • (aka The main theorem of Computing Science) • Let P be an invariant of the statement S. • IfPis true just before the loop • while B do • S • od • thennot B and Pwill be true just after the loop, • provided the loop terminates. • We have seen that in general this is our only tool for reasoning about loops. Remember the black and white balls? • BTW, this is the only theorem in our course, so it’s a good idea to be aware of it… A reminder
The fundamental invariance theorem for the iterative construct • (aka The main theorem of Computing Science) • Let P be an invariant of the statement S. • IfPis true just before the loop • while B do • S • od • thennot B and Pwill be true just after the loop, • provided the loop terminates. • We have seen that in general this is our only tool for reasoning about loops. Remember the black and white balls? • How do we find the “interesting invariant”? The only effective way is to start with finding the invariant, then write the loop. A reminder
The fundamental invariance theorem for the iterative construct • (aka The main theorem of Computing Science) • Let P be an invariant of the statement S. • IfPis true just before the loop • while B do • S • od • thennot B and Pwill be true just after the loop, • provided the loop terminates. • We have seen that in general this is our only tool for reasoning about loops. Remember the black and white balls? • This theorem leads to the following standard method of writing a loop: A reminder
The fundamental invariance theorem for the iterative construct • (aka The main theorem of Computing Science) • Let P be an invariant of the statement S. • IfPis true just before the loop • while B do • S • od • thennot B and Pwill be true just after the loop, • provided the loop terminates. • This theorem leads to the following standard method of writing a loop: • We want to attain a state in which some predicate R holds. R A reminder
The fundamental invariance theorem for the iterative construct • (aka The main theorem of Computing Science) • Let P be an invariant of the statement S. • IfPis true just before the loop • while B do • S • od • thennot B and Pwill be true just after the loop, • provided the loop terminates. • This theorem leads to the following standard method of writing a loop: • We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. P R A reminder
The fundamental invariance theorem for the iterative construct • (aka The main theorem of Computing Science) • Let P be an invariant of the statement S. • IfPis true just before the loop • while B do • S • od • thennot B and Pwill be true just after the loop, • provided the loop terminates. • This theorem leads to the following standard method of writing a loop: • We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that [ P and not B implies R ] . P R P and not B A reminder
The fundamental invariance theorem for the iterative construct • (aka The main theorem of Computing Science) • Let P be an invariant of the statement S. • IfPis true just before the loop • while B do • S • od • thennot B and Pwill be true just after the loop, • provided the loop terminates. • This theorem leads to the following standard method of writing a loop: • We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that [ P and not B implies R ] . • We find a way to achieve termination while keeping P invariant: this will get us to R ! P R P and not B A reminder
The fundamental invariance theorem for the iterative construct • (aka The main theorem of Computing Science) • Let P be an invariant of the statement S. • IfPis true just before the loop • while B do • S • od • thennot B and Pwill be true just after the loop, • provided the loop terminates. • This theorem leads to the following standard method of writing a loop: • We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that [ P and not B implies R ] . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • We don’t care about the exact path, which is a BIG WIN . P R P and not B
In some simple cases we may write loops that are so trivial that • this method is not really necessary: our operational intuition is good • enough. • This theorem leads to the following standard method of writing a loop: • We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • We don’t care about the exact path, which is a BIG WIN . P R P and not B
In some simple cases we may write loops that are so trivial that • this method is not really necessary: our operational intuition is good • enough. • But even in those cases it is good practice to think (and comment!): • ”What is the invariant?”, ”What is the termination argument?”. • This theorem leads to the following standard method of writing a loop: • We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • We don’t care about the exact path, which is a BIG WIN . P R P and not B
In some simple cases we may write loops that are so trivial that • this method is not really necessary: our operational intuition is good • enough. • But even in those cases it is good practice to think (and comment!): • ”What is the invariant?”, ”What is the termination argument?”. • This will keep us out of harm’s way, and practice makes perfect. • This theorem leads to the following standard method of writing a loop: • We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • We don’t care about the exact path, which is a BIG WIN . P R P and not B
In some simple cases we may write loops that are so trivial that • this method is not really necessary: our operational intuition is good • enough. • But even in those cases it is good practice to think (and comment!): • ”What is the invariant?”, ”What is the termination argument?”. • This will keep us out of harm’s way, and practice makes perfect. • It is not difficult to find examples when disregarding the method • leads us into blind alleys: • This theorem leads to the following standard method of writing a loop: • We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • We don’t care about the exact path, which is a BIG WIN . P R P and not B
In some simple cases we may write loops that are so trivial that • this method is not really necessary: our operational intuition is good • enough. • But even in those cases it is good practice to think (and comment!): • ”What is the invariant?”, ”What is the termination argument?”. • This will keep us out of harm’s way, and practice makes perfect. • It is not difficult to find examples when disregarding the method • leads us into blind alleys: • Challenge: Without looking at the slides entitled • ”Binary search” write a binary search program and • convince yourself (by testing) that it works in all cases. • This theorem leads to the following standard method of writing a loop: • We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • We don’t care about the exact path, which is a BIG WIN . P R P and not B
We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • When we write loops that process arrays, we very often have predicates of the following form: • ( A j : i =< j < k : P( j ) ) A reminder
We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • When we write loops that process arrays, we very often have predicates of the following form: • ( A j : i =< j < k : P( j ) ) • P( j ) is some predicate in which j is a free variable, e.g., a[ j ] = 0 . A reminder
We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • When we write loops that process arrays, we very often have predicates of the following form: • ( A j : i =< j < k : P( j ) ) • P( j ) is some predicate in which j is a free variable, e.g., a[ j ] = 0 . • In the entire expression above, j is a bound variable, but i and k are free variables, so we often write • Q( i, k ) : ( A j : i =< j < k : P( j ) ) A reminder
We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • When we write loops that process arrays, we very often have predicates of the following form: • ( A j : i =< j < k : P( j ) ) • P( j ) is some predicate in which j is a free variable, e.g., a[ j ] = 0 . • In the entire expression above, j is a bound variable, but i and k are free variables, so we often write • Q( i, k ) : ( A j : i =< j < k : P( j ) ) • This just means that we give this predicate a name, Q, and point out that i and k are its free variables: Q( i, k ) might be true of false depending on the values of i and k . A reminder
We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • ( A j : i =< j < k : P( j ) ) • This predicate is just an abbreviation for • true and P( i ) and P( i + 1) and ... and P( k – 1 ) A reminder
We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • ( A j : i =< j < k : P( j ) ) • This predicate is just an abbreviation for • true and P( i ) and P( i + 1) and ... and P( k – 1 ) • For example, • ( A i : i =< j < k : a[ j ] = 0 ) • is just an abbreviation for • true and a[ i ] = 0 and a[ i + 1 ] = 0 and ... and a[ k – 1 ] = 0 A reminder
We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • ( A j : i =< j < k : P( j ) ) • This predicate is just an abbreviation for • true and P( i ) and P( i + 1) and ... and P( k – 1 ) • An important point to remember is that this predicate is true when i >= k, i.e., when the range is empty, i.e., when there is no j that satisfies i =< j < k . A reminder
We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • ( A j : i =< j < k : P( j ) ) • This predicate is just an abbreviation for • true and P( i ) and P( i + 1) and ... and P( k – 1 ) • If we have • ( A j : i =< j < k : P( j ) ) and ( A j : k =< j < m : P( j ) ) • then this is equivalent to • ( A j : i =< j < m : P( j ) ) • Do you see why ? A reminder
We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • ( A j : i =< j < k : P( j ) ) • This predicate is just an abbreviation for • true and P( i ) and P( i + 1) and ... and P( k – 1 ) • If we have • ( A j : i =< j < k : P( j ) ) and ( A j : k =< j < m : P( j ) ) • then this is equivalent to • ( A j : i =< j < m : P( j ) ) • We simply combine the conjunctions! • Conjunction is associative: • (a and b and c) and (d and e ) = a and b and c and d and e A reminder
We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • ( A j : i =< j < k : P( j ) ) • This predicate is just an abbreviation for • true and P( i ) and P( i + 1) and ... and P( k – 1 ) • We frequently have • ( A j : i =< j < k : P( j ) ) and P( k ) A reminder
We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • ( A j : i =< j < k : P( j ) ) • This predicate is just an abbreviation for • true and P( i ) and P( i + 1) and ... and P( k – 1 ) • We frequently have • ( A j : i =< j < k : P( j ) ) and P( k ) • this is equivalent to • ( A j : i =< j < k + 1 : P( j ) ) • Again, we simply combine the conjunctions! A reminder
We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • ( A j : i =< j < k : P( j ) ) • This predicate is just an abbreviation for • true and P( i ) and P( i + 1) and ... and P( k – 1 ) • We frequently have • ( A j : i =< j < k : P( j ) ) and P( k ) • this is equivalent to • ( A j : i =< j < k + 1 : P( j ) ) • For example, if Q( i, k ) : ( A j : i =< j < k : a[ j ] = 0 ) holds, then from • a[ k ] = 0 we can conclude that Q( i, k + 1 ) also holds. A reminder
We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • ( A j : i =< j < k : P( j ) ) • This predicate is just an abbreviation for • true and P( i ) and P( i + 1) and ... and P( k – 1 ) • We frequently have • ( A j : i =< j < k : P( j ) ) and P( k ) • this is equivalent to • ( A j : i =< j < k + 1 : P( j ) ) • For example, if Q( i, k ) : ( A j : i =< j < k : a[ j ] = 0 ) holds, then from • a[ k ] = 0 we can conclude that Q( i, k + 1 ) also holds. And vice versa: if we want to • ensure that Q( i, k + 1 ) holds, we must simply perform WHAT? A reminder
We want to attain a state in which some predicate R holds. • We find P, a weakening of R that looks like a good invariant, and is easier to • establish than R. • We find a boolean condition B such that P and not B implies R . • We find a way to achieve termination while keeping P invariant: this will get us to R ! • ( A j : i =< j < k : P( j ) ) • This predicate is just an abbreviation for • true and P( i ) and P( i + 1) and ... and P( k – 1 ) • We frequently have • ( A j : i =< j < k : P( j ) ) and P( k ) • this is equivalent to • ( A j : i =< j < k + 1 : P( j ) ) • For example, if Q( i, k ) : ( A j : i =< j < k : a[ j ] = 0 ) holds, then from • a[ k ] = 0 we can conclude that Q( i, k + 1 ) also holds. And vice versa: if we want to • ensure that Q( i, k + 1 ) holds, we must simply perform the assignment a[ k ] := 0 . A reminder