Application Center - Maplesoft

App Preview:

Recurrence relations and recursion

You can switch back to the summary page by clicking here.

Learn about Maple
Download Application


 

0702.mws

Module 7: Discrete Mathematics

702 : Recursion

Gregory Moore

P U R P O S E

In this module, we'll examine recursion in various forms and from symbolic, numeric, and geometric points of view.

_______________________________________________________________________________________

A. Explicit & Recursive Sequences

_______________________________________________________________________________________

For a sequence to be defined explicitly, there must be a function or rule that allows the computation of any member of the sequence.

> restart;

> s := k -> 3*k +2;

s := proc (k) options operator, arrow; 3*k+2 end pr...

> seq( s(k), k = 1..12);

5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38

The basic idea of a recursively defined sequence is that the defiition of each term depends on one or more previous terms. There are two basic components. First, you need a starting value which acts as a seed for the rest of the sequence. Next, you need a rule which tells you how to compute one term, given the previous one. Together these two components form the recursive definition.

> s||1 := 1;

s1 := 1

> for k from 2 to 10 do s||k := 3*s||(k-1) +2; od;

s2 := 5

s3 := 17

s4 := 53

s5 := 161

s6 := 485

s7 := 1457

s8 := 4373

s9 := 13121

s10 := 39365

In a sense, the explicitly defined sequence allows for random access to any element in the sequence with direct computatioin, while a recursive definition requires the computation of all of the elements prior to the desired element in a sequential manner. Clearly an explicit definition is more convenient in this way. However, many sequences are much more easily defined by recursive definitions. Here is an example of the Fibonacci numbers.

> FF||0 := 0; FF||1 := 1;

FF0 := 0

FF1 := 1

> for k from 2 to 10 do FF||k := FF||(k-1) + FF||(k-2); od;

FF2 := 1

FF3 := 2

FF4 := 3

FF5 := 5

FF6 := 8

FF7 := 13

FF8 := 21

FF9 := 34

FF10 := 55

There is an explicit formula for this sequence, which we will see later in this module, however, it is a not an extremely simple not easily found formula.

_______________________________________________________________________________________

B. Resolving 1st Order Recurrences

_______________________________________________________________________________________

One of our goals is to take recursively defined sequences, or recurrences, and find explicit definitions for the same sequence. We will start with "1st order recurrences" which are recurrences which only depend on a single previous term at a time.

Maple has a specific command, rsolve, to solve recurrences. Lets see how it works. Here is the recursive definition of a sequence, followed by the rslove command. The final command, seq, is a way of then evaluting this function to find the first 20 elements of the sequence.

> restart;

> { f(n) = f(n-1) + 9, f(0) = 7};

{f(n) = f(n-1)+9, f(0) = 7}

> rsolve( %, f(k));

7+9*k

> seq( subs( k = j, %), j = 0..20);

7, 16, 25, 34, 43, 52, 61, 70, 79, 88, 97, 106, 115...

This can also be done in slightly more compact way as follows.

> rsolve( {f(n) = 3 * f(n-1), f(0) =1 }, f(k));

3^k

> seq(subs(k = j, %) , j = 0..10);

1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049...

_______________________________________________________________________________________

C. 2nd Order Recurrence

_______________________________________________________________________________________

A 2nd recurrence is a recurively defined sequence which depends on two previous terms to find each additional term. Many of these sequences have more complicated formulas. The method is essentially the same. One difference is that there needs to be two seed values to start the process.

> restart;

> rsolve( { f(n) = f(n-1) + 2*f(n-2), f(0..1) = 1}, f(k));

1/3*(-1)^k+2/3*2^k

> seq( subs( k =j, %), j = 0..10);

1, 1, 3, 5, 11, 21, 43, 85, 171, 341, 683

_______________________________________________________________________________________

D. Recursive Procedures

_______________________________________________________________________________________

Another aspect to recursion is its application to computer programming and Maple programming. As in most computer languages ( such as Pascal , C++, and Fortran ) its possible to define procedures or functions. Maple allows for this same capability. In particular, we can use this method to define recursive procedures and examine how they work.

