3

Programming: The Beauty and Power of the Wolfram Language

In this chapter we will discuss some of the basic concepts that we need to know to program in Mathematica using the Wolfram Language. We will also cover some useful notions for generating efficient code. In particular, we will learn how to code using pure functions, very important if you want to create compact programs that take full advantage of the power of Mathematica. We will also include examples of some of the most commonly used programming functions and describe the fundamental ideas behind package development, essential to build new applications that incorporate user-defined functionality. Finally, we will provide guidance on tools available for large projects or to develop programs that can be run from a browser.

3.1 Mathematica’s Programming Language: The Wolfram Language

As we have seen already in previous chapters, Mathematica is not only a program to perform symbolic and numeric calculations. It is a complete technical system that can be used to develop anything: from traffic control applications to sophisticated image manipulation interfaces. All of this is possible thanks to the power of the Wolfram Language, the high-level general-purpose programming language used by Mathematica. To start using it we need to know its fundamentals and that’s what we are going to learn in this chapter. This section will cover the basic components of the language.

3.1.1 Expressions

Everything in Mathematica is an expression, including notebooks. All expressions are written in the form: Head [..., {}]. Head is always capitalized and followed by a pair of enclosing brackets containing elements separated by commas. Those elements sometimes go inside braces. Here is one example:

Head[a + b + c]

Plus

  • Instead of x + y + z we write:

    Plus[x, y, z]

    x + y + z

  • With FullForm we can see the basic form of expressions: One head, Plus in this case, and elements separated by commas inside brackets:

    FullForm[x + y + z]

    Plus[x, y, z]

Cells are also expressions. Shown below is a copy of this cell displaying its contents. This was done by selecting the copied cell and clicking on: CellShow Expression.

Cell[TextData [{
 "Cells are also expressions. Shown below is a copy of this cell displaying its contents.
 This was done by selecting the copied cell and \
clicking on: ",
 StyleBox["Cell",
  FontWeight-> "Bold"],
 " \ [FilledRightTriangle] ",
 StyleBox["Show Expression",
  FontWeight -> "Bold"],
 ". "}], "Texto AM",
CellChangeTimes->{{3.627622*^9, 3.627622`*^9}, {3.6396977`*^9, 3.6396977*^9},
{3.6396978`*^9, 3.6396978*^9}, {3.6396979*^9, 3.6396979*^9}, {3.63969798*^9,
 3.63969798`*^9}}]

3.1.2 Atomic Objects

All objects in Mathematica are one of the following types:

Numbers: (i) Integers: Any number without a decimal separator, (ii) Reals: Any number with a decimal separator, (iii) Rationals: the ratio between two integers such as 3/4 o 27/8, (iv) Complex: The sum of a real number and an imaginary number: 3 + 2 Images.

Symbols: A sequence of letters, digits or symbols not starting with a number (we will describe them later).

Strings: Any expression between double quotation marks: “this is a string”.

SparseArrays: Matrices or lists where most of the elements have the same value:

MatrixForm[SparseArray[{i_, i_} :→ RandomInteger[8], {4, 4}]]

(6000050000700002)

Graphs: A collection of objects, joined by vertices in pairs.

Images

Mathematica internally always separates expressions first into their atomic components before computing them.

3.1.3 Symbols

Symbols is the name of one of the types of atomic objects in Mathematica. They can be: letters, digits, combinations of letters and digits not starting with a digit, and special symbols such as: $, π, ∞, Images, Images, Images. Upper and lower-case letters are distinguished. Once a symbol has been created during a session, it will remain in memory unless explicitly removed. An alternative is to use functions that automatically delete a symbol once it’s been used.

3.1.4 The Mathematica Paradigm

  • If we have a list and we’d like to know the type of objects that it contains, we apply Head to each of the list elements. This can be done using Map (We will refer later to this important programming function).

    Images

    {Integer, Rational, Real, Complex, Complex,
     Power, Symbol, List, Symbol, Graphics, Image}

3.2 Functional vs. Procedural Programming

The power of Mathematica can be seen specially when we use it to create programs. Readers with experience in procedural programming using languages such as C or FORTRAN, sometimes use the same approach with Mathematica even though it may not be the most appropriate one. Because of this, if you are a programmer we would like to encourage you not to replicate the procedural paradigm when programming with Mathematica. It will be worth the effort.

Let’s see an example for creating a function to calculate the factorial of a number using different programming styles without using the built-in factorial function n!:

