1 / 86

# Advanced Recursion Design by Contract Data Abstraction - PowerPoint PPT Presentation

Lecture 7. Advanced Recursion Design by Contract Data Abstraction. Advanced Recursion. Recursive Function Example: Factorial. Problem: calculate n! (n factorial) n! = 1 if n = 0 n! = 1 * 2 * 3 *...* n if n > 0 Recursively: if n = 0 , then n! = 1

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.

## PowerPoint Slideshow about 'Advanced Recursion Design by Contract Data Abstraction' - vilmos

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

### Advanced RecursionDesign by ContractData Abstraction

Problem: calculate n! (n factorial)

n! = 1 if n = 0

n! = 1 * 2 * 3 *...* n if n > 0

Recursively:

if n = 0, then n! = 1

if n > 0, then n! = n * (n-1)!

• See recursive solutions as two sections:

• Current

• Rest

N! = N * (N-1)!

7! = 7 * 6!

7! = 7 * (6 * 5 * 4 * 3 * 2 * 1 * 1)

function Factorial returnsa Num

(n isoftype in Num)

// Calculates n factorial, n!

// Precondition: n is a non-negative

// integer

if (n = 0) then

Factorial returns 1

else

Factorial returns n * Factorial(n-1)

endif

endfunction //Factorial

then Fact returns 1

else

Fact returns 1

endif

endfunction //Fact

if (1 = 0)

then Fact returns 1

else

Fact returns 1 * Fact(0)

endif

endfunction //Fact

if (2 = 0)

then Fact returns 1

else

Fact returns 2 * Fact(1)

endif

endfunction //Fact

if (3 = 0)

then Fact returns 1

else

Fact returns 3 * Fact(2)

endif

endfunction //Fact

algorithm Test

ans <- Fact(3)

endalgorithm

5. Return value and release stack frame

3. Create a new Stack Frame

2. Recursive call to Fact

Tracing Details

function Fact returnsa Num (2)

if (2 = 0)

then Fact returns 1

else

Fact returns 2 * Fact(1)

endif

endfunction //Fact

Call the function: answer <- Fact(5)

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 3rd: N=3, Unfinished: 3*Fact(2)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 4th: N=2, Unfinished: 2*Fact(1)

Fact. 3rd: N=3, Unfinished: 3*Fact(2)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 5th: N=1, Unfinished: 1*Fact(0)

Fact. 4th: N=2, Unfinished: 2*Fact(1)

Fact. 3rd: N=3, Unfinished: 3*Fact(2)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 6th: N=0, Finished: returns 1

Fact. 5th: N=1, Unfinished: 1*Fact(0)

Fact. 4th: N=2, Unfinished: 2*Fact(1)

Fact. 3rd: N=3, Unfinished: 3*Fact(2)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 5th: N=1, Finished: returns 1*1

Fact. 4th: N=2, Unfinished: 2*Fact(1)

Fact. 3rd: N=3, Unfinished: 3*Fact(2)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 4th: N=2, Finished: returns 2*1

Fact. 3rd: N=3, Unfinished: 3*Fact(2)

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 3rd: N=3, Finished: returns 3*2

Fact. 2nd: N=4, Unfinished: 4*Fact(3)

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 2nd: N=4, Finished: returns 4*6

Fact. 1st: N=5, Unfinished: 5*Fact(4)

Main Algorithm: Unfinished: answer <- Fact (5)

Fact. 1st: N=5, Finished: returns 5*24

Main Algorithm: Unfinished: answer <- Fact (5)

Main Algorithm: Finished: answer <- 120

Exponentiation

baseexponent

e.g. 53

Could be written as a function

Power(base, exp)

Can we write it recursively?

be = b * b(e-1)

What’s the limiting case?

When e = 0 we have b0 which always equals?

1

function Power returnsa Num

(base, exp isoftype in Num)

// Computes the value of BaseExp

// Pre: exp is a non-negative integer

if (exp = 0) then

Power returns 1

else

