180 likes | 287 Views
CSE 3341.03 Winter 2008 Introduction to Program Verification. implementing ADTs. verifying ADT implementations (ch. 6). example: if we implement stacks with arrays, we need to verify that the stack axioms are still valid.
E N D
CSE 3341.03 Winter 2008Introduction to Program Verification implementing ADTs
verifying ADT implementations (ch. 6) • example: if we implement stacks with arrays, we need to verify that the stack axioms are still valid. • need a description of arrays which allows us to prove equations involving array expressions
motivation • why implement stacks (and queues and lists?) using arrays?
array axiom • unbounded arrays, array index ≥ 0. • what axioms do we need? just one! • 2 functions: array and change • array(A, I) returns the value of the array A at location I corresponds to A[I] • change(A, I, V) returns an array which has the value V at I. • corresponds to A[I] = V • combine into an axiom? array(change(Array(I, Value), J) = if(J=I, Value, array(Array, J))
general strategy • translate ADT functions into implemented (non-abstract) functions -- for clarity & convenience e. g. pop(S) ->> popA(S) • delete original ADT axioms, add axioms for the ADT used in implementation (e. g. array axiom) • what happens to rules for dup, over, etc.?
implementation in terms of the target ADT • e. g., a stack = array and # of values on the stack (= index) = [Array, Index] nil = [nilA, 0] nilA is the array component (with no elements) of the implementation of the empty stack)
array axiom • unbounded arrays, array index ≥ 0. • what axioms do we need? just one! • 2 functions: array and change • array(I) returns the value of the array at I • change(A, I, V) returns an array which has the value V at I. • combine into an axiom? • array(change(Array(I, Value), J) = if(J=I, Value, array(Array, J))
general strategy • translate ADT functions to implemented (non-abstract) functions -- for clarity & convenience • e. g., pop(S) ->> popA(S) • delete original ADT axioms • add axioms for ADT used in implementation (e. g. array axiom)
implementation in terms of the target ADT • e. g. a stack = array & # of values on the stack (= index) • define getter functions to access the parts of the implementation e. g. a([A, I]) ->> A, i([A, I]) ->> I. • define ADT functions in terms of new ADT topA(Stack) ->> array([a(S), i(S)]). popA(Stack) ->> [a(Stack), i(Stack) - 1] pushA(X, Stack) ->> [change(a(Stack), i(Stack)+1, X), i(Stack)+1]? • in English?
verification using prover • use prover with trace on and theory files try to verify the original ADT axioms • e. g. pop(push(x,s)) = s |: theory('stackA.simp'). % what goes in here? |: theory('array.simp'). % what goes in here?
tracing . . . pop(push(x,s))=s popA(push(x,s))=s [a(push(x,s)),i([change(a(s),i(s)+1,x),i(s)+1])-1]=s . . . [change(a(s),i(s)+1,x),i(s)]=s * Cannot prove [change(a(s),i(s)+1,x),i(s)]=s. easy to add a simplification rule to prove the identity what's the general case? how would you prove it?
exercise 6.6: implementing queues • a key line: firstA(Q) = array(a(Q), 1) mathematically (abstractly), first needs a recursive definition, if defined in terms of the ADT functions but can be implemented efficiently (without recursion), using arrays. • that's the purpose of translating queues into something built from arrays.
verifying a logic circuit: Section 6.3 • a different kind of implementation: • objects (gates) connected to form a (storage-free) logic circuit • each kind of gate has a definition: e.g. or_gate(V, W, X) ->> X iff (V or W). • this is not the only way to do it • chosen to make the “wiring” easier, but the logic is more complicated
how else might we represent the circuit? • try just using functions: e. g., Z = or(or( . . ), and(. . . )) the nesting makes it harder to translate without error from the diagram to a Boolean expression
vote circuit: p. 55 • what’s the purpose of the function int(X) ->> if(X, 1, 0) ? • what’s the purpose of the implementation term? to specify the gates and connections of a circuit in the equality to be verified: implementation(a, b, c, z) implies z = majority(a, b, c).
Skolem constants • the implementation predicate implicitly introduces existentially quantified variables: • e. g., for all A, B, there exists a d such that d(A, B) = and_gate(A, B) or more simply: and_gate(A, B, d).
exercise 6.9: • what’s “half” mean in the context of a “half-adder” ? • anyone not sure of what the gate symbols mean? • what are the outputs supposed to be (arithmetically)? • what portion of the exercise is more or less mechanical?
what is being verified? • what part of the exercise requires some understanding & insight? • identifying the intended goal as a function of the inputs to the circuit: 2*Carry + Sum = A + B