Programming via Mathematica

Introduction

We have been studying Mathematica for a variety of reasons.  We began by thinking of
Mathematica as a numerical calculator, and studied the consequences of its allowing
the user to specify the number of significant digits to use when calculating.
We continued by thinking of Mathematica as a ``symbolic calculator,'' and saw that
Mathematica can compute with symbols as easily as it can with numbers.  More
recently, we have been using Mathematica as a tool for scientific visualization by
exploiting its graphing and animation capabilities.

Another important reason that we have chosen to study Mathematica, however, is that
it is a programming language.  It is not a traditional programming language
like C or Fortran, but it is a programming language nonetheless.

This is the last lesson that is devoted entirely to Mathematica.  We are about to
turn our attention to the problem of writing programs in C and Fortran.  As we
do this, you will come to appreciate that much of what you have learned about
Mathematica, and much of what you have experienced while using Mathematica, will make it
easier for you to learn C and Fortran in the coming weeks.

Before leaving Mathematica behind, we also want to show you a few more aspects of
Mathematica that we have not previously covered.  It is possible to use Mathematica in a
way that is almost identical to the way that C and Fortran are used.  Studying
these aspects of Mathematica will give you a good head start towards understanding
the equivalent aspects of C and Fortran.

We stress at the outset, however, that we do not expect you to become expert
(or even competent) at using these new aspects of Mathematica.  We are introducing
them primarily so that what you are about to see in the context of C and
Fortran will be familiar.

Programming Languages

As you'll soon learn, when you use Fortran or C to solve a problem, the first
step is to write out a complete list of instructions, or commands for the
computer, called a program.  This program is generally stored in a file.

How is this different from the way we've been using Mathematica?

Click here for an answer.

You might say that with Mathematica, we've been using the computer more ``directly.''
Computer scientists often say that systems like Mathematica are ``interactive''
because you enter your commands one by one and see the results immediately.

When you use Mathematica, you type in your commands and Mathematica carries out your
instructions directly.  You get the results right then, and you don't have to
decide upon all of your commands ahead of time.  You can decide what you want
to do as you go along.

But when you use Fortran or C, you don't enter your commands one at a time and
the computer doesn't carry out your commands as you type them in.  Instead, you
have to ``plan ahead'' and write down every command before the computer will
start carrying out any of your commands.  And you have to go through some
extra intermediate steps to get the computer to carry out your program at all.

What a bother!  Mathematica seems so simple and straightforward, and writing programs
seem to be so complicated!  So why does anybody write complete programs at all?

Click here for an answer.

Because frankly, it usually pays in the long run to ``plan ahead.''  It also
pays to save your programs in files so that you can use them again.

Let's look at some of the advantages to writing programs.

Doing It Over and Over

Once a program is written and saved, it can be used many times.  You don't have
to spend any time re-teaching the computer how to do the job you've already
taught it to do.

So if you have to do the same kind of work over and over, it generally makes
sense to plan ahead and write a program.  Suppose that you need to solve some
set of equations over and over for hundreds of different input values.  It
makes a lot of sense to write the equations down once in a program, and then
have the computer run that program for the different input values.

Suppose that you had to solve those same equations the next day, too, for even
more input values.  Wouldn't it make sense for you to have saved the work you
did teaching the computer how to solve those equations?  Wouldn't it be nice to
to just run your saved program a few more times, rather than spend extra time
re-teaching the computer how to solve the equations?

In short, it pays to save your work in programs, so that you can reuse those
programs in the future.  Fortran and C require to save your commands (programs)
in files, but that's not a problem --- you should want to do that anyway.

Programs are Easy to Change

Once you've written and saved a complete program, it's often easy to change
that program to do something a little different.  When you can create a new
program by just making a small change to an existing program, you can save a
lot of time and effort.  After all, most of the new program has already been
written!

Suppose that you had a homework problem to solve, and instead of writing a C or
Fortran program, you had used Mathematica.  You typed all of your commands to Mathematica,
determined your results, and didn't save any of your commands.  And now you
want to do the whole thing over, but with just one little change.

Which would you rather do --- make a little change the Fortran or C program
that you had already saved, or start from scratch with Mathematica?

