$$ \newcommand{\tp}{\thinspace .} $$

This chapter is taken from the book A Primer on Scientific Programming with Python by H. P. Langtangen, 5th edition, Springer, 2016.

Exercises

Exercise 1: Make an interactive program

Make a program that asks the user for a temperature in Fahrenheit degrees and reads the number; computes the corresponding temperature in Celsius degrees; and prints out the temperature in the Celsius scale. Filename: f2c_qa.

Exercise 2: Read a number from the command line

Modify the program from Exercise 1: Make an interactive program such that the Fahrenheit temperature is read from the command line. Filename: f2c_cml.

Exercise 3: Read a number from a file

Modify the program from Exercise 1: Make an interactive program such that the Fahrenheit temperature is read from a file with the following content:

Temperature data
----------------

Fahrenheit degrees: 67.2

Hint. Create a sample file manually. In the program, skip the first three lines, split the fourth line into words and grab the third word.

Filename: f2c_file_read.

Exercise 4: Read and write several numbers from and to file

This is a variant of Exercise 3: Read a number from a file where we have several Fahrenheit degrees in a file and want to read all of them into a list and convert the numbers to Celsius degrees. Thereafter, we want to write out a file with two columns, the left with the Fahrenheit degrees and the right with the Celsius degrees.

An example on the input file format looks like

Temperature data
----------------

Fahrenheit degrees: 67.2
Fahrenheit degrees: 66.0
Fahrenheit degrees: 78.9
Fahrenheit degrees: 102.1
Fahrenheit degrees: 32.0
Fahrenheit degrees: 87.8
A sample file is Fdeg.dat. Filename: f2c_file_read_write.

Exercise 5: Use exceptions to handle wrong input

Extend the program from Exercise 2: Read a number from the command line with a try-except block to handle the potential error that the Fahrenheit temperature is missing on the command line. Filename: f2c_cml_exc.

Exercise 6: Read input from the keyboard

Make a program that asks for input from the user, applies eval to this input, and prints out the type of the resulting object and its value. Test the program by providing five types of input: an integer, a real number, a complex number, a list, and a tuple. Filename: objects_qa.

Exercise 7: Read input from the command line

a) Let a program store the result of applying the eval function to the first command-line argument. Print out the resulting object and its type.

b) Run the program with different input: an integer, a real number, a list, and a tuple.

Hint. On Unix systems you need to surround the tuple expressions in quotes on the command line to avoid error message from the Unix shell.

c) Try the string "this is a string" as a command-line argument. Why does this string cause problems and what is the remedy?

Filename: objects_cml.

Exercise 8: Try MSWord or LibreOffice to write a program

The purpose of this exercise is to tell you how hard it may be to write Python programs in the standard programs that most people use for writing text.

a) Type the following one-line program in either MSWord or LibreOffice:

print "Hello, World!"
Both Word and LibreOffice are so "smart" that they automatically edit "print" to "Print" since a sentence should always start with a capital. This is just an example that word processors are made for writing documents, not computer programs.

b) Save the program as a .docx (Word) or .odt (LibreOffice) file. Now try to run this file as a Python program. What kind of error message do you get? Can you explain why?

c) Save the program as a .txt file in Word or LibreOffice and run the file as a Python program. What happened now? Try to find out what the problem is.

Exercise 9: Prompt the user for input to a formula

Consider the simplest program for evaluating the formula \( y(t)=v_0t - \frac{1}{2}gt^2 \):

v0 = 3; g = 9.81; t = 0.6
y = v0*t - 0.5*g*t**2
print y
Modify this code so that the program asks the user questions t=? and v0=?, and then gets t and v0 from the user's input through the keyboard. Filename: ball_qa.

Exercise 10: Read parameters in a formula from the command line

Modify the program listed in Exercise 9: Prompt the user for input to a formula such that v0 and t are read from the command line. Filename: ball_cml.

Exercise 11: Use exceptions to handle wrong input

