Mathematics and Programming

Jason I. Brown

Having a computer is one thing; knowing when to use it is another. In this section we explore how Maple and mathematics might be brought together so that the "sum is greater than the parts". There are two principles to keep in mind:

If it's easier to do something by hand, do so! Use Maple in an essential way to help with the computations.

Let the mathematics drive Maple, rather than the other way around. Decide what you want to do mathematically first, and then figure out how to ask Maple for help.

Example 1: Finding Roots

Again, we'll stick to the principle of learning Maple as we go along. Consider the following typical problem.

Find the roots of [Maple Math] .

That is, we want to find all values [Maple Math] that make [Maple Math] . I guess that one way to do this is to first ask Maple to solve this equation. First we'll name the function f(x).

> f:=x->x^7+2*x-5;

[Maple Math]

All this does is make the polynomial into a function [Maple Math] .

Now let's ask Maple to solve
[Maple Math] .

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

[Maple Math]

No luck! Let's try thinking mathematically about the function [Maple Math] . First, we see that if [Maple Math] , then [Maple Math] and [Maple Math] are both negative, so that [Maple Math] . Thus [Maple Math] won't have any roots to the left of 0.


A Visual Approach


Let's plot
[Maple Math] say from [Maple Math] to [Maple Math] .

> plot(f(x),x=0..5);

[Maple Plot]

Well, that what you'd expect. The dominant term when [Maple Math] is large in the polynomial [Maple Math] is the leading term [Maple Math] , which is positive, so that when [Maple Math] is large enough, the function should be positive. In fact, when [Maple Math] is at least 2, [Maple Math] is at least [Maple Math] and [Maple Math] is at least [Maple Math] , so [Maple Math] is at least [Maple Math] , and thus positive. Therefore, there can't be any roots to the right of [Maple Math] ; all the roots have to be between [Maple Math] and [Maple Math] . Let's try a plot on this domain.

> plot(f(x),x=0..2);

[Maple Plot]

It certainly looks like there is exactly one root, somewhere between [Maple Math] and [Maple Math] . You can actually click on where you think the point is, and Maple will display the coordinates, if the plot is in a seperate window. For example, when I clicked, I got an [Maple Math] value of about [Maple Math] (it was interesting that the [Maple Math] value was close to [Maple Math] but not quite [Maple Math] ). You can continue to find more precise estimates for the root by "zooming" in on the graph. That is, you can keep plotting [Maple Math] on smaller and smaller domains that contain the root. Let's zoom a few times.

> plot(f(x),x=1..2);

[Maple Plot]

> plot(f(x),x=1..1.3);

[Maple Plot]

> plot(f(x),x=1.1..1.2);

[Maple Plot]

By clicking (or just by looking) we see that the root is about [Maple Math] .

An Analytic Approach

Now can you argue why mathematically there has to be a root around [Maple Math] ? Well, a simple calculation shows that [Maple Math] and [Maple Math] . Now if you reach back into the dark recesses of your mind to your first year calculus class, you'll recall that you learned:

The Intermediate Value Theorem (IVT) : A continuous function [Maple Math] on a closed interval [Maple Math] takes on all values between [Maple Math] and [Maple Math] .

Any polynomial is continous (everywhere!), so if we apply the IVT to our function [Maple Math] on [Maple Math] , as [Maple Math] lies between [Maple Math] and [Maple Math] , there must be a value of [Maple Math] between [Maple Math] and [Maple Math] for which [Maple Math] . In fact, I guess we could use the plot above to guess that the answer is about [Maple Math] or so. To get a more accurate answer, let's think more mathematically.

The IVT tells us that as [Maple Math] is negative and [Maple Math] is positive, there is a root of [Maple Math] between [Maple Math] and [Maple Math] . Let's see what happens in the middle:

> f(1.5);

[Maple Math]

Now we see that [Maple Math] is negative at [Maple Math] and positive at [Maple Math] , so again by the IVT there is a root of [Maple Math] between them. A good guess might be half way in between. Let's see what happens at [Maple Math] (the half-way point):

