Some heuristics for deriving invariant LN sections 6.7 , 6.8

Slides:



Advertisements
Similar presentations
Analysis of Algorithms II
Advertisements

ML Lists.1 Standard ML Lists. ML Lists.2 Lists  A list is a finite sequence of elements. [3,5,9] ["a", "list" ] []  Elements may appear more than once.
ML Lists.1 Standard ML Lists. ML Lists.2 Lists  A list is a finite sequence of elements. [3,5,9] ["a", "list" ] []  ML lists are immutable.  Elements.
Chapter 10 Recursion Instructor: alkar/demirer. Copyright ©2004 Pearson Addison-Wesley. All rights reserved.10-2 Recursive Function recursive functionThe.
מבוא מורחב למדעי המחשב בשפת Scheme תרגול 2. 2 Outline Scoping and block structure Recursive and iterative processes Orders of growth.
1 Recitation 7. Developing loops Introduction. This recitation concerns developing loops using their invariants and bound functions. Your recitation instructor.
Proofs, Recursion, and Analysis of Algorithms Mathematical Structures for Computer Science Chapter 2 Copyright © 2006 W.H. Freeman & Co.MSCS SlidesProofs,
CHAPTER 10 Recursion. 2 Recursive Thinking Recursion is a programming technique in which a method can call itself to solve a problem A recursive definition.
Nirmalya Roy School of Electrical Engineering and Computer Science Washington State University Cpt S 122 – Data Structures Recursion Review.
Reading and Writing Mathematical Proofs
Chapter 8. Section 8. 1 Section Summary Introduction Modeling with Recurrence Relations Fibonacci Numbers The Tower of Hanoi Counting Problems Algorithms.
Recursive Algorithms &
Copyright © 2009 Pearson Education, Inc. Chapter 5 Section 1 - Slide 1 Chapter 1 Number Theory and the Real Number System.
MA/CSSE 473 Day 02 Some Numeric Algorithms and their Analysis.
Example of a Worked-out Proof. Consider again this program Let 0  n. This program checks if all elements of the segment a[0..n) are zero. {* 0  n *}
A Different Solution  alternatively we can use the following algorithm: 1. if n == 0 done, otherwise I. print the string once II. print the string (n.
Application: Algorithms Lecture 19 Section 3.8 Tue, Feb 20, 2007.
1 Chapter 2 Algorithm Analysis Reading: Chapter 2.
Maitrayee Mukerji. Factorial For any positive integer n, its factorial is n! is: n! = 1 * 2 * 3 * 4* ….* (n-1) * n 0! = 1 1 ! = 1 2! = 1 * 2 = 2 5! =
CORRECTNESS ISSUES AND LOOP INVARIANTS Lecture 8 CS2110 – Fall 2014.
1 Proving Properties of Recursive Functions and Data Structures CS 270 Math Foundations of CS Jeremy Johnson.
Dr Nazir A. Zafar Advanced Algorithms Analysis and Design Advanced Algorithms Analysis and Design By Dr. Nazir Ahmad Zafar.
Nyhoff, ADTs, Data Structures and Problem Solving with C++, Second Edition, © 2005 Pearson Education, Inc. All rights reserved Recursion,
Chapter 9 Recursion. Copyright ©2004 Pearson Addison-Wesley. All rights reserved.10-2 Recursive Function recursive functionThe recursive function is –a.
Hoare Logic LN chapter 5, 6 but without 6.8, 6.12, 6.13 (to be discussed later) Hoare Logic is used to reason about the correctness of programs. In the.
ALGORITHMS PROVING ALGORITHMS (PROGRAMS) CORRECT WITH AND WITHOUT INDUCTION.
Recursion Great fleas have little fleas upon their backs to bite 'em, And little fleas have lesser fleas, and so ad infinitum. And the great fleas themselves,
CS314 – Section 5 Recitation 9
Recursion The programs discussed so far have been structured as functions that invoke one another in a disciplined manner For some problems it is useful.
Topic 6 Recursion.
Chapter 10 Recursion Instructor: Yuksel / Demirer.
MA/CSSE 473 Day 06 Euclid's Algorithm.
Further with Hoare Logic Sections 6.12, 6.10, 6.13
OBJECT ORIENTED PROGRAMMING II LECTURE 23 GEORGE KOUTSOGIANNAKIS
Correctness issues and Loop invariants
Lesson #6 Modular Programming and Functions.
Analysis of Algorithms
Recursion notes Chapter 8.
Lesson #6 Modular Programming and Functions.
More on Recursive Methods
MA/CSSE 473 Day 02 Some Numeric Algorithms and their Analysis
Reasoning About Code.
Reasoning about code CSE 331 University of Washington.
Revisiting Predicate Logic LN chapters 3,4
Algorithm Analysis CSE 2011 Winter September 2018.
Hoare Logic LN chapter 5, 6 but without 6. 8, 6. 12, 6
CS 213: Data Structures and Algorithms
CS21b: Structure and Interpretation
Recursion Great fleas have little fleas upon their backs to bite 'em, And little fleas have lesser fleas, and so ad infinitum. And the great fleas themselves,
Proving Properties of Recursive Functions and Data Structures
Recursion "To understand recursion, one must first understand recursion." -Stephen Hawking.
Looping.
Copyright © Cengage Learning. All rights reserved.
Algorithm design and Analysis
Dynamic Programming.
Copyright © Cengage Learning. All rights reserved.
Fundamentals of Programming
Axiomatic semantics Points to discuss: The assignment statement
Hoare Logic LN chapter 5, 6 Hoare Logic is used to reason about the correctness of programs. In the end, it reduces a program and its specification to.
Example of a Worked-out Proof
Statement-Level Control Structures
Recursion Great fleas have little fleas upon their backs to bite 'em, And little fleas have lesser fleas, and so ad infinitum. And the great fleas themselves,
Recursion Great fleas have little fleas upon their backs to bite 'em, And little fleas have lesser fleas, and so ad infinitum. And the great fleas themselves,
Output Variables {true} S {i = j} i := j; or j := i;
Application: Algorithms
This Lecture Substitution model
5 INTEGRALS.
ECE 103 Engineering Programming Chapter 18 Iteration
At the end of this session, learner will be able to:
Programming Languages and Compilers (CS 421)
Presentation transcript:

Some heuristics for deriving invariant LN sections 6.7 , 6.8

Overview Examples of “Replace constant with counter” heuristic Fibbonaci Longest “X” segment Tail invariant Revisiting array reverse GCD Other examples 2

Loop Reduction rule [Init] [IC] [EC] [TC1] [TC2] P  I // setting up I {* g /\ I *} S {* I *} // invariance I /\ g  Q // exit cond {* I /\ g *} C:=m; S {* m<C *} // m decreasing I /\ g  m > 0 // m bounded below ---------------------------------------- {* P *} while g do S {* Q *} 3

Heuristic “replace constant with counter” i := 0 ; r := true ; while i<n do { r := r /\ (a[i]=0) ; i++ } {* r = (k : 0k<n : a[k]=0) *} 1. Indentify the loop counter The loop iterates on the counter up to some upperbound/lowerbound. 2. Identify this upper/lower bound. If the post-cond is of the form Q(n). Try Q(i) /\ ... as then invariant. Notice that: Q(i) /\ i=n  Q(n) 3. Takes Q(i) as inv, + a range expr over the counter, e.g.   i   4

Fibonacci sequence The Fibonacci “sequence” can be generated by: fib 0 = 0 fib 1 = 1 fib (t + 2) = fib (t+1) + fib t Nice (but bad execution time)

Let’s take a multi-vars example: iterative Fibonacci Fibonacci’s original problem: rabbit growth problem. If we start if n pairs of rabits, how many rabits we’ll have at the end of the year? Simplified model: Start with one new pair A new pair needs 1 month to become adult Each month each adults pair produce a new pair Our rabbits don’t die :)