The next example consists of building, using different programming styles, a command to add the elements of a list of consecutive integer numbers and compare execution times (we use the function AbsoluteTiming to show the absolute number of seconds in real time that have elapsed, together with the result obtained). We avoid directly applying the formula for calculating the sum of an arithmetic series which would be the easiest and most effective way.

The functional method (using different instructions in each case) is much more efficient.

In this example we build a function, using different styles, to calculate the sum of the square roots of n consecutive integers: {1+...+n}, and apply it with n = 50.

Another way of programming where Mathematica displays its power and flexibility is rule-based programming.

The previous approach is very useful to perform operations, such as reordering, on lists.

3.3 Set vs. SetDelayed

A frequently asked question is how to differentiate between "=" (Set) and ":=" (SetDelayed).

What has happened? When "=" is used in f = exp, the result of evaluating exp is assigned to f immediately. From then on, whenever f is called, the program will always replace f with the value of exp. In the previous example, the value of x was stored right away, while in the case of y, what gets stored is the function that will be executed every time it’s called. Because of that, when calculating y-y, RandomReal [] is executed twice, returning each time a different result.

It’s normal to use “:=”when defining functions. However, in many cases it is also possible to use "=" or ":=" without affecting the final result.

The same role that “ =” y “:=” play when defining functions, “→” and “: → (or :>)” play when making replacements:

3.4 Matrices and Lists Operations

Clear["Global`*"]

In this section we are going to see some functions that are very useful when performing operations on lists, matrices and vectors. We already mentioned some of them in Chapter 2.

3.4.1 A Random Walk

Any time we want to do something in Mathematica, it’s possible that the program already has a built-in function to perform the operation.

  • In this example we sum consecutively all the elements in a list.

    Accumulate[{a, b, c, d, e}]

    {a, a + b, a + b + c, a + b + c + d, a + b + c + d + e}

As mentioned previously, we will not always find the specific function for what we want to do. However, there are versatile functions useful to know that we can use to perform a specific computation. When operating with lists FoldList is such a function.

  • Here we use FoldList as an alternative to Accumulate.

    Rest[FoldList[Plus, 0, {a, b, c, d, e}]]

    {a, a + b, a + b + c, a + b + c + d, a + b + c + d + e}

Using any of the two previous functions we can build a simple expression to simulate a random walk, also known as the drunk man’s walk. Let’s suppose that a drunk man tries to cross the street and each step he takes can randomly go in any direction. Many physical phenomena, such as Brownian motion, are variations of random walks (The Mathematica built-in function is RandomWalkProcess).

  • The function below is a very simple case of a random walk along a line. Each step has a maximum length of 1 and can go toward both ends of the line with equal probability. To simulate it, we generate random numbers between −1 and 1 (if it goes in one direction we use + and in the opposite direction –) What will be the distance covered after n steps?

    RandomWalk[steps_] := Accumulate[RandomReal[{-1, 1}, {steps}]]

  • We create a function to graphically represent the distance covered after n steps. In this case we assume n = 500.

    ListPlot[RandomWalk[500], Filling → Axis]

    Images

3.4.2 Matrix Operations

Matrix operations appear very often when performing algebraic calculations. The use of SparseArray speeds up computations significantly.

  • Generate a random matrix:

    mat = RandomInteger[10, {5, 5}]

    {{9, 10, 6, 2, 7}, {7, 4, 2, 10, 9},
     {6, 10, 10, 3, 1}, {1, 0, 5, 10, 9}, {7, 10, 9, 1, 1}}

  • The next command displays the previous output in matrix format and evaluates its transpose, inverse, determinant and eigenvalues. We use TabView to place the outputs under different labels visible after clicking on the corresponding tab.

    TabView[
     {"Matrix A" → MatrixForm[mat], "Transpose" → MatrixForm[Transpose[mat]],
      "Inverse" → MatrixForm[Inverse[mat]], "Determinant" → Det[mat],
      "Eigenvalues" → N[Eigenvalues[mat]]}]

    Images

Next, we create an equation of the form m x = b, where m corresponds to the matrix mat. We will solve it and check that the solution is correct.

  • We generate matrix b randomly.

    b = RandomInteger[10, {5}]

    {2, 10, 1, 4, 0}

  • We solve the equation using LinearSolve.

    xvec = LinearSolve[mat, b]

    {6911893,234631,14681893,20261893,6711893}

  • We verify that the solution is correct ("." is used for matrix multiplication).

    mat.xvec

    {2, 10, 1, 4, 0}