Power returns base * Power(base, exp-1)

endif

endfunction //Power

Power base = 3 exp = 0 Finished:1

1

Power base = 3 exp = 1 3 *Power(3,0)

3

Power base = 3 exp = 2 3 *Power(3,1)

9

Power base = 3 exp = 3 3 *Power(3,2)

27

Power base = 3 exp = 4 3 *Power(3,3)

81

Algo: total <- Power(3,4)

Function Power returnsa Num (base, exp isoftype in Num)

//Computes the value of BaseExp

//Preconditions: exp is a non-negative integer

if(exp = 0 ) then

Power returns 1

else

Power returns

(base *

Power(base, exp – 1))

endif

endfunction //Power

Activations Stack Example

1

3

9

27

Total <- 81

Bunnies?

• The Time: 13th Century

• The Place: Italy

• The Man: Fibonacci

• The Problem: We start with a pair of newborn rabbits. At the end of the 2nd month, and each month thereafter the female gives birth to a new pair of rabbits: one male and one female. The babies mature at the same rate as the parents and begin to produce offspring on the same schedule. So how many rabbits do we have at the end of one year?

Fibonacci Number Sequence

if n = 1, then Fib(n) =1

if n = 2, then Fib(n) = 1

if n > 2, then Fib(n) = Fib(n-2) + Fib(n-1)

Numbers in the series:

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

function Fib returnsa Num (n iot in Num)

// Calculates the nth Fibonacci number

// Precondition: N is a positive integer

if ((n = 1) OR (n = 2)) then

Fib returns 1

else

Fib returnsFib(n-2) + Fib(n-1)

endif

endfunction //Fibonacci

Fib(5): Fib returns Fib(3) + Fib(4)

Fib(3): Fib returns Fib(1) + Fib(2)

Fib(5): Fib returns Fib(3) + Fib(4)

Fib(1): Fib returns 1

Fib(3): Fib returns Fib(1) + Fib(2)

Fib(5): Fib returns Fib(3) + Fib(4)

Fib(3): Fib returns 1 + Fib(2)

Fib(5): Fib returns Fib(3) + Fib(4)

Fib(2): Fib returns 1

Fib(3): Fib returns 1 + Fib(2)

Fib(5): Fib returns Fib(3) + Fib(4)

Fib(3): Fib returns 1 + 1

Fib(5): Fib returns Fib(3) + Fib(4)

Fib(5): Fib returns 2 + Fib(4)

Fib(4): Fib returns Fib(2) + Fib(3)

Fib(5): Fib returns 2 + Fib(4)

Fib(2): Fib returns 1

Fib(4): Fib returns Fib(2) + Fib(3)

Fib(5): Fib returns 2 + Fib(4)

Fib(4): Fib returns 1 + Fib(3)

Fib(5): Fib returns 2 + Fib(4)

Fib(3): Fib returns Fib(1) + Fib(2)

Fib(4): Fib returns 1 + Fib(3)

Fib(5): Fib returns 2 + Fib(4)

Fib(1): Fib returns 1

Fib(3): Fib returns Fib(1) + Fib(2)

Fib(4): Fib returns 1 + Fib(3)

Fib(5): Fib returns 2 + Fib(4)

Fib(3): Fib returns 1 + Fib(2)

Fib(4): Fib returns 1 + Fib(3)

Fib(5): Fib returns 2 + Fib(4)

Fib(2): Fib returns 1

Fib(3): Fib returns 1 + Fib(2)

Fib(4): Fib returns 1 + Fib(3)

Fib(5): Fib returns 2 + Fib(4)

Fib(3): Fib returns 1 + 1

Fib(4): Fib returns 1 + Fib(3)

Fib(5): Fib returns 2 + Fib(4)

Fib(4): Fib returns 1 + 2

Fib(5): Fib returns 2 + Fib(4)

Fib(5): Fib returns 2 + 3

Recursion doesn’t always occur because a routine calls itself...

Mutual Recursion occurs when two routines call each other.

A

B

A

B

