IMSE Chapter 2

IMSE-02(Functions).nb
Functions and Such in Mathematica
RCH 7/19/01
revised 6/10/02 - rjerwin

In this notebook you will explore the use of functions in Mathematica.  The tools learned here will be very useful in almost every Mathematica calculation.  We will explore a few "quirky" features of Mathematica that you need to be aware of to avoid some frustrating and sometimes confusing results.  Mathematica doesn't do anything wrong, but it does handle functions in ways that sometimes can catch you off guard.

As you learned in IMSE-01, Mathematica's built-in functions all have names that begin with upper-case letters.  Of course, Mathematica allows you to define your own functions.  Hence, it is good programming practice to use names that begin with lower-case letters for your "custom" functions.  There is no practical limit to the length of the names of functions, so you can use names that help you remember the origin or purpose of the function.

Let's begin by defining a simple function and seeing how to use it within Mathematica.  An example from introductory physics will suffice.  For a particle falling freely under the influence of gravity near the surface of the earth, the vertical location as a function of time t is given by y(t) = yo + vo t + (1/2)g (t^2), where as usual yo is the initial y position, vo is the initial y velocity, and g is the acceleration due to gravity (approximately -9.8 m/(s^2)).  (We will take positive y to be in the upward vertical direction.) The following cell sets up this function in Mathematica in a way that might seem reasonable, but in fact leads to trouble.

y[t] = yo + vo*t - 4.9*t^2

If you activate that cell, you will find that Mathematica returns the function with the terms written in a slightly different order.  (Note that Mathematica treats the symbols yo and vo as individual names, not y times o and v times o.)  Now let's try to use the function to evaluate the position at some particular instant of time.  First, we need to specify values for the initial position and the initial velocity.  That is done in the next cell.  Activate that cell.

yo = 0.5;
vo = 10;

Let's now try to evaluate y at time t = 2.0 seconds.  Activate the following cell.

y[2]

You probably found that the result was not what you expected, that is, Mathematica did not evaluate the function for t = 2 sec.  The difficulty is that the form we used for setting up the function was not what Mathematica wants for a general function, one that can be evaluated for whatever values of the argument we want.  The correct function definition requires having the function independent variable labeled with a subscript _  (obtained by holding down the Shift key and hitting the - key on the top row of the keyboard next to 0) on the left-hand-side of the definition.  Once the function has been defined, you can use y[t] in other expressions.  The next cell illustrates the desired format.  Activate that cell to see what happens.

y[t_] = yo + vo*t - 4.9*t^2

You see that Mathematica has remembered the numerical values you assigned to the initial position and velocity and gives you the function with those values inserted.  Now let's find the position at t = 2 sec.

y[2]

Now we get the expected result.  Try the following cell.

y[t]^2

y[t]^2  // Expand

The previous cell illustrates that Mathematica can perform symbolic algebra manipulations.  These will be explored more fully in IMSE-03.

Let's explore some other features of Mathematica functions.  Mathematica treats the independent variable as a symbol, which can be replaced by other symbols.  Activate the following cell and explain what happens.

y[Tan[θ]]

Here Mathematica has replaced t with Tan[θ] in the formula.

Activate the following cells and explain what happens.

θ = 1;

y[Tan[θ]]

y[1]

We see that you can define functions that make use of Mathematica's built-in functions (for which you do not need the _ subscript for the independent variable because those functions have already been defined).

Using and plotting functions

Now let's use the function for a variety of purposes.  First, let's plot the function by activating the following cell.

Plot[y[t], {t, 0, 3}];

One of Mathematica's strong points is its graphing capabilities.  Anyone who has tried to produce graphs using BASIC, FORTRAN, C++, etc. will appreciate the ease with which one can produce graphs in Mathematica.  We will explore graphics in IMSE-04(Plots).