The program from Exercise 10: Read parameters in a formula from the command line reads input from the command line. Extend that program with exception handling such that missing command-line arguments are detected. In the except IndexError block, use the raw_input function to ask the user for missing input data. Filename: ball_cml_qa.

Exercise 12: Test validity of input data

Test if the t value read in the program from Exercise 10: Read parameters in a formula from the command line lies between \( 0 \) and \( 2v_0/g \). If not, print a message and abort the execution. Filename: ball_cml_tcheck.

Exercise 13: Raise an exception in case of wrong input

Instead of printing an error message and aborting the program explicitly, raise a ValueError exception in the if test on legal t values in the program from Exercise 12: Test validity of input data. Notify the user about the legal interval for \( t \) in the exception message. Filename: ball_cml_ValueError.

Exercise 14: Evaluate a formula for data in a file

We consider the formula \( y(t)=v_0t - 0.5gt^2 \) and want to evaluate \( y \) for a range of \( t \) values found in a file with format

v0: 3.00
t:
0.15592  0.28075   0.36807889 0.35 0.57681501876
0.21342619  0.0519085  0.042  0.27  0.50620017 0.528
0.2094294  0.1117  0.53012  0.3729850  0.39325246
0.21385894  0.3464815 0.57982969 0.10262264
0.29584013  0.17383923
More precisely, the first two lines are always present, while the next lines contain an arbitrary number of \( t \) values on each line, separated by one or more spaces.

a) Write a function that reads the input file and returns \( v_0 \) and a list with the \( t \) values. A sample file is ball.dat

b) Make a test function that generates an input file, calls the function in a) for reading the file, and checks that the returned data objects are correct.

c) Write a function that creates a file with two nicely formatted columns containing the \( t \) values to the left and the corresponding \( y \) values to the right. Let the \( t \) values appear in increasing order (note that the input file does not necessarily have the \( t \) values sorted).

Filename: ball_file_read_write.

Exercise 15: Write a function given its test function

A common software development technique in the IT industry is to write the test function before writing the function itself.

a) We want to write a function halve(x) that returns the half of its argument x. The test function is

def test_halve():
    assert halve(5.0) == 2.5  # Real number division
    assert halve(5) == 2      # Integer division
Write the associated function halve. Call test_halve (or run pytest or nose) to verify that halve works.

b) We want to write a function add(a, b) that returns the sum of its arguments a and b. The test function reads

def test_add():
    # Test integers
    assert add(1, 2) == 3

    # Test floating-point numbers with rounding error
    tol = 1E-14
    a = 0.1;  b = 0.2
    computed = add(a, b)
    expected = 0.3
    assert abs(expected - computed) < tol

    # Test lists
    assert add([1,4], [4,7]) == [1,4,4,7]

    # Test strings
    assert add('Hello, ', 'World!') == 'Hello, World!'
Write the associated function add. Call test_add (or run pytest or nose) to verify that add works.

c) We want to write a function equal(a, b) for determining if two strings a and b are equal. If equal, the function returns True and the string a. If not equal, the function returns False and a string displaying the differences. This latter string contains the characters common in a and b, but for every difference, the character from a and b are written with a pipe symbol '|' in between. In case a and b are of unequal length, pad the string displaying differences with a * where one of the strings lacks content. For example, equal('abc', 'aBc') would return False, 'ab|Bc', while equal('abc', 'aBcd') would return False, 'ab|Bc*|d'. Here is the test function:

def test_equal():
    assert equal('abc', 'abc') == (True, 'abc')
    assert equal('abc', 'aBc') == (False, 'ab|Bc')
    assert equal('abc', 'aBcd') == (False, 'ab|Bc*|d')
    assert equal('Hello, World!', 'hello world') == \ 
           (False, 'H|hello,|  |wW|oo|rr|ll|dd|*!|*')
Write the equal function (which is handy to detect very small differences between texts).

Filename: testfunc2func.

Exercise 16: Compute the distance it takes to stop a car

