CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 1/38

Similar documents
CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 12

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Sections p.

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter p. 1/27

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Section 17.2

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Section 17.1

Proving Theorems with Athena

AXIOMS FOR THE INTEGERS

Fundamental mathematical techniques reviewed: Mathematical induction Recursion. Typically taught in courses such as Calculus and Discrete Mathematics.

Introduction to dependent types in Coq

Lecture Notes on Induction and Recursion

Induction and Semantics in Dafny

Typed Scheme: Scheme with Static Types

c constructor P, Q terms used as propositions G, H hypotheses scope identifier for a notation scope M, module identifiers t, u arbitrary terms

Coq quick reference. Category Example Description. Inductive type with instances defined by constructors, including y of type Y. Inductive X : Univ :=

Typed Racket: Racket with Static Types

CMSC 330: Organization of Programming Languages

Handout 9: Imperative Programs and State

Name: Entry: Gp: 1. CSL 102: Introduction to Computer Science. Minor 2 Mon 21 Mar 2005 VI 301(Gps 1-6)& VI 401(Gps 7-8) 9:30-10:30 Max Marks 40

CS 456 (Fall 2018) Scribe Notes: 2

Foundations of Computer Science Spring Mathematical Preliminaries

Programming Languages Third Edition

Analysis of dependent types in Coq through the deletion of the largest node of a binary search tree

Lecture 14: Lower Bounds for Tree Resolution

HOL DEFINING HIGHER ORDER LOGIC LAST TIME ON HOL CONTENT. Slide 3. Slide 1. Slide 4. Slide 2 WHAT IS HIGHER ORDER LOGIC? 2 LAST TIME ON HOL 1

Summary of Course Coverage

A Simple Supercompiler Formally Verified in Coq

CIS 500 Software Foundations. Midterm I. (Standard and advanced versions together) October 1, 2013 Answer key

Chapter 2 The Language PCF

SEQUENCES, MATHEMATICAL INDUCTION, AND RECURSION

Trees and Inductive Definitions

B-Trees. Based on materials by D. Frey and T. Anastasio

Propositional Logic. Andreas Klappenecker

An Athena tutorial. Konstantine Arkoudas

Infinite Objects and Proofs 1

15.4 Longest common subsequence

Data Structure Lecture#10: Binary Trees (Chapter 5) U Kang Seoul National University

Semantics via Syntax. f (4) = if define f (x) =2 x + 55.

Trees, Part 1: Unbalanced Trees

The Typed Racket Guide

4&5 Binary Operations and Relations. The Integers. (part I)

CSC 501 Semantics of Programming Languages

Figure 4.1: The evolution of a rooted tree.

Proving Properties of Recursive Functions and Data Structures. CS 270 Math Foundations of CS Jeremy Johnson

Programming with C Library Functions Safely

CMSC 330: Organization of Programming Languages. Formal Semantics of a Prog. Lang. Specifying Syntax, Semantics

Lecture 6: Analysis of Algorithms (CS )

Priority Queues. 1 Introduction. 2 Naïve Implementations. CSci 335 Software Design and Analysis III Chapter 6 Priority Queues. Prof.

Data Abstraction. An Abstraction for Inductive Data Types. Philip W. L. Fong.

Coq projects for type theory 2018

We will show that the height of a RB tree on n vertices is approximately 2*log n. In class I presented a simple structural proof of this claim:

4.5 Pure Linear Functional Programming

To prove something about all Boolean expressions, we will need the following induction principle: Axiom 7.1 (Induction over Boolean expressions):

Solutions. Suppose we insert all elements of U into the table, and let n(b) be the number of elements of U that hash to bucket b. Then.

Lecture 15 Notes Binary Search Trees

CS115 - Module 8 - Binary trees

Incremental Proof Development in Dafny

Inductive Definitions, continued

Pierce Ch. 3, 8, 11, 15. Type Systems

Programming Languages Fall 2013

Algorithms. AVL Tree

A Small Interpreted Language

Non-context-Free Languages. CS215, Lecture 5 c

Combining Programming with Theorem Proving

DATA STRUCTURES USING C

Theorem proving. PVS theorem prover. Hoare style verification PVS. More on embeddings. What if. Abhik Roychoudhury CS 6214

