# MAS212 Class Test 1 (2019)¶

## Aim:¶

• To help you learn some Python essentials and programming skills to enjoy this module.

How it works:

• Complete the notebook below, as follows. Click on a question, then from the menu select Insert -> Insert Cell Below. From the dropdown box (next to the "stop" symbol) choose whether you wish to insert 'Code' or 'Markdown'. Save regularly!
• Press Shift-Enter to execute the code in a cell.
• Submit the .ipynb file via https://somas-uploads.shef.ac.uk/mas212 by 23.59pm on Sun 13th Oct 2019. If you are off-campus, you will need to use a VPN to submit.
• Your lecturer will mark each question as either 2 (good), 1 (needs revision), 0 (not attempted/wrong).
• This is an open-book test, which means you may consult books, notes and internet resources. Do not discuss or share your test with anyone. Copy-and-pasting is not permitted. Please give answers in your own words.
• Some of these questions are relatively straightforward, and some are harder (e.g. Q20). Please don't spend any longer than a maximum of 4 hours on this test, as it is for a relatively small amount of credit.

Key Resources:

## A. The Python language

1. Describe two key differences between the list and set data types.

Lists are ordered, whereas sets are not. Lists allow duplicates, whereas sets do not.

2. Describe one way in which a string is similar to a list, and one way in which it is different.

A string can be thought of as an ordered list of characters; string indexing (e.g. s[3]) allows characters to be retrieved from a list in the same way as items in a list. Lists are mutable, whereas strings are immutable, meaning they cannot be changed.

3. True or False?
(i) In Python, function arguments are passed by value.
(ii) Function arguments can be modified within functions.

(i) False. Function arguments are passed by reference in Python.

(ii) True. Function arguments of mutable type can be modified within functions. (And functions can also modify variables defined outside of the function, through the use of the global keyword).

4. What is vectorization in Python, and what benefits can it bring? Give two examples of Universal Functions in Python.

Vectorization is the coding practice of replacing the use of for loops and lists with the use of arrays and Universal Functions (ufuncs), wherever possible. Universal Functions act on the whole array with a single statement, and they are typically implemented in C (a compiled language). This has the benefit of increasing the speed and efficiency of the code, as well as of reducing the number of lines of code.

Two examples of universal functions are np.sin() and np.abs. The unary operators (+, *, **, etc) are also universal functions.

5. What is broadcasting in the context of the numpy module?
What is the shape of A*B, if the arrays A and B have shapes (7,3,1) and (3,7,1,4)?

Broadcasting is a defined way of combining numpy arrays with different shapes so that, subject to certain constraints, the smaller array is “broadcast” across the larger array.

The shape of A*B in the example above is (3,7,3,4).

## B. Python code

6. Python as a calculator: Write code to calculate $8 + 7$, $\sqrt{3^3 + 5^3}$, $\tan(\pi/8)$ and $(2 - 3i)^{3}$.

In [2]:
import math
[8+7, math.sqrt(3**3+5**3), math.tan(math.pi/8), (2-3*1j)**3]

Out[2]:
[15, 12.328828005937952, 0.4142135623730951, (-46-9j)]

7. Find the sum-of-cubes $1 + 8 + 27 + \ldots + 1000$.

In [3]:
sum([k**3 for k in range(1,11)])

Out[3]:
3025

8. Print to screen the values of the square roots of $1,2, \ldots, 10$ to eight decimal places.

In [4]:
for i in range(1,11):
print("The square root of %i is %.8f" % (i, math.sqrt(i)))

The square root of 1 is 1.00000000
The square root of 2 is 1.41421356
The square root of 3 is 1.73205081
The square root of 4 is 2.00000000
The square root of 5 is 2.23606798
The square root of 6 is 2.44948974
The square root of 7 is 2.64575131
The square root of 8 is 2.82842712
The square root of 9 is 3.00000000
The square root of 10 is 3.16227766