A car driver, driving at velocity \( v_0 \), suddenly puts on the brake. What braking distance \( d \) is needed to stop the car? One can derive, using Newton's second law of motion or a corresponding energy equation, that $$ \begin{equation} d = \frac{1}{2}{v_0^2\over \mu g}\tp \tag{7} \end{equation} $$

Make a program for computing \( d \) in (7) when the initial car velocity \( v_0 \) and the friction coefficient \( \mu \) are given on the command line. Run the program for two cases: \( v_0=120 \) and \( v_0=50 \) km/h, both with \( \mu=0.3 \) (\( \mu \) is dimensionless).

Hint. Remember to convert the velocity from km/h to m/s before inserting the value in the formula.

Filename: stopping_length.

Exercise 17: Look up calendar functionality

The purpose of this exercise is to make a program that takes a date, consisting of year (4 digits), month (2 digits), and day (1-31) on the command line and prints the corresponding name of the weekday (Monday, Tuesday, etc.). Python has a module calendar, which makes it easy to solve the exercise, but the task is to find out how to use this module. Filename: weekday.

Exercise 18: Use the StringFunction tool

Make the program integrate.py from the section The magic exec function shorter by using the convenient StringFunction tool from the section Turning string expressions into functions. Write a test function for verifying this new implementation. Filename: integrate2.

Exercise 19: Why we test for specific exception types

The simplest way of writing a try-except block is to test for any exception, for example,

try:
    C = float(sys.arg[1])
except:
    print 'C must be provided as command-line argument'
    sys.exit(1)
Write the above statements in a program and test the program. What is the problem?

The fact that a user can forget to supply a command-line argument when running the program was the original reason for using a try block. Find out what kind of exception that is relevant for this error and test for this specific exception and re-run the program. What is the problem now? Correct the program. Filename: unnamed_exception.

Exercise 20: Make a complete module

a) Make six conversion functions between temperatures in Celsius, Kelvin, and Fahrenheit: C2F, F2C, C2K, K2C, F2K, and K2F.

b) Collect these functions in a module convert_temp.

c) Import the module in an interactive Python shell and demonstrate some sample calls on temperature conversions.

d) Insert the session from c) in a triple quoted string at the top of the module file as a doc string for demonstrating the usage.

e) Write a function test_conversion() that verifies the implementation. Call this function from the test block if the first command-line argument is verify.

Hint. Check that C2F(F2C(f)) is f, K2C(C2K(c)) is c, and K2F(F2K(f)) is f - with tolerance. Follow the conventions for test functions outlined in the sections Verification of the module code and Example: Bisection root finding with a boolean variable that is False if a test failed, and True if all test are passed, and then an assert statement to abort the program when any test fails.

f) Add a user interface to the module such that the user can write a temperature as the first command-line argument and the corresponding temperature scale as the second command-line argument, and then get the temperature in the two other scales as output. For example, 21.3 C on the command line results in the output 70.3 F 294.4 K. Encapsulate the user interface in a function, which is called from the test block.

Filename: convert_temp.

Exercise 21: Organize a previous program as a module

The exercise named "Approximate a function by a sum of sines" in the document Functions and branching [10] asks you to write two functions called f and S. Now collect these functions in a separate file such that this file becomes a module. Put the statements making the table in a separate function table(n_values, alpha_values, T). Make a test block in the module to read \( T \) and a series of \( n \) and \( \alpha \) values as positional command-line arguments and make a corresponding call to table. Filename: sinesum2.

Exercise 22: Read options and values from the command line

Let the input to the program in Exercise 21: Organize a previous program as a module be option-value pairs with the options --n, --alpha, and --T. Provide sensible default values in the module file.

Hint. Apply the argparse module to read the command-line arguments. Do not copy code from the sinesum2 module, but make a new file for reading option-value pairs from the command and import the table function from the sinesum2 module.

Filename: sinesum3.

Exercise 23: Check if mathematical identities hold

Because of rounding errors, it could happen that a mathematical rule like \( (ab)^3 = a^3b^3 \) does not hold exactly on a computer. The idea of testing this potential problem is to check such identities for a large number of random numbers. We can make random numbers using the random module in Python:

