Forward Assignment; Strongest Postconditions

Similar documents
Shared Variables and Interference

Shared Variables and Interference

Program Syntax; Operational Semantics

Hoare Logic: Proving Programs Correct

Types, Expressions, and States

Lecture Notes: Hoare Logic

CS 3512, Spring Instructor: Doug Dunham. Textbook: James L. Hein, Discrete Structures, Logic, and Computability, 3rd Ed. Jones and Barlett, 2010

Specifications. Prof. Clarkson Fall Today s music: Nice to know you by Incubus

Induction and Semantics in Dafny

6. Hoare Logic and Weakest Preconditions

Synchronization: Semaphores

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

Introduction to Axiomatic Semantics

Review: Hoare Logic Rules

Recursively Enumerable Languages, Turing Machines, and Decidability

Spring 2018 PhD Qualifying Exam in Languages

Lectures 20, 21: Axiomatic Semantics

Lecture 5 - Axiomatic semantics

Qualifying Exam Languages

Program Verification & Testing; Review of Propositional Logic

Formal Methods. CITS5501 Software Testing and Quality Assurance

Program Verification. Program Verification 307/434

Reasoning About Imperative Programs. COS 441 Slides 10

Programming Languages Third Edition

AXIOMS OF AN IMPERATIVE LANGUAGE PARTIAL CORRECTNESS WEAK AND STRONG CONDITIONS. THE AXIOM FOR nop

Starting Boolean Algebra

Hardware versus software

PROPER TECHNIQUE OF SOFTWARE INSPECTION USING GUARDED COMMAND LANGUAGE

Binary Decision Diagrams

No model may be available. Software Abstractions. Recap on Model Checking. Model Checking for SW Verif. More on the big picture. Abst -> MC -> Refine

8 NP-complete problem Hard problems: demo

Introduction to Axiomatic Semantics (1/2)

An Annotated Language

Hoare triples. Floyd-Hoare Logic, Separation Logic

The Rule of Constancy(Derived Frame Rule)

(a) (4 pts) Prove that if a and b are rational, then ab is rational. Since a and b are rational they can be written as the ratio of integers a 1

Backward Reasoning: Rule for Assignment. Backward Reasoning: Rule for Sequence. Simple Example. Hoare Logic, continued Reasoning About Loops

SOFTWARE ENGINEERING DESIGN I

Programming Languages and Compilers Qualifying Examination. Answer 4 of 6 questions.

Formalizing Dijkstra

Denotational Semantics of a Simple Imperative Language Using Intensional Logic

COMP 507: Computer-Aided Program Design

Some Hardness Proofs

NP-complete Reductions

CSE 311: Foundations of Computing. Lecture 8: Predicate Logic Proofs

Introduction to Axiomatic Semantics (1/2)

Reasoning about programs

Last time. Reasoning about programs. Coming up. Project Final Presentations. This Thursday, Nov 30: 4 th in-class exercise

Intermediate Algebra. Gregg Waterman Oregon Institute of Technology

CMPSCI 250: Introduction to Computation. Lecture #7: Quantifiers and Languages 6 February 2012

Warm-Up Problem. 1. What is the definition of a Hoare triple satisfying partial correctness? 2. Recall the rule for assignment: x (assignment)

Lecture 6,

Hoare Logic. COMP2600 Formal Methods for Software Engineering. Rajeev Goré

6.170 Lecture 6 Procedure specifications MIT EECS

Incremental Proof Development in Dafny

Example of a Demonstration that a Problem is NP-Complete by reduction from CNF-SAT

Text Input and Conditionals

DATABASE THEORY. Lecture 18: Dependencies. TU Dresden, 3rd July Markus Krötzsch Knowledge-Based Systems

Specification and Verification I

Note that in this definition, n + m denotes the syntactic expression with three symbols n, +, and m, not to the number that is the sum of n and m.

Fall Recursion and induction. Stephen Brookes. Lecture 4

Formal Semantics. Prof. Clarkson Fall Today s music: Down to Earth by Peter Gabriel from the WALL-E soundtrack

Greedy Algorithms. Algorithms

SE 3S03. Zahra Ali. Week of Feb 22, 2016

An Interesting Way to Combine Numbers

