lec16.mws

L-16 MCS 320 Wednesday 28 September 2005

> restart;

1. Procedures returning procedures

In Maple we can execute a procedure numerically or symbolically, giving numbers or symbols on input.  We can also give procedures on input.

> newtonstep := proc(f::procedure)

>  local ix;

>  ix := x -> x;

>  ix - eval(f)/D(eval(f));

> end proc;

newtonstep := proc (f::procedure) local ix; ix := proc (x) options operator, arrow; x end proc; ix-eval(f)/D(eval(f)) end proc

> g := x -> cos(x) -1/2;

g := proc (x) options operator, arrow; cos(x)-1/2 end proc

> gstep := newtonstep(g);

gstep := ix-proc (x) options operator, arrow; cos(x)-1/2 end proc/proc (x) options operator, arrow; -sin(x) end proc

> gstep(0.4); # numerical execution

1.481256192

> gstep(a);  # symbolic execution

a+(cos(a)-1/2)/sin(a)

> y := 0.4: # start point in the Newton iteration

> Digits := 32:

> for i from 1 to 7 do

>  y := gstep(y);

> end do;

y := 1.4812561922652190518509853767005

y := 1.0690253142105819179156628049474

y := 1.0473299708724005629235441552713

y := 1.0471975562573468502021988223847

y := 1.0471975511965977535475256612353

y := 1.0471975511965977461542144610932

y := 1.0471975511965977461542144610932

2. Indexed Procedures

> evalf[33](Pi);

3.14159265358979323846264338327950

The evalf is a procedure with an index.  The "33" in the call above is an index, the Pi is the argument to the function.  We use indices as parameters to functions.

We can test if a name has an index or not:

> b := A[3];

b := A[3]

> op(b); # select the index of A

3

> type(b,`indexed`); # verify if A is indexed

true

In  the definition of a procedure we can test if the name of the procedure is indexed.  If so we can so the value of the index, selected via the op command, or we can use a default.

As example consider the function f(t) = b + (70 - b)*exp(-0.2*t), where b is an index, by default we take b = 32.  The meaning of b is that this is the outside temperature, 70 is the starting temperature.

> cool := proc(t)
 description "an illustration of an indexed procedure":

 local b:

 if type(procname,`indexed`) # see if cool is called with an index

  then b := op(procname); # b takes the value of the index

  else b := 32;           # if no index, use the default value

 end if:

 return b + (70-b)*exp(-0.2*t);

end proc:

> cool(4.3);

48.080159128074455036645901680437

> cool[32](4.3);

48.080159128074455036645901680437

> cool[64](4.3);

66.538972493906492900523037107437

3. Efficient Recursive Procedures

Recursion is a powerful method to define functions.  Let us consider the Fibonacci sequence:

  F(0) = 0, F(1) = 1, F(n) = F(n-1) + F(n-2), for n > 1.

> F := proc(n::nonnegint)
 description "returns the n-th Fibonacci number":

>  option remember; # crucial for an efficient execution !!!
 if n = 0 then

    return 0:

 elif n = 1 then

    return 1:

 else

    return F(n-1) + F(n-2):

 end if:

> end proc:

> for i from 1 to 10 do F(i); end do;

1

1

2

3

5

8

13

21

34

55

> F(20);

6765

> F(40);

102334155

> T := op(4,eval(F));

T := TABLE([0 = 0, 1 = 1, 2 = 1, 3 = 2, 4 = 3, 5 = 5, 6 = 8, 7 = 13, 8 = 21, 9 = 34, 10 = 55, 11 = 89, 12 = 144, 13 = 233, 14 = 377, 15 = 610, 16 = 987, 17 = 1597, 18 = 2584, 19 = 4181, 20 = 6765, 21 ...T := TABLE([0 = 0, 1 = 1, 2 = 1, 3 = 2, 4 = 3, 5 = 5, 6 = 8, 7 = 13, 8 = 21, 9 = 34, 10 = 55, 11 = 89, 12 = 144, 13 = 233, 14 = 377, 15 = 610, 16 = 987, 17 = 1597, 18 = 2584, 19 = 4181, 20 = 6765, 21 ...T := TABLE([0 = 0, 1 = 1, 2 = 1, 3 = 2, 4 = 3, 5 = 5, 6 = 8, 7 = 13, 8 = 21, 9 = 34, 10 = 55, 11 = 89, 12 = 144, 13 = 233, 14 = 377, 15 = 610, 16 = 987, 17 = 1597, 18 = 2584, 19 = 4181, 20 = 6765, 21 ...T := TABLE([0 = 0, 1 = 1, 2 = 1, 3 = 2, 4 = 3, 5 = 5, 6 = 8, 7 = 13, 8 = 21, 9 = 34, 10 = 55, 11 = 89, 12 = 144, 13 = 233, 14 = 377, 15 = 610, 16 = 987, 17 = 1597, 18 = 2584, 19 = 4181, 20 = 6765, 21 ...T := TABLE([0 = 0, 1 = 1, 2 = 1, 3 = 2, 4 = 3, 5 = 5, 6 = 8, 7 = 13, 8 = 21, 9 = 34, 10 = 55, 11 = 89, 12 = 144, 13 = 233, 14 = 377, 15 = 610, 16 = 987, 17 = 1597, 18 = 2584, 19 = 4181, 20 = 6765, 21 ...T := TABLE([0 = 0, 1 = 1, 2 = 1, 3 = 2, 4 = 3, 5 = 5, 6 = 8, 7 = 13, 8 = 21, 9 = 34, 10 = 55, 11 = 89, 12 = 144, 13 = 233, 14 = 377, 15 = 610, 16 = 987, 17 = 1597, 18 = 2584, 19 = 4181, 20 = 6765, 21 ...

We can change the remember table as follows:

> F(39) := 1: # change the outcome of the function

> F(41);

102334156

The following command destroys the remember table:

> forget(F);

> F(41);

165580141

So we now get the correct Fibonacci number.