import random
a = random.uniform(A, B)
b = random.uniform(A, B)
Here, a and b will be random numbers, which are always larger than or equal to A and smaller than B.

a) Make a function power3_identity(A=-100, B=100, n=1000) that tests the identity (a*b)**3 == a**3*b**3 a large number of times, n. Return the fraction of failures.

Hint. Inside the loop over n, draw random numbers a and b as described above and count the number of times the test is True.

b) We shall now parameterize the expressions to be tested. Make a function

equal(expr1, expr2, A=-100, B=100, n=500)
where expr1 and expr2 are strings containing the two mathematical expressions to be tested. More precisely, the function draws random numbers a and b between A and B and tests if eval(expr1) == eval(expr2). Return the fraction of failures.

Test the function on the identities \( (ab)^3 = a^3b^3 \), \( e^{a+b}=e^ae^b \), and \( \ln a^b = b\ln a \).

Hint. Make the equal function robust enough to handle illegal \( a \) and \( b \) values in the mathematical expressions (e.g., \( a\leq 0 \) in \( \ln a \)).

c) We want to test the validity of the following set of identities on a computer:

Store all the expressions in a list of 2-tuples, where each 2-tuple contains two mathematically equivalent expressions as strings, which can be sent to the equal function. Make a nicely formatted table with a pair of equivalent expressions at each line followed by the failure rate. Write this table to a file. Try out A=1 and B=2 as well as A=1 and B=100. Does the failure rate seem to depend on the magnitude of the numbers \( a \) and \( b \)?

Filename: math_identities_failures.

Exercise 24: Compute probabilities with the binomial distribution

Consider an uncertain event where there are two outcomes only, typically success or failure. Flipping a coin is an example: the outcome is uncertain and of two types, either head (can be considered as success) or tail (failure). Throwing a die can be another example, if (e.g.) getting a six is considered success and all other outcomes represent failure. Such experiments are called Bernoulli trials.

Let the probability of success be \( p \) and that of failure \( 1-p \). If we perform \( n \) experiments, where the outcome of each experiment does not depend on the outcome of previous experiments, the probability of getting success \( x \) times, and consequently failure \( n-x \) times, is given by $$ \begin{equation} B(x,n,p) = {n!\over x! (n-x)!} p^x(1-p)^{n-x}\tp \tag{8} \end{equation} $$ This formula (8) is called the binomial distribution. The expression \( x! \) is the factorial of \( x \): \( x!=x(x-1)(x-2)\cdots 1 \) and math.factorial can do this computation.

a) Implement (8) in a function binomial(x, n, p).

b) What is the probability of getting two heads when flipping a coin five times? This probability corresponds to \( n=5 \) events, where the success of an event means getting head, which has probability \( p=1/2 \), and we look for \( x=2 \) successes.

c) What is the probability of getting four ones in a row when throwing a die? This probability corresponds to \( n=4 \) events, success is getting one and has probability \( p=1/6 \), and we look for \( x=4 \) successful events.

d) Suppose cross country skiers typically experience one ski break in one out of 120 competitions. Hence, the probability of breaking a ski can be set to \( p=1/120 \). What is the probability \( b \) that a skier will experience a ski break during five competitions in a world championship?

Hint. This question is a bit more demanding than the other two. We are looking for the probability of 1, 2, 3, 4 or 5 ski breaks, so it is simpler to ask for the probability \( c \) of not breaking a ski, and then compute \( b=1-c \). Define success as breaking a ski. We then look for \( x=0 \) successes out of \( n=5 \) trials, with \( p=1/120 \) for each trial. Compute \( b \).

Filename: Bernoulli_trials.

Exercise 25: Compute probabilities with the Poisson distribution