In matrix operations it is very frequent to have matrices where only few elements have non-zero values. These kinds of matrices are called sparse arrays. In these cases is recommended to use SparseArray.

  • We build a tridiagonal matrix 5×5 whose main diagonal elements are 9s and its adjacent 1s.

    Images

  • We show it numerically and represent it graphically using MatrixPlot.

    MatrixForm[Normal[s]]

    (9100019100019100019100019)

    MatrixPlot[s]

    Images

We build a linear system of 5 equations of the form s x = b, with s and b the matrices previously defined.

  • We solve the equation and check the calculation time:

    Timing [LinearSolve[s, b]]

    {0.,{139314040,17271560,22351,7131560,71314040}}

  • We repeat the same process but for a system of 50000 variables and 50000 equations, of the form s x = b where s and b are called sLarge and bLarge respectively. We use “;” to avoid displaying the output since it would take too much space.

    Timing[bLarge = RandomReal[1, {50 000}];]

    {0., Null}

    Timing[sLarge = SparseArray[
         {{i_, i_} → 9, {i_, j_} /; Abs[i - j] == 1 → 1}, {50 000, 50 000}];]

    {0.453125, Null}

    MatrixPlot[sLarge, ColorFunction → "Rainbow"]

    Images

  • We solve the system sLarge x = bLarge and see that the calculation time is extremely short.

    Timing[xvec = LinearSolve[sLarge, bLarge];]

    {0., Null}

  • We don’t show the result but we can check that the answer is correct by verifying that mxb = 0. With Chop we eliminate the insignificant terms, unavoidable in numerical calculations involving decimal numbers.

    Norm[sLarge.xvec - bLarge] // Chop

    0

3.5 How Mathematica Works Internally

We’ve seen that Mathematica manipulates basic objects located at the head of each expression (Head).

Clear["Global`*"]

If we analyze the previous tree we can see that the first expression is 1/4. Internally it is represented as 4−1. Next, that expression is multiplied by Pi, the result multiplied by 2, and so on until reaching the top of the tree.

If you move the cursor over an individual frame you will notice that it displays the result of the operations until that frame.

Once we know the structure of an expression, we will be able to modify it. Additionally, when encountering outputs from operations that we don’t understand, their internal form can give us clues about how the program works.

3.6 Apply, Map, and Other Related Functions

Clear["Global`*"]

In this section we have selected some of the most commonly used functions for programming.

3.7 Iterative Functions

The most commonly used iterative functions in Mathematica are Nest, FixedPoint, Fold and Catch along with their extensions NestList, NestWhile, FoldList and FixedPointList.

People with experience in other programming languages tend to make iterations using For and Do (also available in Mathematica) but normally we should avoid them and use the commands in the previous paragraph. In the examples that follow and throughout the rest of the book we will do just that.

3.8 Pure Functions

The concept of a pure function is absolutely fundamental to program properly in Mathematica. Pure functions behave like operators telling arguments what to do. Initially they may appear cryptic but their use will end up showing us how powerful they are. Therefore, it’s convenient to start using them as soon as the opportunity arises.

In this last case, instead of Function we have used the # symbol and to finish defining the function we have added & at the end. Since the combination of # and & represent dummy variables we don’t need to store those variables in memory, reducing the computation time. Next we are going to see several examples using this notation.

3.9 Global and Local Variables

A common problem in programming languages is how to avoid conflicts among variables. Be careful and do not confuse the mathematical concept of variable with its concept in programming, the one we use here. In this case, when we mention variables we refer to assignments or definitions made for later use. If we create a variable and later on use the same name to define a new one, conflicts may arise between them.

However, a more logical way to proceed is to avoid global variables and use local variables instead, that is, variables that only have meaning inside an expression.

The main difference between Module and With is that with Module we explicitly indicate what variables are local while when using With, replacement rules are assigned to the local symbols, that is: With [{x = x0, y = y0,}, expr]. In many cases you can use them interchangeably.

Another related command is Block, very similar to Module. The main difference is that while Module creates temporary assignments for the specified variables during the evaluation, Block suspends any existing assignments for those variables and restores the assignments once the evaluation is done.

Module[{y}, Expand[(1 + y) ^2]]

1 + 2 y$1313 + y$13132

Block[{y}, Expand[(1 + y) ^2]]

16