Iterative Fib  O(n) RabitSim (n:int) : int { nNow,nAdult,newPairs,t : int ; t:=1 ; nAdult:=0 ; nNow:=1 ; while t < n do { newPairs := nAdult ; nAdult := nNow ; nNow := nNow + newPairs ; t := t + 1 } ; return nNow }

Let’s prove that the two verions are the same t:=1 ; nAdult:=0 ; nNow:=1 ; while t < n do { newPairs := nAdult ; nAdult := nNow ; nNow := nNow + newPairs ; t := t + 1 } ; return := nNow {* I *} Inv : nNow = fib t /\ 1  t  n term. metric : n-t {* nNow = fib n *} {* return = fib n *} (note multiple variables to accumulate results)

Verifying Invariance /\ nAdult = fib (t-1) {* nNow = fib t /\ 1  t  n /\ t<n *} Not enough info in inv to prove this wp : nNow + nAdult = fib (t+1) /\ 1  t+1  n newPairs := nAdult ; nAdult := nNow ; nNow := nNow + newPairs ; t := t + 1 /\ nNow = fib t /\ nAdult = fib (t-1) the wp of {* nNow = fib t /\ 1  t  n *}

A different example: converting tail recursions Typical recursion: g(x) = if x≤ 0 then x else x + g(x-1) Tail recursion: f (x) = if x≤0 then x else f(x-1) f(2) = f(1) = f(0) = 0 g(2) = 2 + g(1) 1 + g(0) 0

