Physics 230 -- Lab 6 (Programming I)

Fall 2015 - Transtrum

Labs developed by John S. Colton, BYU Physics & Astronomy, based in part on past labs by Branton Cambell and Steve Turley

When carrying out a complicated computational task, we often need to evaluate multiple expressions in order to obtain a final result or sequence of results.  In previous labs, we have occasionally evaluated multiple commands on a single line, possibly by combining them by doing functions inside of functions or repeated postfix notation. Sometimes when multiple commands have been needed we have evaluated expression after expression, and referred to the results of previous commands via % or via variable assignments. However, some tasks are so complicated that this approach becomes impractical, and sometimes you might want to “package” together several commands that you use together often, so that you can easily run them together at other times/places. This is the heart of programming.

Computer programming languages include rules and operations that allow us to combine multiple single-step evaluations into a larger multi-step "program" that can perform a potentially very complex task on its own. In this lab, you will be introduced to the building-blocks of programming: Boolean logic, conditional statements, and loops. Though the details will be specific to Mathematica, the concepts are quite general. At the end of the lab, you will see how to use Module to construct a very basic program. This will serve as a springboard for the next programming lab, which will involve many different programming applications.

Clear["`*" ]

Logic

Boolean expressions

A “Boolean expression” is something that is either true or false. We have already run across such expressions in several previous labs in commands such as FindRoot and Solve--basically anything that uses an inequality or a double equals sign is a Boolean expression. Consider the following:

2<3

a = (2==3)   (* variables can be assigned to Boolean values *)

a

Of course such expressions are not too interesting if the results are obvious as they were here. But such expressions form the building blocks of powerful tools such as conditional commands: “test out <this condition>, and do <these commands> if it’s true”.

Boolean expressions can be formed by combining other Boolean expressions; the most important ways to do that are via And (shortcut &&) and Or (shortcut ||). Two Boolean expressions combined with And will evaluate as True only if they both are true. Two Boolean expressions combined with Or will evaluate as True if either one is true. We ran across this previously with the RegionPlot command; the blueish shaded section is where the expression is true.

RegionPlot[ (4 < 2 x^2 + y^2 )  && ( 2 x^2 + y^2 < 9),{x,-4,4},{y,-4,4}]   (* done previously *)

RegionPlot[x > 3 ||   x< 2,{x,-4,4},{y,-4,4}]    (* a new example, look it over *)

Assignment 1. An interesting RegionPlot

Create a RegionPlot that looks like this. The equation for the circular arc is (x^2)+(y^2)=1. The white horizontal stripe is where y is between 0 and 0.5. You will likely need both an && and an || in your RegionPlot.

Logic gates

Because the binary number system (base 2) has only two digits (aka binary digits = “bits”), namely 0 and 1, and the Boolean logic system has only two values, namely true and false, the two are often used interchangeably. We associate 0 -> False and 1 -> True. This type of association is also done in other contexts; for example, in digital electronics 0V and 5V levels are often considered to be equivalent to False and True (or 0 and 1), respectively. 

And and Or are examples of logic gates, a class of functions which could also be called “binary Boolean functions”--binary, because they take two inputs, and Boolean, because they take Boolean arguments and return a Boolean answer. They are not the only binary Boolean functions, although they are the most common. Other similar functions, such as Nand, Nor, and Xor, can be quite useful at times. Such functions are summarized on the guide page on Logic and Boolean Algebra.  If this is new to you, take a few minutes to become familiar with these operations. 

In addition to the binary functions, you should also become familiar with the single-input Boolean function, Not (shortcut: !, written before the variable). It turns True into False and vice versa.

The effect of a logic gate is often visualized via a “truth table”, which indicates the output for all four possible combinations of inputs. Evaluate the cell below to define functions that will generate two equivalent truth tables for a specified operation.  As an example, we apply each one to the And operation (A && B). Notice how the table indicates that the output is true only if both A and B are true.  (Don’t worry about the code used to generate the tables, just look at the output.)

truthtable[op_] :=Flatten[Table[{A,B,op},{A,{False,True}},{B,{False,True}}],1]//TableForm[#,TableHeadings->{None,{"A","B",op}}]&
truthtable2[op_] :=Flatten[Table[{A,B,op},{A,{False,True}},{B,{False,True}}],1]//TableForm[# //Boole,TableHeadings->{None,{"A","B",op}}]& 

truthtable[A&&B]
truthtable2[A&&B]