To be fair, it is possible to write programs and save your work in Mathematica.  The
point here isn't to discourage you from using Mathematica; it's to make it clear that
writing programs is a good idea, and that you shouldn't avoid Fortran and C
just because you have to ``plan ahead'' and write programs.

Organizing Your Work

As the work you need to do becomes more complicated, the more you will want to
write programs.  By now you should know why:

Click here for an answer.

That's right --- by writing programs you can save and reuse your work.

If the problem you need to solve is big enough, you might not be able to write
down all of the computer instructions in a single day.  And it's easy to
imagine that even if you could do so, you wouldn't want to!

Conclusion

Don't be discouraged from using Fortran and C just because you have to write
programs.

With Mathematica you can enter commands and the computer carries them out directly.
You don't have to plan ahead or save your work.  With Fortran and C, however,
you have to first plan and write a complete program before the computer will
execute your commands.  But as we have seen, even though it seems like using a
system like Mathematica is more straightforward, it usually makes sense to write
programs.

A Sliding Block

In order to warm up for C and Fortran, let's experiment with using Mathematica in a
way closer to the way that you'll be using those languages.

We will consider the problem of a block sliding down a ramp.
\diagram{Click here}{Block on Ramp}{diagrams/block} for a diagram of a block
on a ramp.

The diagram shows a block sitting on a ramp that is inclined from the
horizontal at an angle theta.  Let's ignore any friction between the block and
the ramp for the moment.  The block is initially prevented from moving, but at
time t=0 it is released.  What does your physical intuition tell you about
what should happen next?  What does the angle theta have to do with it?

Click here for an answer.

The block will slide down the ramp, picking up speed (accelerating) as it goes.
The steeper the ramp, the faster the block will go.

Here is a function which, when given the angle at which the ramp is inclined,
will return the acceleration of the block.

gravity[theta_] :=  1/2 * 9.8 * Sin[theta]

The acceleration will be down the ramp in meters/second/second.  The constant
9.8 meters/second/second that appears in the function is acceleration due to
gravity.

Since the block is not initially moving, the distance that the block will slide
after t seconds is given by the function

distance[t_, theta_]:= -1/2 * gravity[theta] * t^2

(You may recognize this as the familiar ``one-half-a-t-squared'' formula from
introductory physics.)

Notice that the distance moved by the block depends upon both t and theta.
Why is that?

Click here for an answer.

The longer we wait, the further the block will slide.  And as we've already
pointed out, the steeper the ramp, the faster the block will go.

One way to visualize the effect of the steepness of the ramp is to graph the
distance that the block will travel in (say) five seconds as a function of
theta.  How could you do that?

Click here for an answer.

Plot[
distance[5, theta], {theta, 0,Pi/2},
PlotLabel -> "Frictionless Motion"];

Friction

Of course, a real block and a real ramp would have friction, which would tend
to retard (or even stop altogether) the motion of the block.  In fact, we can
think of friction as being a force that tries to accelerate the block up
the ramp in opposition to gravity.  The following function gives this
opposing acceleration:

friction[theta_] := 1/2 * 9.8 * 1.0 * Cos[theta]

(For those in the know about such things, the 1.0 that appears in the formula
is the coefficient of friction between the block and the ramp.  The Greek
letter mu is often used to stand for the coefficient of friction.
Slippery things have small coefficients of friction, and rough things have high
coefficients of friction.)

Since gravity will tend to accelerate the block down the ramp, and friction
will tend to accelerate the block up the ramp, we should be able to calculate
the overall acceleration by subtracting the effects of friction from the
effects of gravity.  We can redefine our distance function accordingly:

distance[t_, theta_] := 
1/2 * (gravity[theta]-friction[theta]) * t^2

This uses the same formula as before, only now we take both gravity and
friction into account.  But there is something completely wrong with this
function.  If you can't see right away what it is, plot it just as we did
before and the problem should become obvious.

Click here for the answer

The graph should reveal that the block does not move at all if the ramp is
inclined at Pi/4 radians (45 degrees).  At this angle, friction exactly cancels
out gravity.  (In case you're interested, this is a consequence of choosing 1.0
as the coefficient of friction.)  For angles greater than Pi/4 radians, the
block moves down the ramp, and the steeper the ramp, the further it moves in
five seconds.  But for angles less than Pi/4 radians, the graph shows that the
block starts moving backwards, up the ramp!  Your everyday experience, of
course, tells you that this is not what will happen.