Menu. Algebraic Simplification - Boolean Algebra EEL3701 EEL3701. MSOP, MPOS, Simplification

The complement of PATH is in NL

Foundations, Reasoning About Algorithms, and Design By Contract CMPSC 122

COSC252: Programming Languages: Semantic Specification. Jeremy Bolton, PhD Adjunct Professor

1 Introduction. 1. Prove the problem lies in the class NP. 2. Find an NP-complete problem that reduces to it.

CSE 307: Principles of Programming Languages

NP-Completeness of 3SAT, 1-IN-3SAT and MAX 2SAT

CSE505, Fall 2012, Midterm Examination October 30, 2012

Repetition Through Recursion

Logic and Computation Lecture 20 CSU 290 Spring 2009 (Pucella) Thursday, Mar 12, 2009

Lecture Notes 15 Number systems and logic CSS Data Structures and Object-Oriented Programming Professor Clark F. Olson

CS 125 Section #4 RAMs and TMs 9/27/16

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

Mathematical Logic Prof. Arindama Singh Department of Mathematics Indian Institute of Technology, Madras. Lecture - 37 Resolution Rules

(Refer Slide Time 6:48)

CS161 Handout 07 Summer 2013 July 17, 2013 Guide to Reductions. Thanks to Julie Tibshirani for helping with this handout!

Programming Languages Fall 2013

Proving Programs Correct

Implementation of Lexical Analysis. Lecture 4

SE 3S03 - Tutorial 10. Helen Brown. Week of Mar 23, 2015

CIS 500 Software Foundations. Final Exam. May 3, Answer key

User s Guide for BDDs in Jython

Typing Control. Chapter Conditionals

CS103 Handout 29 Winter 2018 February 9, 2018 Inductive Proofwriting Checklist

Arguing for program correctness and writing correct programs

CS 440: Programming Languages and Translators, Spring 2019 Mon

Abstract Interpretation

Inferring Invariants in Separation Logic for Imperative List-processing Programs

A short manual for the tool Accumulator

Guarded Commands, Nondeterminancy and Formal Derivation of Programs. Edsger W. Dijkstra. CACM 18, 8 pp (Aug. 1975).

Characters, Strings, and Floats

To figure this out we need a more precise understanding of how ML works

Lecture 3: Recursion; Structural Induction

Skill 1: Multiplying Polynomials

CMSC 330: Organization of Programming Languages

Transcription:

3/1 new version Forward Assignment; Strongest Postconditions CS 536: Science of Programming, Spring 2018 A. Why? At times, a forward version of the assignment rule is more appropriate than the backward version. The forward assignment rule is part of calculating the sp (strongest postcondition) of a loop-free program. B. Outcomes At the end of this lecture you should Know the basic assignment axioms. Know what a strongest postcondition is and how to calculate the sp of loop-free programs. C. Forward Assignment Rules We already have a backwards assignment rule, {p(e)} v := e {p(v)} where p is a predicate function. If we just use p as a predicate, the rule is {p[e v]} v := e {p}. Since p[e v] wlp(v := e, p), we know this is the most general possible rule. What about the other direction, {p} v := e {???} what can we use for the postcondition? Most people s first guess is {p} v := e {p v = e}, which can work under certain conditions. New Variable Introduction If v is a new (fresh) variable (doesn t appear free in p and doesn t appear in e) then {p} v := e {p v = e}. For example, {x > y} z := 2 {x > y z = 2} To justify this, using wlp, we know {(p v = e)[e v]} v := e {p v = e}. Expanding, (p v = e)[e v] p[e v] e = e[e v]. Since v is fresh, it doesn't occur in p or e, so p[e v] p and e[e v] e. So we need {p e = e} v := e {p v = e}, which definitely holds. Forward Assignment (General Case) As an example of why {p} v := e {p v = e} doesn t work in general, consider {x > 0} x := x/2 {???}. Since division truncates, if x = 1, the final state doesn t satisfy x > 0. We might want to try x*2 > 0 as the postcondition, but again this fails if x = 1. What we do know is that the value x had before the assignment was positive, and the new value of x is half of the old value of x. If we use x₀ as the name for the value of x before the assignment, we can say {x₀ = x x > 0} x := x/2 {x₀ > 0 x = x₀/2}. Note we don t have to actually store x₀ in memory; it s just a name we use for logical reasoning purposes x₀ is a fresh logical constant ; fresh in the sense that it doesn t appear in p or e, logical because it only appears in the correctness discussion, not the program, and constant because though x changes, x₀ doesn t. (Note in this context, logical doesn t mean boolean.) CS 536-05: Science of Programming 1 James Sasaki, 2018

