From Procedural to Functional Programming in Mathematica

By José Luis Gómez-Muñoz
Adviser of the mexican student group MaTECmatica
http://www.matecmatica.blogspot.com/

Lists of Numbers

This command creates a list of the squares of the integers from 1 to 10:

"sumasFuncionalMaTECmatica_1.gif"

"sumasFuncionalMaTECmatica_2.gif"

This command creates a list of 10 random numbers, each number between 0.0 and 1.0. The list is stored in the variable tenNumbers

"sumasFuncionalMaTECmatica_3.gif"

"sumasFuncionalMaTECmatica_4.gif"

The variable tenNumbers contains the ten numbers generated before:

"sumasFuncionalMaTECmatica_5.gif"

"sumasFuncionalMaTECmatica_6.gif"

We can extract the third element in the list with the following syntax:

"sumasFuncionalMaTECmatica_7.gif"

"sumasFuncionalMaTECmatica_8.gif"

A List of a Million Random Numbers

This command creates a list of 1000000 random numbers, each number between 0.0 and 1.0. The list is stored in the variable millionNumbers. Notice the semicolon ; at the end of the command, the semicolon  ; tells Mathematica that I do not want to see the actual list, I just want to generate it and store it in the variable millionNumbers.

"sumasFuncionalMaTECmatica_9.gif"

We can extract the third element in the list with the following syntax:

"sumasFuncionalMaTECmatica_10.gif"

"sumasFuncionalMaTECmatica_11.gif"

We can extract the 12345th element in the list with the following syntax:

"sumasFuncionalMaTECmatica_12.gif"

"sumasFuncionalMaTECmatica_13.gif"

Inefficient Procedural Way to Add All the Numbers in the List "millionNumbers"

Many Mathematica users have learn to program in procedural languages (C, Fortran, Pascal, etc), therefore when they want to accomplish a task (like adding the one million numbers in the list millionNumbers that was created above) they use old-fashined inefficient Mathematica commands like For:

"sumasFuncionalMaTECmatica_14.gif"

"sumasFuncionalMaTECmatica_15.gif"

The Internal Mathematica Representations of Lists and Additions Are Very Similar

Before we can understand a more efficient way to add all the numbers in a large list, we must understand the internal representation (FullForm) of Lists and Additions in Mathematica.
This is the internal Mathematica representation (FullForm) of the list {a,b,c,d}

"sumasFuncionalMaTECmatica_16.gif"

"sumasFuncionalMaTECmatica_17.gif"

On the other hand, this is the internal Mathematica representation (FullForm) of the addition a+b+c+d

"sumasFuncionalMaTECmatica_18.gif"

"sumasFuncionalMaTECmatica_19.gif"

As you can see, the internal representation of {a,b,c,d} and a+b+c+d are almost the same, except for the "Head" List or Plus. We will take advantage of this structural similarity between expressions in order to add in a fast way all the numbers in a list.

Write List[100,20,30] and Plus[100,20,30] as Mathematica input

Now we will write directly the internal forms of lists and additions of numbers as Mathematica input, and see how Mathematica reacts.
First write List[100,20,30]

"sumasFuncionalMaTECmatica_20.gif"

"sumasFuncionalMaTECmatica_21.gif"

Now write Plus[100,20,30]

"sumasFuncionalMaTECmatica_22.gif"

"sumasFuncionalMaTECmatica_23.gif"

As you can see the diference is that List[100,20,30] is just printed in a formated way, with curly brackets {}, however is the same list. On the other hand Plus[100,20,30] actually performs the calculation. We can say that List[100,20,30] is "stable", it does not "evolve" (it is just printed in a formated way). On the other hand Plus[100,20,30] is "unstable", it does "evolve" to 150.
Now the great, basic idea to add all the numbers in a list is to replace the head List with the head Plus, the generated expression will be "unstable" and it will automatically "evolve" to the result.

Replacing Heads of Expresions with the Command "Apply"

Enter the command Apply, which replaces heads of expressions:

"sumasFuncionalMaTECmatica_24.gif"

"sumasFuncionalMaTECmatica_25.gif"

Here the head "goodbye" is replaced with the head "hello". Both "goodbye" and "hello" are Not Mathematica commands, they do Not have built-in meaning

"sumasFuncionalMaTECmatica_26.gif"

"sumasFuncionalMaTECmatica_27.gif"

Here the head "List" is replaced with the head "hello":

"sumasFuncionalMaTECmatica_28.gif"

"sumasFuncionalMaTECmatica_29.gif"

Exactly the same as the previous example, the head "List" is replaced with the head "hello". We did Not type "List", however Mathematica will transform {100,20,30} into the internal representation List[100,20,30], and after that the "evolution" is exactly the same as the previous example.