Conditionals

The friction of the block with the ramp acts to oppose the force of gravity,
and it may fight gravity to a tie, but it never overpowers it!  There are 
actually two separate cases to consider.

(1) If the acceleration due to friction ( friction[ theta ]) is  greater
than or equal to the acceleration due to gravity ( gravity[ theta ]), then
the block will not move at all.  (It certainly won't move up the ramp!)

(2) If the acceleration due to friction is  less than the acceleration due
to gravity, then the acceleration of the block will be 

gravity[ theta ] - friction[ theta ]

Mathematica will let us treat these two cases separately, but not within the
framework of a simple function.  Instead, we will have to use a more general way of
describing a function that takes the two cases into account.  Here is a
Mathematica function that will calculate the distance moved by the block as a
function of time and angle.

distance[t_, theta_]:=0/; gravity[theta]<=friction[theta];

distance[t_, theta_]:=
N[1/2 * (gravity[theta]-friction[theta]) * t^2]

Now let's see what this procedure is all about, and how it differs from (and is
similar to) a regular function.

We have named the procedure ``distance'' just as we name functions and other
things in Mathematica---via assignment. We assigned two different outcomes to any invocation of the function, as specified by the /; operator.  In the example above we told the function that the value is zero for 

gravity[theta]<=friction[theta]

and otherwise to use the function as we first defined it. How far does the block move in ten seconds if the angle of the ramp is 0 degrees?

distance[10, 0]

How about how far it moves in ten seconds if the angle of the ramp is 90
degrees?

distance[10, Pi/2]

We can also plot the distance covered by the block in five seconds as theta
varies from 0 to 90 degrees (0 to Pi/2 radians).

Plot[distance[5, theta], {theta, 0, Pi/2}];

All of this experimentation should confirm that the block no longer moves
backwards for small angles.  It also reveals an important property of programs.
It is perfectly feasible to use a procedure (or function) without knowing
anything about how the procedure (or function) works.  You only need to
now what it does.  This is called the principle of abstraction, and
is what makes it possible to write large programs.

Now let's look at the internal workings of the function.  In a procedure, we
give step-by-step instructions, called statements, to Mathematica.  In this one the
instructions are rather simple.  We tell Mathematica to do a comparison, and then to
return one value or another based upon the outcome of the comparison.

When you write C and Fortran programs, you'll be writing procedures much like
``distance.''  The procedures that you write will consist of statements that
give step-by-step instructions.  Among other kinds of statements, C and Fortran
have conditional statements much like the one you've just seen. 
Although the details of Fortran and C are different, the surface appearance of programs will be similar.

Building Blocks

Another fact about programming that it's important to appreciate is that only
 tiny programs will consist of a single procedure.  Almost every program is
constructed by combining a number of interdependent procedures and functions.
Is that true of the procedure that we just wrote?

Click here for the answer}

Absolutely!  The ``distance'' procedure can't stand on its own.  It makes use
of the ``gravity'' and ``friction'' functions that we previously defined.  We
have written a program that computes the distance covered by a block sliding on
a ramp, and this program consists of three building blocks: one procedure and
two functions.

In fact, programs often start off being quite small and then grow as more
functions and procedures are added.  Let's see how this might work.

One thing that programmers like to do is to produce easy-to-read output.  For
example, we might want to write a Mathematica procedure that would print out
informative labels for the results produced by the ``distance'' function.
Let's define a procedure called ``labPos'' that does just that.

labPos[t_, theta_]:=
Block[{},
Print["The ramp is elevated at ", theta, " radians"]; 
Print["After ", t, " seconds, the block has moved"]; 
Print[distance[t, theta], " meters"];
]

To see this procedure at work, run it.  Here's a sample execution; you should
try others.

labPos[5, Pi/3]

Now let's look at the new procedure.  This one consists of three statements,
each of which prints information to the display.  The statements are executed
in order from first to last.

Notice that all kinds of information is printed out by this procedure,
including character strings, values of variables, a result returned by a
function, and a result returned by a procedure.  See if you can find examples
of each of these in the procedure.

In what way does this procedure build upon previously existing building blocks?

Click here for the answer