> f(1.125);

[Maple Math]

Aha! It's negative. As [Maple Math] is negative at [Maple Math] and positive at [Maple Math] , the root has to lie between them. Let's continue for a few more via Maple (we'll name the value we're looking at x):

> x:=(1.125+1.5)/2;

[Maple Math]

> f(x);

[Maple Math]

> x:=(1.125+1.3125)/2;

[Maple Math]

> f(x);

[Maple Math]

> x:=(1.125+1.21875)/2;

[Maple Math]

> f(x);

[Maple Math]

Now $f(x)$ is negative at [Maple Math] and positive at [Maple Math] , so a root of [Maple Math] lies between the two values. Thus we can approximate it to 1 decimal place as [Maple Math] . As a check , let's try [Maple Math] :

> f(1.1);

[Maple Math]

That's pretty close to [Maple Math] , so we're not too far off.

What about if we want to improve the acurracy, say we want an answer that is accurate to within [Maple Math] ? It would be a lot of work at the terminal to continue, but it certainly could be done. Maple can automate repetitive tasks, so let's see how Maple can help.


Now we know that an answer is accurate to .00001 if we can determine that the root lies in an interval
[Maple Math] where [Maple Math] . What we want to do is the following: Suppose that we are at a stage where we know that the root is between [Maple Math] and [Maple Math] . We first check to see if [Maple Math] ; if it is, we print say [Maple Math] (actually, any point in [Maple Math] will do). If not, then since [Maple Math] and [Maple Math] we then take the midpoint [Maple Math] and look at [Maple Math] . If [Maple Math] , then we know that the root is between [Maple Math] and [Maple Math] , so we replace [Maple Math] by [Maple Math] . If on the other hand [Maple Math] , then we know that the root is between [Maple Math] and [Maple Math] , so we replace [Maple Math] by [Maple Math] . In any event, we repeat until we stop.

I'll write down the Maple lines we need to do this, and then talk about them. It'll be the first time we write a set of lines rather than just a single one.

> a:=1:
b:=2:
for i from 1 to 100 do
if (b-a <= 0.000001) then
print(`The root is approximately`,evalf(a));
break;
else
c:=(b+a)/2:
if f(c) < 0 then
a:=c:
else
b:=c:
fi:
fi:
od;

[Maple Math]

Now the first two lines initialize [Maple Math] and [Maple Math] to be the endpoints [Maple Math] and [Maple Math] respectively. The next line starts a repetetive loop that runs at most the number of times we are going to keep taking midpoints. The following line checks whether the interval is smaller than [Maple Math] ; if so, we'll print out the left end point as our answer (and "break" out of the procedure and stop). Otherwise, we set [Maple Math] to be the midpoint between [Maple Math] and [Maple Math] , and look at [Maple Math] . If [Maple Math] is negative, we replace [Maple Math] by [Maple Math] (as the IVT tells us that the root lies between [Maple Math] and [Maple Math] ), and if [Maple Math] is positive, we replace [Maple Math] by [Maple Math] . In any event, we go back and repeat the process. The lines of commands make look complicates, but you'll soon catch on.

The procedure above gives an answer of [Maple Math] , and we know that the roots is between [Maple Math] and [Maple Math] .

[Aside: One thing that may come to mind is whether there can be more than one root of the funtion f between 1 and 2. It seems pretty clear from all the plots that there can't be. Can we justify this mathematically? Well, if you recall Rolle's Theorem, again from that dreaded (but useful!) calculus course you took, between any two roots of a differentiable function there must be a root of its derivative. If we look at the derivative of f,

> D(f);

[Maple Math]

we see that the derivative of f is always positi ve. Thus by Rolle's Theorem, f can't have two roots (anywhere!).]

You may have notices a couple of problems with the above routine:

1. What would have happened if we landed up exactly on the root? Well, it would have been caught by the "else" statement, and we would have set
[Maple Math] (the right endpoint) equal to it, and the procedure would have continued. However, at every subsequent midpoint we choose, we see that the function would be negative at it (as the graph showed that the function [Maple Math] is negative to the left of the root). Thus our final answer (which would be when the loop runs out) would be the left endpoint of an interval when the root is the right endpoint. Thus our answer would be less accurate than it should be, and in any event Maple might spend a lot more time trying to find the root than it really should (as it had the root for quite a while but didn't know it!).

2. We really don't know how many times to run the loop (we guessed at most 100 times), but for all we know, it may need more.

A general procedure would help, one that we could use and reuse again and again for different function and different intervals (and one that wouldn't necessarily have the function at the left endpoint being the negative one). A
procedure is a set of lines that carries out a single process based on whatever items are inputted (the latter are called the parameters of the procedure). Below is the corresponding procedure (which we'll call ivtRoot) that takes into account both of the comments above:

> ivtRoot:=proc(f,a,b,acc)
local i,leftEnd,rightEnd,c:
leftEnd:=a:
rightEnd:=b:
while (rightEnd-leftEnd > acc) do
c:=(rightEnd+leftEnd)/2:
if f(c) = 0 then
RETURN(`The root is exactly`,c);
else
print(c,f(c));
if sign(f(c)) = sign(f(leftEnd)) then
leftEnd:=c:
else
rightEnd:=c:
fi:
fi:
od:
print(`The root is approximately`,evalf(leftEnd));
end;

[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]

This routine takes as input a function [Maple Math] , the endpoints of the interval [Maple Math] and [Maple Math] and an accuracy [Maple Math] and returns an approximation to a root of [Maple Math] within an accuracy of [Maple Math] . Here are some more details:

The left hand endpoint, [Maple Math] , is renamed leftEnd, and the right hand endpoint, [Maple Math] , is renamed rightEnd. You need to do this as the left and right hand endpoints change during the course of the procedure, and you can't change the input parameters and [Maple Math] and [Maple Math] !

The procedure uses a "while" loop rather than a "for" loop as we don't know how many times to run the loop, and wish to so do as long as the length of the interval is greater than the accuracy we desire.

If we stumble upon the root (i.e. [Maple Math] ) then we print out our answer. It is important to break out of the procedure, as otherwise, the loop would continue until the interval is small enough (even though we're done already!). The "RETURN" command takes you out of the procedure you're in and sends back its argument, i.e. what is enclosed in the parentheses (for more details, see you Maple manual or the on-line help).

It's impossible to know in general whether [Maple Math] is positive or negative (although we know that [Maple Math] will be the opposite, or we wouldn't be searching for the root between [Maple Math] and [Maple Math] ). The key thing is that [Maple Math] and [Maple Math] have opposite "signs", and that we always search for the root in an interval for which the [Maple Math] values at the endpoints have opposite signs. Luckily, Maple has a built-in function, "sign", for checking the sign of a number.

Let's try out the procedure a few times, first on our original example.

> ivtRoot(f,1,2,0.00001);

[Maple Math]

Well, that was pretty quick, wasn't it? Let's try another example. Note that the function

> g:=x->cos(x)-x;

[Maple Math]

is positive at [Maple Math] (as [Maple Math] ) and negative at [Maple Math] (as [Maple Math] ); see the figure below as well.

> plot(g(x),x=0..Pi/2);

[Maple Plot]

The IVT (and the plot!) tells us that g has a root between [Maple Math] and [Maple Math] . Let's use our procedure to find it, say to within [Maple Math] .

> ivtRoot(g,0,Pi/2,0.001);

Error, (in ivtRoot) cannot evaluate boolean

Well, what's going on? Why do we get an error message? Well, it seems that Maple has difficulty thinking sometimes of some exact numbers as decimals when Maple has to compare them (as in inequalities) or determine their sign (which is again is an inequality to check). The problem here is [Maple Math] . Let's fix the routine by forcing Maple to convert numbers to decimals via the "evalf" command (We'll retype it below, but in actual fact, you can scroll back to where the ivtRoot procedure is and make the changes; don't forget to run it again by hitting the carriage return key afterwards!).

> ivtRoot:=proc(f,a,b,acc)
local i,leftEnd,rightEnd,c:
leftEnd:=evalf(a):
rightEnd:=evalf(b):
while (rightEnd-leftEnd > acc) do
c:=(rightEnd+leftEnd)/2:
if f(c) = 0 then
RETURN(`The root is exactly`,c);
else
if sign(evalf(f(c))) = sign(evalf(f(leftEnd))) then
leftEnd:=c:
else
rightEnd:=c:
fi:
fi:
od:
print(`The root is approximately`,evalf(leftEnd));
end;

[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]

> ivtRoot(g,0,Pi/2,0.001);

[Maple Math]

Well, that's much better (and the answer corresponds well to where the graph of [Maple Math] crosses the [Maple Math] axis in the previous plot ).

The example of root finding above shows precisely how mathematics and programming (via Maple) can connect to solve a problem. This is typical of the approach we'll take throughout this book. You'll let the mathematics decide what you want to do, and then you'll ask Maple to help solve some of the parts.

[Aside: Of course, Maple has a built -in command to find the solutions to equations:

> fsolve(h=0,x,a..b);

will solve the equation [Maple Math] for [Maple Math] in the interval [Maple Math] . If [Maple Math] is a polynomial, it will find all the real roots in the interval (and you can even omit the interval [Maple Math] to find all the real roots!), but for general functions h, the command will only return one root in the interval (of course, there may be more).

Is there any reason not use this command? Why did we bother writing our own commands and procedure for something Maple already does? Well, there are a number of reasons. First, we learned how to take a mathematical theorem like the IVT and use it to write a procedure to do something (like find a root). Using a built-in command like the "fsolve" command wouldn't have taught us anything (beyond how to use it). Secondly, we now know exactly how our procedure works, and why it works ; we have to trust Maple that the "fsolve" command really does what its supposed to do (of course, most times we'll do exactly that!). Thirdly, if we want to alter the procedure, we're free to do so, and we know what's going on inside. Finally, we did learn alot about new Maple commands and the Maple programming language, and these will serve us well in the coming sections.]

Example 2: Maximizing and Minimizing a Polynomial on a Closed Interval

We'll go through one more example of a typical mathematical problem.

For example,

What is the maximum and minimum of [Maple Math] on the interval [Maple Math] ?

Really, the best we can hope for are accurate estimates for the maximum and minimum, so that is what we're after.

Recall from your calculus course:

The Extreme Value Theorem (EVT) : Any continuous function on a closed and bounded interval has a maximum and minimum value.

As any polynomial is continuous everywhere, the problem certainly has a solution. The trick is to convert the mathematics to Maple.

Now the general plan from your calculus course was the following for finding the maximum and minimum of a continuous function [Maple Math] on an interval [Maple Math] :

Find the critical numbers for f that are in (a,b)

The maximum of f on [a,b] is the largest of the f values at the critical numbers and the endpoints, while the minimum of f on [a,b] is the smallest of the f values at the critical numbers and the endpoints

To find the critical numbers, we differentiate the function and find all the roots of the derivative in the interval. To do this we'll use Maple's built-in "fsolve" command, as it finds all the roots of a polynomial in an interval. We can then use Maple's "max" and "min" commands to pick off the largest and smallest values of the polynomial at endpoints and critical numbers.

First we'll let [Maple Math] be the name of the polynomial function.

> p:=x->x^8-x^7-10*x^6+9*x^5+36*x^4-27*x^3-54*x^2+27*x+27;

[Maple Math]

Next, we'll find the derivative of [Maple Math] and use Maple's fsolve command to find all its roots in [Maple Math] .

> p1:=D(p);

[Maple Math]

> fsolve(p1(x),x,-2..3);

[Maple Math]

There are certainly a number of critical numbers in the sequence above. Let's give it a name, say cS.

> cS:=%;

[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]

Now we need apply the polynomial to each value in this list (as well as to the endpoints). We can get at the i-th item in the sequence cS by typing cS[i]. For example,

> cS[2];

[Maple Math]

Finally, we can calculate the maximum and minimum values of p on the interval:

> max(p(-2),p(3),p(cS[1]),p(cS[2]),p(cS[3]),p(cS[4]),p(cS[5]),p(cS[6]),p(cS[7]));

[Maple Math]

> min(p(-2),p(3),p(cS[1]),p(cS[2]),p(cS[3]),p(cS[4]),p(cS[5]),p(cS[6]),p(cS[7]));

[Maple Math]

That does it! The maximum and minimum of [Maple Math] on the interval are [Maple Math] and [Maple Math] respectively. We'll do a quick check of the plot of p on the interval:

> plot(p(x),x=-2..3);

[Maple Plot]

The maximum certainly does seem to happen a little over [Maple Math] at the right endpoint, [Maple Math] . The minimum is a little harder to see, so why don't we replot the graph from [Maple Math] to [Maple Math] (as we can certainly see that the function is negative near [Maple Math] and positive to the right of [Maple Math] (and thus the minimum occurs to the left of [Maple Math] ).

> plot(p(x),x=-2..2);

[Maple Plot]

Ah, we see that the minimum seems to occur around -1, and that it is about -8.

Now the problem that we solved was just one of a more general one:

Find the maximum and minimum of a polynomial on a closed interval.

We'll write a general procedure "maxMinPoly" to do the work; the procedure will take as input a polynomial function [Maple Math] and the endpoints of the interval, and print out the maximum and minimum values. The fact that the functions we're considering are polynomials ensures that Maple's fsolve command (applied to another polynomial, namely the derivative of [Maple Math] ) will find all the roots in the interval

> maxMinPoly:=proc(p,a,b)
local p1,critSeq,maxPoly,minPoly,i:
p1:=D(p):
critSeq:=fsolve(p1(x),x,a..b):
maxPoly:=max(p(a),evalf(p(b))):
minPoly:=min(p(a),evalf(p(b))):
for i from 1 to nops([critSeq]) do
maxPoly:=max(maxPoly,p(critSeq[i])):
minPoly:=min(minPoly,p(critSeq[i])):
od:
print(`The maximum of`,p(x),` on the interval `,[a,b],`is `,maxPoly);
print(`The minimum of`,p(x),` on the interval `,[a,b],`is `,minPoly);
end;

[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]

We need to talk about some of the commands. First, the critical numbers are found by the fsolve command (applied to the derivative [Maple Math] of [Maple Math] ); this sequence is placed into the variable "critSeq". To count the number of items in the sequence critSeq, we need to convert the sequence to a list (simply by enclosing it in square brackets) and using the "nops" command (this picks off the number of "pieces" in a list).

To get the maximum and minimum of the f values at the required points, we use Maple's "max" and "min" commands, which act on sequences of numbers. We'll only use it on pairs of numbers. What we'll do is first calculate the maximum and minimum of the polynomial at the endpoints of the interval. Then we'll suceesively look at the value of the polynomial at each critical number, and update the maximum (and minimum) found so far if the values of the polynomial at that critical number is larger (or smaller) than the maximum (respectively, minimum) found so far.

Let's try out our new maxMinPoly procedure on our particular problem:

> p:=x->x^8-x^7-10*x^6+9*x^5+36*x^4-27*x^3-54*x^2+27*x+27;

[Maple Math]

> maxMinPoly(p,-2,3);

[Maple Math]
[Maple Math]

[Maple Math]
[Maple Math]

[Aside: Rather than try out other examples for our maxMinPoly routine, we'll end this section by remarking that we can "tidy" up the maxMinPoly routine a little bit by using an advanced Maple command called "map". What "map" does is to apply a function to a list (or set). For example:

> lst:=[2,-3,5];

[Maple Math]

> map(ln,lst);

[Maple Math]

Now max and min operate on sequences, not lists. It is important to know that to remove the brackets from a list L, all you need to do is put "[]" after L, that is write L[].

> %[];

[Maple Math]

Here is how we might redo the procedure:

> maxMinPoly:=proc(p,a,b)
local p1,lst,maxPoly,minPoly,i:
p1:=D(p):
lst:=map(p,[fsolve(p1(x),x,a..b),a,b])[]:
maxPoly:=max(lst):
minPoly:=min(lst):
print(`The maximum of`,p(x),` on the interval `,[a,b],`is `,maxPoly);
print(`The minimum of`,p(x),` on the interval `,[a,b],`is `,minPoly);
end;

[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]
[Maple Math]

The command first makes a sequence out of the critical numbers and the endpoints and makes them into a list, then applies the polynomial function p to all of them, and then finally converts the list back to a sequence. Pretty complicated, isn't it?

Trying out the particular example again, we get

> maxMinPoly(p,-2,3);

[Maple Math]
[Maple Math]

[Maple Math]
[Maple Math]

That worked pretty well. If you're not happy with the complexity and brevity of the procedure above, you're certainly not alone. Feel free to write procedures that are easy to understand; writing "tighter" routines will come as you become more and more at home with Maple. For right now, stick with simple but understandable!]

Exercises

1. For each of the following functions [Maple Math] and intervals [Maple Math] , find a root of [Maple Math] in the interval to within an accuracy of 0.00000001.

(a) [Maple Math]

(b) [Maple Math]

(c) [Maple Math]

(d) [Maple Math]

(e) [Maple Math]

2. For each of the problems in question 1, explain clearly why they have exactly one root in the given interval.

3. For each of the following functions, find all the roots of the given function in the interval (use your ivtRoot procedure and some mathematics; don't use Maple "fsolve" command!):

(a) [Maple Math]

(b) [Maple Math]

(c) [Maple Math]

(d) [Maple Math]

(e) [Maple Math]

4. Alter the procedure ivtRoot so that it checks the value of function at the endpoints. If there is a root at an endpoint, return the value(s), and if the function does not have opposite signs at the endpoints, and otherwise print s that the procedure cannot be used.

5. For each of the following polynomial functions [Maple Math] and intervals [Maple Math] , find accurate estimates for the maximum and minimum of [Maple Math] on the interval.

(a) [Maple Math]

(b) [Maple Math]

(c) [Maple Math]

6. For each of the following functions, find accurate estimates for the maximum and minimum on the given interval (hint: use a mix of both mathematics and Maple!).

(a) [Maple Math]

(b) [Maple Math]

(c) [Maple Math]

7. Write a Maple procedure "rollesProc" that takes as input a continuous function [Maple Math] and numbers [Maple Math] and [Maple Math] (with [Maple Math] ) and prints "At most one root in the interval" if the derivative of [Maple Math] has no roots in the interval, and prints "Unsure of the number of roots" otherwise (recall that Rolle's Theorem states that if the derivative of a function [Maple Math] has [Maple Math] roots in an interval [Maple Math] , then [Maple Math] can have no more than [Maple Math] roots in [Maple Math] ). Afterwards, test your procedure on some examples.

8. [Harder] Suppose we are considering the maximum and minimum of a continuous function [Maple Math] (which is not necessarily a polynomial) on an interval [Maple Math] , and we have determined (perhaps through Maple plots) that f has exactly one root in each of the subintervals [Maple Math] ,É, [Maple Math] . Write a Maple procedure maxMinFunc that takes as input [Maple Math] , where intList = [a_1,a_2,É,a_2n], and returns (accurate estimates for) the maximum and minimum of [Maple Math] on the interval [Maple Math] . Afterwards, test your procedure on the problems in exercise 6.