Here is an example of a recursive procedure to compute the factorial of a number. For example, 5 factorial is 5! = 5 4 3 2 1 = 120. Of course, Maple already has this command built in, but we,re going to use it as an example of defining our own procedures. The procedure should be entered in its entirety at one command prompt. You can enter multiple lines without executing by hitting RETURN ( Macitosh ) or SHIFT - RETURN (Windows ).

> fact := proc(n)
if n = 0 then 1;
else n*fact(n-1); ; fi;
end:

The name of the procedure is fact. It receives a value of n and if that value is 0 , it returns the value of 1. Otherwise, it returns n times the value of the procedure evaluated at n - 1. In Maple, the if - then - else - fi is a decision command that allows one of two outcomes depending on the condition - in this case the whether or not n = 0 is a true statement. Lets see what happens when we use this procedure.

> fact(5);

120

> fact(1);

1

> fact(10);

3628800

As you can see, this procedure apparently computes the factorial of what ever number we give it. Here is another version of the procedure. This version makes the same computation, but also prints out the intermediate values and the current value of n. This provides a window to what is going on inside the procedure.

> fact := proc(n) local x;
print( cat("n=",n));
if n = 0 then print("- - - bottom of the heap - - -"); 1;
else x := fact(n-1);
print( cat("n=", n, " fact(",n,")=", x)); n*x;
fi; end:

>

> fact(5);

120

> fact(1);

1

> fact(10);

3628800

The procedure works its way down to the bottom where n = 0, then works it way back up gradually forming the product that will be the final result.

Here is an example of a procedure to create the Fibonacci sequence which shows its inner working.

> fib := proc(n)
print(n);
if (( n = 1) or ( n = 2))
then print(` - - - bottom of the heap - - - n = ` ,n); 1;
else fib(n - 1) + fib(n - 2); fi; end:

> fib(4);

4

3

2

` - - - bottom of the heap - - -   n = `, 2

1

` - - - bottom of the heap - - -   n = `, 1

2

` - - - bottom of the heap - - -   n = `, 2

3

> fib(6);

6

5

4

3

2

` - - - bottom of the heap - - -   n = `, 2

1

` - - - bottom of the heap - - -   n = `, 1

2

` - - - bottom of the heap - - -   n = `, 2

3

2

` - - - bottom of the heap - - -   n = `, 2

1

` - - - bottom of the heap - - -   n = `, 1

4

3

2

` - - - bottom of the heap - - -   n = `, 2

1

` - - - bottom of the heap - - -   n = `, 1

2

` - - - bottom of the heap - - -   n = `, 2

8

_______________________________________________________________________________________

E. Recursive Expressions & Fixed Points

_______________________________________________________________________________________

Related to this concept, there are also expressions which are recursively defined such as sqrt(1+sqrt(1+sqrt(1+sqrt(1+x)))) This can be thought of as a recursively defined sequence such as sqrt(1), sqrt(1+sqrt(1)), sqrt(1+sqrt(1+sqrt(1))) ,.... . We can express this as a recurrence f(n) = sqrt(1+f(n-1)) where f( 1 ) = 0 :. Unfortunately, the rsolve command can not resolve this kind of recurrence. However, we can deal with this in another way. We can simply define a function based on this recurrence, then iterate the function - that is repeatedly compose the function with itself and evaluate at 1.

> f := x -> sqrt( 1 + x);

f := proc (x) options operator, arrow; sqrt(1+x) en...

> f(f(0));

sqrt(2)

> f(f(f(0)));

sqrt(1+sqrt(2))

We can iterate the function 10 times by repeatedly composing it with itself in this way.

> (f@@10)(x);

sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sq...

In fact, we can see what is happening by doing this in a loop.

> for k from 1 to 12 do (f@@k)(0) = evalf( (f@@k)(0)); od;

1 = 1.

sqrt(2) = 1.414213562

sqrt(1+sqrt(2)) = 1.553773974

sqrt(1+sqrt(1+sqrt(2))) = 1.598053182

sqrt(1+sqrt(1+sqrt(1+sqrt(2)))) = 1.611847754

sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(2))))) = 1.6161212...

sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(2)))))) = 1...

sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(2)))...

sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sq...

sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sq...

sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sq...

sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sqrt(1+sq...

> for k from 1 to 12 do evalf( (f@@k)(0) ); od;

1.

1.414213562

1.553773974

1.598053182

1.611847754

1.616121206

1.617442798

1.617851290

1.617977531

1.618016542

1.618028597

1.618032323

It appears that the values are converging to a number around 1.618033989. But how can we find the exact value o the expression? Suppose for a moment that the values of f( n ) where identical. Lets say x = f(n) = f(n+1) = ...... Then the recursion would become x = sqrt(1+x) , or more generally, f(x) = x. If we simply solve that equation for x, we will have our answer.

> f(x) = x;

sqrt(1+x) = x

> solve( %,x); evalf(%);

1/2+1/2*sqrt(5)

1.618033989

A value for which f(x) = x, is called a fixed point .

_______________________________________________________________________________________

F. Newton's Method

_______________________________________________________________________________________

An example of a recursive formula is Newton's Method for finding roots of a function. This method requires that you be familiar with a little bit of Calculus. Newton's Method is to start with a guess for what a root may be. The initial guess is x0 , then repeatedly apply this formula

to get better and better guesses. In many cases, the formula will converge to the value of a root fairly quickly. Lets start with a function f(x), and then define the function N(x) to give the next guess according to Newton's method

> f := x -> x^2 -2;

f := proc (x) options operator, arrow; x^2-2 end pr...

> N := x -> x - f(x)/ D(f)(x);

N := proc (x) options operator, arrow; x-f(x)/D(f)(...

Like any recursive definition, we start with

> x||0 := 1;

x0 := 1

> for k from 1 to 10 do x||k := evalf( N(x||(k-1))) od ;

x1 := 1.500000000

x2 := 1.416666667

x3 := 1.414215686

x4 := 1.414213562

x5 := 1.414213562

x6 := 1.414213562

x7 := 1.414213562

x8 := 1.414213562

x9 := 1.414213562

x10 := 1.414213562

The values seem to converge quite quickly. The actual solution is this.

> sqrt(2) : % = evalf(%);

sqrt(2) = 1.414213562

_______________________________________________________________________________________

G. Geometric View of Recursive Convergence

_______________________________________________________________________________________

The subject of fixed points of recursions is an interesting one for many reasons and one we can investigate algebraically, numerically, and geometrically. We will need the following special plot function.

> restart; with(plots):

Warning, the name changecoords has been redefined

> rec_plot := proc( f1, a , b, x0)
local x1, x2, y1, y2, i , p1, p2, p3, n, a1,a2;
x2 := x0; y2:= 0; n :=10;
for i from 1 to n do
x1 := x2; y1 := y2; y2:=f(x1); x2 := y2;
p1[i] := plot( [[x1, y1], [x1, y2]], x = a..b, color =red):
p2[i] := plot( [[x1, y2], [x2, y2]], x = a..b , color = yellow):
od:
display( plot( f1(x), x = a..b, thickness = 3, color = blue),
plot(x, x = a..b, thickness = 1, color = black),
seq( p1[i], i = 1..n), seq( p2[i], i = 1..n) ); end:

Here is a recursive formula.

> f := x -> (x+6)/2;

f := proc (x) options operator, arrow; 1/2*x+3 end ...

> x||0 := 2;

x0 := 2

> for k from 1 to 16 do x||k := evalf( f(x||(k-1) )); od;

x1 := 4.

x2 := 5.000000000

x3 := 5.500000000

x4 := 5.750000000

x5 := 5.875000000

x6 := 5.937500000

x7 := 5.968750000

x8 := 5.984375000

x9 := 5.992187500

x10 := 5.996093750

x11 := 5.998046875

x12 := 5.999023438

x13 := 5.999511719

x14 := 5.999755860

x15 := 5.999877930

x16 := 5.999938965

It appears to converge but to where exactly? We can use the same method of finding the fixed point as used above.

> f(x) = x; solve(%, x);

1/2*x+3 = x

6

A geometric view of this situation will show not only the convergence but also the steps leading to the convergence.

> left := 0; right := 7; start:=2;

left := 0

right := 7

start := 2

> rec_plot( f(x), left, right, start);

[Maple Plot]

The thick blue line is the function f(x). The thin black line is the line y = x. Each of the vertical red lines indicates a new xk. The yellow lines show how the y values "bounce" off of the black y = x line to become new xk values. Finally the green oval indicates where the values converge within a small distance of one another.

>