The last statement prints out the result of calling  distance[ t, theta ].
If the procedure ``distance'' didn't exist, the procedure ``labPos'' would be
useless.

Not surprisingly, it is possible to write C and Fortran code that looks very
similar to this.

Repetition

Let's extend our program in one more way.  Computers excel at repeatedly
carrying out a task.  For example, perhaps we'd like a procedure that would
take an angle as its argument and print out the distance covered by the block
on the ramp every second for ten seconds.  Here's a procedure called
``manyDistances'' that does just that.

manyDistances[theta_]:=
Do[
Print[t, " seconds: ", distance[t, theta], " meters"], 
{t, 0, 10}];

You should try this procedure out for several different values of theta.  For
example:

manyDistances[Pi/3]

This is an example of a kind of statement called a loop.  The printing
statement is executed eleven times, first with t=0, then with t=1, and so
on until t=10.

Mathematica Summary

Our goal in discussing Mathematica procedures in this lesson was to give you an idea
of what it'll be like to program in C and Fortran.  We don't expect you to
understand how to write Mathematica procedures---we just want you to understand
what they are and to appreciate a few ways that they differ from functions.

Homework

If you click below, the tutor will copy a file called ``ramp.txt'' into your
home directory.  The file contains the code for the ``gravity'' and
``friction'' functions, as well as the ``distance'' and ``manyDistances''
procedures, that we discussed in this lesson.

As you do this homework, you will be modifying your copy of the file, and
eventually you will be handing it in.  Every time that you click on the
button below, you will get a fresh copy of the file, and you'll lose any
modifications that you've made.  So don't click on it more than once unless
you really want a fresh copy.

\check{Click here for a copy of ramp.txt}{$files/scripts/setup}{File copied
successfully}{File not copied}

We're going to ask you to make a series of modifications to the program.  Since
you hardly know anything about Mathematica procedures, be sure to proceed carefully.
Be sure that each change that you make works before moving to the next.  As you
go along, you'll probably learn just how picky Mathematica is about the format of a
program.  But if you pay careful attention to the format of our program,
you should be able to make the modifications without too much pain.

(1) First of all, read the program into Emacs and take a look at it. You
will see that there are more comments than code.  It is generally a good
idea to include lots of explanatory comments.

(2) Next, read the program into Mathematica and make sure that you can run it.  To
read the program into Mathematica, pull down Mathematica's {\bf File} menu and choose the
{\bf Include ...}\ option.  A small window will pop up.  You should see
``ramp.txt'' in the ``Files'' list.  Click on ``ramp.txt'', and then click on
the ``Read'' button, and the program will be read into Mathematica.  Finally, go to
the Mathematica window and type the Enter key once so that everything that you just
read will be evaluated.

(3) Go back to your Emacs window and modify the program.  Change it so that
instead of printing out the words ``seconds'' and ``meters'', it prints out the
letters ``s'' and ``m''.  Save the changed program, and then read it into
Mathematica.  Don't forget to use the Enter key to evaluate everything you've just
loaded.  Make sure that the program works as modified.

(4) Again in your Emacs window, add a parameter to ``manyDistances'' so that
the user can specify the number of lines that the procedure should print
out.  Right now, it prints out 10.  Read the changed program into Mathematica and
make sure it works as modified.

(5) Back in your Emacs window, modify the program so that the user of
``manyDistances'' can specify the coefficient of friction between the block and
the ramp.  This will require making small modifications to ``manyDistances,''
``distance,'' and ``friction.''  Note that in ``friction,'' the constant 1.0 is
the coefficient of friction.  Read the changed program into Mathematica and make sure
it works as modified.  (Small coefficients of friction mean small amounts of
friction, large coefficients of friction mean large amounts of friction.)

(6) Finally, back in your Emacs window, modify the program so that the user of
``manyDistances'' can specify the acceleration due to gravity.  This will allow
the user to see how the block would move on the moon (where acceleration due to
gravity is 1.67 meters/sec/sec) or on Jupiter (22.9 meters/sec/sec) and not
just on Earth (9.8 meters/sec/sec).  Read the changed program into Mathematica and
make sure it works as modified.

When you're done, submit your modified program for grading by doing

\begin{verbatim}
handin cai cs100 6 ramp.txt
\end{verbatim}