You can find an interesting comparison between them, using the new function Inactive, in: http://www.wolfram.com/mathematica/new-in-10/inactive-objects/optimize-code.html.

Remember that unless you exit the session, even though you create a new notebook the functions previously defined during the session will still be active.

There’s another way to limit the use of variables to a specific context by choosing in the menu bar: Notebook’s Default Context. With this method you will be able to restrict the variables to a notebook or a group of cells. For example:

3.10 Conditional Expressions

Clear["Global`*"]

A predicate is a function that can take two values: {True, False}. This type of function is called Boolean. Figure 3.1 shows all the built-in symbols in Mathematica used to represent Boolean functions and their corresponding Wolfram Language command:

Images

Figure 3.1     Boolean Functions in Mathematica.

Predicates are used when defining conditions. These can appear under very different situations.

In a function, the easiest way to limit a parameter n so that the function will not be executed unless the parameter meets the condition cond, is_cond.

Another way to establish a condition is with_?Test (guide/TestingExpressions). As a matter of fact, this is best way to do it since it’s the fastest one.

A condition can also be defined using “/;”, the function f: =exp/;cond is evaluated only if the condition is met. Other equivalent forms are: f/;cond:=exp and f:>exp/;cond.

In the next example we combine several conditions that must be met to apply the binomial coefficients formula (nr). There is a specific function for this calculation: Binomial, but here we want to create it ourselves.

We can also define conditions with the following functions (see the program’s help): If, Which, Switch and Piecewise.

In the examples that follow we use DeleteCases to eliminate those elements of a list that meet certain criteria.

3.11 Accuracy and Precision

The number of significant digits of a number x used in calculations is called precision. To know the precision used in a calculation used Precision [x]. Accuracy (Accuracy [x]) is the number of significant digits to the right of the decimal point. Precision is a relative error measure while accuracy measures the absolute error.

WorkingPrecision controls the precision level during internal calculations while PrecisionGoal determines the precision in the final result. Other options related to accuracy and precision are: Accuracy, AccuracyGoal and Tolerance.

Besides knowing how to use the options mentioned above, there’s an important issue that you should know: Mathematica has different rules for working with accuracy and precision. An approximate quantity is identified by the presence of a decimal point. Therefore, 0.14 and 14.0 are approximate numbers and we will refer to them as decimals. If we rationalize 0.14 we get 14/100, the ratio of two integers. When doing operations with integers or combinations of them (rationals, integer roots, etc.) Mathematica generates exact results.

There are several functions to convert a decimal number into an exact one.

In the next example we are going to see the difference between operating with integers (or expressions composed of integers, such as fractions) and operating with decimal approximations.

Let’s show another more complicated example where we will see as well the effect of using decimal approximations instead of exact calculations.

Consider the following system of differential equations:

x1'(t) = 1 - 2.5 x1(t) + x2(t)

x2'(t) = 2x1(t) - x2(t)

Initial Conditions : x1(0) = x1(0) = 0

Another situation where it is common to experience difficulties similar to the previous ones is when performing matrix operations (matrix inversion, resolution of systems of differential equations with decimal coefficients, etc.) Therefore, it is often desirable to rationalize the decimal matrix elements; although you may have to consider the increase in computation time.

3.12 Choosing the Method of Computation

The power of Mathematica becomes particularly evident in the precision with which you can do calculations and the ability to choose the most appropriate method or algorithm given the required computation.

3.13 Optimizing the Computation Time

Another interesting aspect of Mathematica is its use of previously calculated results. Before showing it with an example, it would be better to quit the session to remove any previous information stored in memory.

  Quit[]

The calculation time is faster in this last case. It seems logical, since in the first example the integral f1 is calculated 10 times, each time applying a different integration limit, while in the second case f2 provides the solution to the integral as a function of the integration limit x1, and then replaces the value of x1 directly in the solution 10 times.

