Preface


This is a tutorial made solely for the purpose of education and it was designed for students taking Applied Math 0330. It is primarily for students who have very little experience or have never used Mathematica before and would like to learn more of the basics for this computer algebra system. As a friendly reminder, don't forget to clear variables in use and/or the kernel.

Finally, the commands in this tutorial are all written in bold black font, while Mathematica output is in regular fonts. This means that you can copy and paste all comamnds into Mathematica, change the parameters and run them. You, as the user, are free to use the scripts to your needs for learning how to use the Mathematica program, and have the right to distribute this tutorial and refer to this tutorial as long as this tutorial is accredited appropriately.

Return to computing page for the first course APMA0330
Return to computing page for the second course APMA0340
Return to Mathematica tutorial for the second course APMA0330
Return to Mathematica tutorial for the first course APMA0340
Return to the main page for the course APMA0340
Return to the main page for the course APMA0330

Functions


Since the Mathematica programming language (called the Wolfram language) is to a large extent a functional programming language, functions are the central objects here. The Wolfram Language has the most extensive collection of mathematical functions ever assembled. They can be accessed through the following web site:

https://reference.wolfram.com/language/guide/MathematicalFunctions.html

To define a function, just type in the formula. We need to use a special form for the left hand side, which includes an underscore after the name of the variable, and a special "colon-equals" sign for the function definition:

f[x_] := (Cos[x] -1)/ x^2
There is no output on this imput. To see it, type Print[f[x]] You can use this function with different arguments or obtain its numerical values:
f[2 x+1]
Out[2]= (Cos[2 x+1]-1)/(2 x+1)^2
Function evaluation in Mathematica is indicated by square brackets. That is, while in mathematical notation, we write \( f(x), \) in Mathematica the correct syntax is f[x]. Ordinary parentheses are used exclusively for algebraic grouping. Thus we write (a*t) to indicate that the exponent is the product of a and t.
N[f[1.5]]
Out[3]= -0.413006

The simplest user-defined functions are the "one-liners", where the quantity of interest can be computed by a single formula. However, in may cases, you may find it impossible to define the function's value in a single simple formula. Instead, you may need to carry out several steps of computation, using temporary variables. You may want several input values, and you may want the user to group some of those input values in curly brackets.

There are a few things to note when defining functions:

However, if you need 20 digits, type
N[Pi,20]
Out[2]= 3.1415926535897932385
In[2]:= t:=Now
In[3]:= t
Out[3]= Mon 30 Nov 2015 08:15:13
However, if you use the same command later, you will get
In[4]:= t
Out[4]= Mon 30 Nov 2015 08:39:36
In[5]:= t= Sunset[]
In[6]:= t
Out[6]= Mon Nov 30 2015 16:17 GMT-5.

A function can also be defined analytically in another way. Say we want to define a cubic root function; then we type

f = #1^(1/3) &;
f[27]
Out[2]= 3

The notion of a pure function comes from the calculus, and is widely used in functional programming languages, Mathematica in particular. From the practical viewpoint, the idea is that often we need some intermediate functions which we have to use just once, and we don' t want to give them separate names. Pure functions allow to use them without assigning them names, storing them in the global rule base etc. Another application of them is that while they can be assigned to some symbols, they exist independently of their arguments and can be called just by name with the arguments being supplied separately, so that the "assembly" to the working function happens already at the place where the function is used. Finally, these functions may be dynamically changed and modified during the program' s execution.

Wolfram language allows one to define a pure function in which arguments are specified as #, #1, #2, etc. There are several equivalent ways to write pure functions in the Wolfram Language. The idea in all cases is to construct an object which, when supplied with appropriate arguments, computes a particular function. Thus, for example, if fun is a pure function, then fun[a] evaluates the function with argument a. There are some examples.

We start with definding a pure function that squares its argument:

square = Function[x, x^2]
square1 = #^2&
and then rule-defined function
square2[x_] := x^2
To see their differences, we type
DownValues[square]
DownValues[square1]
DownValues[square2]
{}
{}
{HoldPattern[square2[x_]] :> x^2}
There are two differences that immediately come to mind:
  1. Functions with down values won't autocompile when you use them in Table, Map, Nest etc. so therefore are less efficient when used that way.
  2. Functions with down values may (in all likelihood will) cause a security warning when present in an embedded CDF.

These two forms of functions may be similar on the surface, but they are very different in terms of the underlying mechanisms invloved. In a sense, Function represents the only true (but leaky) functional abstraction in Mathematica. Functions based on rules are not really functions at all, they are global versions of replacement rules, which look like function calls.

