CS 641 Lecture -*- Outline -*- * Overview of specification and correctness (Formal methods) ** why care about program specification and correctness? *** why specification? need to describe behavior of infinite number of things (finitely) e.g., runs of a program communication between users and developers less costly than "is this what you want" (20 questions) helps in debugging assigning responsibility/blame great aid in maintenance how can improve it if don't know what it already does? program understanding = abstraction non-executable prototype abstraction with less detail than a working prototype *** why correctness? users want to get what they paid for e.g., building a house, customer doesn't know how to check it all but is concerned with correct building do we really care if the program works in *all* cases? what do we mean by *all*, ones specified if we didn't care, why did we specify them? why not warranty service? ok for customer, but inconvenient expensive for implementor *** how does it relate to this class? specification languages close to programming langauges both specify programs, spec language more abstract spec languages use many of same tools as prog. languages syntax, type checking, modules, etc. similar semantic techniques (fixpoints, environments, ...) semantics =specification of programming language if fixpoint semantics inadequate, then want some other spec ** why use formal methods? (as opposed to informal) help reveal ambiguity, inconsistency, incompleteness faster than informal methods this is *not* a formal claim allow for automated support e.g., proof assistants, consistency checking (syntax, types,...) ** definitions *** digital system thing that interacts with environment in a discrete fashion across a well-defined boundary examples: soda machine, telephone network counter-example: the solar system *** program says how (algorithm) can ask questions about its performance given from implementors point of view constructive (executable) *** specification says what (behavior) spec is a contract between user and implementer of a system **** a set of behaviors e.g., I/O relation of a procedure e.g., if length(x) < 100, then Ordered(sort(x)) & Permuation(x,sort(x)) **** given from the client's point of view (suppresses internal details) counter-example: don't care if use bubble-sort program determines a specification (its behavior), but is not itself usually considered a specification fuzzy boundary **** may be non-constructive (non-executable) e.g., this class, school as a whole, a game (football) counter-example: **** parts: behavior + interface ***** behavior: pre- and post-conditions pre-condition: what is required of user (correct use) e.g., length(x) < 100 post-condition: what system ensures e.g., Ordered(sort(x)) & Permuation(x,sort(x)) ***** interface: how the user uses it e.g., name of the procedure, language buttons on a machine ** specification language provides notation, universe of objects, a notion of satisfaction --------------------------- formally: L = , where Syn = set of specifications (syntax) e.g. first order logic, types in \-calc Sem = set of things (semantic domain) e.g., first-order structures, terms of \-calc Sat a relation between Syn and Sem e.g., notion of model in a logic, |- relation if Sat(s,p), then s is a specification of p, p is a specificand (implementation) of s p is correct wrt s denotation of s in Syn is Sat(s) = {p | Sat(s,p)} --------------------------- a s in Syn is consistent (satisfiable) iff Sat(s) is nonempty e.g., terminal transition systems, denotational semantics type systems *** pragmatics (finite presentations) syntax usually presented as a finite set of rules (grammar) semantics usually described using some other spec. language (mathematics), or in foundational studies axiomatically sat is given using a set of rules (a logic) ** correctness problem given a specification s, produce a p such that Sat(s,p) *** approaches to correctness *** verification (after the fact) given: an axiomatization (presentation) of Sat, and a program p show: Sat(s,p) this approach does not work, except for the smallest problems, probably never will! too hard to find proof after the fact (impossible in general) researchers realized this long ago *** goal-directed program construction much like proofs that a term has a type that we've done so far: work "backwards", that is, by construction of proof tree start with post-condition of procedure try to transform post-condition to pre-condition using statements e.g., in SML fun intersect(s1: 'a list, s2: 'a list) : 'a list (* REQUIRES: true *) (* empty(s1) or s1 = h::t *) if null(s1) then (* empty(s1) *) s1 (* empty(s1) and intersect(s1,s2) = s1 *) else (* not (empty(s1)) *) let h::t = s1 in (* (all x . ((x in t) or (x = h)) iff (x in s1)) *) if member(h, s2) then (* (all x . ((x in t) or (x = h)) iff (x in s1)) and (h in s2) *) h::intersect(t,s2) (* (all x . ((x in t) or (x = h)) iff (x in s1)) and ((h in s2) and (intersect(s1,s2) = h::intersect(t,s2))) *) else (* (all x . ((x in t) or (x = h)) iff (x in s1)) and (not (h in s2)) *) intersect(t,s2) (* (all x . ((x in t) or (x = h)) iff (x in s1)) and (not (h in s2)) and (intersect(s1,s2) = intersect(t,s2))) *) end (* (all x . ((x in t) or (x = h)) iff (x in s1)) and (((h in s2) and (intersect(s1,s2) = h::intersect(t,s2))) or ((not (h in s2)) and (intersect(s1,s2) = intersect(t,s2)))) *) (* ENSURES: all x. x in intersect(s1,s2) iff ((x in s1) and (x in s2)) *) *** transformation much like above approach in a "wide-spectrum language" (spec + prog lang) start with spec, refine it,..., eventually get program in a normal programming langauge start with correct program (see above) transform it to get efficient program *** programming logic, logic of programs formal system for specifying programs and reasoning about their correctness **** external logic specification not part of program correctness proof not part of program (a comment) can use this to define programming languages (as in Dijsktra's paper) ***** Floyd-Hoare logic triples like P {S} Q partial correctness interpretation (usual): for all states s . if [[P]]s and [[S]]s <> \bot, then [[Q]]([[S]]s) total correctness for all states s . if [[P]]s, then and [[S]]s <> \bot and [[Q]]([[S]]s) ***** Weakest preconditions (predicate transformers) formulas using wp(S,Q) wp(S,Q) is P such that (i) for all states s . if [[P]]s, then and [[S]]s <> \bot and [[Q]]([[S]]s) (ii) for all R that satisfy (i), R => P dual notion: strongest postcondition, sometimes also used, but since work backwards through program typically use wp. allows one to reason about total correctness. **** internal logic see Nordstrom and Petersson paper specification part of program, correctness proof part of program (type checking) usually take a total correctness approach (type theory) types are used to specify programs { x:A | B } like the Dependent type Sum x:A . B e.g., { n:Nat | Even n } and Sum n:Nat . (Even n) how do these ideas differ? see intro and elimination rules suppression of evidence...