Introduction to the Wolfram Language

Basic elements of the Wolfram Language (WL)

Basic idea: everything in the WL is an expression:

f[x,y,z,a1,a2]

The basic elements of an expression are its head and its arguments:

%//Head

Level[%%,{1}]

Often, the arguments of an expression are themselves expressions with their own arguments (sub-expressions):

g[x,y,f[z,t],a1,a2]

%//Head

Level[%%,{1}]

Level[%%%,{2}]

As you can see from the examples, the elements of an expression are organized in levels. This is best understood if we use the tree-form representation of an expression:

g[x,y,f[z,t],a1,a2]//TreeForm

Each branch point gives rise to a new level. Level count starts at zero, with zero level corresponding to the whole expression:

Level[g[x,y,f[z,t],a1,a2],{1}]

Level[g[x,y,f[z,t],a1,a2],{2}]

Level[g[x,y,f[z,t],a1,a2],{0}]

Individual expression elements can be also accessed by their part number (again, part count starts at zero):

Part[g[x,y,f[z,t],a1,a2],0]

Part[g[x,y,f[z,t],a1,a2],1]

Part[g[x,y,f[z,t],a1,a2],2]

Part[g[x,y,f[z,t],a1,a2],3]

Part[g[x,y,f[z,t],a1,a2],4]

Part[g[x,y,f[z,t],a1,a2],5]

The third part is an expression with sub-parts:

Part[g[x,y,f[z,t],a1,a2],3,1]

Part[g[x,y,f[z,t],a1,a2],3,2]

Sometimes, due to the formatting by the front-end, the expression structure of the contents displayed by the front end are not apparent:

x^2+y z+1/u

Use FullForm or TreeForm to find the complete structure of any expression :

%//FullForm

%%//TreeForm

Notebooks are also expressions composed by cells (which are themselves expressions):

Notebook[{Cell["Hello World","Section"],Cell["x","Input"],Cell["y","Output"]}]

NotebookPut@%

Summary

Everything in the WL is an expression.

The most important elements of an expression are its head and its arguments.

Elements of an expression are accessed using Level and Part .

Exercises

Exercise 1

Find the expression representation of the elements inside the list:

elements={A,1/(1+1/(1+1/(1+x))),1/8,x==1+y^2,}

How many levels does each expression contain? Hint look up the on-line help of Depth:

?Depth

Answer

We test the expression representation of each of the elements in the list and compute the corresponding depth:

elements[[1]]==Symbol["A"]

Depth[elements[[1]]]

elements[[2]]==Power[Plus[1,Power[Plus[1,Power[Plus[1,x],-1]],-1]],-1]

Depth[elements[[2]]]

elements[[2]]//TreeForm

elements[[3]]==Rational[5,40]

Depth@elements[[3]]

elements[[4]]==Equal[x,1+Power[y,2]]

Depth@elements[[4]]

elements[[4]]//TreeForm

In the last case we can find the expression representation using either InputForm or TreeForm:

elements[[5]]//InputForm

elements[[5]]==Graphics[{{RGBColor[1,0,0],Disk[{0,0}]},{RGBColor[0,0,1],Rectangle[{1/2,1/2},{1/2,1/2}]}},ImageSize->{76.,Automatic}]

Depth@elements[[5]]

elements[[5]]//TreeForm

Exercise II

What is the expression representation of the arguments of a given expression? Hint: look up the  on-line help of Sequence.

?Sequence

Answer

Any expression can be re-written in the following fashion:

f[a,b,c,d,f,g]==f[a,Sequence[b,c,d],f,g]

The expression Sequence[b,c,d] is the expression representation of the arguments b,c,d.

Exercise III

Consider the following expression:

G[p,q][x,y,z]

How can you access the element q ?:

Answer

Lets look at the tree form:

G[p,q][x,y,z]//TreeForm

The element q is in the head of the expression which is always part 0. Therefore:

Part[G[p,q][x,y,z],0,2]

Evaluation principles of the Wolfram Language

Basic ideas:

Expressions are evaluated using definitions until they no longer change.