The general rule is {p v = v₀} v := e {p[v₀ v] v = e[v₀ v]}. In the precondition, we may be able to omit v = v₀ as being understood. Example 1a: {x > 0 x = x₀} x := x-1 {x₀ > 0 x = x₀-1}. Example 2a: {s = sum(0,i) s = s₀} s := s+i+1 {s₀ = sum(0,i) s = s₀+i+1}. The x = x₀ and s = s₀ clauses are a bit annoying; we could drop them by using an existential in the postcondition, but that s no fun either: Example 1b: {x > 0} x := x-1 { x₀. x₀ > 0 x = x₀-1} Example 2b: {s = sum(0,i)} s := s+i+1 { s₀.s₀ = sum(0,i) s = s₀+i+1}. Let s drop the existential as implied when a symbol appears in the postcondition but not the precondition, then we re implicitly quantifying it existentially in the postcondition. We ve actually been doing something similar with the precondition: Variables free in the precondition are treated as being universally quantified across both the precondition and postcondition. Example 1c: (For all x, there is an x₀ such that) {x > 0} x := x-1 {x₀ > 0 x = x₀-1} Example 2c: (For all s and i, there is an s₀ such that) {s = sum(0,i)} s := s+i+1 {s₀ = sum(0,i) s = s₀+i+1}. Example 3: {s₀ = sum(0, i) s = s₀+i+1} i := i+1 {s₀ = sum(0, i₀) s = s₀+i₀+1 i = i₀+1}. The postcondition of this example can be weakened to s = sum(0,i), which will be useful later for explaining the loop while i < n do s := s+i+1; i := i+1 od. Correctness of The Forward Assignment Rule The forward assignment rule appears to be very different from our earlier backward assignment rule, but actually, we can derive the forward assignment rule using the backward assignment rule. Theorem (Correctness of Forward Assignment {p v = v₀} v := e {p[v₀ v] v = e[v₀ v]}, where v₀ is a fresh logical constant. Proof: We'll argue that the precondition p v = v₀ implies the wlp of the assignment and postcondition. We need (p v = v₀) wlp(v := e, q), where q (p[v₀ v] v = e[v₀ v]). Simplifying, wlp(v := e, q) q[e v] (p[v₀ v] v = e[v₀ v])[e v] p[v₀ v][e v] v[e v] = e[v₀ v][e v] We can simplify p[v₀ v][e v] v[e v] = e[v₀ v][e v] by looking at its three parts. The easiest one is v[e v] e. For p[v₀ v], since v doesn t appear in it, we have p[v₀ v][e v] p[v₀ v], which is p v = v₀. Similarly, since v doesn t appear in e[v₀ v], we have e[v₀ v][e v] = e[v₀ v] = e when v = v₀. So (p[v₀ v][e v] v[e v] = e[v₀ v][e v]) p v = v₀ e = e p v = v₀. For a particular example, with {x > 0 x = x₀} x := x-1 {x₀ > 0 x = x₀-1}, we find wlp(x := x-1, x₀ > 0 x = x₀-1) x₀ > 0 x-1 = x₀-1, which is implied by x > 0 x = x₀. CS 536-05: Science of Programming 2 James Sasaki, 2018

Note that the simpler rule for introducing a new variable is a special case of the general rule: We want {p} v := e {p v = e} if v doesn t occur in e or and v is not free in p. The forward assignment rule says {p} v := e {p[v₀ v] v = e[v₀ v]}, where v₀ is a fresh logical constant. Since v does not occur in e, we know e[v₀ v] e. Similarly, since v isn t free in p, we know p[v₀ v] p. Substituting into {p} v := e {p[v₀ v] v = e[v₀ v]} gives us {p} v := e {p v = e}. D. The Strongest Postcondition (sp) Definition: Given a precondition p and program S, the strongest postcondition of p and S is (the predicate that stands for) the set of states we can terminate in if we run S starting in a state that satisfies p. In symbols, sp(p, S) = {τ τ M(S, σ) Σ for some σ where σ p}. Equivalently, sp(p, S) = (M(S, σ) Σ) where σ p. I.e., sp(p, S) is the image of M(S, ) (considered as a function) over the set of states that satisfy p. Figures 1 and 2 show the relationship between p, S, and sp(p, S) and sp( p, S) If σ p, then every state in M(S, σ) Σ is by definition in sp(p, S), so {p} S {sp(p, S)}. This is only valid for partial correctness: Starting in a state that satisfies p might yield an error. (To get total correctness, we need termination: tot {p} S {sp(p, S)} iff tot {p} S {T}.) For sp( p, S), the situation is symmetric: If σ p, then every state in M(S, σ) Σ is by definition in sp( p, S). We have partial correctness for {p} S {sp( p, S)}. We only get total correctness if S always terminates starting in p. Notice that sp(p, S) and sp( p, S) can have states in common: sp(p, S) sp( p, S), just means it s possible for states satisfying p and p to map to a common final state. p S err X sp(p, S) sp(p, S) X p sp( p, S) Figure 1: sp(p, S) is the set of states reachable via S from p CS 536-05: Science of Programming 3 James Sasaki, 2018

p sp(p, S) X p S err X sp( p, S) sp( p, S) Figure 2: sp( p, S) is the set of states reachable via S from p Example 4: For an example where sp(p, S) and sp( p, S) overlap, since x := x 4 maps x = 0, 1, 2, and 3 to x = 0, the state {x = 0} can be reached using x := x 4 from states where x 2 and also from states where x < 2, so x = 0 sp(x 2, x := x 4) sp(x < 2, x := x 4). Example 5: Let W while i 0 do i := i-1 od. Clearly, if W terminates, it s with i = 0, so for any precondition p, if i isn t free in p, we have sp(p, W) p i = 0, so {p} W {p i = 0} is partially correct. However, it s not totally correct for every p: It terminates iff we start in a state with i 0 (i.e., tot {i 0} W {T}). So {i 0} W {i = 0} is totally correct. However, {i < 0} W {i = 0} is partially correct but never totally correct. Strongest postcondition: For partial correctness, {p} S {sp(p, S)} (i.e., sp(p, S) is a postcondition). What makes it the strongest postcondition is that it implies any other postcondition: for general q, {p} S {q} iff sp(p, S) q. The proof of strength is easy: By definition of sp, every state τ sp(p, S) comes from some M(S, σ) where σ p. Since {p} S {q} is partially correct, we also know τ q. Since every state satisfying sp(p, S) also satisfies q, we know that sp(p, S) q is valid. E. Strongest Postconditions for Loop-Free Programs Recall the forward assignment rule: {p v = v₀} v := e {p[v₀ v] v = e[v₀ v]}, where v₀ is a fresh logical constant and the v = v₀ conjunct is optional and implicit. It turns out (we won t prove this) that this rule gives the strongest postcondition of the precondition and assignment, and we can use it as the base for calculating the strongest postcondition of a loop-free program: sp(p, skip) p sp(p, v := e) p[v₀ v] v = e[v₀ v], where v₀ is a fresh constant. sp(p, S₁; S₂) sp(sp(p, S₁), S₂) The most we can know after S₁ ; S₂ is the most we know after executing S₂ in the state that is the most we know after S₁. sp(p, if B then S₁ else S₂ fi) sp(p B, S₁) sp(p B, S₂) After executing an if-else, we know what we know after executing the true branch (after the test succeeded) or the false branch (after the test failed), but we don t know which branch was taken. CS 536-05: Science of Programming 4 James Sasaki, 2018

For specific p, B, S₁, and S₂, we might be able to infer which branch was taken, but in the general case, we can t. sp(p, if B₁ S₁ B₂ S₂ fi) sp(p B₁, S₁) sp(p B₂, S₂). As with deterministic if-else, once the nondeterministic if-fi finishes, we know it evaluated one of the guarded commands but not necessarily which one. F. Examples of Strongest Postconditions Example 6: Let s use sp to fill in the postcondition of {x > y} x := x+k; y := y+k {???} (Presumably, the postcondition will imply that x is still > y.) Let p x > y, then sp(p, x := x + k; y := y + k) sp(sp(p, x := x + k), y := y + k). Let s calculate the inner sp first: sp(p, x := x + k) sp(x > y, x := x + k) (x > y)[x₀ x] x = (x + k)[x₀ x] x₀ > y x = x₀ + k Then going back to our original problem and the outer sp, we get sp(p, x := x + k; y := y + k) sp(sp(p, x := x + k), y := y + k) sp(x₀ > y x = x₀ + k, y := y + k) (x₀ > y x = x₀ + k)[y₀ y] y = (y + k)[y₀ y] x₀ > y₀ x = x₀ + k y = y₀ + k So our original triple can be filled in as {x > y} x := x + k; y := y + k {x₀ > y₀ x = x₀ + k y = y₀ + k} Example 7: Using the same program, let s compare the triple we got using sp with a triple we get using wp. For the postcondition, let s use x > y: wp(x := x + k; y := y + k, x > y) wp(x := x + k, wp(y := y + k, x > y)) wp(x := x + k, (x > y)[y+k y]) wp(x := x + k, (x > y + k)) (x > y + k)[x+k x] x + k > y + k Which gives us {x+k > y+k} x := x+k; y := y+k {x > y} Example 8: Let p y = y₀ and S if x 0 then y := x else y := -x fi. Then sp(p x 0, y := x) (x 0)[y₀ y] y = x[y₀ y] x 0 y = x sp(p x < 0, y := -x) (x < 0)[y₀ y] y = -x[y₀ y] x < 0 y = -x CS 536-05: Science of Programming 5 James Sasaki, 2018

So sp(y = y₀, if x 0 then y := x else y := -x fi) sp(p x 0, y := x) sp(p x < 0, y := -x) x 0 y = x x < 0 y = -x Note that since the assignments to y don't depend on y₀. we don't find y₀ occurring in the result. Example 9: Let S if even(x) then x := x+1 else x := x+2 fi and let p x 0, then sp(p, S) sp(p, if even(x) then x := x+1 else x := x+2 fi) sp(p even(x), x := x+1) sp(p odd(x), x := x+2) For the true branch, sp(p even(x), x := x+1) (p even(x))[x₀ x] x = (x+1)[x₀ x] (x 0 even(x))[x₀ x] x = (x+1)[x₀ x] x₀ 0 even(x₀) x = x₀+1 For the false branch, sp(p odd(x), x := x+2) (p odd(x))[x₀ x] x = (x+2)[x₀ x] (x 0 odd(x))[x₀ x] x = x₀+2 x₀ 0 odd(x₀) x = x₀+2 So sp(p, S) sp(p even(x), x := x+1) sp(p odd(x), x := x+2) (x₀ 0 even(x₀) x = x₀+1) (x₀ 0 odd(x₀) x = x₀+2) If we want to logically simplify, we get x₀ 0 (even(x₀) x = x₀+1 odd(x₀) x = x₀+2). That s about as far as we can simplify without losing information. For example, we could simplify to (x₀ 0 (x = x₀ + 1 x = x₀ + 2)) or to (x 1 odd(x)), but whether we want to simplify or not depends on where we re using the sp in the overall proof of correctness for the program. Old values before conditionals If we modify a variable in both arms of a conditional statement, then we need an implicit old value clause before the conditional: { x = x₀} if then x := else x := fi. Even if the variable is modified in only one arm of the conditional, to avoid losing information, it might still be necessary to track the old value before the conditional, not just in the arm that changes it I.e., { x = x₀} if then x := else x := fi Versus { } if then { x = x₀} x := else no change to x fi Example 10: Let S if x y then x := x-y else y := y-x fi Let q₁ sp(x = x₀ y = y₀, S) sp(x = x₀ y = y₀ x y, x := x-y) sp(x = x₀ y = y₀ x < y, y := y-x) (y = y₀ x₀ y x = x₀-y) (x = x₀ x < y₀ y = y₀-x) With q₁, if the first disjunct holds, then x₀ y₀; if the second disjunct holds, then x₀ < y₀. CS 536-05: Science of Programming 6 James Sasaki, 2018

If we only introduce x₀ and y₀ just before the assignments to x and y, we get For the true branch, sp(x = x₀ x y, x := x-y) (x₀ y x = x₀-y) For the false branch, sp(y = y₀ x < y, y := y-x) (x < y₀ y = y₀-x) Let q₂ be their disjunction, (x₀ y x = x₀-y) (x < y₀ y = y₀-x). With q₂, if the first disjunct holds, we know x₀ y, but not x₀ y₀. Symmetrically, if the second conjunct holds, we know x < y₀, but not x₀ < y₀. (We certainly know x₀ y₀ or x₀ < y₀, but we've lost the connections with them and the two disjuncts.) Since q₁ implies q₂ but not vice versa, we know q₁ is the stronger of the two, so it, not q₂, should be the strongest postcondition. CS 536-05: Science of Programming 7 James Sasaki, 2018

Illinois Institute of Technology Activity 13 Assignment; Calculating sp CS 536: Science of Programming G. Why Sometimes the forward assignment rule is more helpful than the backward assignment rule. The strongest postcondition of a program is the most we can say about the state a program ends in. H. Objectives At the end of this activity you should be able to Calculate the sp of a simple loop-free program. Fill in a missing postcondition of a simple loop-free program. I. Questions 1. What basic properties does sp(p, S) have? For Questions 2-7, syntactically calculate the following, including intermediate sp calculation steps. Don t logically simplify the result unless asked to. 2. sp(y 0, skip) 3. sp(i > 0, i := i+1) [Hint: add an i = i₀ conjunct to i > 0] 4. sp(k n s = f(k, n), k := k+1) 5. sp(t, i := 0; k := i) [Go ahead and logically simplify as you go by dropping uses of T in the predicates] 6. sp(i j j-i < n, i := i+j; j := i+j). 7. Let S if x < 0 then x := -x fi a. Calculate sp(x = x₀, S). b. Logically simplify your result from part (a). Feel free to use the function abs( ) or. c. Suppose we had calculated sp(t, if x < 0 then x := -x fi) introducing x₀ in the true branch only. What would we get for the sp and what is the problem with it? CS 536: Science of Programming 8 James Sasaki, 2018

Illinois Institute of Technology Activity 13 Solution to Activity 13 (Forward Assignment; Strongest Postconditions) 1. The sp has two properties: sp(p, S) is a partial correctness postcondition: {p} S {sp(p, S)}. sp(p, S) is strongest amongst the partial correctness postconditions: {p} S {q} iff sp(p, S) q. (The second property actually implies the first, since sp(p, S) sp(p, S).) 2. y 0 (For the skip rule, the precondition and postcondition are the same.) 3. Let's implicitly add i = i₀ to the precondition, to name the starting value of i. Then sp(i > 0, i := i+1) (i > 0)[i₀ i] i = (i+1) [i₀ i] i₀ > 0 i = i₀+1 4. As in the previous problem, let's introduce a variable k₀ to name the starting value of k. Then sp(k n s = f(k, n), k := k+1) (k n s = f(k, n))[k₀ k] k = (k+1)[k₀ k] k₀ n s = f(k₀, n) k = k₀+1 5. We don't need to introduce names for the old values of i and k (they're irrelevant). sp(t, i := 0; k := i) sp(sp(t, i := 0), k := i) sp(i = 0, k := i) // We've dropped the "T " part of T i = 0) i = 0 k = i 6. Let's introduce i₀ and j₀ as we need them, then sp(i j j-i < n, i := i+j; j := i+j) sp(sp(i j j-i < n, i := i+j), j := i+j) sp(i₀ j j-i₀ < n i = i₀+j, j := i+j) i₀ j₀ j₀-i₀ < n i = i₀+j₀ j = i+j₀ 7. (Old value before an if-else) a. sp(x = x₀, if x < 0 then x := -x fi) sp(x = x₀ x < 0, x := -x) sp(x = x₀ x 0, skip fi) (x₀ < 0 x = -x₀) (x 0 x = x₀) b. We can simplify (x₀ < 0 x = -x₀) (x 0 x = x₀) x = x₀. c. If we had calculated sp(t, if x < 0 then x := -x fi) sp(t x < 0, x := -x) sp(t x 0, skip fi) (x₀ < 0 x = -x₀) x 0 Then we would have lost the information about the else clause not changing x, so we wouldn t have been able to conclude x = x₀. CS 536: Science of Programming 9 James Sasaki, 2018