Problem: Determine whether a number, N, is odd or even.

• If N is equal to 0, then n is even

• N is odd if N-1 is even

function Odd returnsa Boolean (n iot in Num)

if (n = 0) then

Odd returns FALSE

else

Odd returns Even (n - 1)

endif

endfunction //Odd

function Even returnsa Boolean (n iot in Num)

if (n = 0) then

Even returns TRUE

else

Even returns Odd (n - 1)

endif

endfunction //Even

• Decide on the terminating condition

• Decide the final actions when you terminate

• There may be none

• If you are computing something, this usually starts a “ripple” of returned data

• Decide how to take a step closer to terminating

• Decide how to call a “clone” of this module

• Decide what work to do at this step in recursion

### Design by Contract

• function Fibonacci returnsa Num(n isoftype in num)

• // Returns Nth fibonacci number

• if ((n=0) OR (n=1)) then

• Fibonacci returns 1

• else

• Fibonacci returns Fibonacci(n-1) + Fibonacci(n-2)

• endif

• endfunction // Fibonacci

What if we call it via:

some_var <- Fibonacci(-1)

or

some_var <- Fibonacci(4.3)

The module will never reach its terminating condition and willnever end!

• function Fibonacci returnsa num (n iot in num)

• // Returns Nth fibonacci number

• // Ensure n is a non-negative integer

• if ((n < 0) or ((n mod 1) < > 0)) then

• print( "Illegal n in function!" )

• else

• // Old module body follows...

• if((n = 0) OR (n = 1)) then

• Fibonacci returns 1

• else

• New_Fibonacci returns Fibonacci(n-1) +

• Fibonacci(n-2)

• endif

• endif

• endfunction // Fibonacci

• Inefficient because we’re doing the test unnecessarily at each iteration

• Functions must always return a value

• Mixes “correctness” part with “carrying out algorithm” part

• Doing more than one thing

• Functions cannot print!

• Like a business contract (house-building)

• The module’s client is the caller of the module.

• The supplier is the called module

• The pre-condition states the responsibilities of the client

• The post-condition states the guarantees made by the supplier

• Make both client and supplier responsibilitiesexplicit as part of documentation.

• Both client and supplier know what is expected of them and what to expect of the other.

• function Fibonacci returnsa num(n isoftype in num)

• // Purpose: Returns nth fibonacci number

• // Pre-condition: n is a non-negative integer

• // Post-condition: The returned number is the nth// number in the fibonacci

• // sequence

### Introduction to Data Abstraction: Records

beans

canned peaches

chips

coke

dental floss

ice cream

shoe polish

John Tesh CD

carrots

groceries

LB

Where ya been?Krogers.What’s in the bag?

• Separating the essence from the particular instance or implementation.

• The most fundamental technique:

• Descriptive identifiers that are brief and informative (not cryptic or cute)

• Example:

• For the purpose of representing an employee’s ID number, which one features the highest data abstraction?

• this_num isofype Num

• someone_num isoftype Num

• employee_ID_num isoftype Num

Data Abstraction allows us to:

• Combine data that belongs together

• Consider the logical grouping of data

• Apart from the specific implementation

Records are the mechanism for data grouping.

• Defined in the algorithm

• A heterogeneous collection of data(we can mix different types of data in a single structure)

• Information concerning a student:

name isoftype String

age isoftype Num

is_male isoftype Boolean

• This should be abstractly grouped together!

name (String)

age (Num)

is_male (Boolean)

Record Definition Example

Student_Type definesa record

name isoftype String

age isoftype Num

is_male isoftype Boolean

endrecord // Student_Type

Instead of a collection of 4 variables, we have defined a new data type and now have the ability to create variables of Student_Type, each with the appropriate information.

Record Templates

Definition:

<Type Name> definesa record

<field definitions>

endrecord

Declaration:

<Identifier> isoftype <Type Name>

Student_Type definesa record

name isoftype String

age isoftype Num

is_male isoftype Boolean

endrecord // Student_Type