Examples last s = #s=1  hd s | last (tail s) lsum (z,s) = s=[]  z | lsum (z + hd s, tail s) You can calculate sum via lsum: sum s = lsum (0,s)

Tail Recursion, general form A function F of this general form: F x = g x  base x // base case | F ( x) // recursion This is called tail recursion. Can be optimized by: Last recursion returns directly to the first/root call. Use less stack space With iteration  cost no stack space for passing params. Terminates if … ? F : AB. Find a term. metric m : AInt such that:  g x  m ( x) < m x  g x  m x > 0 12

Implementing tail recursive function F x = g x  base x | F ( x) Compute F  With this simple loop  x :=  ; while  g x do x :=  x ; r := base x ; Inv: F x = F  {* true *} Term. Metric : m x bsearch(x,a,N) = bsworker(x,a,0,N) bsworker (x,a,left,right) = // not optimized ... could break if a[left] = x, but let’s not do that let d = right – left m = left + (right – left) /2 in if d <= 1 then left<right /\ a[left]=x else if x<=a[m-1] then bsworker(x,a,left,m) else bsworker(x,a,m,right) base x = F  {* r = F  *} 13

Example : GCD Given X,Y > 0, compute gcd X Y. Straight forward solution: O(X min Y). We can do better than that (Euclides, 320 BC) Approach: try to cast the problem into tail recursion. We will need to explore some properties of common divisors.

Some properties of gcd We’ll assume positive integers! Define : d divides x = k : k>0 : x = k*d d comdiv x,y = d divides x /\ d divides y Theorem : \\ hmm … looks like a “split” If x>y then d comdiv x,y  d comdiv (x-y),y if d comdiv x,y then: (1) x = k1*d, for some k1>0 (2) y = k2*d, for some k2>0 If y>x, then x-y = (k1 – k2)*d ... so d is also a divisor of x-y, so d is comdiv of x-y as well. 15

Some properties of gcd Define gcd via this equation :  = gcd x y =  comdiv x,y /\ (e : e comdiv x,y : e   ) Theorem : if x>y then gcd x y = gcd (x-y) y Theorem : gcd x x = x 16

Gcd in tail recursion So we can infer this recursive relation for gcd : gcd x y = x = y  x | x > y  gcd (x-y) y | x < y  gcd x (y – x) Implemented by this loop: x,y := X,Y ; while x  y do if x>y then x:=x-y else y:=y-x inv : gcd x y = gcd X Y {* X>0 /\ Y>0 *} term. metric : x+y {* x = gcd X Y *} 17

Another example Consider an array a[0..n) of non-negative integers representing a number. Write a program that computes the “value” of the number represented by such an array. a [0..3) 3 1 2 value a 3 = 312 value