Suppose that over a period of \( t_m \) time units, a particular uncertain event happens (on average) \( \nu t_m \) times. The probability that there will be \( x \) such events in a time period \( t \) is approximately given by the formula $$ \begin{equation} P(x,t, \nu) = {(\nu t)^x\over x!}e^{-\nu t}\tp \tag{9} \end{equation} $$ This formula is known as the Poisson distribution. (It can be shown that (9) arises from (8) when the probability \( p \) of experiencing the event in a small time interval \( t/n \) is \( p=\nu t/n \) and we let \( n\rightarrow\infty \).) An important assumption is that all events are independent of each other and that the probability of experiencing an event does not change significantly over time. This is known as a Poisson process in probability theory.

a) Implement (9) in a function Poisson(x, t, nu), and make a program that reads \( x \), \( t \), and \( \nu \) from the command line and writes out the probability \( P(x,t,\nu) \). Use this program to solve the problems below.

b) Suppose you are waiting for a taxi in a certain street at night. On average, 5 taxis pass this street every hour at this time of the night. What is the probability of not getting a taxi after having waited 30 minutes? Since we have 5 events in a time period of \( t_m=1 \) hour, \( \nu t_m= \nu = 5 \). The sought probability is then \( P(0, 1/2, 5) \). Compute this number. What is the probability of having to wait two hours for a taxi? If 8 people need two taxis, that is the probability that two taxis arrive in a period of 20 minutes?

c) In a certain location, 10 earthquakes have been recorded during the last 50 years. What is the probability of experiencing exactly three earthquakes over a period of 10 years in this area? What is the probability that a visitor for one week does not experience any earthquake? With 10 events over 50 years we have \( \nu t_m = \nu \cdot 50 \hbox{ years} = 10 \hbox{ events} \), which implies \( \nu = 1/5 \) event per year. The answer to the first question of having \( x=3 \) events in a period of \( t=10 \) years is given directly by (9). The second question asks for \( x=0 \) events in a time period of 1 week, i.e., \( t=1/52 \) years, so the answer is \( P(0,1/52,1/5) \).

d) Suppose that you count the number of misprints in the first versions of the reports you write and that this number shows an average of six misprints per page. What is the probability that a reader of a first draft of one of your reports reads six pages without hitting a misprint? Assuming that the Poisson distribution can be applied to this problem, we have "time" \( t_m \) as 1 page and \( \nu \cdot 1 = 6 \), i.e., \( \nu=6 \) events (misprints) per page. The probability of no events in a "period" of six pages is \( P(0,6,6) \).

Filename: Poisson_processes.

References

  1. H. P. Langtangen. Introduction to classes in Python, \emphhttp://hplgit.github.io/primer.html/doc/pub/class, http://hplgit.github.io/primer.html/doc/pub/class.
  2. H. P. Langtangen. Object-oriented programming, \emphhttp://hplgit.github.io/primer.html/doc/pub/oo, http://hplgit.github.io/primer.html/doc/pub/oo.
  3. J. E. Grayson. Python and Tkinter Programming, Manning, 2000.
  4. D. Harms and K. McDonald. The Quick Python Book, Manning, 1999.
  5. H. P. Langtangen. Python Scripting for Computational Science, 3rd edition, Texts in Computational Science and Engineering, Springer, 2009.
  6. M. Lutz. Programming Python, 4th edition, O'Reilly, 2011.
  7. H. P. Langtangen. Unit testing with nose, \emphhttp://hplgit.github.io/primer.html/doc/pub/nose, http://hplgit.github.io/primer.html/doc/pub/nose.
  8. G. Ward and A. Baxter. Distributing Python Modules, \urlhttp://docs.python.org/2/distutils/, http://docs.python.org/2/distutils/.
  9. H. P. Langtangen. Quick Intro to Version Control Systems and Project Hosting Sites, \emphhttp://hplgit.github.io/teamods/bitgit/html/, http://hplgit.github.io/teamods/bitgit/html/.
  10. H. P. Langtangen. Functions and branching, \emphhttp://hplgit.github.io/primer.html/doc/pub/funcif, http://hplgit.github.io/primer.html/doc/pub/funcif.