There are two types of definitions: user-made definitions and built-in definitions.

Exit

Expression evaluated according to its built-in definition:

Sin[4Pi]

Expression evaluated according to its user-made definition:

f[x_]:=x^2

f[5]

f[x+y]

We can add more definitions:

f[x_,y_]:=x^2+y^2

f[4,5]

f[x,y+z]

IMPORTANT IDEA: user made definitions are always stored in one of the symbols which are part of an expression. The list of user-made definitions of a symbol can be consulted at any time using Information:

?f

The WL can classify the definitions that the user makes and sort them, using first the definitions which are more restrictive:

f[x_,x_]:=Log[x]

?f

Definitions towards the top of the list are always tried first:

f[x,x]

f[x,2y]

We can remove definitions from the list at any time. Use Unset for that:

f[x_]=.

?f

Summary

There is a list of definitions for each symbol in the WL.

During evaluation definitions from the list of definitions are applied, from top to bottom.

Exercises

Exercise 1

Can you tell the difference between Clear and Remove in the following piece of code ?

Clear[f]

?f

Remove[f]

?f

Answer

Clear deletes all the definitions attached to a particular symbol:

{x[3]=a,x[4]=b,x[5]=c};

?x

Clear@x

However, the symbol x still exists in our session:

?x

Use Remove to delete the symbol x from the session altogether:

Remove[x]

?x

Use Unset to delete particular definitions. Example:

{x[3]=a,x[4]=b,x[5]=c};

?x

Delete one of the definitions:

x[4]=.

?x

Delete all definitions

Clear[x]

?x

Remove the symbol x altoghether:

Remove[x]

Performing definitions in the Wolfram Language

There are different types of definitions in the WL

In the WL definitions are always attached to a symbol. The most frequent ones are:

Ownvalues

Downvalues

Upvalues

A symbol is an expression with head Symbol:

RT

%//Head

Full form:

Symbol["RT"]

These are not symbols:

53+2.5 I

%//Head

%%//FullForm

5.4

%//Head

Ownvalues:

x=4;

OwnValues@x

Downvalues;

g[4]=10;

DownValues@g

Upvalues;

H[y]^=10;
UpValues[y]

We remember the previous example. The definitions were downvalues:

f[x_]:=x^2

f[x_,y_]:=x^2+y^2

f[x_,x_]:=Log[x]

DownValues@f

Ownvalues and downvalues are defined with Set or SetDelayed . Upvalues are defined with UpSet or UpSetDelayed .

Hold[g[4]=10]//FullForm

Hold[H[y]^=10]//FullForm

Let an expression be given:

G[a,b,c,a1,a2,a3]

Ownvalues are definitions made for the symbol used in the head of an expression:

G=H

G[a,b,c,a1,a2,a3]

Ownvalues are attached to the symbol representing the head of an expression:

OwnValues@G

Downvalues are definitions made for the the head and the arguments of an expression:

P[a,b,1,F]=Sin[a b F];

P[a,b,F]=Sin[a b F];

As for any definition, they are attached to a symbol which in this case is also the head of the expression:

DownValues@P

Upvalues are definitions also made for the head and the arguments of an expression:

Z[a,b,F]^=Sin[a b F];

However, upvalues are attached to the symbols which appear as the arguments of the expression:

UpValues@F

UpValues@a

UpValues@F

If we want to attach the definition to a specific argument then we need to specify it at definition time. The syntax is then slightly different:

B/:Volume[A,B,H]=A B H;

UpValues@B

In this case, instead of using  UpSet what is used is  TagSet or  TagSetDelayed

Hold[B/:Volume[A,B,H]=A B H]//FullForm

Remember that definitions must be always attached to a suitable symbol. If we try to make a definition and there is no suitable symbol to attach the definition to, then the definition will not be carried out:

45=z

1=z

"This definition cannot be done"=z

d_=3

Summary

For any expression f[x,y,a1,a2]the following definitions can be made:

Ownvalues: the definition is made for the HEAD of the expression and it is attached to the HEAD of the expression.