Possible solutions: Iterative: :i=0 ; r:=0 ; while i<n do { Recursive: Both are less efficient in computing 10^... :i=0 ; r:=0 ; while i<n do { r := r + a[i] * 10^(n-i) i++ } value [] = 0 value (x:s) = x*10^(length s) + value s

Tail recursive definition of “value” Or, using tail recursion (more efficient): val x s = s=[]  x | /* else */ val (10*x + hd s) (tail s) Note that value s = val 0 s Now you can convert it to an iterative solution

Implementation Recall: val x s = s=[]  x | /* else */ val (10*x + hd s) (tail s) Inv: val x s = val 0 (a[0..n)) /\ 0  i  n {* 0≤n *} x , s := 0 , a[0..n) ; while s[] do { x := 10*x + hd s ; s := tail s } result = x You can further refine this to get rid of the lists. {* result = val 0 (a[0..n)) *} 21

Data refinement inv: {* ... /\ s = a[i..n) *} x , s := 0 , a[0..n) ; while s[] do { x := 10*x + hd s ; s := tail s } result = x i = 0 Introduce new variables Add invariant to express their intention Add statements in order to maintain the new inv. Use the new vars to optimize Drop what you don’t need Repeat i < n a[i] i++ {* result = val 0 (a[0..n)) *} 22

Oh, note that foldl is tail recursive... Well, foldl is tail recursive: Roll out your implementation... Compare it with : foldl f e [] = e foldl f e (x:s) = foldl f (f e x) s F(z) = F(z) SUM [] = 0 SUM (x:s) = x + SUM s This is not TR

Tail invariant Previously,our invariants express “what has been computed” : nNow = fib t s = SUM (a[0..i)) Tail invariant has this forms : still to-do = goal The loop shrinks the “todo” part, so that in the end we have: remainder = goal If remainder can be easily calculated and the result is put in a variable r, then in r we would have goal.

Tail invariant Or more generally, this form : x  todo = goal When the loop terminates, we again hope that x  todo can be easily calculated, and hence we get the goal. An instance of the above scheme is to reduce the todo part to the unit of , so that in the end we have: x = goal

A bit more complicated: Longest Zero Segment Given an array a (of lenght n), find the longest segment in a containing of only 0’s. We’ll simplify this a bit: just find the length of that longest segment. Naive solution is O(n2); but we can also do it in O(n). 1 3 2

Analogous problems Longest “flat” segments Longest increasing segments Longest segment satisfying predicate X : [T]  bool It will be important that X has a “nice” split property, e.g. : X (x:s) = x  X s // for some  27

Some helping concepts TAILS gives all tails of an array : TAILS a i = [ a[p . . . i) | p from [0 . . . i] ] SEGS gives the segments; we’ll define it in terms of TAILS: SEGS a 0 = [[]] SEGS a (i+1) = SEGS a i ++ TAILS a (i+1)

Specification of “Longest Zero Segment” This gives the length of the logest zero-segment: LZS a i = MAX [# s | s from SEGS a i, ALLZ s ] ALLZ s = … // list s consists of only zeros # s // length of s (COUNT s) We’ll need a split theorem a[0..i+1) a[0..i) 1 3 2 a[i] LZS a (i+1) = LZS a i max LZTail a (i+1)

LZS Split The LZS split theorem: // require i0 LZS a (i+1) = LZS a i max LZTail a (i+1) Longest “zero tail” : LZTail a i = MAX [ # t | t from TAILS a i, ALLZ t ]

Specifying and Deriving the program  Inv: lz = LZS a i /\ 0  i  n term. metric : n - i <initialization> while i<n do { <some statement> ; i := i+1 } {* lz = LZS a n *}

Deriving the body {* lz = LZS a i /\ 0in /\ i<n *} {* lz max LZTail a(i+1) = LZS a i max LZTail a(i+1) *} // wp lz := lz max LZTail a (i+1) // intro solution {* lz = LZS a i max LZTail a(i+1) *} // split {* lz = LZS a (i+1) /\ 0i+1n *} // wp i := i+1 {* lz = LZS a i /\ 0in *}

So we obtain … Inv: lz = LZS a i /\ 0  i  n {* n0 *} /\ lt = LZTail a i Inv: lz = LZS a i /\ 0  i  n {* n0 *} <initialization> while i<n do { lz := lz max LZTail a (i+1) ; i := i+1 } How to compute this efficiently?? Idea: compute it side by side. Extend inv to capture this. {* lz = LZS a n *}

Splitting LZTail Split The LZTail split theorem: // require i0 LZTail a (i+1) = a[i]0  0 | (LZTail a i) + 1 a[0..i+1) a[0..i) 1 3 2 a[i] LZTail a (i+1) = a[i]  0  0 | …

Continue… {* lz = LZS a i /\ lt = LZTail a i /\ 0  i  n /\ i<n *} {* a[i]0  0 | lt + 1 = a[i]0  0 | LZTail a i + 1 *} lt := a[i]0  0 | lt + 1 {* lt = a[i]0  0 | LZTail a i + 1 *} // split {* lt = LZTail a (i+1) *} lz := lz max LZTail a (i+1) ; i := i+1 replace this with “lt” {* lz = LZS a i /\ lt = LZTail a i /\ … *}

Finishing it i:=0 ; lz,lt := 0,0 {* n0 *} Inv : lz = LZS a i /\ lt = LZTail a i /\ 0  i  n <initialization> while i<n do { if a[i]0 then lt:=0 else lt:=lt+1 ; lz := lz max lt i := i+1 } {* lz = LZS a n *}