Because there are four possible configurations of inputs (the four rows to the truth table), and each configuration yields one of two options (true or false), there are 2x2x2x2 possible two-input truth tables. That is, there are 16 unique binary Boolean functions. However, most are not especially useful. The useful ones are the named functions mentioned above:  And, Or, Nand, Nor, and Xor. On the relatively rare occassions you might need one of the other, un-named, functions, you can always construct it using a named function and Not functions operating on the inputs and/or output. And any crazy combination of And, Or, Nand, Nor, and Xor functions must result in one of the 16 types. For example, here is a depiction of  (A and (not B)) or ((not A) and B).  Turns out to be just the same as Xor.

truthtable2[(A&& !B) || (!A  && B) ]

Potentially useful note: Additional shortcut symbols for all of the named logic functions can be obtained by pressing Esc, typing the name, then pressing Esc again.

Assignment 2. Using “Xor”

Use Xor to generate the following RegionPlot. (Note that unless you increase “PlotPoints” from the default, Mathematica will artificially chop off the sharp edges of the boundary.)

Conditional Decisions

Conditional functions choose their output based on a logical test against the input. There are three main conditional functions in Mathematica.  If selects between two possible outputs based on a single Boolean (i.e. True/False) input.  Which tests multiple conditions one at a time, and returns the output corresponding to the first True it finds.  Switch compares an expression against multiple patterns, but only returns the output corresponding to the first pattern that matches the expression.  The Conditionals Tutorial and the Conditionals Guide may prove to be useful references. 

Tip: We haven’t really emphasized the difference between defining functions with = vs with :=. Up until now, either has been acceptable in nearly all of our applications. However, now it matters. Functions using conditional statements nearly always should be defined with :=. That’s because you’ll nearly always be interested in the value of the condition when the function is evaluated, not the value of the condition when the function is defined. Thus delayed assignment with := is the way to go.

"If"

The If command is called with three parameters: the first one is a conditional test, the next two are possible outputs. If the test is true, it returns the first output; if the test is false, it returns the second output. The format is If[testcondition, output1, output2]. It is very useful in defining special functions. If is the simplest of the three main conditional commands, and is the one that I myself use most frequently (by far). 

Here, for example, is a “rectified sine wave”--a sine wave which gets chopped off when it goes negative.

y[x_] := If[Sin[x]>0, Sin[x], 0]
Plot[y[x],{x,0,5 Pi}, PlotRange->{-1,1}]

Assignment 3. Using “If”

(a) Use If to create a function, myabs[x_], that mimics the Abs function.  Plot it over the range from {x, -3, 3}.
(b) Use If to create a function, happyprime[n_], that returns a  when n is a prime number and a  otherwise (you can copy/paste these icons into your function).  Then try it out on the integers from 1 to 10. Hint: read about the PrimeQ function.

"Which"

Although If is a great function it does have limitations. In particular, if you want to choose between more than two alternatives, then you would need to use at least one extra If statement within your original If statement (called “nested if statements”), and possibly more. That can make things hard to write and hard to follow. This limitation is described in the Conditionals Tutorial: “The function If provides a way to choose between two alternatives. Often, however, there will be more than two alternatives. One way to handle this is to use a nested set of If functions. Usually, however, it is instead better to use functions like Which and Switch.”

The Which command is called with as many conditions as you want to give it. The parameters you give the command alternate between conditional tests and outputs to return if the tests are true.  Which tests the conditions one by one, stops when it reaches the first true one, then returns the corresponding output. The format is Which[condition1, result1, condition2, result2, ...]. If none of the conditions are true, then it doesn’t return anything. To prevent that, you might want to use a simple True as the final conditional element to indicate “return this final result if nothing previous has been found to be true”. 

Which can be useful when you are trying to determine where in a range a parameter falls. You just need to take care that the conditionals don’t overlap, or if they do that they are in the order you want, because once Which reaches a true condition it stops testing. Here’s an example:

test[x_] := Which[x<0, "Negative", x==0, "Zero", x>0, "Positive"];
test[-2]
test[0]
test[14]
newtest[x_] := Which[x<0, "Negative", x==0, "Zero", True, "Positive"];  (* does the same thing, but it's OK to have simply "True" for the last test since the number must always be positive if it gets that far *)
newtest[-2]
newtest[0]
newtest[14]

And here’s another example:

comparison[x_,y_] := Which[x==y, "They are equal!", x>y, "First one is bigger.", x<y,"Second one is bigger."]  (* or could use "True" as last test *)
comparison[1,2]
comparison[14,14]
comparison[49,-111]

If you wanted to do that same thing with an If statement, it would need to look like this:

comparisonwithif[x_,y_] := If[x==y, "They are equal!", If[x>y, "First one is bigger.", "Second one is bigger."]]  (* Notice the "nested if" statements *)
comparisonwithif[1,2]
comparisonwithif[14,14]
comparisonwithif[49,-111]

Another good use of Which is to define a piecewise function, that is a function whose definition is different in different domains of its independent variable. Here’s an example:

	

You could do that like this:

f[x_] := Which[x<-Pi/2, Sin[x], -Pi/2 ≤x <Pi/2, Tan[x],True, Cos[x]]    (* instead of "True" as the last test, I could have used "x>Pi/2". Either way is fine. *)
Plot[f[x],{x,-10,10}]

Although If and Which are in my opinion the best/easiest ways to define piecewise functions--I use If if there are two sections of domain and Which if there are more--there is actually a built-in command dedicated to creating piecewise functions. It’s called Piecewise. I’ll let you read more about that on your own if you wish; here’s the previous function defined using the Piecewise command.

f[x_] := Piecewise[{{Sin[x],x<-Pi/2}, {Tan[x],-Pi/2 ≤x <Pi/2},{Cos[x],x>Pi/2}}]
Plot[f[x],{x,-10,10}]

"Switch"

Switch does much the same job as Which, but has a slightly different syntax. I have found it to be most useful when you know the input has to be one of a limited set of values, like an integer between 1 and 10. In that context it can be used exactly like you used Which in the last assignment. The format is Switch[testparameter, comparison1, result1, comparison2, result2, ...]. The first argument is a parameter you want to test (often just “x” itself); the subsequent arguments alternate between possible values of the test parameter and the outputs to return for each case. An underscore _ can be used as the final comparison element to indicate “do this if nothing previous has matched”. 

Here’s Switch used in a function that tests whether a number is 1, 2, or 3.

f123[x_] := Switch[x, 1, "One", 2, "Two", 3, "Three", _, "Not 1, 2, or 3"]
f123[1]
f123[2]
f123[3]
f123[4]

Assignment 4. Using “Which” or “Switch”

Use Which or Switch to create a function that creates a plot of x if the input is equal to 1, a plot of (x^2) if the input equals 2, a plot of (x^3) if the input equals 3, and a plot of (e^(-x)) otherwise. That is, the output of the function should be the plots themselves. (That’s not a problem: functions can output numbers, or text strings, or plots, or any other kind of Mathematica objects you want.) All plots should go from x = -2 to 2. Take care that the function input is not called x, if you’re using x as the variable in the various Plot commands. Test it for inputs of 1, 2, 3, and 4.

Built-in Piecewise Functions

The following is a partial list of built-in piecewise functions. Many of these are functions related to rounding numbers. Many have additional functionality if you give them additional arguments--for example, Round will round to a specified decimal place if you give it a second argument, and Clip can be used to force the number into any desired range, not just between -1 and 1.

Round - rounds up or down to nearest integer
Floor - rounds down to nearest integer
Ceiling - rounds up to nearest integer
IntegerPart - gives the integer part of a number (rounds towards zero)
FractionalPart - gives the fractional (decimal) part of a number
Chop - rounds to zero if close to zero
Clip - rounds down to 1 (if above 1) or up to -1 (if below -1).
Sign - rounds to 1 (if positve) or to -1 (if negative); has very different behavior for complex numbers
Unitize - rounds to 1, unless argument is 0 (in which case remains 0)
UnitStep - rounds up to 0 (if negative) or to 1 (if positive)
Abs - gives the absolute value of a number

Here’s a way to visualize what the functions are doing, which should make it clear why these particular functions qualify as “piecewise”.

funclist = {Round, Floor, Ceiling, IntegerPart, FractionalPart,Chop[#,.2]&, Clip, Sign,Unitize, UnitStep,  Abs }
Plot[#[x], {x, -3,3},{PlotRange->All,ExclusionsStyle->Automatic,PlotLabel->#,PlotStyle->Thick}]&/@funclist

Compound Expressions

You have already seen that a semicolon supresses output and you may also have seen that a series of expressions separated by semicolons can be entered in a single line. Such a series is called a CompoundExpression. If the last item in the expression is not given its own semicolon, then that is the only output that will be displayed. In the context of functions, we say that the last output is “returned” by the function.

M = 2; Q = 3^M; 5*Q

Until now, compound expressions probably didn't seem very important. In the context of programming, however, compound expressions are essential. In fact, any argument that you feed to any Mathematica function can be replaced with a compound expression.  Re-read that last sentence three times for emphasis!

Here’s a trivial example:

Sin[y;z]  (* y is not used for anything *)

Here’s a more interesting example:

Sin[y = 3; z=y^2]

Since the compound expression “y =3; z = y^2” returns the value of 9, that’s what got sent into the sine function.

Evaluate the cells below to see two equivalent definite integrals.

Integrate[x^2,{x,0,1}]

Integrate[base = x; exponent = 2; base^exponent, {x,0,1}]

What to observe: The second case employs compound expressions. Notice that the semicolons do NOT separate function arguments. Only commas can do that. In the second Integrate, the first argument is the output from the string of commands “base = x; exponent = 2; base^exponent”. The second argument is “{x,0,1}”.

Warning: If you, like myself, frequently use the % symbol to refer to the results of the last expression, be warned that it does NOT function as you might expect when you are using compound expressions. That's because the entire compound expression is considered to be a single expression for this purpose, so that % will not point back to the last result inside the compound expression. See this example:

angle = 90 Degree; 
Sin[%]  //N 
(* this works, gives you an answer of 1 *)
newangle = 90 Degree; Sin[%] //N    
(* this does NOT work; gives you sin(1 rad) instead of sin(90 deg). *)

Coming up: Compound expressions are incredibly important in loop structures, which are coming up shortly. They are the only way you can have multiple commands executed in a loop. (If you’re not yet familiar with programming loops, you will be soon.)

Special Assignment Function Shortcuts

Variables have their values modified by assignment functions. The simplest such function is just the equals sign =, which is actually the Set command. Something like “x = 3” sets the value of the variable x to 3. Often, however, we may want to set the value of x to be something based on the current value of x. That type of thing can be done via commands like “x = x + 5”:

x = 3
x = x+5;  (* this means "set x equal to the old value of x, plus 5" *)
x

Since that type of variable modification is such a common need in programming, there are a number of special shortcut commands designed specifically for it. See the tutorial on Special Forms of Assignment. The syntax of these assignments is essentially the same as in the C and Java languages.

As a first example, the command “x = x+ 5” can be written in shortcut notation using the  +=  operator:

x = 3
x += 5;  (* this means "set x equal to the old value of x, plus 5" *)
x

Other common shortcuts are the following (arbitrarily using the number 5 for examples):
	x -= 5, which is like saying “x = x - 5” 
	x *= 5, which is like saying “x = x*5”
	x /= 5, which is like saying “x = x/5”
	++x (increment by 1), which is like saying “x = x + 1”
	--x (decrement by 1), which is like saying “x = x -1”

See if you can follow the output here:

r = 2
r*= 3
r+= 7
r-= 1
r/=4 
++r

Pre vs. post increment. There are actually two separate increment (and decrement) functions. They both increase (or decrease) x by 1, but they differ in which value they return. 

	++x : adds 1 to x, and returns the new value of x. Called PreIncrement
	x++ : adds 1 to x, but returns the old value of x. Called Increment

	--x : subtracts 1 from x, and returns the new value of x. Called PreDecrement
	x-- : subtracts 1 from x, but returns the old value of x. Called Decrement

r=2;
++r  (* sets r to 3, and returns value of 3 *)
r

r=2;
r++  (* sets r to 3, but returns value of 2 *)
r

Loop Structures: Do, While, and For

A computer program is a sequence of commands you want the computer to run. Usually the commands involve conditional branching, such as “do this if condition A is true, otherwise do this other thing”. That’s closely related to the conditional commands you learned above: If, Which, and Switch. And quite frequently the commands involve loops, such as “keep doing this until condition A is met”, or “do this set of commands 100 times in a row”. That’s the topic of this section. Looping combined with conditional branching allows you to write full-fledged programs and will be a major topic of next week’s lab.

Very important side note: local vs. global variables. If you've ever had a programming class, you likely already understand the difference between local and global variables. If not, please read this carefully. It is critical that you understand this or you will be extremely confused for the rest of today's lab. Next week's lab, too. The difference lies in what parts of the program can access the information stored in the variables. Global variables have what is called a "global scope", or universal accessibility: the variables can be used by any part of Mathematica. If you change the variable in one place, anything else that tries to access the variable thereafter will use the modified value. Nearly all of the variable assignments you've done in Mathematica so far are global variables--and sometimes it's a pain! You've probably noticed as you're working on assignments that if you don't define your variables that have different names in the different parts of your notebook, stuff you do for one assignment can interefere with stuff you do for another one. In Mathematica the global nature of variables even spans between notebooks, which frankly seems quite odd to me. Although that type of "variable interference" may have been only a mild pain so far, once you start doing more serious programming tasks, it could easily cause your programs to crash and burn.

Local variables are the way around this. A local variable is just like the # sign in a nameless function definition, such as this:

Sqrt[#^2 + 3 # + 5]&    @  {2 ,3,4}    (* computes the value of sqrt( x^2 + 3x + 5 ), for x = 2, 3, and 4 *)

The symbol # doesn’t have any meaning outside of that statement. It’s “scope” is just one line long. You can’t refer to the “#” variable later on, or anything like that.  Local variables are exactly the same--except you give them names instead of using the # symbol. You can only access them for a limited time, such as inside one command, and then they are gone.

Similarly, when you give a command such as Table in the following example, the “i” doesn’t have any meaning after the command is complete. It is a local variable.

Table[Sin[i x],{i,1,3,.1}]
i  (* has no value *)

If you are not following the distinction between local and global variables, please get a neighbor or a T.A. to help you sort it out before proceeding.

Back to loop structures.  Loops allow you to sequentially run though a list of similar computations.  Examples might include counting to 10, performing a finite sum, performing the same operation on each element of a list, or even iteratively searching for the numerical solution to a nonlinear equation. In the exercises below, we will introduce three loop commands (Do, While and For). Oddly, they produce no direct outputs (unlike most of Mathematica's functions), but they can perform global-variable assignments.

"Do"

Mathematica's Do command is the most basic type of loop. It is quite similar to “for loops” that are ubiquitously used in other programming languages. Do executes a particular command or sequence of commands a certain number of times. The number of times is specified inside the command by an “iterator” variable having the same form as the Table example above:  {variablename, startvalue, stopvalue, stepsize}. The loop terminates when the iterator has traversed its range. The iterator variable itself can be used in commands inside the loop by referring to it by name, as in the following example. The iterator variable is a local variable. It has no meaning outside of the loop.

Do[Print[n],{n,1,5, 0.5}]
n   (* has no value outside the loop *)

You may have noticed that the output of the Print command looks different than a regular output cell. In fact, it’s not regular output. It sends values directly to the display, but you can’t access those values from later Mathematica commands like you can with regular output.

What’s more, the Do command never produces regular output. Neither do While or For. Something like the following will not give you any output, even though it might look like it should output the values of n.

Do[ n,{n,1,5, 0.5}]    (* Notice how n doesn't get displayed as loop progresses without the Print command *)

That’s a serious limitation. However, you can bypass that limitation by using the Do command to change the value of a global variable. (We will later see another way around this, namely to incorporate a loop into a program, aka a Module.) 

This loop continually sets the value of global1 to be equal to the loop iterator variable, n.

Do[ global1 = n ,{n,1,5, 0.5}]  
global1   (* Notice that it now has a value of 5, because that was the last value it was set to, inside the Do loop. *)

Here’s another example, where I insert the values of n repeatedly into a list named global2. Notice how n is a local variable, but global2 is a global variable.

global2 = {}; (* sets it initially equal to an empty list, so that we can Append to it. *)
Do[global2 = Append[global2, n], {n,1,5,.5}]    (* this is the loop *)
global2  (* If this line weren't here, we'd never see the final version of the list *)

Assignment 5. Using “Do”

(a) Use Do and  +=  to compute the sum of the integers from 1 to 100 and store the answer in a global variable named result. Display the answer after the loop is complete. Hint: initialize result to 0 (i.e. “result = 0;”) before starting the Do loop.

(b) Use Do to start with decimal number latest = 1.0, and recursively compute 100 cosines, taking the cosine of the most recent result each time.  Show the final value.

(c) In this example, I use a Do loop to accumulate a list of the integer sums of the form (Underoverscript[∑ , (n =1), p])n  for p values running from 1 to 10.  Evaluate the example and figure out how it works.  Then modify it to accumulate a list of the squared-integer sums of the form  (Underoverscript[∑ , (n =1), p])(n^2). Tip: I recommend you copy this code to a different cell before you start modifying it.

resultlist = {}; result=0;
Do[ result+=p;resultlist = Append[resultlist,result], {p,1,10}]
resultlist

"While"

Mathematica's While loop is much like while loops in other programming languages.  It has no iterator by default (although you can define one using a global variable). Instead, the loop executes an unknown number of times, and terminates when some condition stops being met. You can read it like this: “As long as [this condition] is met, do the stuff in the loop”. This means you must be careful about getting into an infinite loop--a loop that keeps going and going for ever, never terminating because the test condition never goes False. If you suspect you’ve gotten into an infinite loop, Evaluation -> Abort Evaluation will be your friend (shortcut: Alt-period). The loop condition is given as the first argument of While; if the condition is not met immediately, it does not even execute the loop a single time.

n = 1;   (* this is a global variable *)
While[n !=1 ,  Print[ n^2]; n++ ]  (* This never does anything because the condition is not true right off the bat*)
n   (* still 1 *)
While[n < 10 , Print[ n^2]; n++ ]  (* Each time through the loop this executes two commands: display n^2,  then increment n *)
n   (* ends up as 10, because the last time through the loop n was 9 and there was a final n++ *)

Evaluate the example below, where a While loop is used to find the largest Prime number less than (10^6).  I’m uisng the global variable m as an iterator.

m = 1;
While[Prime[m]<10^6,m++]
Prime[m-1]   (* it's "m-1" because m got incremented at the end of the last time through the loop *)

Assignment 6. Using “While”

Use While to create a list of the powers of 2 (i.e. (2^n)) that are less than (10^6).  Hints: First define resultlist = { } and n=0  for future use.  Then, do a While loop. Inside the loop, test to see if (2^n)<(10^6) and if so use Append or AppendTo to add (2^n) to resultlist; then increment n.

Side note: AppendTo is a shortcut for using Append to add to a list. The following two commands are exactly equivalent:
	resultlist = Append[resultlist,result]      (used above)
	AppendTo[resultlist,result]

Assignment 7. Solving Cos[x]=x

Start with decimal number latest = 1.0, and use While to recursively compute cosines until the magnitude of the change between recursions is less than (10^(-6)).  In other words, keep evaluating  latest = Cos[latest] as long as Abs[Cos[latest]-latest]  > 10^-7.  Use a second global variable to count the number of iterations the loop goes through before the (10^(-6)) tolerance is reached. Display the answer along with the number of iterations.  In case it’s not obvious, when cos(x) - x = 0 to the desired tolerance, you’ve found the answer to the transcendental equation x = cos(x), doing the same sort of thing that the FindRoot command does internally. Congratulations! You can use FindRoot to check your answer if you’d like.

"For"

Personally I don’t find much use for Mathematica’s For command, but you can glance over the examples in the help file if you want to try it out. It’s a combination of Do and While: there is a built-in iterator variable like Do; however it is a global variable rather than a local variable. There is a mechanism for automatically changing the iterator that’s a little more advanced than Do, and the loop exits when a condition fails to be met, like While. Most--if not all--tasks that you can accomplish with For, you can also accomplish with either Do or While loops. My own preference, is if I know there’s a pre-determined number of times I want the loop to execute, I’ll use Do. If I want the loop to execute until a condition is met, I’ll use While. So For is the odd man out. But which loop type you choose is often a matter of personal preference, and you might feel differently than I do.

Recursive Function Evaluation

“Nest”-type functions

If all you want your loop to do is recursively evaluate a function (i.e. feed the result of the previous calculation back in as the new argument of the function, over and over again), then these four commands are useful:  Nest, NestList, NestWhile,and NestWhileList. The guide page on Functional Iteration is a useful quick reference for this type of thing.

As an example, if you wanted to apply the cosine function repeatedly to the number 3.3 for some reason, these two commands are equivalent:

Cos[Cos[Cos[Cos[3.3]]]] //N
Nest[Cos,3.3,4]    (* notice how you only specify the function name, i.e. Cos rather than Cos[x] *)

NestList takes it a step farther, by compiling a list of all of the intermediate results.

NestList[Cos,3.3,4]  (* the last element of list is the answer *)

Just as While has a condition to break out of a loop, NestWhile and NestWhileList also allow you to specify a “break out of loop” condition rather than looping for a predetermined number of iterations. However, the condition is given as the last parameter rather than the first parameter as with While. Here’s an example of using NestWhileList to solve the “Cos(x) = x” problem you solved in the assignment above, keeping all of the intermediate terms for you to peruse. If you are still uncomfortable with nameless functions, it’s time to get comfortable now.  Seriously.  Don’t go on until you understand them.

NestWhileList[Cos[#] &, 1, Abs[Cos[#] - #] > 10^-6 &] //N        (* The loop continues as long as condition is met; the last element of list is the answer. *)
Length[%]-1  (* it took this many iterations after our starting point *)

Assignment 8. Using “NestList”

Use NestList to create a function which accumulates a list of the next 5 prime numbers after a user-specified number (not including the number, even if it is prime). Hint: NextPrime should be quite helpful.

Writing Programs With Module

Introduction to Module

The Mathematica  Module command is the main vehicle we will employ for writing programs that do calculations with local variables. Module has the form of a command or a function, like everything in Mathematica, but you can really think of a Module as being its own independent program. Among other things, Module allows you to create your own functions in a much more powerful fashion than you have done so far using regular function definition such as  f[x_] := Sin[x] Cos[x]. 

Variables defined inside a Module are local: they can be used throughout the Module, have no value outside the Module. They do not affect the values of any global variables--although global variables can also be used inside Modules if you want. 

The format for using the Module command is this:

	Module[ {localvariable1, localvariable2, ...},   commands separated by semicolons ].

The output of the last command inside the Module (assuming it doesn’t have a semicolon) is the output of the whole Module command. Here’s an example:

Clear[a,b,c]
(* it's good form to write out Module in multiple rows like this, even though everything could be put on a single line *)
Module[ {a,b,c},  
a = 1; 
b = 10; 
c = 100; 
a+b+c   
]

a  (* these all have no value outside of the Module *)
b
c

Things to notice: 
1. Please put commands on separate rows in the Modules you write, in just the same way the example does. It’ll make life easier for both you and the TAs.
2. Specifically, have the list of local variables on the first line, and then the commands on subsequent lines, with semicolons.
3. The last command generally should NOT have a semicolon. In this example a+b+c has an output of 111, with no semicolon to suppress the output. Therefore that’s what gets displayed when you run the Module.
4. The variables a, b, and c in this example are strictly local. The Module does not change their value at all.

If the final statement inside the Module, a+b+c, had had a semicolon after it, the Module would have produced no output. However, even if a Module produces no output, that doesn’t mean it is powerless. Here’s a situation where the Module doesn’t produce any output--but it does have an effect, in that it modifies the value of a global variable.

lifetheuniverseandeverything  (* has no value now *)

Module[{},   
lifetheuniverseandeverything =42;
]

lifetheuniverseandeverything  (* now it does! *)

Things to notice:
1. Even though that Module used no local variables, you still have to have the { } symbols (an empty list) as the first argument.
2. There was no output when the Module was executed, but it still did something.

Caution: Even though you can modify global variables from within a Module, that doesn’t mean that you necessarily should. In fact, normally you shouldn’t. I can’t offhand think of a time that I’ve ever written a module that deliberately modified a global variable--aside from the “lifetheuniverseandeverything” example just given. I exclusively use local variables inside a Module. But it’s good to know the power is there, in case you should ever need it.

Using While inside a module: the protection Module affords

You may have noticed that if you want to use an interator variable inside a While command to e.g. keep track of how many times the loop has run, it needs to be a global variable (in contrast to Do, which has a built-in local variable iterator). Therefore the While command is more susceptible to variable-name conflicts. Can you see the problem in doing the (x^2) integral after the While command (which computes 10!)?

x=1; factorial=1;
While[x<=10,factorial*=x;  x++]
factorial
Integrate[x^2,x]

The Integrate command throws an error because the global variable x is now equal to 10 so it’s trying to integrate (10^2)d10. Of course that makes no sense.

Global variable iterators such as in While become much less of a problem when they are “wrapped” in a Module. If you define them properly as local variables inside the Module, they exist outside the While loop within the Module, but still not outside the Module.

Clear[x, factorial];
Module[{x, factorial},
x=1;
factorial=1;
While[x<=10,factorial*=x;  x++];
factorial
(* same commands as before, just now inside a Module *)
]
Integrate[x^2,x] (* This works now! *)

Things to notice:
1. The integral worked! When While set the variable x to the values 1 through 10, that only applied to the local version of x within the Module.

To guard against accidental setting of variables, I personally nearly always use a Module whenever I use While loops. Also, Module has the additional bonus of being able to return a value at the end, whereas While cannot do that on its own.

Defining functions with Module

Even though Module can be used as a stand alone command as in the examples above, 97% of the time you use Module it will be in the context of defining a new function. To start out, just use the same type of function definition we’ve done before for “pure” (argumentative) functions. A delayed function assignment with  :=  will nearly always be best. Here’s an example which defines a simple (x^2) function using a Module.

f[x_]:= Module[{},
x^2
]
f[3]

That didn’t have any advantage over defining the function like f[x_] := x^2,  but we’re just getting started.

This next example uses Module to create a more complicated pure function, which also employs three local variables.

f[x_,y_,z_] := Module[{a,b,c},
a = 1;
b = 10; 
c = 100; 
c*x+b*y+a*z]
f[3,4,7]

Although there’s still no real difference between that function definition and a simpler, “f[x_,y_,z] := 100x + 10 y + z”,  you will soon see that Module really does allow for a lot of additional flexibility.

Sometimes it may be useful to give the local variables initial values as they are being defined. That is called “initializing” the variables, and can be done this way:

(* same thing as previous program *)
f[x_,y_,z_] := Module[{a = 1,b = 10,c = 100},  
 c*x+b*y+a*z
]
f[3,4,7]

The incoming arguments don’t necessarily have to be numbers. Here’s a Module that does this: “square the expression and add the square to the original expression”. It takes an algebraic expression as its input, and gives an algebraic expression as its output.

squareadd[f_]:= Module[{fsquared},
fsquared=f^2;
f+fsquared
]
squareadd[x^2]
squareadd[Sin[x]]
squareadd[3]  (* "3" counts as an algebraic expression *)

Finally, it’s worth pointing out that--just as when you define functions the regular way--you can give additional type specifiers when defining a function that uses a Module. For example:

blah[realnum_Real, intnum_Integer, {arrayelem1_, arrayelem2_}] := Module[{fraction},
fraction = arrayelem1/arrayelem2;
Floor[realnum] + intnum  + fraction
]

blah[1.2,3,{4,5}]

What happens if you try to use the “blah” function without your first argument being a real number, your second argument being an integer, and your third argument being a two-element array? Try it out.

Assignment 9. Your First Two Modules

(a) It is traditional when learning a new programming language, that your first program should be to have the computer announce “Hello world”.  See this Wikipedia article for a bit more info, if you’d like. Let’s keep with tradition. Create a Module that takes one input, but outputs “Hello world” regardless of what the input is.

(b) Here’s a slightly harder task than “Hello world”. Use Module to create a pure function f1[xlist_] that takes a list of real numbers as input (unknown length), computes the Mean and the StandardDeviation of the list, subtracts the mean from each element of the list, divides each element of the resulting list by the standard deviation, then returns that list of numbers as the function’s output.  Try your new function out on a list of 100 RandomReal numbers that lie between 0 and 10.  The results should lie primarily between -1.5 and +1.5.  Plot a Histogram of the list to verify this.

Warning: This is important, so please read to spare yourself some grief. When you pass an argument into a Module from a function definition, such as the value of “x” when doing this function definition, f[x_] := Module[.....], you cannot change the value of x inside the Module. Trying to set x equal to something else will result in an error. If you want to modify the value, you have to set a local variable equal to x, and then modify the local variable instead.

Assignment 10. Temperature converter

Create a temperature converter function. There should be two inputs and one output. The first input should be the temperature you wish to convert. The second input should be a string, either “FtoC” or “CtoF”. Based on the value of the string, the program should convert from Fahrenheit to Celsius or vice versa and output a decimal number.

Wrap-up

The following functions were discussed in today's lab, or are very closely related:
Logic gates: Not, And, Or, Nand, Nor, Xor
Conditionals: If, Which, Switch
Built-in piecewise functions (mostly related to rounding): Round, Floor, Ceiling, IntegerPart, FractionalPart, Chop, Clip, Sign, Unitize, UnitStep, Abs
Loops: Do, While, For
Recursive functions: Nest, NestList, NestWhile, NestWhileList
Shortcuts to modify variables: +=, -=, *=, /=, ++x, x++, --x, x--
To transform true/false into 1 and 0: Boole
To find out the variable type: Head
To query if prime: PrimeQ
The nth prime number: Prime
To add an element to the end of an array: AppendTo

Potentially useful summary/tutorial pages:
Guide: Logic and Boolean Algebra
Tutorial: Conditionals
Guide: Conditionals
Guide: Functional Iteration
Guide: Assignments
Tutorial: Special Forms of Assignment