One big difference is in the semantics of parameter-passing. For rules (and therefore functions based on rules), it is more intruding, in the sense that they don't care about the inner scoping constructs, while Function (with named arguments only) will care. Functions are more concise and generally faster but patterns are a lot more expressive. When you don't need the expressive power of patterns you should probably use functions.

Next we define a sum of squares with Map command:

Map[#^2 &, a+b+c]
a^2 + b^2 + c^2
Map[Take[#,2] &, {{1,2,3},{4,5,6},{7,8,9}}]
{{1,2}, {4,5}, {7.8}}
Consider a function that takes the second element from the list:
Clear[takeSecond];
takeSecond = #[[2]] &;
We check
takeSecond[Range[20]]
2
takeSecond[{3,5,7,9}]
5
It is recommended to use SetDelayed to define a function in most cases. What will happen, if we use the Set (=) command instead of SetDelayed (:=), when defining a function? This depends on the state of global variables present or defined in the system at the given moment. Here is an example:
Clear[f,x];
f[x_]= x^2;
{f[1],f[2],f[Pi],f[y]}
{ 1, 4, \[Pi]^2 , y^2 }
The function works fine, but this is so only because by the moment of the definition, the variable < x > did not have any global value (no global rule was associated with it), and thus the right-hand side \( x^2 \) evaluated trivially (to itself) and was recorded in the rule for function < f > in this way. This is what happens when < x > has a value at the moment of assignment :
Clear[f,x];
x=5;
f[x_]=x^2;
{f[1],f[2],f[Pi],f[y]}
{ 25, 25, 25, 25 }
We see that now any input expression, regardless of its structure, will be replaced by 25. This behavior is in full agreement with the principles of operation of Set ( = ) assignment operator. It allows the right-hand side of the definition to evaluate. This evaluation happens as usual, using the values for all global variables or expressions which exist in the system at the moment of the definition. Then Set uses the result of this evaluation as a right-hand side for the new global rule, associated with the left-hand side of the assignment. Since had a global value 5, it was used in the calculation of the right-hand side, which then became the right-hand side of the global rule associated with function < f > (definition of f).

So, the conclusion is that in the majority of cases functions must be defined with SetDelayed (:=) rather than Set (=). Since SetDelayeddoes not evaluate the right-hand side of an assignment, we are safe in this case. However, there are instances when Set operator is more appropriate do define a function. In particular, this happens when a function may be symbolically precomputed so that it is stored in a form which allows a more efficient computation.

f[x_] = IntegerPart[x]
g[x_] = Floor[x]
h[x_] = f[x] - g[x]
For posive real inputs, the function h[x] always show 0, but for negative inputs it is 1; so the function s[x]=1-h[x] is the Heaviside function:
s[x_]=1-h[x]
h[Pi]
Out[5]= 3
s[Pi]
Out[6]= 1
h[-Pi]
Out[7]= 1
s[-Pi]
Out[8]= 0
While Mathematica knows many standard functions, it does not use all equivalent relations. For instantce, Mathematica does not know that
\[ \mbox{arctanh} x = \frac{1}{2}\, \ln \frac{1+x}{1-x} . \]
ff[x_] = Simplify[ArcTanh[x] - (1/2)*Log[(1 + x)/(1 - x)]]
Plot[ff[x], {x, -1, 1}]

 

II. Discontinuous functions

Consider a discontinous function

f[t_] := Piecewise[{{t^2, 0 < t < 2}, {4 - t, 2 < t < 4}}, 2]

First, we calculate some values:
f[2]
Out[35]= 1
f[1.5]
Out[36]= 2.25
f[3.5]
Out[37]= 0.5
f[4.5]
Out[38]= 2
Quiet[expression]                   (* calculate without actually outputting any messages generated *)
FindMaxValue[f[x],x]             (* gives the value at a local maximum of f *)
Out[39]= 4.
FindMinValue[f[x],x]
Out[40]= 4
FindMinValue[Sin[x] Sin[2 y], {x, y}]
Out[41]= -1.

The derivative of the piecewise continuous function    f[t]:

D[f[t], t]
Out[42]=
0 t<0 || t==0
2t 0<t<2
-1 2<t<4
0 t>4
Indeterminate True


 

Return to Mathematica page

Return to the main page (APMA0330)
Return to the Part 1 (Plotting)
Return to the Part 2 (First Order ODEs)
Return to the Part 3 (Numerical Methods)
Return to the Part 4 (Second and Higher Order ODEs)
Return to the Part 5 (Series and Recurrences)
Return to the Part 6 (Laplace Transform)