Downvalues: the definition is made for  THE HEAD AND THE ARGUMENTS of the expression and it is attached to the HEAD of the expression.

Upvalues: the definition is made for  THE HEAD AND THE ARGUMENTS of the expression is attached to ONE OR ALL THE ARGUMENTS of the expression.

Exercises

Exercise 1

Select the expressions corresponding to symbols in the following list:

{3/4,5.432333,Pi,E,aWZ,Sin[x^2+y^2],"Hello world",A111,1/z}

Answer

These are the symbols:

Cases[%,_Symbol]

Explicit check

{Symbol["Pi"],Symbol["E"],Symbol["aWZ"],Symbol["A111"]}==%

Exercise 2

For the symbols found in the previous exercise define ownvalues, downvalues and upvalues:

Answer

Downvalues:

{aWZ[Pi]=3.5,A111[E]=E+Pi}

DownValues/@{aWZ,A111}

Ownvalues: note that in this case the symbol is protected:

Unprotect@E;
E=aWZ;
Protect@E;

OwnValues@E

Upvalues:

A111/:aWZ+A111+Pi=1/5

UpValues@A111

z+aWZ+A111+Pi

Pattern matching in the Wolfram Language

Patterns are one of the strongest capabilities of the WL

They can be regarded as a variable representing an expression. They enable the recognition of  expressions.

They are widely used to make definitions and construct rules.

They are very useful when dealing with tensor manipulations.

Exit

This is a pattern:

x_

The pattern matches (recognizes) any expression. Use MatchQ to test it:

MatchQ[f,x_]

MatchQ[H[a,b,c,a1,a2,a3],x_]

MatchQ[a+b^2+c^2+d^111,x_]

Internal representation:

x_//FullForm

The first argument of the pattern is the pattern name (the variable name) and the second argument (pattern object) is the type of expression which the pattern is able to match. In this case Blank[] means that the pattern is able to match any expression. We can construct different types of patterns to recognize different kinds of expression. Example:

Sin[x_]

This will recognize the sine of any expression:

MatchQ[Sin[1/(5x^2+1)],Sin[x_]]

This will recognize any expression with 5 arguments. The head and each of the five arguments can be anything:

T_[x_,y_,z_,u_,v_]

MatchQ[B[a,b,c,(1+x)^n,1/50],T_[x_,y_,z_,u_,v_]]

MatchQ[x1+x2+x3+x4+x5,T_[x_,y_,z_,u_,v_]]

Recognition fails when the expression does not have 5 arguments:

MatchQ[B[b,c,(1+x)^n,1/50],T_[x_,y_,z_,u_,v_]]

MatchQ[x1+x2+x3+x4+x5+x6,T_[x_,y_,z_,u_,v_]]

Use of patterns to make a definition:

T[x_,y_,z_,u_,v_]:=x y z/(u v)

DownValues@T

When the patterns match any of the expressions which enter in the definition, the definition is applied:

T[A,B,R,S,Y^2]

Most common patterns

We present next the most common patterns

Matching of any expression:

Blank[]

MatchQ[AnyExpression[f1,f2,f3],Blank[]]

MatchQ[5.33,Blank[]]

Sequence of arguments of an expression:

exp[BlankSequence[]]

MatchQ[exp[f1,f2],exp[BlankSequence[]]]

MatchQ[exp[],exp[BlankSequence[]]]

Sequence of arguments of an expression including the case with no arguments:

exp[BlankNullSequence[]]

MatchQ[exp[f1,f2],exp[BlankNullSequence[]]]

MatchQ[exp[],exp[BlankNullSequence[]]]

Expression with given head:

Blank[GP]

MatchQ[GP[a1,a2,a3,a4],Blank[GP]]

Sequence of expressions with given head:

{BlankSequence[GP]}

MatchQ[{GP[a1,a2,a3,a4],GP[b1,b2,b3,b4]},{BlankSequence[GP]}]

The sequence is the argument of  List:

MatchQ[List[GP[a1,a2,a3,a4],GP[b1,b2,b3,b4]],List[BlankSequence[GP]]]