Mathematica automatically sets up the graph with appropriate numerical values on the abscissa and ordinate axes.  Note that within the Plot command, the function argument t appears without the _ subscript because we are using the function, not defining it.  The arguments inside the curly brackets within the Plot function specify the range of t values to be used in the plot.   Mathematica evaluates the function at enough points across that range to represent the function reasonably accurately and connects those points with lines to make the graph.  If you want more points plotted -- for example, if there are many rapid oscillations of the function across that range -- you can change the number of points plotted.   In IMSE-04 we will explore the plotting options in more detail.  For example, the "default" plot above does not put labels on the axes (and hence loses 5 points for its lab report).

In the following cell type and activate a command that will plot the function y[t] between t = -3 and t = +5.

Another important feature of Mathematica's use of functions, as mentioned above, is the flexibility of using other variables for the independent variable.  Activate the following cell and explain what has happened.

Plot[y[u], {u, 0, 3}];

Below we have added a command that puts labels on the axes.  (We need the extra 5 points.)

Plot[y[u^2], {u, 0, 3}, 
        AxesLabel -> {"u", "y[u]"}];

The command in the previous cell is equivalent to plotting  y[(u^2)] = (Subscript[y, 0]) + (Subscript[v, 0])(u^2) + 4.9 (u^4)  because Mathematica has substituted t = (u^2) in expression for y[t].

Functions of several variables

You can also have functions of several variables.  For example, the next cell defines a function of two variables x and y.

g[x_, y_] = x^2 + y^2

Now evaluate the function at x = 3 and y = 12.

g[3, 12]

An aside:  You have the option of  "segregating" the independent variables when you define a function.  This is sometimes useful for very complicated functions or for numerical calculations.

r[x_][y_] = x^2 + y^2
r[3][12]

Calculus

Now let's do some calculus with our functions.  Suppose we want to integrate the function.  The first cell is meant to remind you about the current form of the function y[t].  The second cell performs the integration.

y[t]

Integrate[y[t], t]

Note that Mathematica is still using your assigned numerical values for the initial position and velocity.  Let's get rid of those values.  The following command removes the numerical values.  Activate the cell, note the form of y[t], and then activate the Integrate cell.  Explain what happens.

Clear[vo, yo]

y[t]

However, the function y[t_] itself is still defined with the numerical values of yo and vo.  For example, if you evaluate y[4] you get a number instead of an expression with yo and vo.  We need to reassign these variables to the function y[t_].

y[t_] = yo + vo*t - 4.9*t^2

Integrate[y[t], t]

You now have a symbolic expression involving the symbols vo and yo.

An Important Lesson:  What happens when you activate a command in Mathematica depends on the order in which commands are executed, not on the order in which they appear in the notebook.  In other words, you can go back earlier in a notebook and reactivate a command.  The results that you get upon reactivation may be different from what you got the first time because later commands may have changed the meaning of symbols or the numerical values associated with the symbols.

NOTE: Variables with subscripts are different.  If you use (Subscript[y, 0]) instead of yo, you'll have to use the command (Subscript[y, 0]) = . instead of Clear[(Subscript[y, 0])].  Alternatively, you could say Clear[Subscript], though this will remove the values of all variables with subscripts.

Now let's do a derivative.  The first argument of the command Derivative indicates which derivative (first, second, etc.) you want to find.  The second argument specifies the function whose derivative is to be evaluated.

Derivative[1][y]

This form looks rather strange, but it illustrates an important Mathematica feature.  First, this particular form is called a "pure function" in Mathematica.  The independent variable t has been been replaced by #1 meaning the first independent variable.  The & following the function indicates that this function is expressed in the "pure function" form.  The pure function form of the derivative of y is a differentiation operator -- you can apply it to almost any argument (such as t, in this case, or m, or q, or some other variable).  In IMSE we will not have to use pure functions, but they may appear from time to time in your own work and you should know what they are.

To get the form with the symbols, we use an alternative command with symbol D for derivative:

D[y[t], t]