The reason behind this behavior is that for functions such as: Integrate, Simplify and others, Mathematica keeps a cache of previous results that it will use later if necessary to make calculations more efficient (http://library.wolfram.com/infocenter/Conferences/5832/).

In many situations we can significantly reduce the computation time by using Compile. Normally it’s used with functions that only need to evaluate numerical arguments. This approach enables the program to save time by avoiding checks related to symbolic operations. The command generates a compiled function that applies specific algorithms to numerical calculations.

If you need to create highly efficient programs for calculations that could take hours or even days, it’s recommended to try several alternative approaches first. It’s not unusual for two commands generating the same result to have very different computation times (a carefully crafted programming instruction can be tens or sometimes even thousands of times faster than one that is not).

3.14 Cloud Deployment

The function CloudDeploy deploys objects to the Wolfram Cloud. Let’s take a look at some examples.

Images

Figure 3.4     Manipulate in the cloud.

For further information:

http://reference.wolfram.com/language/guide/CloudFunctionsAndDeployment.html

3.15 Package Development

Mathematica’s capabilities can be extended substantially with the use of packages. Packages are conceptually similar to what other programming languages call subroutines or subprograms. They basically involve the creation of functions, often complex, that can be called when needed without having to define them again.

3.15.1 The Structure of a Package

Clear["Global`*"]

A package has the following structure :

BeginPackage["name of the package`"]

f::usage = "f brief description", … (here we would include the headings of the functions that we are going to use with a brief description, that will be seen by the user later on).

Begin["`Private`"]

f[args]= value, (here we would have the option to place functions that will be used by f but that will remain private. That is, the user will not be able to access them). f[args] = value, (here we would program the package functions accessible to the user).

End[]

EndPackage[]

A simple package

We’d like to build the function below and make sure that it’s going to be available for later use in any notebook.

f(n, r, p) = (nr) [pk (1 − p)nr, n ≥ 1, nr, 0 ≤ p ≤ 1

  • Write the following in a code cell (FormatStyleCode)

    BeginPackage["Binomialpackage`"]


    Binomialdistribution::usage =
    "Binomialdistribution [n, r, p] calculates the binomial probability
    distribution under the conditions that n must be an integer, n ≥ 1,
    N >= r and 0 <= p <= 1.";


    Begin["`Private`"]


    Binomialdistribution[n _Integer, (r_Integer)?NonNegative,
       (p_)?NonNegative]/; n >= r && 0<= p<= 1 :=
      (n!/(r!*(n - r)!))*p^r*(1 - p)^(n - r);


    Binomialdistribution[n_, r_, p_] := "Check that n is an integer,
    r is a non-negative integer, n >= r and 0 ≤ p ≤ 1."


    End[]


    EndPackage[]

  • Next, from the main menu bar select FileNewPackage. A new window in the package environment will appear (Figure 3.5). After that, copy the previous cell to this new notebook, turn it into an initialization cell (Cell ▶ Cell PropertiesInitialization) and save it as a package (FileSave asWolfram Mathematica Package) in the Data folder located in our working directory. Use as the name the one defined in BeginPackage: “Binomialpackage.m” (remember to choose the extension .m).

    Images

    Figure 3.5     Developing packages in Mathematica.

  • In this environment we can test, modify and even debug the package. Once we see it is working correctly we will save it. A package is an ASCII file. It can also be modified using a text editor such as Notebook (in Windows).

  • As the last step, we exit the session (to be precise: we exit the kernel) to start a new one. This can be done without closing the notebook by choosing in the menu bar Evaluation ▶Quit Kernel or with the command:

    Quit[]

  • Let’s make the folder Data our working directory.

    SetDirectory[FileNameJoin[{NotebookDirectory[], "Data"}]]

    C:\Users\guill\Documents\MathematicaBeyond\Data

  • To use the package we need to load it first (or, for testing purposes, execute it inside a notebook). We can use either << or Needs but in this case we choose the latter since it has the advantage of only loading the package if it hasn’t been loaded previously.

    Needs["Binomialpackage`"]

  • One way to know what functions are available inside the package is as follows:

    ?Binomialpackage`*

    Binomialdistribution[n, r, p] calculates the binomial probability distribution

    under the conditions that n must be an integer, n ≥ 1, n >= r, 0 <= p <= 1.

  • At the time of loading the package, all its functions are executed, in this case just one: Binomialdistribution.

    Binomialdistribution[5, 3, 0.1]

    0.0081

    Binomialdistribution[5, 3, 1.4]

    Check that n is an integer, r
       is a non-negative integer,n >= r and 0 ≤ p ≤ 1.

3.15.2 Package Use

If you want the package to be available to all users, copy it to a Mathematica subdirectory named Applications that can be found executing the command $InstallationDirectory or $BaseDirectory.

FileNameJoin[{$InstallationDirectory, "Addons", "Applications"}]

C:\Program Files\Wolfram Research\Mathematica\11.0\Addons\Applications

3.15.3 Adding Options to Packages

Here we show a way to build a package with options. For that purpose we use the syntax: f[x_, opts___]. Note the use of the triple underscore symbol (BlankNullSequence) “___” that we have mentioned before.

  • Before building a function with options remember the replacement rules:

    m /. m -> opt1 /. m1 -> opt2

    opt1

    m1 /. m -> opt1 /. m1 -> opt2

    opt2

  • These rules are applied when defining a function where users can choose different options. One option will be used by default (“Method1”):

    Opt1[function1] = Method → "Method1";

    f1[x1_, opts_ _ _] := {x1, Method /. Flatten[{opts}] /. Opt1[function1]}

  • If we don’t write any option or we write Method→ “Method1” then Method 1 is applied:

    f1[v1]
    {v1, Method1}

  • The method written in opts will be used in other cases. We have used Flatten[{opts}] to ensure that the function works even if the user writes the option between nested brackets.

    f1 [v2, {{Method → "Method2"}}]
    {v2, Method2}

  • Now we will develop a package with options. Let’s suppose that we would like to do an operation between two lists (a = list1, b = list2). The operation f will be different depending on the chosen method: If the method is “Automatic” then f = a * b; if it’s “Method1” then f = a / b; and if it’s “Method2” then f = a + b. If the user doesn’t choose a method then the default method, “Automatic”, will be applied. We will also include a message in case there are problems. For example, if we mistype the name of the method we will get the message “Something is wrong”.

    BeginPackage ["PackageWithOptions`"]
    (* This is a comment. It doesn't affect the package functionality
     and cannot be seen by the user. Comments can be useful to
     understand the package if we'd like to modify it later on. *)
    (* We associate a message to the function name to be
    displayed when we request help about the function. *)

    listOperation::usage =
      "listOperation [listA, listB, options]. This function
       will multiply,divide or add the elements of
       two lists depending on the chosen method.";

    Options [listOperation]={Method → "Automatic"} ;

    Begin "`Private`"]

    listOperation [listA_List, listB_List, opts_ _ _]:=
      With [{m = Method / . Flatten[{opts}] / . Options[listOperation]},
       Module [{a, b, r}, a = listA;
        b = listB;
        r = a b] /;m = = = "Automatic"];

    listOperation[listA_List, listB_List, opts___]:=
      With[{m =Method /. Flatten[{opts}]/. Options[listOperation]},
       Module[{a, b, r}, a =listA;
        b =listB;
        r =a/b]/; m ==="Method1"];

    listOperation[listA_List, listB_List, opts___]:=
      With[{m =Method /. Flatten[{opts}]/. Options[listOperation]},
       Module[{a, b, r}, a =listA;
        b =listB;
        r =a +b]/; m ==="Method2"];

    listOperation[listA_, listB_, opts___]:="Something is wrong";

    End[]
    EndPackage[]

Now, we proceed to save the package under the name “PackageWithOptions”. This can be done once again by copying the cell into a new notebook, changing the cell style to Code, initializing the cell and finally saving the notebook as a Mathematica package with the “.m” extension. It’s recommended to copy the file in the subdirectory Applications.

  • As mentioned before, if you want the package to be available to all users, copy it to Addons\Applications in:

    FileNameJoin [{$InstallationDirectory, "Addons", "Applications"}]

    C:\Program Files\Wolfram Research\Mathematica\11.0\Addons\Applications

  • If you’d like only the current user to access it, place it in the following Applications subdirectory:

    $UserBaseDirectory

    C:\Users\guill\AppData\Roaming\Mathematica

    Needs["PackageWithOptions`"]

    ? PackageWithOptions`

    listOperation[listA, listB, options]. This function will multiply,

    divide or add the elements of two lists depending on the chosen method.

    listOperation[{1, 2, 3}, {1, 2, 3}, {1, 2, 3}]

    {1, 4, 9}

    {listOperation[{1, 2, 3}, {1, 2, 3}, Method   "Method1"]

    {1, 1, 1}

    {listOperation[{1, 2, 3}, {1, 2, 3}, Method   "Method2"]

    {2, 4, 6}

    listOperation[1, 2]

    Something is wrong

In later chapters we will see other examples of real applications of packages.

3.15.4 Error and Warning Messages

In the previous section we have learned how to display a very simple error message. If we want to create more detailed ones we can proceed as follows: A message has the form Message [symbol::tag], where symbol is the function associated to the message, and tag is a message identifier.

  • Let’s create a message associated with a function fu using generalmsg as the tag (as a precaution we remove any previous reference to fu.)

    Clear [fu]

    fu::generalmsg = "This a message about fu.";

  • We can see the output type that Message uses.

    Message [fu::generalmsg]

    fu: This a message about fu.

  • Let’s define fu so that Message will be generated when fu is called with just one argument.

    fu[_] := Message[fu::generalmsg]

    fu [0]

    fu: This a message about fu.

  • We define fac to calculate the factorial of a number and we limit the argument to positive integers.

    fac [n_Integer? Positive] := n fac[n - 1] ;

    [0]= 1;

  • The following message is generated if we use fac with the wrong argument type.

    fac::wrongargs: =

      "the argument of fac must be a single positive integer."

    fac[___] := Message[fac::wrongargs]

  • Let’s see some examples with incorrect inputs.

    fac [2, 3]

    fac: the argument of fac must be a single positive integer.

    [2.3]

    fac: the argument of fac must be a single positive integer.

  • We can include more complex messages to display specific information related to the type of error. For example, we can include a particular message in the position defined by a double backquote punctuation mark (``) inside a general message.

    fac::error : =
     "A positive integer is expected in fac [``]."

    fac[wrong_?NumericQ] : = Message [fac::error, wrong]

    fac[- 6]

    fac: A positive integer is expected in fac [-6].

    You can find additional information about the use of messages in: Message.

3.15.5 Integrating Package Help Files with Mathematica’s Help System

If you are going to develop an application that includes multiple notebooks, you may find the AuthorTools package useful: AuthorTools/tutorial/MakeProject.

Another alternative way of creating packages would be to use Wolfram’s IDE, Wolfram Workbench (http://www.wolfram.com/products/workbench), which we will cover in Chapter 12.

3.16 Advanced Programming Tools

In addition to Workbench, there’s a complementary set of Mathematica tools that we will cover as well in Chapter 12 such as: WLGM (Wolfram Lightweight Grid Manager) to connect multiple computers and use them in parallel computations and webMathematica, to develop applications that run on a web server and can be accessed from any browser. The latest Mathematica versions also include the possibility of CUDA programming (to take advantage of the GPUs in NVidia graphics cards) and incorporate several CUDA functions optimized for list processing, image processing, and linear algebra and Fourier transforms applications among others.

3.17 Additional Resources

As in most cases, the best available information comes from Mathematica’s own documentation or Wolfram’s website:

Fast Introduction for Programmers, a short introduction to the Wolfram Language for programmers, is available from HelpWolfram DocumentationIntro for programmers ≫, or on the web: (http://www.wolfram.com/language/fast-introduction-for-programmers/)

Stephen Wolfram’s book: An Elementary Introduction to the Wolfram Language covers the basic principles of the Wolfram Language. It’s available directly from within the Wolfram documentation: HelpWolfram DocumentationIntroductory Book ≫ or on the web: http://www.wolfram.com/language/elementary-introduction

Wolfram’s reference page for the Wolfram Language: http://www.wolfram.com/language/

Functions and references:

http://reference.wolfram.com/mathematica/tutorial/FunctionsAndProgramsOverview.html

The following sources contain links to Mathematica programming documents available on the Internet. Even though they were written for previous versions, most of their contents are still relevant.

Ted Ersek's collection of Mathematica Tricks:

http://www.verbeia.com/mathematica/tips/Tricks.html

Roman E. Maeder's Mathematica's Programming Language:

http://library.wolfram.com/infocenter/Conferences/183/

Michael A. Morrison’s Mathematica’s Tips, Tricks and Techniques: Syntax

http://www.nhn.ou.edu/~morrison/Mathematica/TipSheets/Syntax.pdf

Leonid Shifrin's Mathematica programming - an advanced introduction:

http://www.mathprogramming-intro.org

There are many books for learning how to program with Mathematica. One of the best ones is Power Programming with Mathematica: The Kernel by David B. Wagner (available as a free download); though written for Mathematica 3, its ideas are still useful. Another one is The Computer Science with Mathematica by Roman E. Maeder. The bible of programming with Mathematica is probably The Mathematica GuideBooks collection written by Michael Trott (in Mathematica 5.) A great reference for those who aspire to become Mathematica programming gurus.

http://packagedata.net/ is a global repository of Mathematica packages that makes it easy for users to find additional functionality in a wide variety of scientific and technical fields.