"sumasFuncionalMaTECmatica_30.gif"

"sumasFuncionalMaTECmatica_31.gif"

Finally replace the head "List" with the head "Plus", the expression Plus[100,20,30] is generated, but this expression is "unstable" and it "evolves" to the numerical result:

"sumasFuncionalMaTECmatica_32.gif"

"sumasFuncionalMaTECmatica_33.gif"

We can store the list in a variable, and then use the variable in the command Apply

"sumasFuncionalMaTECmatica_34.gif"

"sumasFuncionalMaTECmatica_35.gif"

This is exactly the same as the previous example, with the command "Apply" writen in the infix format @@

"sumasFuncionalMaTECmatica_36.gif"

"sumasFuncionalMaTECmatica_37.gif"

Finally a better (not the best yet!) way to add all the numbers in a list

At the begining of this document a large list of random numbers was generated and stored in the variable millionNumbers.
This is the 3rd number of that large list:

"sumasFuncionalMaTECmatica_38.gif"

"sumasFuncionalMaTECmatica_39.gif"

And this is a the addition of all the numbers: just replace the head List with the head Plus, and the generated expression will evolve to the result

"sumasFuncionalMaTECmatica_40.gif"

"sumasFuncionalMaTECmatica_41.gif"

Exactly the same using the infix notation @@

"sumasFuncionalMaTECmatica_42.gif"

"sumasFuncionalMaTECmatica_43.gif"

Compare the slow procedural way and the faster (not the fastest yet!) functional way to add all the numbers in a list

We have a list of numbers called millionNumbers that was generated at the begining of this document, and we will compare the two ways of adding the numbers that have being described in this document. We will use the Mathematica command Timing, which reports CPU time used by the Mathematica Kernel.
First the CPU time used by the procedural way:

"sumasFuncionalMaTECmatica_44.gif"

"sumasFuncionalMaTECmatica_45.gif"

Now the CPU used by the functional way:

"sumasFuncionalMaTECmatica_46.gif"

"sumasFuncionalMaTECmatica_47.gif"

Which is of course very similar if we use the infix notation for "Apply", the @@

"sumasFuncionalMaTECmatica_48.gif"

"sumasFuncionalMaTECmatica_49.gif"

As you can see, the functional approach is more than ten times faster. The reason is that Mathematica does Not have to use CPU time to increment, compare and store the variables j and result that were used in the procedural approach, neither it has to access the list elements one-by-one.
However, functional programming is Not the best way to add all the numbers in a list in Mathematica. There is more.

The best (fastest) way to add all the numbers in a list: The specialized command Total[]

The variable millionNumbers contains a list of 1000000 random numbers that were generated at the begining of this document.
The fastest way to add all the numbers is to use the specialized command Total:

"sumasFuncionalMaTECmatica_50.gif"

"sumasFuncionalMaTECmatica_51.gif"

As you can see, Total is so fast to add all the 1000000 numbers in the list, that the CPU time it takes could not be measured.
Total was designed to be efficient when adding numbers. It is specialized. On the other hand, Plus is general-purpose, it can add numbers, algebraic expressions, Matrices, undefined objects (you can even "add" two graphics. The result is not very interesting, but Plus is so general that it can accept that input). Thas is the reason for Plus being slower than Total.

What can we learn from this document?

Many times procedural programming is the slowest way to implement a calculation in Mathematica.
Functional programming is usually faster, and the functional programs are usually really small.
Specific-purpose commands, like Total, can be many orders of magnitude faster than both procedural and functional programming.

What is next?

Apply is just the simplest of a series of Functional Programming Mathematica commands (Apply, Map, MapThread, Nest, FixedPoint, etc).
Many of this commands have a small InputForm, like the @@ for Apply.
Here are some examples:

Function composition @

"sumasFuncionalMaTECmatica_52.gif"

"sumasFuncionalMaTECmatica_53.gif"

Apply @@

"sumasFuncionalMaTECmatica_54.gif"

"sumasFuncionalMaTECmatica_55.gif"

Apply at level 1 @@@

"sumasFuncionalMaTECmatica_56.gif"

"sumasFuncionalMaTECmatica_57.gif"

Map /@ (compare @@@ with /@)

"sumasFuncionalMaTECmatica_58.gif"

"sumasFuncionalMaTECmatica_59.gif"

ReplaceAll /.

"sumasFuncionalMaTECmatica_60.gif"

"sumasFuncionalMaTECmatica_61.gif"

Map a pure Function (#,&)

"sumasFuncionalMaTECmatica_62.gif"

"sumasFuncionalMaTECmatica_63.gif"


Created by Wolfram Mathematica 6.0  (14 February 2008) Valid XHTML 1.1!