9. Write code to demonstrate that the ratio of Fibonacci numbers $f_{k+1} / f_{k}$ tends towards the Golden Ratio as $k \rightarrow \infty$.
[N.B. The Fibonacci sequence is defined by $f_{k+1} = f_k + f_{k-1}$ with $f_{0} = f_{1} = 1$. The Golden Ratio is $\frac{1}{2}(\sqrt{5} + 1)$.]

In [6]:
f = [1,1]
nmax = 50
for i in range(2,nmax+1):
f.append(f[-1]+f[-2])
print("The ratio of successive Fibonacci numbers f[%i]/f[%i] is %.10f" % (nmax,nmax-1,f[-1]/f[-2]))
print("The Golden Ratio is                                      %.10f" % (1/2*(math.sqrt(5)+1)))

The ratio of successive Fibonacci numbers f[50]/f[49] is 1.6180339887
The Golden Ratio is                                      1.6180339887


10. Write a function expfn(x) to calculate $e^x$ by truncating the series expansion $$e^x = \sum^{}_{n=0} \frac{x^n}{n!}$$ at $n_{max} = 10$.
Test your function by calculating $e^{i \pi}$. How accurate is the result?

In [9]:
def expfn(x):
nmax=10
return sum([x**k/math.factorial(k) for k in range(0, nmax+1)])
y = expfn(1j*math.pi)
print("The true value of exp(i pi) is -1.")
print("The truncated series gives ", y)
print("The absolute error is ", (y + 1.0))

The true value of exp(i pi) is -1.
The truncated series gives  (-1.0018291040136216+0.006925270707505149j)
The absolute error is  (-0.0018291040136215742+0.006925270707505149j)


11. Write a function to compute and display the first 10 rows of Pascal's triangle.

In [13]:
def pascaltriangle(rows):
pasc = [1]
n = 100
for k in range(rows):
s2 = " ".join([repr(i) for i in pasc])
pasc = [1] + [pasc[k]+pasc[k+1] for k in range(len(pasc)-1)] + [1]
return

pascaltriangle(10)

                                                 1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1


12. Write code to save your initials and registration number, on separate lines, into a file "me.txt".

In [15]:
f = open("me.txt", "w")
f.write("Sam Dolan\n")
f.write("012345679")
f.close()


## C. String Processing

In [16]:
s = """Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, and what is the use of a book,' thought Alice without pictures or conversation?'
So she was considering in her own mind (as well as she could, for the hot day made her feel very sleepy and stupid), whether the pleasure of making a daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly a White Rabbit with pink eyes ran close by her."""


13. How many times does the first letter of the alphabet appear in the string s? (please count both uppercase 'A' and lowercase 'a').

In [17]:
s.count('a') + s.count('A')

Out[17]:
31

14. How many words are there in the string? How many distinct words?

In [21]:
# First I will remove the punctuation
letters = "abcdefghijklmnopqrstuvwxyz"
alphabet = letters + letters.upper() + " "
s1 = ""
for c in s:
if c in alphabet:
s1 += c
print(s1 + "\n")
# Now split into words using the space character.
words = s1.split(" ")
print("There are %i words." % len(words))
print("There are %i distinct words." % len(set(words)))

Alice was beginning to get very tired of sitting by her sister on the bank and of having nothing to do once or twice she had peeped into the book her sister was reading but it had no pictures or conversations in it and what is the use of a book thought Alice without pictures or conversation So she was considering in her own mind as well as she could for the hot day made her feel very sleepy and stupid whether the pleasure of making a daisychain would be worth the trouble of getting up and picking the daisies when suddenly a White Rabbit with pink eyes ran close by her

There are 112 words.
There are 76 distinct words.


15. What is the longest word in s, and how many characters does it have?

In [29]:
longwords = [w for w in words if len(w) > 12]
longword = longwords[0]
print("The longest words is '%s' and it has %i characters." % (longword, len(longword)))

The longest words is 'conversations' and it has 13 characters.


## D. Linear algebra and numpy

(Use code cells).

In [30]:
import numpy as np


16. Make a 2D array of shape $4 \times 5$ containing the integers 1, 2, ... 20. Print this array to screen.

In [31]:
A = np.arange(1,21).reshape(4,5)
print(A)