Solutions to the Second Midterm Exam

3.4 Deduction and Evaluation: Tools Conditional-Equational Logic

15 212: Principles of Programming. Some Notes on Continuations

Tree Parsing. $Revision: 1.4 $

Syntax of Eiffel: a Brief Overview

Lecture Notes on Binary Search Trees

Chapter 11 :: Functional Languages

Formal Semantics of Programming Languages

3EA3 Lecture 16: Linear Search

1.3. Conditional expressions To express case distinctions like

CHAPTER 10 GRAPHS AND TREES. Alessandro Artale UniBZ - artale/

Trees. (Trees) Data Structures and Programming Spring / 28

To prove something about all Boolean expressions, we will need the following induction principle: Axiom 7.1 (Induction over Boolean expressions):

CSE 20 DISCRETE MATH. Fall

Definition of Graphs and Trees. Representation of Trees.

COMP 410 Lecture 1. Kyle Dewey

Lecture 15 Binary Search Trees

Problem Set 5 Solutions

Trees. 3. (Minimally Connected) G is connected and deleting any of its edges gives rise to a disconnected graph.

CIS 500: Software Foundations

Meeting13:Denotations

Static Program Analysis Part 1 the TIP language

SEQUENCES, MATHEMATICAL INDUCTION, AND RECURSION

Module 9: Trees. If you have not already, make sure you. Read How to Design Programs Sections 14, 15, CS 115 Module 9: Trees

Expr_annotated.v. Expr_annotated.v. Printed by Zach Tatlock

Lecture Notes on Tries

Finite Model Generation for Isabelle/HOL Using a SAT Solver

SOFTWARE ENGINEERING DESIGN I

Part 2: Balanced Trees

CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Dan Grossman Spring 2011

Recursion and Structural Induction

Functional Languages. Hwansoo Han

FOUR EDGE-INDEPENDENT SPANNING TREES 1

1 Leaffix Scan, Rootfix Scan, Tree Size, and Depth

Trees. Binary arithmetic expressions. Visualizing binary arithmetic expressions. ((2 6) + (5 2))/(5 3) can be defined in terms of two smaller

Transcription:

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 1/38 CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 Instructor: Carlos Varela Rensselaer Polytechnic Institute Spring 2018

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 2/38 A Binary Search Algorithm Goal: to introduce reasoning about algorithms using a binary search algorithm as an example. defining the algorithm first correctness properties correctness of an optimized binary search algorithm

