Upload
others
View
4
Download
0
Embed Size (px)
Citation preview
CITS2401 Computer Analysis & Visualisation
SCHOOL OF COMPUTER SCIENCE AND SOFTWARE ENGINEERING
FACULTY OF ENGINEERING, COMPUTING AND MATHEMATICS
Topic 11 Programming in
Mathematica
Based on material by Paul Abbott
The University of Western Australia
Mathematica ◊ Mathematica has a rich and powerful programming
environment.
◊ This environment includes three different paradigms:
• Procedural programming
• Rule based programming
• Functional programming
◊ Each of these paradigms could have an entire unit based on it. However, it is important that you are able to recognize the different paradigms and understand code that uses them.
The University of Western Australia
Expressions
◊ Everything in Mathematica is an Expression, and every expression has a head and a sequence of arguments.
◊ Examples are:
• List[1,2,3,4,5]
• Rational[3,5]
• Derivative[1][f][Times[Rational[1,2],x]]
◊ In order to stop the recursion going on forever, there are atoms: Number, Symbol and String.
◊ Numbers are further divided into: Integer, Rational, Real and Complex
The University of Western Australia
Programs as expressions
◊ A program should take an input and transform it to produce an output.
◊ The simplest programs can be thought of as a function. Eg: F[x_] = x+1
◊ The x_ is referred to as a blank which will match any variable that is passed to F.
◊ Note this is different to using a function (eg y = x+1). F is now a variable itself, which can be passed to other functions. This has a similar affect to the inline or @(x) notation of Matlab.
◊ To see the value of F, use ?F
The University of Western Australia
Functions
◊ When we define a function F[x_]=x+1, Mathematica will first attempt to solve the RHS, and then assign the value to F.
◊ Typically, we want to wait until we know the value of x, so we use delayed assignment which waits until x is given:
• F[x_] := x+1
◊ Both types of assignment are required:
• randImmediate=RandomReal[]
• randDelayed:=RandomReal[]
• Table[randDelayed,{3}]
• Table[randDelayed,{3}]
The University of Western Australia
Programming with functions:
◊ Most programs are more complex than one line functions. There are a number of ways to deal with this complexity in Mathematica:
• Procedural expressions. This is similar to the for, while and if constructions that Matlab uses. eg: If[x>0, x, -x, x]
• List comprehensions. This is similar to the logical arrays used by Matlab and is uses predicates : Range[n]/.(x_/;x<0)->-x
• Rule-based programming: abs[x_/;x<0] = -x, abs[x_/;x>=0]=x.
• Functional programming works by composing functions together to produce the desired result: F = # Sign[#]&
The University of Western Australia
Procedural Programs
◊ Procedural programs can be written much the same way they would be written at the Matlab command line.
• They are built from simple functions are well as the following control statements:
• If[test,bodyT, bodyF, body?]
• While[test, body]
• Do[body, range]
• For[start,test, incr, body]
• Switch[expression, form1, body1,….,formn,bodyn]
• and several others
The University of Western Australia
Example: ◊ Suppose that we wanted to calculate ab, where b is a non-
negative integer.
◊ Pow[a_,b_]:=
If[!IntegerQ[b] || Negative[b], (*if true*) Pow::argb = "`1` is not non-negative integer";
Message[Pow::argb, b], (*if false*) c = 0; ret = 1;
Do[ ret = a ret, {b}]; ret ]
The University of Western Australia
Conditionals and Composition ◊ The normal conditionals are If and Switch.
• If[x<0, “X<0”, “X>=0”,”I don’t know”]
• Switch[grade, 0,”P”,1,”P”,2,”HD”]
◊ Note that each of these statements is still an expression. The expression evaluates as the body text corresponding to the given option.
◊ A ; is a composition operation. It means do one line first, then the other.
◊ x=2; x = x x ◊ The result of the expression is the result of the last statement
that is executed.
The University of Western Australia
Looping constructs
◊ Do[body, {x}] means execute the body code x times
◊ Do[body, {x, l, u}] means execute the body code with the variable x ranging from l to u
◊ For[init,test,incr, body] runs the init code, and while the test is true, it keeps performing the body code, and then running the incr code. eg For[i=1,i<n,i++, body]
◊ While[test, body] repeatedly runs the code body until test returns false.
◊ There are various other advanced looping constructs, such as Fold, NestWhile, Nest, Apply.
The University of Western Australia
Errors ◊ Mathematica can be quite forgiving. Typically if it receives an
unknown input it will just not reduce the expression:
• Pow(“cat”, 3) returns cat3
◊ Other times the result may be incorrect, or loop infinitely if the wrong value is used.
◊ In this case, we would want to send a message to the user:
• Fun::type = ”Message param `1`” creates a message template
◊ We can display the message by calling:
• Message[Fun::type, value]
• > Message param value
The University of Western Australia
Modules.
◊ As in Matlab, each kernal has a common namespace for all symbols and variables. This can easily lead to errors, where a symbol x may already have a value.
◊ To create a separate namespace we can use a Module:
• Module[{local variables}, body]
◊ This is similar to a function in Matlab. The local variables are given new names for the body code to evaluate:
• Module[{x,y}, x+y]
• > x$9041 + y$9041
The University of Western Australia
Putting it all together:
◊ Pow[a_,b_]:= Module[{c,ret}, If[IntegerQ[b] && !Negative[b], c=0;ret=1; Do[ ret=a ret,{c,1,b}]; ret, Pow::argb = "`1` is not a non-negative integer”; Message[Pow::argb,b]; ]]
The University of Western Australia
Rule-based Programming
◊ Mathematica is a symbolic computing engine, so it has sophisticated “rule-checking” algorithms.
◊ We can use rules to define functions:
• PowR[a_, b_] = a PowR[a, b-1]
• PowR[a_,0] = 1
◊ This function evaluates recursively. To see how it works we can use Trace[PowR[4,4]]
◊ There is a recursion limit to stop infinite loops. You can increase this if necessary:
• $RecursionLimit = 10,000
The University of Western Australia
Checks and Predicates ◊ There is still the possibility that someone might use a negative
exponent, which would lead to an infinite loop.
◊ We can use rules to check the Head of a parameter:
• PowR[a_, b_Integer]
(Try Head[exp] to find the head of expressions, or TreeForm).
◊ and we can also apply predicates to check properties of the arguments:
• PowR[a_, b_Integer?Positive]
• PowR[a_,b_Integer/;b>0]
◊ Beware that new rule definitions don’t overwrite old rule definitions. Use Clear[PowR] to remove prior definitions.
The University of Western Australia
Applying Rules ◊ The rules
• PowR[a_, 0] = 1
• PowR[a_, b_Integer/;b>=0] = a PowR[a, b-1]
can conflict with one another. Use ?PowR to see the rules that define PowR and the order that they will be applied.
◊ Rule based programming is a very powerful symbolic technique:
• log[a_ b_] = log[a] + log[b]
• log[a_^n_] = n log[a]
These definitions work naturally with Expressions so they define log[a b c], log[a/b] etc
The University of Western Australia
Functional Programming ◊ Functional programming treats everything as a function .
◊ The Mathematica environment is closely based on the LISP (list programming) environment that dates back to 1958
• (+ 1 2 3 4) in LISP is like Plus[1,2,3,4] in Mathematica
◊ Mathematica allows us to define new functions from existing functions:
• PowF = Apply[Times,Table[#1,{#2}]]&
◊ This function uses Table to define a list containing b copies of a, and then applies the Times function to this list.
◊ PowF(2,3) gives 8, although we still need to do the usual checks for positive integers.
The University of Western Australia
Functional Programming
◊ We can include checks using patterns as before:
PowF[a_,b_Integer/;b>=0]:= Times@@Table[a,{b}]
◊ This can be a little difficult to read at first, but is often the most efficient way of performing computations.
◊ There are a number of list functions like FoldList, and NestList that can be used very effectively with functional programming.
◊ FoldList[f, a, {b,c,d}] = {a, f[a,b], f[f[a,b],c], f[f[f[a,b],c],d]]
◊ NestList[f,a,3] = {a,f[a],f[f[a]], f[f[f[a]]]}
◊ NestList[Framed,Plot[Sin[x],{x,0,2 Pi}],3]
The University of Western Australia
More on Patterns and Rules
◊ A definition is just a replacement rule that is applied whenever possible.
◊ A replacement/transformation rule is applied to an expression when the expression matches the pattern on the left-hand side of the rule.
◊ Pattern-matching is a simple and elegant way to write programs, often without requiring and functional or procedural methods -although these can also (and should when appropriate) be used. Patterns are best explained via examples.
◊ eg x->2 is the replacement rule stating that x should be replaced by 2.
The University of Western Australia
Rules and Lists
◊ Replacement Rules can be applied to expressions and Lists:
• {x,y,z}/.x->2 will give {2,y,z}
• (x^y+y^x)/. x->2 will give 2^y + y^2
• {x,x,x]/.x->RandomReal[] will give ?
◊ As with SetDelayed (:=) there is also RuleDelayed (:>)
• {x,x,x]/.x:>RandomReal[] gives 3 different values.
◊ We can restrict how a replacement rule is used by using the Head of the expression, or by using predicates:
• {1,a,2/3}/.x_Integer -> 3x gives {3,a,2/3}
• {1,a,2/3}/.(x_/;x<1) -> 3x gives {1,a,2}
The University of Western Australia
Predicates ◊ Predicates are properties of expressions. You can think of
them things which evaluate to True/False.
• Examples are x<3, Positive, EvenQ, Prime, IntegerQ
◊ The syntax /; can be read as where and can be used to guard parameters and replacement rules.
• x/.(x_/;EvenQ[x])->x-1 will replace x by x-1 if it is even.
◊ Using PatternTest (?) instead:
• {1,2,3,4,5}/.x_?PrimeQ:>x^2 gives {1,4,9,4,25}
◊ Both Head and Predicates can be used
• {1,2,a}/.x_Integer?PrimeQ:>x^2 gives {1,4,a}
The University of Western Australia
Blank, BlankSequence and BlankNullSequence
◊ The symbol _ is called a Blank and by itself it is a pattern that matches any expression.
◊ By putting a symbol in front of the Blank we give it a label that can be used later. We can restrict matches by either specifying a Head (x_head) or by using a predicate (x_?TestQ).
◊ There are also a couple of generalisations:
• BlankSequence ( __) match one or more expressions.
• f[{x,y},{},{x},{x,y,z}]/.{a__}:>Plus[a]f
• BlankSequence ( ___) match one or more expressions.
• f[{x,y},{},{x},{x,y,z}]/.{a___}:>Plus[a]f
The University of Western Australia
Example: Number Puzzle ◊ Suppose that we want to find four numbers in a list of
numbers that sum to 100.
◊ list = {24,10,6,16,4,7,11,34,13,26,17,14,29}; ◊ list/.{___,a_,___,b_,___,c_,___,d_,___}:>{a,b,c,d}
• (this will select any four numbers out of the list):
◊ Applying the predicate
• /; a+b+c+d==100
will force Mathematica to go through all choices looking for one which matches the condition.
◊ This is an example of declarative programming. We describe only the result, not how to find it.
The University of Western Australia
Example: ◊ These basics will help you learn to
program with Mathematica, but you will require considerable practice before you become proficient.
◊ You should be getting to the stage where you are able to parse and understand programs, and by reading other peoples programs, you will become more confident at writing your own.