Evaluation of Expressions

Classnotes for CPSC 215

C. Jacob — March (20^th) and (22^nd)

Evaluation of Expressions

With this previous knowledge about patterns, we can learn how Mathematica actually works. This will help us to single-mindedly develop our calculations and to understand why Mathematica sometimes returns unexpected results.

We begin with preliminaries about associated definitions and definitions with attributes and then observe the evaluation process of expressions

We will first look at attributes, through which one can control the evaluation process, and then have a detailled look at the evaluation process itself.

Attributes

Functions can have attributes assigned to them in order to determine properties such as associativity, commutativity, or automatic mapping on lists.

A complete list of all possible attributes can be found in the documentation to Attributes.

Example 1: Listable

This function shows us that Sin carries the attribute Listable.

Attributes[Sin]

As a consequence Sin is mapped automatically on the elements of lists.

Sin[{0, Pi/4, Pi/2}]

User-defined functions do not behave this way:

isNotMapped[{0,  Pi/4,  Pi/2}]

Attributes[isNotMapped]

But we can assign the attribute Listable to define a function which is automatically mapped on lists:

SetAttributes[isMapped, Listable]

isMapped[{0,  Pi/4,  Pi/2}]

Attributes[isMapped]

Note: We can set the attributes even without giving a definition for the function.

The automatic mapping also works on nested lists:

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

Example 2: NumericFunction

With the NumericFunction attribute set, Mathematica can determine whether a function generates a numerical value without actually having to perform the evaluation the function:

NumericQ[Sin[E]]

Attributes[Sin]

Example 3: HoldAll

Normally, arguments to functions are evaluated.

h[1 + 2, 4 + 5*6]

% // FullForm

If a function is assigned the attribute HoldAll, however, the arguments are left un-evaluated:

SetAttributes[h, HoldAll]

h[1 + 2, 4 + 5*6]

% // FullForm

ClearAttributes[h, HoldAll]

Mathematica´s Evaluation Process

Outline of the Evaluation Process in a Cell

Mathematica’s evaluation process can be divided into three phases:

1. Reading the cell and transforming it into the internal representation as an expression.

2. Evaluating the expression.

3. Formatting the result for output.

For now, only the second step is of interest to us.

Here all built-in and user-defined transformation rules and definitions are used to rewrite the expression, until nothing more changes.

Mathematica does this in the following order:

2.1 Evaluation of the head.

2.2 Evaluation of each argument, in order (recursion!).

2.3 Re-ordering using the attributes Flat (associative) and Orderless (commutative).

2.4 Mapping to lists (attribute Listable).

2.5.1 Application of user-defined definitions associated to the head of an argument.

2.5.2 Application of built-in definitions associated to the head of an argument.

2.6.1 Application of user-defined definitions associated to the head of the expression.

2.6.2 Application of built-in definitions associated to the head of the expression.

Through pattern recognition, the steps 2.5-2.6 are used to test whether the pattern of a rule or definition matches. If it does, the right-hand side of the definition is substituted and the evaluation restarts for the new expression.

After the evaluation of the head, step 2.2 of this process introduces a recursion, thereby finally evaluating the expression from the inside out. The recursion comes to an end in every branch of the tree (TreeForm) when atoms are reached: numbers, strings, and symbols without definitions evaluate to themselves; for a symbol with definitions, the right-hand side of the definition is evaluated in step 2.7.

This standard evaluation scheme can be changed (see Section 2.5.5 of the Mathematica Book), and several built-in functions must deviate from this in order to function properly. We will, however, not go into this further here.

Evaluation Step-by-Step: Using Trace (1)

Trace lists each step in the evaluation:

k = Plus

Trace[k[g, h[Plus[a, Plus[b, Times[3, 5]]]]]]

% // FullForm

Here is the step-by-step evaluation, with the symbols or expressions marked in 	red being evaluated:

k[g, 
      h[Plus[a, Plus[b, Times[3, 5]]]]]

k[g,h[Plus[a, Plus[b, Times[3, 5]]]]]

k[g,h[Plus[a, Plus[b, Times[3, 5]]]]]

k[g,h[Plus[a, Plus[b, Times[3, 5]]]]]

k[g,h[Plus[a,Plus[b, Times[3, 5]]]]]

k[g,h[Plus[a,Plus[b, Times[3, 5]]]]]

k[g,h[Plus[a,Plus[b,Times[3, 5]]]]]

k[g,h[Plus[a,Plus[b,Times[3, 5]]]]]

k[g,h[Plus[a,Plus[b,Times[3,5]]]]]

k[g,h[Plus[a,Plus[b,Times[3,5]]]]]

k[g,h[Plus[a,Plus[b,Times[3, 5]]]]]

k[g,h[Plus[a,Plus[b, Times[3, 5]]]]]

k[g,h[Plus[a, Plus[b, Times[3, 5]]]]]

k[g,h[Plus[a, Plus[b, Times[3, 5]]]]]

k[g, h[Plus[a, Plus[b, Times[3, 5]]]]]

Evaluation Step-by-Step: Using Trace (2)

Trace lists each step in the evaluation:

testFunction[x_, y_] := Simplify[x^2 - y^2]

someName = testFunction;

tr = Trace[someName[Expand[(a + a + b)^2], a]]

We see how first the head someName evaluates to testFunction. The evaluation of the first argument begins with the evaluation of the argument of Expand, then Expand itself is applied. Next, the definition for testFunction is used and its right-hand side is evaluated.

Here we look at the evaluation step by step:

2.1 Evaluation of the head.

someName[Expand[(a + a + b)^2], a]

tr[[1]]

testFunction[Expand[(a + a + b)^2], a]

2.2 Evaluation of each argument, in order.

2.2.1 First argument:

testFunction[Expand[(a + a + b)^2],a]

tr[[2]]

2.2.2 Second argument:

testFunction[4  (a^2) + 4  a b + (b^2),a]

2.3 Re-ordering using the attributes Flat (associative) and Orderless (commutative).

— not applicable for this example —

testFunction[4  (a^2) + 4  a b + (b^2), a]

2.4 Mapping to lists (attribute Listable).

— not applicable for this example —

testFunction[4  (a^2) + 4  a b + (b^2), a]

2.5.1 Application of user-defined definitions associated to the head of an argument.

— not applicable for this example

testFunction[4  (a^2) + 4  a b + (b^2), a]

2.5.2 Application of built-in definitions associated to the head of an argument.

— not applicable for this example —

2.6.1 Application of user-defined definitions associated to the head of the expression.

tr[[3]]

tr[[4]]

Simplify[(((4 (a^2) + 4 a b + (b^2)))^2) - (a^2)]

2.6.2 Application of built-in definitions associated to the head of the expression.

The evaluation process starts again for the Simplify command:

2.1 Evaluation of the head.

Simplify[(((4 (a^2) + 4 a b + (b^2)))^2) - (a^2)]

2.2 Evaluation of each argument, in order.

— only one argument, nothing to evaluate —

2.3 Re-ordering using the attributes Flat and Orderless.

tr[[5]]

2.4 Mapping to lists (attribute Listable).

— not applicable for this example —

2.5.1 Application of user-defined definitions associated to the head of an 		         argument.

— not applicable for this example

2.5.2 Application of built-in definitions associated to the head of an 		 	         argument.

— not applicable for this example —

2.6.1 Application of user-defined definitions associated to the head of the 		         expression.

— not applicable for this example —

2.6.2 Application of built-in definitions associated to the head of the 		         expression.

tr[[6]]

Final Result:

tr[[7]]