Stu1, Stu2, Stu3 isoftype Student_Type

This creates three variables of type Student_Type. Each of these variables contains information about name, age, is_male, and letter_grade.

• We use records to construct new “user-defined” data types

• The newly created data type is treated like any of the “built-in” types

• Cannot read or print user defined data types directly. Since the new type is new to the language, read and print don’t know how to process the request.

• Creating variables of a new data type is a two-step process: define & then declare

• Creating the new data type does not provide any variables, only the template by which variables may then be declared.

Create a database to keep track of the kids in an elementary school

To make the example simple, we will only store:

• Student number

• Age

• Grade in math this year

### Creating New Data Types Example

Step 1: Define the new type:

Kid_Record definesa Record

student_num isoftype Num

age isoftype Num

endrecord

Step 2: Declare Record variables of this new type:

mary, zach, herbert isoftype Kid_Record

• We can access the individual fields of a record using the dot (.) operator:

<var_name>.<field_name>

Examples:

• mary.student_num <- 45137

• mary.age <- 13

• zach.age <- 12

Assignment works just as before with built-in types (both sides must be of the same type):

• // assigns ALL fields in single op

• zach <- mary

Printing and reading can only take built-in types as parameters, so we print and read fields, not records.

Note: Items of the form

• some_record_var.some_field

• are L-values - they may appear on the left of an assignment & may be passed as in, in/out, or out parameters.

• Often, data abstractions (for example, records) need corresponding procedural abstractions (modules) as helpers.

• Common examples include:

• Modifier modules: procedures usedto read in or update data values

• Accessor modules: procedures used to print out information in a record, or functions which return data values to other modules

• We will revisit this idea when we talk about behavioral abstractions later in the course

• For example:

• Student_Rec definesa Record

• name isoftype String

• ssn isoftype Num

• num_hours isoftype Num

• endrecord

• procedure Print_Student(somebody isoftype in Student_Rec)

• // An accessor module which prints out all // data values stored in a Student_Rec print(“Name: ”, somebody.name)

• print( “SSN: ”, somebody.ssn )

• print( “Hours:”, somebody.num_hours )

• endprocedure

• procedure Read_Student (somebody isoftype out Student_Rec)

• // A modifer module which obtains data// values and stores them in a Student_Rec

• print(“Enter the student’s name: ” )

• print(“Enter the student’s ssn: ” )

• print( “Enter the student’s hours taken: ” )

• ...

• Student_1 isoftype Student_Rec

• // call to modifier

• // call to accessor

• Print_Student(Student_1)

• ...

• Student_2 isoftype Student_Rec

• // call to modifier

• // call to accessor

• Print_Student(Student_2)

There is nothing to prevent us from placing records inside of records (a field within a record):

Date_Type definesa record

day, month, year isoftype num

Endrecord

Student_Type definesa record

name isoftype string

gpa isoftype num

birth_day isoftype Date_Type

endrecord

name

gpa

day month year

day month year

Record Within Records

Date_Type:

Student_Type:

bob isoftype Student_Type

bob.birth_day.month <- 6

birth_day

• TYPE Definitions

• Create templates for new kinds of variables

• Do not create a variable – no storage space is allocated

• Have unlimited scope

• VARIABLE Declarations

• Actually create storage space

• Have limited scope - only module containing the variable can “see” it

• Must be based on an existing data type

• This_Record isoftype record

• silly isoftype Num

• stupid isoftype Char

• endrecord // This_Record

• Anonymous data typescombine the declaration of a complex variable with a data type definition.

• Thus, the data type itself has no name.

• Some languages allow this

• Removesbenefits of data typing

• Is in general bad; do not do this even if a language allows it

• If two different variables are anonymous data types with identical structure, then they can hold the same data, but:

• They are not of the same type; they are of no type

• Cannot assign one to another

• Cannot pass grouped data between them via parameter

• Must assign field-by-field

• Must make changes in multiple places

• Don’t do it!!

• In our pseudo-code, cannot do it