Defining the algorithm Binary search is an algorithm capable of searching a binary tree containing n items with only O(log n) comparisons, assuming the tree is balanced. Roughly speaking, balanced means that each path from the root to a leaf node is about log 2 n in length. To define the binary search function on binary trees of natural numbers, we start as usual with its declaration: extend-module BinTree { define [x y z T L R] := [?x:n?y:n?z:n?t:( BinTree N)?L:( BinTree N)?R:( BinTree N)] declare binary-search: [N ( BinTree N)] - > ( BinTree N) module binary-search { #... CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 3/38

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 4/38 Defining the algorithm To define how binary-search is computed, we call upon a library procedure named fun to translate a simpler input into defining axioms: assert axioms := ( fun [( binary-search x ( node L y R)) = [( node L y R) when (x = y) ( binary-search x L) when (x < y) ( binary-search x R) when (x =/= y & ~ x < y)] ( binary-search x null ) = null ]) define [ at-root go-left go-right empty ] := axioms

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 5/38 Defining the algorithm The effect of the assert of the fun together with the define is exactly the same as if we had written assert* at-root := (x = y ==> ( binary-search x ( node L y R)) = ( node L y R)) assert* go-left := ( x < y == > ( binary-search x ( node L y R)) = ( binary-search x L)) assert* go-right := (x =/= y & ~ x < y == > ( binary-search x ( node L y R)) = ( binary-search x R)) assert* empty := (( binary-search x null) = null )

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 6/38 The fun procedure The procedure fun is used to define either a predicate or a nonpredicate. In either case, it takes one argument, a list containing defining clauses, and translates it into a list [s 1... s k ] where each s i is a sentence. A defining clause for a nonpredicate function f is a triplet (three consecutive list elements): a term l of the form (f t 1... t n ), called a left-hand-side term; the symbol =; and a right-hand-side term or list. In the left-hand-side term, the number of arguments n must be the same as f s arity, and each argument t i must be either a variable or a term of the sort required by f s i th argument position (so that the whole term is legal).

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 7/38 The fun procedure In the case of a right-hand-side term r, r must be a term whose sort is the return sort of f and the corresponding sentence is the closure of (l = r). In the case of a right-hand-side list, it must consist of a sequence of triplets, each triplet consisting of a right-hand-side term r, followed by the meta-identifiers when, followed by a guard p. For each such triplet, the corresponding sentence is the closure of (p ==> l = r). (We can allow writing when instead of when with define when := when.)

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 8/38 The fun procedure The fun syntax is similar to multipart definitions in conventional mathematical notation, where one might write, e.g., node(l, y, R) binary-search(x, node(l, y, R)) = binary-search(x, L) binary-search(x, R) Instead of otherwise, we write explicitily where x y and ~ x < y. where x = y where x < y otherwise

The fun procedure Writing the third condition as the conjunction of the negations of the preceding conditions, makes it explicit that the condition is disjoint from all of the previous ones. This helps with proof structures such as: (! two-cases assume (x = y) # here at-root can be applied... assume (x =/= y) (! two-cases assume (x < y) # here go-left can be applied, since ( x < y) is # in the assumption base... assume (~ x < y) # here go-right can be applied, since both (x =/= y) # and (~ x < y) are now in the assumption base... )) CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 9/38

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 10/38 Efficiency considerations While the order of presentation makes no difference for the use of axioms in proofs, it can have a significant effect on efficiency when the axioms are used for computation. In Athena, axioms defining a function f are compiled into code by the name f or f. Let s look at the code that is compiled from the axioms generated by our fun definition of binary-search: define ( binary-search t1 t2) := match [t1 t2] { [x3 ( node x1 x4 x2 )] => check {(= x3 x4) => ( node x1 x4 x2) (N. Less.< x3 x4) => ( binary-search x3 x1) else => ( binary-search x3 x2 )} [ x1 null :( BinTree N)] => null :( BinTree N) }

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 11/38 Efficiency considerations The axioms have been compiled into a match expression with two clauses, one for each of the two constructors of the BinTree datatype, which constitute a case analysis for the structure of the second argument to binary-search. The clause corresponding to the node constructor includes a further case analysis implemented by a check, which first tests whether the key is equal to the root value, and then whether it is less than it. But note that the last clause of the check expression does not include a proper condition, having a catch-all else guard instead.

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 12/38 Efficiency considerations Whereas a completely straightforward translation of the corresponding clause of the fun definition, namely (binary-search x R) when (x =/= y & x < y) would result in: check {(= x3 x4) => ( node x1 x4 x2) (N. Less.< x3 x4) => ( binary-search x3 x1) (&& ( negate (= x3 x4 )) ( negate (N. Less.< x3 x4 ))) => ( binary-search x3 x2 )} But because each conjunct in the last guard negates a condition already tested in previous clauses, the guard simplifies to (&& true true), and thus it can be replaced by else.

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 13/38 Efficiency considerations These simplifications depend on the order of the given conditions. For most purposes, the following guarantees about the compiled Athena code suffice: 1. the order in which check clauses (or potentially match clauses with where guards) are listed is the same as the order in which the axioms with the corresponding conditions are presented; and 2. each guard in a clause is simplified by removing the negation of any guard of a preceding clause. These guarantees ensure that lines in a fun serve, for purposes of computation, essentially like an if-then-else or cond construct in conventional high-level languages.

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 14/38 Correspondence to other languages In a programming language that allows datatype constructor patterns as formal parameters of function definitions, such as ML or Haskell, one can write the binary search definition similarly to using fun, e.g., in ML: datatype BinTree = null node of BinTree * int * BinTree fun binarysearch(x, node(l,y,r)) = if x = y then node(l,y,r) else if x < y then binarysearch(x,l) else binarysearch(x,r) binarysearch(x, null) = null

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 15/38 Correspondence to other languages In languages which lack such pattern matching, we would be restricted to using only variables as formal parameters. Then, in the body of the function, we would need to replace occurrences of pattern variables with the corresponding accessor function call or other component access notation, e.g., in C++: struct node; typedef node* BinTree; struct node { BinTree left; int key; BinTree right ; node( BinTree L, int y, BinTree R) : left(l), key(y), right (R) {} };

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 16/38 Correspondence to other languages BinTree binarysearch( int x, BinTree T) { if ( T == NULL) return NULL; if (x == T->key) return T; if (x < T->key) return binarysearch(x, T->left ); return binarysearch(x, T- > right ); } Note that in this case, the test for the empty tree must be done first, since otherwise the expression T->key, etc., would cause an error when T is a null pointer.

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 17/38 Interface design One additional factor in algorithm design is the interface. In the case of binary-search, it would be simpler to return a Boolean value, true if the target value is found, false otherwise. (Most significantly, that interface would make some of the issues we have to deal with in the upcoming proofs disappear.) By returning a node or null, however, we still have an easy test for success ((binary-search x T ) =/= null) and we make it possible to continue with other computations at the position in the tree where the search value is found, without recomputing that position.

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 18/38 Binary search trees A sample binary tree with Int elements follows: define tree1 := ( node ( node null 2 ( node ( node null 3 null ) 5 null )) 7 ( node ( node null 11 null ) 13 null )) 2 3 5 7 11 13

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 19/38 Testing with evaluation We can use input expansion and output transformation to work with trees such as the one defined earlier. expand-input binary-search [ int- > nat int-tree- > nat-tree ] transform-output eval [ nat-tree- > int-tree ] > ( eval ( binary-search 5 tree1 )) Term : ( node ( node null :( BinTree Int ) 3 null :( BinTree Int )) 5 null :( BinTree Int )) > ( eval ( binary-search 12 tree1 )) Term : null :( BinTree Int )

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 20/38 First correctness properties The first correctness properties we consider concern what the result returned by (binary-search x T ) implies about the presence or absence of x in T. extend-module binary-search { define found := ( forall T. BST T == > forall x L y R. ( binary-search x T) = ( node L y R) == > x = y & x in T) define not-found := ( forall T. BST T == > forall x. ( binary-search x T) = null == > ~ x in T)

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 21/38 First correctness properties The proof of found is by induction on binary trees, with basis case: define tree-axioms := ( datatype-axioms BinTree ) define ( binary-search-found-base ) := conclude ( BST null == > forall x L y R. ( binary-search x null ) = ( node L y R) == > x = y & x in null ) assume ( BST null ) pick-any x:n L:( BinTree N) y:n R:( BinTree N) assume i := (( binary-search x null ) = ( node L y R)) let {A := (! chain [ null :( BinTree N) = ( binary-search x null ) [ empty ] = ( node L y R) [i ]]); -A := (! chain- > [ true ==> ( null =/= ( node L y R)) [ tree-axioms ]])} (! from-complements (x = y & x in null ) A -A)

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 22/38 First correctness properties Now we can check the basis case proof before going on to the induction step: > (! binary-search-found-base) Theorem : (if ( BinTree.BST null :( BinTree N)) ( forall?x: N ( forall?l:( BinTree N) ( forall?y:n ( forall?r:( BinTree N) ( if (= ( BinTree. binary-search?x:n null :( BinTree N)) ( node?l:( BinTree N)?y:N?R:( BinTree N ))) ( and (=?x:n?y:n) ( BinTree.in?x:N null :( BinTree N )))))))))

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 23/38 First correctness properties We therefore continue with the induction step. To simplify the notation somewhat, we introduce a property procedure, found-property, which allows us to express the desired found result as follows: (forall T. BST T ==> found-property T). define [x1 y1 L1 R1] := [? x1:n?y1:n?l1 :( BinTree N)?R1 :( BinTree N)] define ( found-property T) := ( forall x L1 y1 R1. ( binary-search x T) = ( node L1 y1 R1) == > x = y1 & x in T) After applying the definition of BST to (node L y R) and combining the result with the induction hypotheses, the proof proceeds by case analysis, setting up cases according to whether x is found at the root, in the left subtree, or in the right subtree, and applying the corresponding binary-search axiom in each case.

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 24/38 First correctness properties define binary-search-found-step := method (T) match T { ( node L:( BinTree N) y:n R:( BinTree N)) => let {[ ind-hyp1 ind-hyp2 ] := [( BST L == > found-property L) ( BST R == > found-property R )]} assume hyp := ( BST T) conclude ( found-property T) let {p0 := (BST L & ( forall x. x in L == > x <= y) & BST R & ( forall z. z in R ==> y <= z)); _ := (! chain- > [hyp ==> p0 [BST. nonempty ]]); fpl := (! chain- > [ p0 == > ( BST L) [ prop-taut ] ==> ( found-property L) [ ind-hyp1 ]]); fpr := (! chain- > [ p0 == > ( BST R) [ prop-taut ] ==> ( found-property R) [ ind-hyp2 ]])}

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 25/38 First correctness properties pick-any x:n L1 y1:n R1 let { subtree := ( node L1 y1 R1 )} assume hyp := (( binary-search x T) = subtree ) conclude ( x = y1 & x in T) (! two-cases assume (x = y) (! both conclude ( x = y1) (! chain- > [ T = ( binary-search x T) [ at-root ] = subtree [ hyp ] == > (y = y1) [ tree-axioms ] ==> (x = y1) [(x = y )]]) conclude ( x in T) (! chain- > [(x = y) ==> (x in T) [in. root ]]))

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 26/38 First correctness properties } assume ( x =/= y) (! two-cases assume ( x < y) (! chain- > [( binary-search x L) = ( binary-search x T) [ go-left ] = subtree [ hyp ] ==> (x = y1 & x in L) [ fpl ] ==> (x = y1 & x in T) [in. left ]]) assume (~ x < y) (! chain- > [( binary-search x R) = ( binary-search x T) [ go-right ] = subtree [ hyp ] ==> (x = y1 & x in R) [ fpr ] ==> (x = y1 & x in T) [in.right ]])))

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 27/38 First correctness properties The complete proof is then: > by-induction found { null => (! binary-search-found-base) (T as ( node _)) => (! binary-search-found-step T)} Theorem : ( forall?t:( BinTree N) (if ( BinTree. BST?T:( BinTree N)) ( forall?x:n ( forall?l:( BinTree N) ( forall?y:n ( forall?r:( BinTree N) ( if (= ( BinTree. binary-search?x:n?t:( BinTree N)) ( node?l:( BinTree N)?y:N?R:( BinTree N))) (and (=?x:n?y:n) ( BinTree.in?x:N?T:( BinTree N ))))))))))

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 28/38 First correctness properties Turning to the proof of not-found, we will write the basis case and induction step proofs inline. The basis case is an immediate consequence of BinTree.in.empty. In the induction step, we again start by applying the definition of BST to T and combining the result with the induction hypotheses. The conclusion we seek being a negative, we naturally use proof by contradiction, but there are several different cases to be considered, and we must find a contradiction within each. We define a property procedure (not-found-prop) for this proof, too. define ( not-found-prop T) := ( forall x. ( binary-search x T) = null == > ~ x in T)

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 29/38 First correctness properties by-induction not-found { null => assume ( BST null ) conclude ( not-found-prop null ) pick-any x: N assume (( binary-search x null) = null ) (! chain- > [ true ==> (~ x in null) [in. empty ]]) (T as ( node L y:n R)) => let { p1 := ( not-found-prop L); p2 := ( not-found-prop R); [ ind-hyp1 ind-hyp2 ] := [( BST L == > p1) ( BST R == > p2 )]} assume hyp := ( BST T) conclude ( not-found-prop T)

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 30/38 First correctness properties let { smaller-in-left := ( forall x. x in L == > x <= y); larger-in-right := ( forall z. z in R == > y <= z); p0 := (BST L & smaller-in-left & BST R & larger-in-right); _ := (! chain- > [ hyp ==> p0 [ BST. nonempty ]]); _ := (! chain- > [ p0 == > smaller-in-left [ prop-taut ]]); _ := (! chain- > [ p0 == > larger-in-right [ prop-taut ]]); _ := (! chain- > [p0 ==> (BST L) [ prop-taut ] ==> ( not-found-prop L) [ ind-hyp1 ]]); _ := (! chain- > [p0 ==> (BST R) [ prop-taut ] ==> ( not-found-prop R) [ ind-hyp2 ]])}

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 31/38 First correctness properties pick-any x assume hyp := (( binary-search x T) = null) (! by-contradiction (~ x in T) assume (x in T) let { disj := (! chain- > [( x in T) == > (x = y x in L x in R) [in. nonempty ]])} (! two-cases assume (x = y) (! absurd (! chain [ null :( BinTree N) = ( binary-search x T) [ hyp ] = T [ at-root ]]) (! chain- > [ true ==> ( null =/= T) [ tree-axioms ]]))

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 32/38 First correctness properties assume (x =/= y) (! two-cases assume (x < y) (! cases disj assume (x = y) (! absurd (x = y) (x =/= y)) assume ( x in L) (! absurd (x in L) (! chain- > [( binary-search x L) = ( binary-search x T) [ go-left ] = null [ hyp ] ==> (~ x in L) [p1 ]]))

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 33/38 First correctness properties assume ( x in R) (! absurd (x < y) (! chain- > [(x in R) == > ( y <= x) [ larger-in-right] ==> (~ x < y) [N. Less =. trichotomy4 ]]))) assume (~ x < y) (! cases disj assume (x = y) (! absurd (x = y) (x =/= y))

First correctness properties assume (x in L) (! absurd (x =/= y) (! chain- > [( x in L) == > (x <= y) [ smaller-in-left] == > (x < y x = y) [N. Less =. definition ] ==> (~ x < y & (x < y x = y)) [ augment ] ==> (x = y) [ prop-taut ]])) assume (x in R) (! absurd (x in R) (! chain- > [( binary-search x R) = ( binary-search x T) [ go-right ] = null [ hyp ] ==> (~ x in R) [p2 ]])))))) } # by-induction CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 34/38

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 35/38 An optimized binary search algorithm The binary search algorithm first compares for equality of the search value with the current node s key. Notice, however, that until the equality comparison succeeds, the algorithm expends two comparisons per tree level. And in a balanced n-element tree, most searches will require descending through almost log 2 n levels (since about n/2 elements reside in the bottom level, n/4 at the next lowest level, etc.) Thus, on average, a total of almost 2 log 2 n comparisons will be required. An alternative definition is: assert axioms := ( fun [( binary-search x ( node L y R)) = [( binary-search x L) when (x < y) ( binary-search x R) when (y < x) ( node L y R) when (~ x < y & ~ y < x)] ( binary-search x null ) = null ]) define [ go-left go-right at-root empty ] := axioms

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 36/38 Correctness of optimized algorithm With this control structure, if the search value is in the left subtree, only one comparison is required to descend a level; if it is in the right subtree, two are required. Assuming it is equally likely to take one path or the other at each level, a total of about 1.5 log 2 n comparisons are required, on average a 25 percent reduction from the traditional version of the algorithm. This is a significant optimization, but before adopting it as the preferred version of binary search, we should be sure that it is correct. This is a small example, but it is illustrative of one of the most important applications of logic and proof in computer science, correctness of algorithm optimizations.

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 37/38 Correctness of optimized algorithm One way to prove the optimized algorithm is to modify the proofs for found and not-found by restructuring the case analyses to match the new when conditions. Another way to establish found and not-found using the optimized version of binary-search is to start with the new axioms of the optimized version and prove the axioms of the original version as lemmas. Then the original proofs will still work.

CSCI.6962/4962 Software Verification Fundamental Proof Methods in Computer Science (Arkoudas and Musser) Chapter 11 p. 38/38 Correctness of optimized algorithm That is, from the new axioms first prove define at-root := ( forall x L y R. x = y == > ( binary-search x ( node L y R)) = ( node L y R)) define go-right := ( forall x L y R. x =/= y & ~ x < y == > ( binary-search x ( node L y R)) = ( binary-search x R)) (go-left is unchanged). Then reprove not-found with let {[ at-root go-right ] := [ at-root go-right ]} conclude not-found #... same proof as above. and similarly for found.