We can also compute a second derivative.

D[y[t], {t, 2}]

Mathematica also uses the Leibnitz prime notation, which gives a pure function form (with the #1 notation rather than the symbols):

y'

We can get the pure function back into a standard form by doing the following:

y'[t]

Note that you can apply the differentiation operator y' to any variable.

y'[m]

Delayed evaluation of functions

As we have seen, how Mathematica "remembers" functions and whether or not numerical values are used or whether symbols are used is a bit tricky, depending on the sequence history of the commands.  When first setting up a calculation or debugging a notebook, this can become a serious issue.

Here is a simple example.  Suppose at some point during a session you assign a number to what looks like a function.

z[0] = 1. ;

Later in the session, we define z as a function of y.

z[y_] = y^2;

Then we evaluate the function at y = 0.

z[0]

Surprise! You see that Mathematica has remembered the earlier numerical value and returns it in place of what you might have expected.  To avoid this difficulty you must either avoid making assignments like z[0] = 1 (which is difficult to do if you are trying out various aspects of a long calculation) or use the command Clear[z] before defining the function, just to be sure you haven't used it before.

It turns out that there is a simple way of avoiding (most of) these problems.  When you define a function, you can use what is called the delayed evaluation form.  This form uses a colon (:) in front of the equals sign.  That tells Mathematica to delay evaluating the function until the function is used in subsequent commands.  This procedure forces Mathematica to go back to the definition every time the function is used.  Let's see how this works by defining a new function x[t].

x[t_] := yo + vo*t + Sin[t]
vo = 2.5;

Derivative[1][x]

Note that the derivative was evaluated with the numerical value 2.5 assigned to vo.  Now let's Clear vo and take another derivative.

Clear[vo]
Derivative[1][x]

The symbol now appears as expected.  This rather long lesson shows that using delayed evaluation is almost always a good strategy.  It has other advantages we shall meet later.

I have found that Mathematica's memory for earlier definitions of functions is one of its greatest sources of confusion.  Of course, under the right circumstances, it can be a very helpful tool, but if you are like me and often forget exactly what you defined a few hours ago in a long Mathematica session, look for previously defined variables and functions when Mathematica does not seem to be doing what you expect.  Generous use of the Clear[] command will help quite a bit.  If you want to remove a symbol completly, use the Remove[] command.

Comment

The following sections are not crucial for most of what we will do in the other IMSE notebooks.  They do, however, introduce you to several other features and quirks of Mathematica's use of functions, so I recommend trying them out.

Special Packages of Functions

Mathematica comes with several packages that contain special functions and operations.  To use these functions, you need to load the specific package containing the desired function.  For example, the package Statistics`DescriptiveStatistics` contains functions for finding the mean, standard deviation, etc. of a set of numbers.  (The use of these functions will be discussed in more detail in IMSE-10(Statistics).)  To load the package, use the << symbols as shown in the following cell.

<< Statistics`DescriptiveStatistics`
Mean[{1, 2, 4, 7, 10, 4, 11}]

Many graphics commands and special mathematical commands are not automatically loaded into Mathematica when you first start the program.  To load them, you'll need to use the format indicated in the input cell above: <<directory`package`.  Mathematica Help has information about these commands and the packages in which they are contained.

One difficulty may arise in using the functions from packages.  If you mistakenly use the name of a function before the relevant package is loaded, of course, Mathematica doesn't know what to do.  That's not so bad.  Here is where the trouble comes in: if you subsequently load the package and then try to invoke the function, Mathematica uses whatever is associated with the name when you first used it.  Let's illustrate this problem with the function RandomPermutation from the package DiscreteMath`Permutations`.  (If you want to know what RandomPermutation does, check Help.)

RandomPermutation[5]

Mathematica doesn't recognize the function RandomPermutation, so it just returns what was typed in.

In the next cell, we load the package and invoke the function.

<< DiscreteMath`Permutations`
RandomPermutation[6]

The warning message tells you that something is going wrong (but not how to fix the problem).  The fix is to use the Remove[] command to get rid of your RandomPermutation.  Here is how it works:

Remove["RandomPermutation"]
RandomPermutation[5]

Mathematica now responds correctly by giving 5 integers (from 1 through 5) in random order.

Conditional Functions (Functions with Conditions)

This is a somewhat more advanced topic but one that turns our to be useful in many scientific and engineering calculations.  In many situations, we may want to use different analytic forms of a function for different ranges of the independent variable(s).  For example, we may want to model the slope of a hillside (where we are designing a ski slope for the Olympics) with two different functions for different parts of the slope.  Mathematica has a simple way to deal with this situation.

Let's suppose that we want to have a linear slope near the top of the hill and then an exponential slope towards the bottom.  The following cell sets up the functions.  Note that we use := instead of just = to set up the function.  This is another use of the delayed assignment: Mathematica does not evaluate the function until it is needed.  The condition to be satisfied follows the /; symbol combination.

We also plot the function to see what the slope looks like.

h[x_] := 100 - 10*x  /;  x ≤ 5
h[x_] := 
      50*Exp[-(x - 5)]  /;  
        x ≥ 5
\(\(Plot[
        h[x], {x, 0, 
          10}, 
AxesLabel -> {"x", "height"}];\)\)

Strictly speaking, we should make sure the ranges of x specified by the conditions don't overlap.  In our example, the numerical values at x = 5 are the same so it doesn't matter.  Below is an example where the two functions don't match up.  (Obviously not a good design for a ski slope!)

h2[x_] := 100 - 10*x  /;  x ≤ 5
h2[x_] := 
      60*Exp[-(x - 5)]  /;  
        x ≥ 5
\(\(Plot[
        h2[x], {x, 0, 
          10}, 
AxesLabel -> {"x", "height"}];\)\)

Which function does Mathematica use at x = 5?  The next cell gives you the answer.

h2[5]

Remember the quirk mentioned above.  Mathematica remembers the first definition in the sequence and uses that. 

To avoid any ambiguity in the conditions, you should make sure each range is unique.

What happens if the ranges do not overlap?

h3[x_] := 100 - 10*x  /;  x ≤ 4
h3[x_] := 
      60*Exp[-(x - 5)]  /;  
        x ≥ 5
\(\(Plot[
        h3[x], {x, 0, 
          10}, 
AxesLabel -> {"x", "height"}];\)\)

The error messages tell us that there is some range of x for which the function is not defined.

Exercise:  In the following Input cell, use conditional function statements to define a function that is Cos[x] for x < 0 and a straight line with a slope of -1 and a y intercept of +1 at x = 0 (to match the Cos function) for x ≥ 0.  Then plot the result for -2 ≤ x ≤ 2.  Label your axes!

Using Multiple Notebooks Simultaneously

You can have several Mathematica notebooks open simultaneously.  One notebook might be designed to carry out some calculations, while the second notebook does some plotting and graphing based on those calculations.  Mathematica allows the results calculated in one notebook to be accessed by the other notebook automatically.

Let's illustrate what can happen with a simple example.  Activate the File menu and click on New to create a new notebook.  In that notebook type b = 3 in an input cell and then activate the cell.  Then use the Window menu to return to IMSE-02.

After returning, activate the following cell:

a = 7;
c = a*b

You see that Mathematica "remembers" that b = 3  from your new notebook and uses that value in this notebook.  This feature makes it easy to transfer results from one notebook to another.  It also means that changes in one notebook can affect variables in another notebook.  These changes carry over even if you close the first notebook.

Lesson: Beware of possible linkages between notebooks.  Generous use of Clear[] can help avoid confusion.

Exercise:  In the Input cell below, set b = 4 and then switch to your new notebook and see if b = 4 carries over to that notebook by using a new input cell with Print[b].