MatchQ[{GP[a1,a2,a3,a4],HP[b1,b2,b3,b4]},{BlankSequence[GP]}]

Matching of specific expressions: suppose  we wish to match 1/(1+x^2):

MatchQ[1/(1+x^2),Pattern[a,1/(1+x^2)]]

The pattern does not match any other expression:

MatchQ[1/(1+x^3),Pattern[a,1/(1+x^2)]]

Note that in addition to the pattern object we had to use a pattern name. Alternative syntax:

a:1/(1+x^2)

MatchQ[1/(1+x^2),a:1/(1+x^2)]

The pattern name is irrelevant (but it must be a symbol):

MatchQ[1/(1+x^2),aaabbww:1/(1+x^2)]

In addition to definitions, patterns are also used to define rules:

rule1=f[x_]:>x^2

f[5]/.rule1

f[Sin[q]/q]/.rule1

rule2=a_H:>a^2+a+1

H[5,5,5]/.rule2

rule3=K1[x___]:>Plus@x

K1[x1,x2,x3,x4,x5,x6]/.rule3

K1[]/.rule3

Exit[]

Summary

Patterns can be regarded as variables representing expressions.

The main use of patterns is in definitions but they can be also used in rules.

There are different kind of patterns which recognize different kinds of expressions.

Exercises

Exercise 1

Construct patterns that match all the expressions of the given lists. Try to find patterns as specific as possible.

list1={Sin[x^2],Sin[x^3]}

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

Answer

There are different possibilities:

MatchQ[#,a:(Sin[x^(2)]|Sin[x^(3)])]&/@list1

MatchQ[#,Sin[x^(a:(2|3))]]&/@list1

The second list contains expressions with 2 summands, 3 summands, 4 summands and 5 summands. We have 2 possibilities:

MatchQ[#,Alternatives[a_+b_,a_+b_+c_,a_+b_+c_+d_,a_+b_+c_+d_+f_]]&/@list2

MatchQ[#,HoldPattern@Plus@Repeated[Blank[],{2,5}]]&/@list2

Assigning values in the Wolfram Language

Values can be assigned in two ways

Assign without evaluation (delayed assignment). This is what it is done in most rules and definitions.

Assign with evaluation (non-delayed assignment).

Delayed assignments

Exit

We give a value to the variable x:

x=5

This is a delayed assignment:

f[x_]:=x^2

The actual value of  the variable x does not play any role on the assignment:

{f[5],f[Sin[y]],f[1/a]}

We change the value of the variable x to illustrate this point:

x=189

{f[5],f[Sin[y]],f[1/a]}

x=1+y+y^3+Log[y]

{f[5],f[Sin[y]],f[1/a]}

The delayed assignment is a downvalue attached to f :

DownValues@f

Rules with the same properties can be defined in a similar fashion. These are called “delayed rules”. The actual value of the variables in the right hand side of the rule does not have any effect in the rule definition:

y=45+z;

rule1=T[x_,y_,z_,t_]:>A[x,y,z,t]^2

T[Sin[z],z,15,10]/.rule1

y=z+1/(z-1);

T[Sin[z],z,15,10]/.rule1

Non delayed assignments

Exit

We give a value to the variable x:

x=5

This is a non-delayed assignment:

f[x_]=x^2

In this case, the assignment depends on the value of the variable x:

{f[5],f[Sin[y]],f[1/a]}

However, it is still true that changing the value of the variable x does not alter the assignment:

x=189

{f[5],f[Sin[y]],f[1/a]}

x=1+y+y^3+Log[y]

{f[5],f[Sin[y]],f[1/a]}

The assignment is again a downvalue attached to f :

DownValues@f

Summary

In a delayed assignment the value being assigned is not evaluated. Very useful to construct general rules and definitions without worrying about values already given to variables.

In a non-delayed assignment the value being assigned is evaluated.

Exercises

Exit

Exercise 1

Write a function which computes the factorial for any natural number.

Answer

Use a recursive definition:

Fact[n_]:=n Fact[n-1];
Fact[1]=1;

Fact[100]

If we use a non-delayed assignment then we might run into trouble if the variable n had already a value:

Fact[n_]=.

n=1000;

Fact[n_]=n Fact[n-1];
Fact[1]=1;

Fact[10]

n=8;

Fact[10]

This problem doesn’t happen with the delayed assignment:

Fact[n_]=.

Fact[n_]:=n Fact[n-1];
Fact[1]=1;

Fact[10]

However, for bigger values of the natural number we might need to raise the value of $RecursionLimit:

Fact[3000]

$RecursionLimit=4000;

Fact[3000]

Working with expressions in the WL

Two ways to work with an expression:

Operate with the complete expression.

Operate with subsets or parts of the expression.

Exit

This is an expression:

Expr={a,b,c,{d,f}}

We need a way to enumerate the parts of an expression. Use the tree-form representation:

%//TreeForm

Each new branch gives rise to a new level (level count starts at zero).

Level[Expr,{0}]

Level[Expr,{1}]

Level[Expr,{2}]

Level[Expr,{3}]

Individual expression elements can be also accessed by their part number (again, part count starts at zero):

{Part[Expr,0],Part[Expr,1],Part[Expr,2],Part[Expr,3],Part[Expr,4],Part[Expr,4,1],Part[Expr,4,2]}

Use Map to act on expressions by level specification:

SomeProcedure/@Expr

Map[SomeProcedure,Expr,{2}]

Use MapAt to act on expressions by part specification:

MapAt[SomeProcedure,Expr,{-1,-1}]

More examples:

Expr=x+y+z+u

Log/@Expr

MapAt[Log,Expr,-1]

MapAt[Log,Expr,{{-1},{1}}]

Summary

Map is used to act on expressions by level specification.

MapAt is used to act on expressions by part specification.

Exercises

Exercise 1

Try to isolate the product x y in the following equation:

(x y)+1+z==0

Answer

We cannot use Solve directly:

Solve[(x y)+1+z==0,x y]

A possible way of doing this is the following: find the position of the factor x y:

Position[(x y)+1+z==0,x y]

Apply Hold to that position:

MapAt[Hold,(x y)+1+z==0,{1,2}]

Now we can use Solve:

Solve[%,Hold[x y]]

First@%//ReleaseHold

Pure functions in the WL

Two ways of introducing a function:

Use a definition as studied before (downvalues, upvalues). The function is attached to a symbol by means of a definition.

Function not attached to any symbol or definition: pure function or Lambda-function

Function given through a definition:

f[x_]:=Sin[x]

The function is attached to a symbol:

DownValues@f

Pure function:

Function[{x},Sin[x]]

The variable x inside the Function construct is just a dummy:

x=3;

Function[{x},Sin[x]][y]

D[Function[{x},Sin[x]][y],y]

Alternative notation for the Function construct:

Sin[#]&

%//FullForm

Sin[#]&[y]

Action over lists:

Power[#,2]&/@{a,b,c,d}

It is possible to work with pure functions of several variables:

Function[{x1,x2,x3},Sin[x1 x2 x3]-1/Pi]

Function[{x1,x2,x3},Sin[x1 x2 x3]-1/Pi][1,1,1]

Alternative notation using slots:

Sin[#1 #2 #3]-1/Pi&

(Sin[#1 #2 #3]-1/Pi&)[1,1,1]

Summary:

The notion of Lambda-function or anonymous function is implemented in the WL through the Function  construct. Within the WL it is called “pure function”.

The WL admits pure functions of one or several variables.

Exercises

Exit

Exercise 1

How would you replace y[x] by some specific function in the following expression:

y'''[x]+2 x+3

Answer

A direct replacement does not work if we have derivatives:

y'''[x]+2 x+3/.y[x]->x^4

y'''[x]+2 x+3/.y[x_]:>x^4

This yields an incorrect result:

y'''[x]+2 x+3/.y_[x_]:>x^4

We need to do the replacement through a pure function:

y'''[x]+2 x+3/.y->Function[{x},x^4]