[[ 1  2  3  4  5]
[ 6  7  8  9 10]
[11 12 13 14 15]
[16 17 18 19 20]]


17. By broadcasting together two arrays, make a 2D array of shape $12 \times 12$ to represent the multiplication tables up to 12. It should look like this: $$\begin{pmatrix} 1 & 2 & 3 & \ldots & 12 \\ 2 & 4 & 6 & \ldots & 24 \\ \ldots & \ldots &\ldots &\ldots \\ 12 & 24 & 36 & \ldots & 144 \end{pmatrix}$$

In [32]:
n = 12
row = np.arange(1,n+1).reshape((1,n))
col = np.arange(1,n+1).reshape((n,1))
A = row*col
print(A)

[[  1   2   3   4   5   6   7   8   9  10  11  12]
[  2   4   6   8  10  12  14  16  18  20  22  24]
[  3   6   9  12  15  18  21  24  27  30  33  36]
[  4   8  12  16  20  24  28  32  36  40  44  48]
[  5  10  15  20  25  30  35  40  45  50  55  60]
[  6  12  18  24  30  36  42  48  54  60  66  72]
[  7  14  21  28  35  42  49  56  63  70  77  84]
[  8  16  24  32  40  48  56  64  72  80  88  96]
[  9  18  27  36  45  54  63  72  81  90  99 108]
[ 10  20  30  40  50  60  70  80  90 100 110 120]
[ 11  22  33  44  55  66  77  88  99 110 121 132]
[ 12  24  36  48  60  72  84  96 108 120 132 144]]


18. A square matrix $N$ is said to be nilpotent if $N^k = 0$ for some $k > 1$ (where e.g. $N^2 = N N$). Demonstrate that the following matrix is nilpotent: $$A = \begin{bmatrix} 2 & 2 & -2 \\ 5 & 1 & -3 \\ 1 & 5 & -3 \end{bmatrix}$$

In [39]:
N = np.matrix("2 2 -2 ; 5 1 -3 ; 1 5 -3")
print(N*N*N)
# The matrix is nilpotent, as the cube of the matrix is zero (k=3).

[[0 0 0]
[0 0 0]
[0 0 0]]


19. By using a function found in the module np.linalg, find the eigenvalues of the real symmetric matrix $$A = \begin{bmatrix} 1 & 2 & 3 \\ 2 & 4 & 1 \\ 3 & 1 & -5 \end{bmatrix} .$$ Verify that the sum of the eigenvalues is zero.

In [44]:
A = np.matrix("1 2 3 ; 2 4 1 ; 3 1 -5")
eigs = np.linalg.eig(A)[0]
print("Eigenvalues : ", eigs)
print("The sum of the eigenvalues is %.10f" % sum(eigs))

Eigenvalues :  [-6.24524198  0.72518186  5.52006013]
The sum of the eigenvalues is 0.0000000000


## E. Cryptography

20. A musician has encrypted the notes of a famous melody using a One Time Pad. Write code to decrypt ciphertext using keytext, to recover the melody as a string of letters, A to G.

From what piece of music is this melody taken? (this last part not assessed)

In [45]:
ciphertext = "SYFOMNHALYDMKVKJPUYUOBZDIJKSSGSVYRQHWNNERLPGPPWVYWDMHNJETVVZIM"
keytext    = "MGASUSXDREASUITVPLIMRDEZUUULKWLIGLNXJRPZNUPXNOKJGJDUYRUYJIJEUQ"

In [55]:
s = ""
i0 = ord('A')
for k in range(0, len(ciphertext)):
i1 = ord(ciphertext[k]) - i0
i2 = ord(keytext[k]) - i0
i3 = (i1 + i2) % 26
s += chr(i3 + i0)
print("The list of notes is: ", s)
print("This is the melody from Ludwig van Beethoven's 'Ode to Joy' (9th symphony, movement 4).")

The list of notes is:  EEFGGFEDCCDEEDDEEFGGFEDCCDEDCCDDECDEFECDEFEDCDGEEFGGFEDCCDEDCC
This is the melody from Ludwig van Beethoven's 'Ode to Joy' (9th symphony, movement 4).

In [ ]: