• No results found

In this chapter we examine how recursion is used to implement algorithms in computer algebra. We begin, in Section 5.1, by describing how a sim-ple recursive procedure is imsim-plemented by a CAS. In Section 5.2, we give recursive procedures for a number of operators and describe an approach using transformation rules that provides a simple way to implement some recursive operations. Finally, in Section 5.3 we describe a recursive algo-rithm for a simple version of the Integral operator that utilizes some basic integration rules together with the substitution method.

5.1 A Computational View of Recursion

In Chapter 3 we gave the following recursive definition for the factorial operation:

n! =

1, if n = 0,

n· (n − 1)!, if n > 0. (5.1) For n = 4, the computation based on this definition (5.1) proceeds as follows:

4! = 4(3!) = 4(3(2!)) = 4(3(2(1!))) = 4(3(2(1(0!))))

= 4(3(2(1(1)))) (5.2)

= 24.

To perform the calculation, we repeatedly apply (5.1) until n = 0 is en-countered. Once this point is reached, 0! is replaced by the value 1, and the numerical computation proceeds as indicated by the parentheses in the second line of Equations (5.2).

171

Procedure Rec fact (n);

Input

n : non-negative integer;

Output n!;

Local Variables f ;

Begin

1 if n = 0 then

2 f := 1

3 else

4 f := n∗ Rec fact(n − 1) 5 Return(f )

End

Figure 5.1. An MPL recursive procedure for n!. (Implementation: Maple(txt), Mathematica(txt),MuPAD(txt).)

Figure5.1shows an MPL recursive procedure that performs this calcu-lation. For the case n > 0, the procedure calls on itself (line 4) to perform a “simpler” version of the calculation. A procedure that calls on itself di-rectly (as in this example) or indidi-rectly through a sequence of procedures is called a recursive procedure. The case n = 0 (lines 1, 2) is called a ter-mination condition for the procedure, since it is defined directly and does not require further calls on Rec fact . For each positive integer n, the cal-culation is eventually reduced to the termination condition which stops the recursion. Each recursive procedure must have one or more termination conditions.

Let’s trace the execution of the procedure in response to the evaluation of Rec fact (4) from the interactive mode. When the procedure is invoked, a CAS allocates a block of computer memory that includes storage loca-tions for the local variable f , the input variable n, and the next statement executed by the system once Rec fact is done. The storage allocation for Rec fact (4) (before the calculation in line 4) is shown in Figure5.2(a). At this point, the local variable f has not been assigned, and the “next state-ment executed” refers to the interactive mode that invoked the procedure and will display the result once the operation is done.

The actual calculation is done in line 4. But before this can be done, we need the value for Rec fact (3), and this requires another call on the pro-cedure. To invoke Rec fact (3), a CAS again allocates a block of memory

n f next statement executed 4 interactive

mode

(a) The storage allocation stack for Rec fact (4) before calculation on line 4.

n f next statement executed 3 Rec fact , line 4

(n = 4 case) 4 interactive

mode

(b) The storage allocation stack for Rec fact (3) and Rec fact (4). The local variable f has not

been assigned a value in either block.

n f next statement executed 0 1 Rec fact , line 4

(n = 1 case) 1 Rec fact , line 4

(n = 2 case) 2 Rec fact , line 4

(n = 3 case) 3 Rec fact , line 4

(n = 4 case) 4 interactive

mode

(c) The storage allocation stack for the sequence of Rec fact procedure calls before the recursion unwinds.

Figure 5.2. The storage allocation stack for the procedure Rec fact at various points in the computation of 4!.

to store the information associated with this procedure call. Figure5.2(b) illustrates the memory allocation for Rec fact at this point in the calcula-tion. There are now two separate blocks of memory, one for the current case n = 3 and one for the previous case n = 4 which is not yet done and remains in memory. Notice that each block has its own storage locations for the input variable n and the local variable f . In the computer’s mem-ory, these two blocks reside in an internal data structure known as a stack.

Briefly, a stack is a data structure for which data (or blocks of data) can only be inserted or removed from the top of the stack1. I n this case, the top of the stack (n = 3) contains the active version of Rec fact , and lower levels of the stack contain previous versions of Rec fact , which have been invoked but are not yet done. For n = 3, the local variable f has not been assigned, and “next statement executed” refers to line 4 in the previous version Rec fact (4) which invoked Rec fact (3).

Now, to compute Rec fact (3), we need the value of Rec fact (2), which means we again invoke Rec fact and assign yet another block of memory to the procedure. To complete the calculation, we continue invoking the procedure for successively smaller integer values until the termination con-dition n = 0 is reached. The memory allocation stack at this point is shown in Figure5.2(c). Observe that the currently active version (n = 0) is at the top of the stack, and the other levels of the stack represent the previous procedure calls that led to this place in the calculation. At this point, the variable f (for the n = 0 case) is assigned the value 1 (with lines 1, 2), and this value is returned as the value of Rec fact (0). Once this is done, the block of memory allocated for Rec fact (0) is no longer needed and is removed from the top of the stack. Control is now transferred back to line 4 in Rec fact (1) which performs the multiplication and assignment:

f := 1∗ Rec fact(0) → 1 ∗ 1 → 1 (calculation in Rec fact (1)).

This value is returned to Rec fact (2) which invoked Rec fact (1), and the memory allocated for Rec fact (1) is removed from the top of the stack.

The recursive process continues to unwind in this fashion, performing the multiplication and assignment in line 4 for the different versions of Rec fact :

f := 2∗ Rec fact(1) → 2 ∗ 1 → 2 (calculation in Rec fact (2)), f := 3∗ Rec fact(2) → 3 ∗ 2 → 6 (calculation in Rec fact (3)), f := 4∗ Rec fact(3) → 4 ∗ 6 → 24 (calculation in Rec fact (4)).

In each case, once an expression has been returned by Rec fact (n− 1) to the calling procedure Rec fact (n) (or the interactive mode), the block of memory associated with Rec fact (n− 1) is removed from the top of the stack. After the last calculation, the expression 24 is returned as the value of Rec fact (4).

The Rec fact procedure is presented to illustrate simply what is meant by a recursive procedure and to show how it is evaluated by a CAS. In practice, the recursive procedure for n! is less efficient in terms of computer time and memory than a non-recursive iterative procedure.

1A useful metaphor for a stack data structure is a stack of food trays. For safety’s sake, we always remove a tray from the top of the stack and add a tray to the stack by placing it on the top.