I am working on the file "Foundations/Math/Titanic_exercises.ipynb".
The first task is:
Take random samples of 100 passengers and find out how many you need before the fraction of those samples where at least 42 passengers survive matches the probability you calculated previously (within Δp≈0.05).
Answers will vary based on chosen seeds. What would happen if you drew every sample with the same seed?
Plot the survival fraction vs the number of random samples.
Can you write Python code for it?

# Set the seed (if I used the same seed for every sample I would always get the same result,
# so the fraction of samples would always be the same, namely 0 or 1 depending on the sample)
random.seed(42)

# Set the target probability from above and Δp
target_prob = 0.2594
delta = 0.05

# Initialize list of fraction of samples with at least 42 survivors
# and counters for number of samples drawn and number of samples with at least 42 passengers
survival_frac = []
n_samples = 0
n_over = 0

# Iterate until the fraction of samples is within delta
while True:
    # Take a new sample
    n_samples += 1
    samp = random.sample(set(np.arange(len(titanic))), 100)
    # Check if survivors >= 42 and add to n_over
    if titanic.iloc[samp, 1].sum() >= 42:
        n_over += 1
    # Calculate the fraction of samples
    survival_frac.append(n_over / n_samples)
    if abs(n_over / n_samples - target_prob) < delta:
        break

survival_frac

print('Number of samples needed:', len(survival_frac))

fig = plt.figure(figsize=(16, 6))
ax = plt.axes()
ax.plot(survival_frac)
# Set labels
ax.set_xlabel('Number of samples')
ax.set_ylabel('Samples with at least 42 survivors')
# Set x axis limits, locators and formatters
ax.set_xlim(0, len(survival_frac) - 1)
ax.xaxis.set_major_locator(plt.MaxNLocator(8))
ax.xaxis.set_major_formatter(plt.FuncFormatter(lambda value, pos: int(value + 1)))
# Add a reference line for the target probability
ax.hlines(0.2594, 0, len(survival_frac) - 1, colors='red', linewidth=.5);


I am working on the file "Foundations/Math/Titanic_exercises.ipynb".
The first task is:
The difference between the fares paid by passengers from Queenstown and Cherbourg is statistically significant (the p-value is less than 0.001):
Can you write Python code for it?

print('Fares paid by passengers embarked in Queenstown average:', titanic[titanic['Embarked'] == 'Q']['Fare'].mean())
print('Fares paid by passengers embarked in Cherbourg average:', titanic[titanic['Embarked'] == 'C']['Fare'].mean())

print(titanic[titanic['Embarked'] == 'Q']['Fare'].std())
print(titanic[titanic['Embarked'] == 'C']['Fare'].std())

stats.ttest_ind(titanic[titanic['Embarked'] == 'Q']['Fare'].dropna(),
                titanic[titanic['Embarked'] == 'C']['Fare'].dropna(),
                equal_var=False)


I am working on the file "Foundations/Math/Titanic_exercises.ipynb".
The first task is:
The highest average ticket price was paid by passengers from which port? Null ports don’t count.
Can you write Python code for it?


I am working on the file "Foundations/Math/Titanic_exercises.ipynb".
The first task is:
What is the most common passenger class for each port?
Can you write Python code for it?

for port in titanic['Embarked'].dropna().unique():
    print('Most common class for {}: {}'.format(port, titanic.where(titanic['Embarked'] == port)['Pclass'].mode()[0]))


I am working on the file "Foundations/Math/Titanic_exercises.ipynb".
The first task is:
What’s the probability that at least 42 of those 100 passengers survive?
Can you write Python code for it?

1 - stats.binom.cdf(41, 100, survival_rate)


I am working on the file "Foundations/Math/Titanic_exercises.ipynb".
The first task is:
Within what range of standard deviations from the mean (0-1, 1-2, 2-3) is the median ticket price? Is it above or below the mean?
It's between 0 and 1 standard deviations and below the mean:
Can you write Python code for it?

print((titanic['Fare'].mean() - titanic['Fare'].median()) / titanic['Fare'].std())
print(titanic['Fare'].mean() > titanic['Fare'].median())


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
11 - How would you go about solving the equation $\textbf{A}\vec{x} = 0$, using $\textbf{A}$ as above for an unknown $\vec{x}$?  Do so and comment on your results.  Hint consider parts (6) and (7).
Can you write Python code for it?


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
13 - Solve the system of equations $$x_0 + 2x_1 = 3$$ $$-x_0 + x_1 = 1$$ using both matrix inversion and built in numpy functions.
Can you write Python code for it?

A = np.array([[1, 2], [-1, 1]])
b = np.array([3, 1])

# Using inversion
x = np.linalg.inv(A).dot(b)
x

# Using linalg.solve
x = np.linalg.solve(A, b)
x


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
2 - Construct a matrix $\textbf{Q}$ whose columns are the eigenvectors of $\textbf{A}$.
Can you write Python code for it?


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
2 - Using $\vec{v}$ above, compute the inner, or dot, product, $\vec{v} \cdot \vec{v}$.  Is this quantity reminiscent of another vector quantity?
Can you write Python code for it?


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
3 - Construct a set of three vectors $\vec{\lambda_1} \dots \vec{\lambda_n}$, whose $n^{th}$ element is the $n^{th}$ eigenvalue of $\textbf{A}$ while all other elements are 0.  The second vector, for example, would be $$\vec{\lambda_2} = \begin{bmatrix} 0 \ \lambda_2 \ 0 \end{bmatrix}$$
Can you write Python code for it?


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
3 - Create 3 matrices $\textbf{A}$, $\textbf{B}$, $\textbf{C}$ of dimension $2\times2$, $3\times2$, and $2\times3$ respectively such that $$\textbf{A} = \begin{bmatrix} 1 & 2 \ 3 & 4 \end{bmatrix} \textbf{B} = \begin{bmatrix} 1 & 2 \ 3 & 4 \ 5 & 6\end{bmatrix} \textbf{C} = \begin{bmatrix} 1 & 2 & 3\ 4 & 5 & 6 \end{bmatrix}$$ and perform the following multiplications, stating the final dimensions of each: $\textbf{AA}$, $\textbf{AB}$, $\textbf{AC}$, $\textbf{BB}$, $\textbf{BA}$, $\textbf{BC}$, $\textbf{CC}$, $\textbf{CA}$, $\textbf{CB}$.  Comment on your results.
Can you write Python code for it?

A = np.arange(1, 5).reshape(2, 2)
B = np.arange(1, 7).reshape(3, 2)
C = np.arange(1, 7).reshape(2, 3)


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
3 - How do the results of part (2) differ from part (1)?
The vectors in part (1) are rotated by $A$ while the eigenvectors of part (2) are just scaled by the transformation.
4 - Define a new 3x3 matrix of the form $$\textbf{A} = \begin{bmatrix} -2 & -4 & 2 \ -2 & 1 & 2 \ 4 & 2 & 5 \end{bmatrix}$$ and compute the eigenvalues and vectors.  What can you say about the number of eigenvectors in your results?
Since the matrix has rank 3 we get three eigenvectors as expected:
Can you write Python code for it?


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
4 - Now try multiplying various combinations of $\textbf{A}$, $\textbf{Q}$, and $\vec{\lambda_n}$ together.  What is the relationship among them?
Each $\lambda_i$ multiplied by $Q$ gives one of the columns of $A \cdot Q$:
Can you write Python code for it?

print(l[0] * Q)
print(l[1] * Q)
print(l[2] * Q)
print(A.dot(Q))


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
4 - Using $\textbf{A}$ and $\textbf{B}$ above, compute $(\textbf{BA})^T$ and $\textbf{A}^T \textbf{B}^T$.  What can you say about your results?
The result is the same:
Can you write Python code for it?


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
5 - Define a new 3x3 matrix of the form $$\textbf{B} = \begin{bmatrix} -2 & -4 & 2 \ -2 & 1 & 2 \ 1 & 2 & -1 \end{bmatrix}$$ and compute the eigenvalues and vectors.  What can you say about the eigenvalues in your results?  Do they differ from what you saw in part (4)?
The matrix has rank 2 (the third column is equal to the first times $-1$), so I expect two eigenvectors; the fact that we get three is due to float arithmetic precision: the second eigenvalue is almost 0.
Can you write Python code for it?


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
5 - Using $\textbf{A}$, $\textbf{B}$, and $\textbf{C}$ above, compute the following sums: $\textbf{A+A}$, $\textbf{A+B}$, $\textbf{A+C}$, $\textbf{B+B}$, $\textbf{B+A}$, $\textbf{B+C}$, $\textbf{C+C}$, $\textbf{C+A}$, $\textbf{C+B}$.  Comment on your results.
We can only sum the matrices with themselves because they have to have the same dimension in order to be added (and because of their dimensions numpy can't broadcast them):
Can you write Python code for it?

for tab in [(x, y) for x in (A, B, C) for y in (A, B, C)]:
    try:
        if tab[0] is A:
            left = 'A'
        elif tab[0] is B:
            left = 'B'
        else:
            left = 'C'

        if tab[1] is A:
            right = 'A'
        elif tab[1] is B:
            right = 'B'
        else:
            right = 'C'

        print('{}+{} =\n{}'.format(left, right, tab[0] + tab[1]))

    except ValueError as e:
        print('{}+{} returns the error: {}'.format(left, right, e))


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
6 - Another very useful matrix decomposition is the Singular Value Decomposition (SVD) which is used, for example, in Principal Component Analysis.  A full discussion of this decomposition is beyond the scope of this exercise, but singular values are the square roots of the eigenvalues of $\textbf{A}\textbf{A}^T$ (for the real case).  Using numpy, perform a SVD on $\textbf{A}$ used above, and verify that the values on the main diagonal of the singular matrix are the square roots of the eigenvalues of $\textbf{A}$.
Can you write Python code for it?

u, diag, v = np.linalg.svd(A)

eigenval, eigenvec = np.linalg.eig(A.dot(A.T))

print(diag**2)
print(eigenval)

print(u.dot(np.diag(diag)).dot(v))
print(A)


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
6 - Compute the inverse of $\textbf{A}$ and $\textbf{B}$ above.  Comment on your results.
We can't invert the matrix $B$ because it has two proportional columns:
Can you write Python code for it?


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
7 - Construct three matrices $\textbf{A}^{-1}$, $\textbf{B}^{-1}$, and $\textbf{C}^{-1}$ such that $\textbf{A}^{-1}\textbf{A} = \textbf{I}_A$, $\textbf{B}^{-1}\textbf{B} = \textbf{I}_B$, and $\textbf{C}^{-1}\textbf{C} = \textbf{I}_C$.  Comment on your results. Hint This may not always be possible!
Can you write Python code for it?

Ainv = np.linalg.inv(A)
print(A)
print(Ainv.dot(A))

print(B)
print('Not possible because B is 3x2 and Ib is 3x3')

print(C)
print('Not possible because C is 2x3 and Ib is 2x2')


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
8 - Consider the rotation matrix $$\textbf{R} = \begin{bmatrix} cos(\theta) & sin(\theta) \ -sin(\theta) & cos(\theta)\end{bmatrix}$$.  Using a value of $\theta = 90$, compute the inner product of the columns, $\textbf{R}^T$, $\textbf{R}^{-1}$, $det(\textbf{R})$, and the eigenvalues and eigenvectors.  Comment on your results.
A rotation matrix is unitary, so it has determinant equal to 1 and $R^T = R^{-1}$.
Can you write Python code for it?

t = np.pi/2
R = np.array([[np.cos(t), np.sin(t)], [-np.sin(t), np.cos(t)]])

print(R.T)
print(np.linalg.inv(R))
print(np.linalg.det(R))


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
8 - Using $\textbf{A}^{-1}$ compute $(\textbf{A}^{-1})^T$ and comment on your results.
$(A^{-1})^{T}$ is the same as $(A^T)^{-1}$:
Can you write Python code for it?

print(Ainv.T)
print(np.linalg.inv(A.T))

print(np.linalg.inv(Ainv.T))


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
Applying the transformation $A$ causes the vector to be rotated and scaled:
Can you write Python code for it?

fig = plt.figure(figsize=(10, 10))
ax = plt.axes()
ax.set_xlim(-5, 5)
ax.set_ylim(-5, 5)
plot_vector2d(v1, color='red', label='v1')
plot_vector2d(v2, color='blue', label='v2')
plot_vector2d(v1a, color='orange', label='v1a')
plot_vector2d(v2a, color='green', label='v2a');
#ax.legend();


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
Eigenvalues and Eigenvectors
No discussion of Linear Algebra would be complete without taking a look at Eigenvalues and Eigenvectors.  The root word "eigen" comes from the German meaning "characteristic", and these values and associated vectors, represent some interesting properties of a given matrix.  Namely, for a given matrix $\textbf{A}$ and vector $\vec{v}$, the eigenvalue(s), $\lambda$, of $\textbf{A}$, are the $\lambda$ that satisfy the relationship $$\textbf{A} \vec{v} = \lambda \vec{v}$$ Keep in mind that $\lambda$ is a scalar quantity, and when you multiply a vector by a scalar quantity, you just scale, or stretch, the vector in space.  Therefore, the above relationship says that the eigenvalues $\lambda$ of $\textbf{A}$, and associated eigenvectors $\vec{v}$, are the vectors that when multiplied by $\textbf{A}$ just "stretch" in space (no rotations).
Now that may not sound very special, but the applicability of these concepts cannot be understated.  Eigenvalues and vectors have a tendency to crop up in any mathematically grounded discipline and Data Science is no exception.
For a more detailed explanation, see
- Great math formula explanation
- Visual explanation of Eigenvectors and Eigenvalues
before proceding with the following exercises.
1 - Generate a matrix $$\textbf{A} = \begin{bmatrix} 0 & 1 \ -2 & -3 \end{bmatrix}$$ and two vectors of your choosing, labeled $\vec{v}_1$ and $\vec{v}_2$.  Then compute the vectors $$\vec{v}_1' = \textbf{A}\vec{v}_1$$ $$\vec{v}_2' = \textbf{A}\vec{v}_2$$ And plot all 4 vectors with appropriate labels.  Comment on your results.
Can you write Python code for it?

import matplotlib.pyplot as plt
%matplotlib inline

A = np.array([[0, 1], [-2, 3]])
v1 = np.array([1, 0])
v2 = np.array([-1, 1])
v1a = A.dot(v1)
v2a = A.dot(v2)

# This is the plotting function from the instructional notebook:
def plot_vector2d(vector2d, origin=[0, 0], **options):
    return plt.arrow(origin[0], origin[1], vector2d[0], vector2d[1],
              head_width=0.2, head_length=0.3, length_includes_head=True,
              **options)


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
Eigenvalues and eigenvectors are complex numbers because a rotation has no fixed directions:
Can you write Python code for it?


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
Matrix Decomposition
Matrix Decomposition can be thought of as rewriting a given matrix as a product of other (and often simpler) matrices.  For example, given a matrix $\textbf{A}$, one can decompose $\textbf{A}$ into the following. $$\textbf{A} = \textbf{Q} \Lambda \textbf{Q}^{-1}$$
where $\textbf{Q}$ is a matrix whose $i^{th}$ column is the $i^{th}$ eigenvector of $\textbf{A}$, and $\Lambda$ is a matrix containing all of the corresponding eigenvalues on the main diagonal.  Decomposing $\textbf{A}$ in this manner is called an Eigendecomposition.  Such matrix decompositions, form the basis of many techniques in Data Science and other mathematical disciplines.
1 - Compute the eigenvalues and eigenvectors of matrix $$\textbf{A} = \begin{bmatrix} -2 & -4 & 2 \ -2 & 1 & 2 \ 4 & 2 & 5 \end{bmatrix}$$
Can you write Python code for it?


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
This also works because $v$ is truly a row vector, so we have $1\times2$ times $2\times2$ and all is good:
Can you write Python code for it?


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
This quantity is the same as the norm squared:
Can you write Python code for it?


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
This works and is the correct product even if $v$ is not really a column vector:
Can you write Python code for it?


I am working on the file "Foundations/Math/linear-algebra_exercise.ipynb".
The first task is:
We can't compute the determinant for $B$ and $C$ since they are not square matrices.
10 - Construct a square ($2\times2$) matrix, $\textbf{D}$,that is not invertible.
Can you write Python code for it?


I am working on the file "Foundations/Python CS/Activity 02.ipynb".
The first task is:
Approximate root under $1 \times 10^{-6}$ tolerance
Can you write Python code for it?

# Desired precision
prec = 1e-6
# Counter for number of iterations
n_iter = 0

# Initialize x_0 and x_1
x_0 = 3
x_1 = 6

while(True):

    # Update the number of iterations
    n_iter += 1

    # Compute x_mid
    x_mid = (x_0 + x_1) / 2

    # Compute f for the three values
    f_0 = x_0**3 - 6*x_0**2 + 4*x_0 + 12
    f_1 = x_1**3 - 6*x_1**2 + 4*x_1 + 12
    f_mid = x_mid**3 - 6*x_mid**2 + 4*x_mid + 12

    # Check the value of f_0*f_mid to determine how to update the endpoints
    if f_0*f_mid < 0:
        x_1 = x_mid
    else:
        x_0 = x_mid

    # Check if the desired precision is reached and break
    if abs(f_mid) < prec:
        break

print('Approximated root:', x_mid)
print('Number of iterations required:', n_iter)


I am working on the file "Foundations/Python CS/Activity 02.ipynb".
The first task is:
Exercise 02.2 (bisection)
Bisection is an iterative method for approximating roots of a function. Say we know that the function $f(x)$ has one root between $x_{0}$ and $x_{1}$ ($x_{0} < x_{1}$). We then:

Evaluate $f$ at the midpoint $x_{\rm mid} = (x_0 + x_1)/2$, i.e. compute
   $f_{\rm mid} = f(x_{\rm mid})$

Evaluate $f(x_0) \cdot f(x_{\rm mid})$

If $f(x_0) \cdot f(x_{\rm mid}) < 0$:
$f$ must change sign somewhere between $x_0$ and $x_{\rm mid}$, hence the root must lie between
$x_0$ and $x_{\rm mid}$, so set $x_1 = x_{\rm mid}$.

Else
$f$ must change sign somewhere between $x_{\rm mid}$ and $x_1$, so set
$x_0 = x_{\rm mid}$.

The above steps can be repeated a specified number of times, or until $|f_{\rm mid}|$
is below a tolerance, with $x_{\rm mid}$ being the approximate root.
Task: The function
$$
f(x) = x^3 - 6x^2 + 4x + 12
$$
has one root somewhere between $x_0 = 3$ and $x_1 = 6$.

Use the bisection method to find an approximate root $x_{r}$ using 15 iterations
   (use a for loop).
Use the bisection method to find an approximate root $x_{r}$ such that
   $\left| f(x_{r}) \right| < 1 \times 10^{-6}$ and report the number of iterations
   required (use a while loop).

Hint: Use  abs to compute the absolute value of a number, e.g. y = abs(x) assigns the absolute value of x to y.
Approximate root using 15 iterations
Can you write Python code for it?

# Number of iterations to do
n_iter = 15

# Initialize x_0 and x_1
x_0 = 3
x_1 = 6

for i in range(n_iter):

    # Compute x_mid
    x_mid = (x_0 + x_1) / 2

    # Compute f for the three values
    f_0 = x_0**3 - 6*x_0**2 + 4*x_0 + 12
    f_1 = x_1**3 - 6*x_1**2 + 4*x_1 + 12
    f_mid = x_mid**3 - 6*x_mid**2 + 4*x_mid + 12

    # Check the value of f_0*f_mid to determine how to update the endpoints
    if f_0*f_mid < 0:
        x_1 = x_mid
    else:
        x_0 = x_mid

print('Approximated root:', x_mid)


I am working on the file "Foundations/Python CS/Activity 02.ipynb".
The first task is:
Exercise 02.3 (series expansion)
The power series expansion for sine is:
$$
\sin(x) = \sum_{n = 0}^{\infty} (-1)^n \frac{x^{2n +1}}{(2n+1)!}
$$
(See mathematics data book for a less compact version; the compact version is preferred here as it is simpler to program.)

Using a for statement, approximate $\sin(3\pi/2)$ using 15 terms in the series exansion and report the absolute error.

Using a while statement, compute how many terms in the series are required to approximate $\sin(3\pi/2)$ to within $1 \times 10^{-8}$.

Note: Calculators and computers use iterative or series expansions to compute trigonometric functions, similar to the one above (although they use more efficient formulations than the above series).
Hints
To compute the factorial and to get a good approximation of $\pi$, use the Python math module:
python
import math
nfact = math.factorial(10)
pi = math.pi
You only need 'import math' once at the top of your program. Standard modules, like math will be explained in a later exercise. If you want to test for angles for which sine is not simple, you can use
python
a = 1.3
s = math.sin(a)
to get an accurate computation of sine to check the error.
Can you write Python code for it?

# Import math module to compute factorial and sine
import math


I am working on the file "Foundations/Python CS/Activity 02.ipynb".
The first task is:
Taylor series with 15 terms
Can you write Python code for it?

# Number of iterations to do
n_terms = 15

# Initialize x and its sine
x = 3*math.pi/2
sin_x = 0

for i in range(n_terms):

    # Add the next term to the summatory
    sin_x += (-1)**i * (x**(2*i+1) / math.factorial(2*i+1))

print('Calculated sine:', sin_x)
print('Absolute error:', abs(sin_x - math.sin(x)))


I am working on the file "Foundations/Python CS/Activity 03.ipynb".
The first task is:
Exercise 03.2
For the polynomial
\begin{align}
f(x, y) &= (x + y)^{6}
\
&=  x^6 + 6x^{5}y + 15x^{4}y^{2} + 20x^{3}y^{3} + 15x^{2}y^{4} + 6xy^{5} + y^{6}
\end{align}
compute $f$ using: (a) the compact form $(x + y)^{6}$; and (b) the expanded form for:

$x = 10$ and $y = 10.1$
$x = 10$ and $y = -10.1$

and compare the number of significant digits for which the answers are the same.
For the second case compare the computed and analytical solutions.
Which approach would you recommend for computing this expression?
I would choose the compact form since, containing less terms, it minimizes the possibility of errors due to the floating point representation of numbers
Can you write Python code for it?


I am working on the file "Foundations/Python CS/Activity 03.ipynb".
The first task is:
Exercise 03.3
Consider the expression
$$
f = \frac{1}{\sqrt{x^2 - 1} - x}
$$
When $x$ is very large, the denominator approaches zero, which can cause problems.
Try rephrasing the problem and eliminating the fraction by multiplying the numerator and denominator by $\sqrt{x^2 - 1} + x$ and evaluate the two versions of the expression when:

$x = 1 \times 10^{7}$
$x = 1 \times 10^{9}$ (You may get a Python error for this case. Why?)
Can you write Python code for it?

# Import math to compute square root
import math


I am working on the file "Foundations/Python CS/Activity 03.ipynb".
The first task is:
The expression obtained by multiplying the numerator and denominator by $\sqrt{x^2 - 1} + x$ is
$$
f = -\sqrt{x^2 - 1} - x.
$$
Let's try the first value $1 \times 10^{7}$
Can you write Python code for it?

# Initialize x
x = 1e7

# Compute the two expressions
f1 = 1 / (math.sqrt(x**2-1) - x)
f2 = -math.sqrt(x**2-1) - x

print('Result of the first expression:', f1, '\nResult of the second expression:', f2)


I am working on the file "Foundations/Python CS/Activity 04.ipynb".
The first task is:
Bisection algorithm function:
Can you write Python code for it?

def compute_root(f, x0, x1, tol, max_it):
    """Computes the root of f between x0 and x1 using bisection,
        stops if the value of f at the root is under tol or if max_it is reached
        and returns the root, the value of f at the root and the number of iterations"""
    for i in range(max_it):

        # Compute x_mid
        x_mid = (x0 + x1) / 2

        # Compute f for the three values
        f_0, f_1, f_mid = f(x0), f(x1), f(x_mid)

        # Check the value of f_0*f_mid to determine how to update the endpoints
        if f_0*f_mid < 0:
            x1 = x_mid
        else:
            x0 = x_mid

        # Check if f is under tol
        if abs(f_mid) < tol:
            return x_mid, f_mid, i+1

    # Return the approximate root in case max_it is reached
    return x_mid, f_mid, i+1

# Test for the function f
x, f_x, num_it = compute_root(f, x0=3, x1=6, tol=1.0e-6, max_it=1000)

print('Approximate root:', x)
print('Value of f:', f_x)
print('Number of iterations:', num_it)

print('-----------------------------------------------------------')

x, f_x, num_it = compute_root(f, x0=-7, x1=0, tol=1.0e-6, max_it=1000)

print('Approximate root:', x)
print('Value of f:', f_x)
print('Number of iterations:', num_it)


I am working on the file "Foundations/Python CS/Activity 04.ipynb".
The first task is:
Exercise 04.1 (simple function)
Write a function called is_odd which takes an integer as an argument and returns True if the argument is odd, otherwise returns False. Test your function for several values.
Can you write Python code for it?

def is_odd(n):
    "Check if n is odd"
    # Check if n is divisible by 2
    if n%2 == 0:
        return False
    else:
        return True

# Test the function for integers from 0 to 10
for i in range(11):
    print('Is', i, 'odd?', is_odd(i))


I am working on the file "Foundations/Python CS/Activity 04.ipynb".
The first task is:
Exercise 04.2 (functions and default arguments)
Write a single function that takes the components of a vector of length 2 or 3 and returns the magnitude.
Use default arguments to handle vectors of length 2 or 3 with the same code. Test your function for correctness against hand calculations for a selection of values.
Can you write Python code for it?

def magnitude(x, y, z=0):
    "Calculate the length of a 2 or 3-dimensional vector"
    return math.sqrt(x**2 + y**2 + z**2)

# Test some cases
print(magnitude(0, 0)) # 0
print(magnitude(1, 1)) # square root of 2
print(magnitude(3, 4)) # 5
print(magnitude(3, 4, 5)) # 7.07106...


I am working on the file "Foundations/Python CS/Activity 04.ipynb".
The first task is:
Exercise 04.3 (functions)
Given the coordinates of the vertices of a triangle, $(x_0, y_0)$, $(x_1, y_1)$ and $(x_2, y_2)$, the area $A$ of a triangle is given by:
$$
A = \left| \frac{x_0(y_1  - y_2) + x_1(y_2 - y_0) + x_2(y_0 - y_1)}{2} \right|
$$
Write a function that computes the area of a triangle given the coordinates of the vertices.
Test the output of your function against some known solutions.
Can you write Python code for it?

def area(x0, y0, x1, y1, x2, y2):
    "Calculate the area of a triangle given the vertices coordinates"
    return abs((x0*(y1-y2) + x1*(y2-y0) + x2*(y0-y1)) / 2)

# Test some cases
print(area(0, 0, 1, 0, 0, 1)) # 0.5
print(area(0, 0, 5, 0, 0, 8)) # 20


I am working on the file "Foundations/Python CS/Activity 04.ipynb".
The first task is:
Exercise 04.5 (functions and passing functions as arguments)
Restructure your program from the bisection exercise in Activity 02 to

Use a Python function to evaluate the mathematical function $f$ that we want to find the root of;

and then

Encapsulate the bisection algorithm inside a Python function, which takes as arguments:
the function we want to find the roots of,
the points $x_{0}$ and $x_{1}$ between which we want to search for a root,
the tolerance for exiting the bisection algorithm (exit when $|f(x)| < \text{tol}$)
maximum number of iterations (the algorithm should exit once this limit is reached)

For the first step, use a function for evaluating $f$, e.g.:
def f(x):
    # Put body of the function f(x) here, and return the function value

For the second step, encapsulate the bisection algorithm in a function:
def compute_root(f, x0, x1, tol, max_it):
    # Implement bisection algorithm here, and return when tolerance is satisfied or
    # number of iterations exceeds max_it

    # Return the approximate root, value of f(x) and the number of iterations
    return x, f, num_it

# Compute approximate root of the function f
x, f_x, num_it = compute_root(f, x0=3, x1=6, tol=1.0e-6, max_it=1000)

Try testing your program for a different function. A quadratic function, whose roots you can analytically, would be a good test case.
Function for evaluating $f$.
Note that this method does not work for functions tanget to the $x$ axis, such as $x^2 - 8x + 16 = (x - 4)^2$.
Can you write Python code for it?


I am working on the file "Foundations/Python CS/Activity 05.ipynb".
The first task is:
Using the above as a guide, examine the compression efficiency of

Compressing one large string made up of the passage by Shakespeare repeated 100 times; and
Compressing a random string of the same length as the repeated Shakespeare passage.

To help you, the below function generates a random string of length N:
Can you write Python code for it?

import random
import string

def random_string(N):
    return ''.join([random.choice(string.ascii_letters + string.digits) for n in range(N)])

print(random_string(8))

def compression_efficiency(string):
    "Calculate the compression efficiency obtained applying zlib.compress"
    # Convert Python string to bytes
    text_bytes = string.encode('utf-8')

    # Compress string
    text_comp = zlib.compress(text_bytes)

    # Calculate the compression efficiency
    return len(text_comp)/len(text_bytes)

# Comparison of compression efficiency (the smaller the better)
print('Compression efficiency for Shakespeare\'s passage repeated 100 times:', compression_efficiency(text*100))
print('Compression efficiency for a random string of the same length:', compression_efficiency(random_string(len(text)*100)))


I am working on the file "Foundations/Python CS/Activity 06.ipynb".
The first task is:
Find the college with the greatest number of students and print the abbreviation
Can you write Python code for it?

# Initialize the result
more_students = ''
# Initialize the variable that keeps track of the max number of students
n_students = 0

# Iterate over the colleges in the dict
for coll, data in colleges_ext.items():
    # If the number of students of the current college is greater than n_students
    # update n_students with the current number and more_students with the current college name
    if data['students'] > n_students:
        more_students, n_students = coll, data['students']

# Print the college with more_students
print('The college with more students is', more_students)


I am working on the file "Foundations/Python CS/Activity 06.ipynb".
The first task is:
Find the oldest college, and print the number of students and the abbreviation for this college
Can you write Python code for it?

# Initialize the result
out = [0, '']
# Initialize the variable that keeps track of the oldest year found to an arbitrary large year
year = 2500

for coll, data in colleges_ext.items():
    # If the year of foundation of the current college is lesser than year
    # update year with the current number and out with the current college number of students and abbreviation
    if data['year'] < year:
        out, year = [data['students'], data['abbreviation']], data['year']

# Print the oldest college number of students and name
print('{} is the oldest college and it has {} students'.format(out[1], out[0]))


I am working on the file "Foundations/Python CS/Activity 06.ipynb".
The first task is:
Optional (advanced): Try writing a one-line version of this operation using list comprehension and the built-in function zip.
Can you write Python code for it?

def add_vec2(x, y):
    "Sum two vectors of arbitrary length using list comprehension"
    # Check if the vectors have the same length
    if len(x) == len(y):
        # Create a new list summing the two vectors element-wise
        return [a + b for a, b in zip(x, y)]
    else:
        return 'The two vectors must have the same size'

# Test cases
print(add_vec2((1, 4), (2, -3)))
print(add_vec2((1, 4), (2, -3, 1))) # Error message
print(add_vec2((1, 4, -5, 9), (2, -3, 1, 7)))


I am working on the file "Foundations/Python CS/Activity 06.ipynb".
The first task is:
Optional extension: Create a dictionary that maps college names (the key) to dictionaries of:

College abbreviation
Year of foundation
Total number students

For at least 5 colleges. Take the data from https://en.wikipedia.org/wiki/Colleges_of_the_University_of_Cambridge#Colleges. Using this dictionary,

Find the college with the greatest number of students and print the abbreviation; and
Find the oldest college, and print the number of students and the abbreviation for this college.
Can you write Python code for it?

# Colleges dictionary with additional info
colleges_ext = {'Christ\'s':{'abbreviation':'CHR', 'year':1505, 'students':541}
                , 'Churchill':{'abbreviation':'CHU', 'year':1960, 'students':704}
                , 'Clare':{'abbreviation':'CL', 'year':1326, 'students':655}
                , 'Clare Hall':{'abbreviation':'CLH', 'year':1966, 'students':155}
                , 'Corpus Christi':{'abbreviation':'CC', 'year':1352, 'students':467}
                , 'Darwin':{'abbreviation':'DAR', 'year':1964, 'students':674}
                , 'Downing':{'abbreviation':'DOW', 'year':1800, 'students':623}
                , 'Emmanuel':{'abbreviation':'EM', 'year':1584, 'students':750}
                , 'Fitzwilliam':{'abbreviation':'F', 'year':1869, 'students':688}
                , 'Girton':{'abbreviation':'G', 'year':1869, 'students':677}
               }


I am working on the file "Foundations/Python CS/Activity 07.ipynb".
The first task is:
Bottom right $2 \times 2$ block as a 2D sub-array
Can you write Python code for it?


I am working on the file "Foundations/Python CS/Activity 07.ipynb".
The first task is:
Exercise 07.4 (optional extension)
In a previous exercise you implemented the bisection algorithm to find approximate roots of a mathematical function. Use the SciPy bisection function optimize.bisect (http://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.optimize.bisect.html) to find roots of the mathematical function that was used in the previous exercise. Compare the results computed by SciPy and your program from the earlier exercise, and compare the computational time (using %time).
Can you write Python code for it?

def f(x):
    return x**3 - 6*x**2 + 4*x + 12
    #return x**2 + x - 20 # Roots = -5, 4

def compute_root(f, x0, x1, tol, max_it):
    """Computes the root of f between x0 and x1 using bisection,
        stops if the value of f at the root is under tol or if max_it is reached
        and returns the root, the value of f at the root and the number of iterations"""
    for i in range(max_it):

        # Compute x_mid
        x_mid = (x0 + x1) / 2

        # Compute f for the three values
        f_0, f_1, f_mid = f(x0), f(x1), f(x_mid)

        # Check the value of f_0*f_mid to determine how to update the endpoints
        if f_0*f_mid < 0:
            x1 = x_mid
        else:
            x0 = x_mid

        # Check if f is under tol
        if abs(f_mid) < tol:
            return x_mid, f_mid, i+1

    # Return the approximate root in case max_it is reached
    return x_mid, f_mid, i+1

# Test for the function f
%time x, f_x, num_it = compute_root(f, x0=3, x1=6, tol=1.0e-6, max_it=1000)

print('Approximate root:', x)
print('Value of f:', f_x)
print('Number of iterations:', num_it)


I am working on the file "Foundations/Python CS/Activity 07.ipynb".
The first task is:
First two rows as a 2D sub-array
Can you write Python code for it?


I am working on the file "Foundations/Python CS/Activity 07.ipynb".
The first task is:
Function that returns the maximum, minimum and mean of the raw scores as a dictionary
Can you write Python code for it?

def max_min_mean(scores):
    "Return a dictionary with max, min and mean score from a list of scores"
    out = {}
    out['min'] = scores.min()
    out['max'] = scores.max()
    out['mean'] = scores.mean()
    return out

print(max_min_mean(scores))


I am working on the file "Foundations/Python CS/Activity 07.ipynb".
The first task is:
Transpose of A
Can you write Python code for it?


I am working on the file "Foundations/Python CS/Activity 07.ipynb".
The first task is:
use array slicing to

Extract the third column as a 1D array
Extract the first two rows as a 2D sub-array
Extract the bottom-right $2 \times 2$ block as a 2D sub-array
Sum the last column

Print the results to the screen to check. Try to use array slicing such that your code would still work if the dimensions of A were enlarged.
Also, compute the tranpose of A (search online to find the function/syntax to do this).
Third column as a 1D array
Can you write Python code for it?


I am working on the file "Foundations/Python CS/Activity 08.ipynb".
The first task is:
Create a plot to represent crimes by year-month and category (not sure about order of the data in the dictionary):
Can you write Python code for it?

# Initialize figure setting size
plt.figure(figsize=(20,20))
# for each category in the above list create a dict of frequencies and plot it on a line
for category in categories:
    category_freq = {}
    for crime in all_crimes:
        if crime[2] == category:
            if crime[1] in category_freq:
                category_freq[crime[1]] += 1
            else:
                category_freq[crime[1]] = 1
    # Define values for x axis ticks
    x_values = np.arange(len(category_freq))
    # Create a plot using dict values (not sure if they are in the right order here...)
    plt.plot(x_values, list(category_freq.values()), '-o', label=category)
    # Add x axis values labels using keys
    plt.xticks(x_values, category_freq.keys(), rotation=90)

# Add legend, title and labels
plt.legend()
plt.title('Crime categories in time')
plt.xlabel('Month')
plt.ylabel('Number of Crimes');


I am working on the file "Foundations/Python CS/Activity 08.ipynb".
The first task is:
Exercise 08.1 (function plotting)
Consider the function
$$
f(x) = e^{x/10} \sin(\omega_{1}x)\cos(\omega_{0}x)
$$
from $x = -4\pi$ to $x = 4\pi$.

Plot the function when $\omega_{0} = \omega_{1} = 1$. Label the axes.
Create an interactive plot with sliders for $\omega_{0}$ and $\omega_{1}$, varying from 0 to 2.

Plot for $\omega_0 = \omega_1 = 1$:
Can you write Python code for it?

def function_plot(ω0=1, ω1=1):
    # Define x axis range
    x = np.linspace(-4*np.pi, 4*np.pi, 100)
    # Add labels to x and y axis
    plt.xlabel('$x$')
    plt.ylabel('$\exp(x/10) \cdot \sin(\omega_{1}x) \cdot \cos(\omega_{0}x)$')
    # Limit x axis between start and end point of the range
    plt.xlim(x[0], x[-1])
    # Add a title
    plt.title('Plot of $f$ for $ω_0 = {}$ and $ω_1 = {}$'.format(ω0, ω1))
    # Plot the function
    plt.plot(x, np.exp(x/10) * np.sin(ω1*x) * np.cos(ω0*x))

plot()


I am working on the file "Foundations/Python CS/Activity 08.ipynb".
The first task is:
Exercise 08.2 (multiple function plotting)

Plot the function

$$
   f(x)  = \frac{\sin(x)}{x}
   $$
from $x = -6\pi$ to $x = 6\pi$. Think carefully about which $x$ values you use when
   $x$ is close to zero.

Add to the above plot the graph of $1/ \left| x \right|$, and limit the range of the $y$ axis to 1 using
   plt.ylim. (Hint: use np.abs(x) to return the absolute values of each
   component of a NumPy array x.

Plot of $\sin(x) / x$ between $-6\pi$ and $6\pi$:
Can you write Python code for it?

# Define x axis range using an even number of points to avoid division by 0
x = np.linspace(-6*np.pi, 6*np.pi, 100)
# Add labels to x and y axis
plt.xlabel('$x$')
plt.ylabel('$\sin(x)/x$')
# Limit x axis between start and end point of the range
plt.xlim(x[0], x[-1])
# Plot the function
plt.plot(x, np.sin(x)/x);


I am working on the file "Foundations/Python CS/Activity 08.ipynb".
The first task is:
Exercise 08.3 (demographics and interactive plotting)
A county planning body has requested an interactive tool to visualise the population distribution in Cambridgeshire (by district) from 2011 to 2021 for different population growth rate scenarios in each district. It can be assumed that:

the growth rates are constant in each district;
the growth rate will not be negative in any district; and
the annual growth rate in any one district will not exceed 10%.

Building on the pie chart example with population data in the body of the notebook, create an interactive plot with:

A slider for the year (from 2011 to 2021); and
Sliders for the annual population growth for each district (in percentage), with an
   initial value of zero for each district.
Can you write Python code for it?

def demographics_plot(year=2011, grCC=0, grEX=0, grFL=0, grHS=0, grSC=0):

    # Initialize district tuple, population and annual growth arrays
    district = ('Cambridge City', 'East Cambridgeshire', 'Fenland', 'Huntingdonshire',
                'South Cambridgeshire')
    population = np.array((123900, 83800, 95300, 169500, 148800))
    annual_growth = np.array((grCC, grEX, grFL, grHS, grSC))

    # Specify slice colours
    colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral', 'red']

    # Explode the 1st slice (Cambridge City)
    explode = (0.1, 0.0, 0, 0, 0)

    # Set figure size
    plt.figure(figsize=(10,10))

    # Plot pie chart using a linear annual growth in population
    plt.pie(population * (1 + (year-2011) * annual_growth / 100), explode=explode, labels=district, colors=colors,
            autopct='%1.1f%%', shadow=True, startangle=90)

    # Add title
    plt.title('{} population distribution in Cambridgeshire'.format(year))

# Add sliders for the annual growth of each district
interact(demographics_plot,
         year=(2011, 2021, 1),
         grCC=(0, 10, 0.1),
         grEX=(0, 10, 0.1),
         grFL=(0, 10, 0.1),
         grHS=(0, 10, 0.1),
         grSC=(0, 10, 0.1));


I am working on the file "Foundations/Python CS/Activity 08.ipynb".
The first task is:
Exercise 08.4 (crime reports by location)
Background
Your task is to produce a crime report data plot in the neighborhood of your college, by reported crime
category. It will be interesting to see how this varies between colleges!
We can get crime data in the UK from the police data systems using what is known as a REST API,
and turn the data into a list of Python dictionaries. Each entry in the list is a police report
(an entry is a Python dictionary detailing the report).
The first step is the import the modules we will be using:
Can you write Python code for it?


I am working on the file "Foundations/Python CS/Activity 08.ipynb".
The first task is:
Run your program for different parts of Cambridge, starting with the area around your college, and for different months and years.
Hints:
Create an empty dictionary, which will eventually map the report category to the number of incidents:
Can you write Python code for it?


I am working on the file "Foundations/Python CS/Activity 08.ipynb".
The first task is:
Task
Produce a bar chart of the number of reports in different categories. The categories are:
Can you write Python code for it?

categories = ('anti-social-behaviour', 'bicycle-theft', 'burglary', 'criminal-damage-arson', \
              'drugs', 'other-crime', 'other-theft', 'public-order', 'shoplifting', \
              'theft-from-the-person', 'vehicle-crime', 'violent-crime')


I am working on the file "Foundations/Python CS/Activity 08.ipynb".
The first task is:
The following converts the fetched data into a list of dictionaries:
Can you write Python code for it?


I am working on the file "Foundations/Python CS/Activity 08.ipynb".
The first task is:
The service https://data.police.uk has an interface where we can add specific strings to the URL (web address) to define what data we are intersted in, and the police server will return our requested data. The format is
https://data.police.uk/api/crimes-street/all-crime?poly=[LAT0],[LON0]:[LAT1],[LON1]:[LAT2,LON2]&date=YYYY-MM

This return crimes reports in the triangle given by the three geographic coordinate points (latitude0, longitude0), (latitude1, longitude1) and (latitude2, longitude2), for the month YYY-MM.
Below we create this URL string to include a large part of the Cambridge city centre. You can modify this for your own college or other area of interest (Google Maps is a handy way to get the geographic coordinates).
Can you write Python code for it?

# A triangle that includes most of the Cambridge city centre
# (long, lat) for three vertices of a triangle (no spaces!)
p0 = '52.211546,0.116465'
p1 = '52.203510,0.145500'
p2 = '52.189730,0.113050'

# year-month of interest
year_month = '2016-05'

# Construct request URL string using the above data
url = 'https://data.police.uk/api/crimes-street/all-crime?poly=' + p0 + ':' + p1 + ':' + p2 + '&date=' + year_month

# Fetch data from https://data.police.uk
r = requests.get(url)


I am working on the file "Foundations/Python CS/Activity 08.ipynb".
The first task is:
This function retrieves data from the UK police URL and returns it in a json; the default parameters for the coordinates are that of Cambridge used above:
Can you write Python code for it?

def get_crime_data(year_month, p0='52.211546,0.116465', p1='52.203510,0.145500', p2='52.189730,0.113050'):
    "Get the crime data for a given year and month (in the format YYYY-MM) and coordinates"
    # Construct request URL string using the above data
    url = 'https://data.police.uk/api/crimes-street/all-crime?poly=' + p0 + ':' + p1 + ':' + p2 + '&date=' + year_month
    # Fetch data from https://data.police.uk
    r = requests.get(url)

    return r.json()

def crime_plot(year_month, p0='52.211546,0.116465', p1='52.203510,0.145500', p2='52.189730,0.113050'):
    "Plot the crime data on a barplot for a given year and month (in the format YYYY-MM) and coordinates"
    # Get the crime data
    crime_data = get_crime_data(year_month, p0, p1, p2)
    # Initialize a dict for crime category frequencies
    categories_freq = {}
    # Count the frequencies
    for crime in crime_data:
        curr_category = crime['category']
        if curr_category in categories_freq:
            categories_freq[curr_category] += 1
        else:
            categories_freq[curr_category] = 1

    # Define values for x axis ticks
    x_values = np.arange(len(categories_freq))
    # Create barplot
    plt.bar(x_values, categories_freq.values(), align='center')
    # Add labels to x axis ticks
    plt.xticks(x_values, categories_freq.keys(), rotation=90)
    # Add axis labels
    #plt.xlabel('Crime Category')
    plt.ylabel('Number of Crimes')
    # Add title
    plt.title('Crimes in {}'.format(year_month))

# Test for a month
crime_plot('2017-01')


I am working on the file "Foundations/Python CS/Activity 08.ipynb".
The first task is:
When adding the tick labels (crime categories), it may be necessary to rotate the labels, e.g.:
python
plt.xticks(x_pos, categories, rotation='vertical')
Extensions (optional)

Probe the retrieved data to build a set of all crime categories in the data set.
Explore the temporal (time) aspect of the data. Thinks of ways to represent the change in reported incident
   types over time.

Create a list containing all crimes in a given period:
Can you write Python code for it?

# Initialize the starting year and month and the number of months to retrieve
start_year, start_month, num_months = 2016, 1, 6
# Initialize an empty list for all crimes
all_crimes = []
#crime_freq = {}

for unused in range(num_months):
    # For every month in range get crime data
    crime_data = get_crime_data(str(start_year) + '-' + str(start_month))

    # Append every crime retrieved to the list of all crimes
    for crime in crime_data:
        all_crimes.append([crime['id'], crime['month'], crime['category']])

    # Update month and year
    start_month += 1
    if start_month % 13 == 0:
        start_month = 1
        start_year += 1


I am working on the file "Foundations/Python CS/Activity 09.ipynb".
The first task is:
Exercise 09.1 (checking data validity)
The Fibonacci series is valid only for $n \ge 0$. Add to the Fibonacci function in this notebook a check that raises an exception if $n < 0$. Try some invalid data cases to check that an exception is raised.
Optional: Use pytest to test that an exception is raised for some $n < 0$ cases.
Can you write Python code for it?

def f(n):
    "Compute the nth Fibonacci number using recursion"
    if n < 0:
        # Raise error if n is less than 0
        raise ValueError('Fibonacci number can be calculated only for n greater than or equal to 0')
    if n == 0:
        return 0  # This doesn't call f, so it breaks out of the recursion loop
    elif n == 1:
        return 1  # This doesn't call f, so it breaks out of the recursion loop
    else:
        return f(n - 1) + f(n - 2)  # This calls f for n-1 and n-2 (recursion), and returns the sum

# Test cases
print(f(4))
print(f(-1))


I am working on the file "Foundations/Python CS/Activity 09.ipynb".
The first task is:
Test exceptions with pytest:
Can you write Python code for it?

def f(n):
    "Compute the nth Fibonacci number using recursion"
    if n < 0:
        # Raise error if n is less than 0
        raise ValueError('Fibonacci number can be calculated only for n greater than or equal to 0')
    if n == 0:
        return 0  # This doesn't call f, so it breaks out of the recursion loop
    elif n == 1:
        return 1  # This doesn't call f, so it breaks out of the recursion loop
    else:
        return f(n - 1) + f(n - 2)  # This calls f for n-1 and n-2 (recursion), and returns the sum

# Check that n < 0 raises a ValueError
with pytest.raises(ValueError):
    f(-1)
with pytest.raises(ValueError):
    f(-12)
with pytest.raises(ValueError):
    f(-20)


I am working on the file "Foundations/Python CS/Activity 10.ipynb".
The first task is:
Also on a list with a million element it seems faster, I guess it's because sorting is less efficient than just iterating over all elements (which is linear...):
Can you write Python code for it?

# Test and timing the two functions on a random number list
x = np.random.rand(1000000)
%time a = min_max(x)
%time b = min_max_ordered(x)
print(a)
print(b)


I am working on the file "Foundations/Python CS/Activity 10.ipynb".
The first task is:
Exercise 10.1 (search)
We want to find a find the largest and smallest values in a long list of numbers. Implement
two algorithms, based on:

Iterating over the list entries; and
First applying a built-in sort operation to the list.

Encapsulate each algorithm in a function, e.g.
python
def min_max(x);
    # Implement your algorithm here
    return x_min, xmax
To create lists of numbers for testing use, for example:
python
x = np.random.rand(1000)
Can you write Python code for it?

def min_max(x):
    "Return min and max of a list iterating over all elements"
    # Initialize min and max to the first element
    x_min, x_max = x[0], x[0]

    # For each element update min or max if it is less or greater than the current min or max
    for el in x:
        if el < x_min:
            x_min = el
        if el > x_max:
            x_max = el

    return x_min, x_max

# Test cases
print(min_max([1]))
print(min_max([1, 5, 0, 234, -548]))

def min_max_ordered(x):
    "Return min and max of a list sorting the list first"
    # Sort the list
    sorted_x = sorted(x)
    # Return first and last element
    return sorted_x[0], sorted_x[-1]

# Test cases
print(min_max_ordered([1]))
print(min_max_ordered([1, 5, 0, 234, -548]))


I am working on the file "Foundations/Python CS/Activity 10.ipynb".
The first task is:
Exercise 10.2 (Newton's method for root finding)
Newton's method can be used to find a root $x$ of a function $f(x)$ such that
$$
f(x) = 0
$$
A Taylor series expansion of $f$ about $x_{i}$ reads:
$$
f(x_{i+1}) = f(x_{i}) + \left. f^{\prime} \right|{x{i}} (x_{i+1} - x_{i}) +  O((x_{i+1} - x_{i})^{2})
$$
If we neglect the higher-order terms and set $f(x_{i+1})$ to zero, we have Newton's method:
\begin{align}
x_{i + 1} &= - \frac{f(x_{i})}{f^{\prime}(x_{i})} + x_{i}
\
x_{i} &\leftarrow x_{i+1}
\end{align}
In Newton's method, the above is applied iteratively until $\left|f(x_{i + 1})\right|$ is below a tolerance value.
Develop an implementation of Newton's method, with the following three functions in your implementation:
```python
def newton(f, df, x0, tol, max_it):
    # Implement here
return x1  # return root

where `x0` is the initial guess, `tol` is the stopping tolerance, `max_it` is the maximum number
of iterations, andpython
def f(x):
    # Evaluate function at x and return value
def df(x):
    # Evaluate df/dx at x and return value
```
Your implementation should raise an exception if the maximum number of iterations (max_it)
is exceeded.
Use your program to find the roots of:
$$
f(x) = \tan(x) - 2x
$$
between $-\pi/2$ and $\pi/2$. Plot $f(x)$ and $f^{\prime}(x)$ and on the same graph,
and show the roots computed by Newton's method.
Newton's method can be sensitive to the starting value. Make sure you find the root around $x = 1.2$. What happens if you start at $x = 0.9$? It may help to add a print statement in the iteration loop, showing $x$ and $f$ at each iteration.
Extension (optional)
For a complicated function we might not know how to compute the derivative, or it may be very complicated
to evaluate. Write a function that computes the numerical derivative of $f(x)$ by evaluating
$(f(x + dx) - f(x - dx)) / (2dx)$, where $dx$ is small. How should you choose $dx$?
Function for which we want to find a root:
Can you write Python code for it?

def f(x):
    # Evaluate function at x and return value
    return np.tan(x) - 2*x


I am working on the file "Foundations/Python CS/Activity 10.ipynb".
The first task is:
Here's Newton's method implementation:
Can you write Python code for it?

def newton(f, df, x0, tol, max_it):
    """Calculate a root of f using Newton's method starting at x0.
        The function stops if the tolerance tol is reached or raises an error if max_it is exceeded"""
    # Initialize iterations counter to 1 and x1 to x0
    i, x1 = 1, x0

    while i <= max_it:
        # Uncomment this to check the values calculated by the method
        #print(x1, f(x1))
        # Update x1
        x1 = -f(x1)/df(x1) + x1
        # Check if we are under the tolerance and return
        if np.abs(f(x1)) < tol:
            return x1
        # Update the counter
        i += 1

    # Raise an error if max_it is exceeded
    raise RuntimeError('Maximum number of iterations exceeded')

# Test cases
x1, x2, x3 = -1.2, 0, 1.2
sol1 = newton(f, df, x1, 1e-6, 100)
sol2 = newton(f, df, x2, 1e-6, 100)
sol3 = newton(f, df, x3, 1e-6, 100)

print('The solutions of f are {:.5f}, {:.5f} and {:.5f}'.format(sol1, sol2, sol3))


I am working on the file "Foundations/Python CS/Activity 10.ipynb".
The first task is:
Now let's plot $f$, its derivative and the solutions found by Newton's method:
Can you write Python code for it?

# Values for the x axis
x = np.linspace(-np.pi/2 + 0.1, np.pi/2 - 0.1, 100)
# Set the limits for the y axis
plt.ylim(-4, 4)

# Plot f
plt.plot(x, f(x))

# Plot the roots found by Newton's method
plt.plot(sol1, f(sol1), 'xr')
plt.plot(sol2, f(sol2), 'xr')
plt.plot(sol3, f(sol3), 'xr');


I am working on the file "Foundations/Python CS/Activity 10.ipynb".
The first task is:
The default dx is chosen because it seems a good value, smaller and bigger scaling diverge from a good approximation for $f$:
Can you write Python code for it?

print(df(1.2))
print(numerical_derivative(f, 1.2))
print(numerical_derivative(f, 1.2, 1e-5))
print(numerical_derivative(f, 1.2, 1e-4))
print(numerical_derivative(f, 1.2, 1e-7))
print(numerical_derivative(f, 1.2, 1e-8))


I am working on the file "Foundations/Python CS/Activity 10.ipynb".
The first task is:
The task is to write a function that applies a particular low-pass filter algorithm to an image array and
returns the
filtered image. With this particular filter, the value of a pixel in the filtered image is equal to the average value
of the four neighbouring pixels in the original image. For the [i, j, :] pixel, the neighbours are
[i, j+1, :], [i, j-1, :], [i+1, j, :] and  [i-1, j, :].
Run the filter algorithm multiple times on the above image to explore the effect of the filter.
Hint: To create a NumPy array of zeros, B,  with the same shape as array A, use:
python
import numpy as np
B = np.zeros_like(A)
Can you write Python code for it?

def low_pass_filter(img):
    "Apply a filter on an image taking the mean of the neighbouring pixels"
    # Initialize the return array
    B = np.zeros_like(img)

    # Iterate over all pixels in a row
    for i in range(0,np.shape(img)[0]):
        # Iterate over all pixels in a column
        for j in range(0,np.shape(img)[1]):

            if j == 0:
                # First column and first row -> no i-1, j-1 terms
                if i == 0:
                    B[i, j] = (img[i, j+1, :] + img[i+1, j, :]) / 2
                # First column and last row -> no i+1, j-1 terms
                elif i == np.shape(img)[0] - 1:
                    B[i, j] = (img[i, j+1, :] + img[i-1, j, :]) / 2
                # First column, other rows -> no j-1 term
                else:
                    B[i, j] = (img[i, j+1, :] + img[i+1, j, :] + img[i-1, j, :]) / 3

            elif i == 0:
                # First row and last column -> no i-1, j+1 terms
                if j == np.shape(img)[1] - 1:
                    B[i, j] = (img[i, j-1, :] + img[i+1, j, :]) / 2
                # First row, other columns -> no i-1 term
                else:
                    B[i, j] = (img[i, j+1, :] + img[i, j-1, :] + img[i+1, j, :]) / 3

            elif j == np.shape(img)[1] - 1:
                # Last column and last row -> no i+1, j+1 terms
                if i == np.shape(img)[0] - 1:
                    B[i, j] = (img[i, j-1, :] + img[i-1, j, :]) / 2
                # Last column, other rows -> no j+1 term
                else:
                    B[i, j] = (img[i, j-1, :] + img[i+1, j, :] + img[i-1, j, :]) / 3

            # Last row, other columns -> no i+1 term
            elif i == np.shape(img)[0] - 1:
                B[i, j] = (img[i, j+1, :] + img[i, j-1, :] + img[i-1, j, :]) / 3

            # All other cases
            else:
                B[i, j] = (img[i, j+1, :] + img[i, j-1, :] + img[i+1, j, :] + img[i-1, j, :]) / 4

    return B

# Test the filter applying it 10 times
filtered = img

for unused in...


I am working on the file "Foundations/Python CS/Activity 10.ipynb".
The first task is:
This is a function to calculate the numerical derivative of $f$:
Can you write Python code for it?

def numerical_derivative(f, x, dx=1e-6):
    "Calculate the derivative of f using numerical approximation"
    return (f(x+dx) - f(x-dx)) / (2*dx)

# Test cases
print(df(1.2))
print(numerical_derivative(f, 1.2))


I am working on the file "Foundations/Python CS/Activity 10.ipynb".
The first task is:
This is a more clear (to me) version of the same program which is faster because it doesn't require all the iterations:
Can you write Python code for it?

def low_pass_filter2(img):

    # Initialize the return array
    B = np.zeros_like(img)

    # All elements except first and last row and column
    B[1:-1, 1:-1, :] = (img[1:-1, 0:-2, :] # i, j-1
                        + img[0:-2, 1:-1, :] # i-1, j
                        + img[1:-1, 2:, :] # i, j+1
                        + img[2:, 1:-1, :]) / 4 # i+1, j

    # First row but not first or last column
    B[0, 1:-1, :] = (img[0, 0:-2, :] # i, j-1
                        + img[0, 2:, :] # i, j+1
                        + img[1, 1:-1, :]) / 3 # i+1, j

    # Last row but not first or last column
    B[-1, 1:-1, :] = (img[-1, 0:-2, :] # i, j-1
                        + img[-2, 1:-1, :] # i-1, j
                        + img[-1, 2:, :]) / 3 # i, j+1

    # First column but not first or last row
    B[1:-1, 0, :] = (img[0:-2, 0, :] # i-1, j
                        + img[1:-1, 1, :] # i, j+1
                        + img[2:, 0, :]) / 3 # i+1, j

    # Last column but not first or last row
    B[1:-1, -1, :] = (img[1:-1, -2, :] # i, j-1
                        + img[0:-2, -1, :] # i-1, j
                        + img[2:, -1, :]) / 3 # i+1, j

    # First row and first column
    B[0, 0, :] = (img[0, 1, :] # i, j+1
                        + img[1, 0, :]) / 2 # i+1, j

    # First row and last column
    B[0, -1, :] = (img[0, -2, :] # i, j-1
                        + img[1, -1, :]) / 2 # i+1, j

    # Last row and first column
    B[-1, 0, :] = (img[-2, 0, :] # i-1, j
                        + img[-1, 1, :]) / 2 # i, j+1

    # Last row and last column
    B[-1, -1, :] = (img[-1, -2, :] # i, j-1
                        + img[-2, -1, :]) / 2 # i-1, j

    return B

# Test the filter applying it 10 times
filtered2 = img

for unused in range(10):
    filtered2 = low_pass_filter2(filtered)

# Display the original image and the filtered one
plt.figure(figsize=(10,10))
plt.imshow(img);
plt.figure(figsize=(10,10))
plt.imshow(filtered2);


I am working on the file "Foundations/Python CS/Activity 10.ipynb".
The first task is:
Timing the functions, it seems that the function that iterates over all the elements is faster for a list with a 1000 elements:
Can you write Python code for it?

# Test and timing the two functions on a random number list
x = np.random.rand(1000)
%time a = min_max(x)
%time b = min_max_ordered(x)
print(a)
print(b)


I am working on the file "Foundations/Python CS/Activity 10.ipynb".
The first task is:
Using 0.9 as the starting value the method diverges:
Can you write Python code for it?

print('Solution of f using 0.9 as the starting value:', newton(f, df, 0.9, 1e-6, 100))


I am working on the file "Foundations/Python CS/Activity 10.ipynb".
The first task is:
and its derivative:
Can you write Python code for it?

def df(x):
    # Evaluate df/dx at x and return value
    return (1 / np.cos(x)**2) - 2


I am working on the file "Foundations/Python CS/Activity 11.ipynb".
The first task is:
$O(n^2)$ seems a good fit, to see it better let's try again with powers of 10:
Can you write Python code for it?

# Test dimensions
N = 10**np.arange(1, 5)

# Initialize times vectors
times = []

# Time executions for each dimension
for n in N:
    A = np.random.rand(n, n)
    t1 = %timeit -q -n4 -r1 -o np.linalg.slogdet(A)
    times.append(t1.best)

print(N)
print(times)

# Plot and label the time taken
plt.loglog(N, times, marker='o', label='Matrix determinant')
plt.xlabel('$n$')
plt.ylabel('$t$ (s)')

# Show a reference line of O(n^2)
plt.loglog(N, 1e-6*np.array(N)**2, label='$O(n^2)$')

# Add legend
plt.legend(loc=0);


I am working on the file "Foundations/Python CS/Activity 11.ipynb".
The first task is:
Exercise 11.1
Determine by operating counting the complexity of:

Dot product between two vectors
Matrix-vector product
Matrix-matrix product

for vectors of length $n$ and matrices of size $n \times n$. (This is a reasoning exercise - you do not need to write a program.)
Optional
Test the complexity experimentally with your own functions for performing the operations, and
with the NumPy 'vectorised' equivalents.

Dot product between two vectors of length $n$: we have to iterate through all elements of the vectors, so the complexity is $O(n)$
Matrix-vector product between a vector of length $n$ and a $n \times n$ matrix: to obtain an element of the product we have to multiply each row of the matrix with the vector, which is like doing $n$ times a dot product; therefore the complexity is $O(n^2)$
Matrix-matrix product between $n \times n$ matrices: the $(i,j)$-th element of the product is the dot product between the $i$-th row of the first matrix and the $j$-th column of the second one; since we have $n^2$ elements in the product the complexity is $O(n^3)$

Functions for calculating dot product and matrix-vector/matrix-matrix product for experimentally determine the complexity:
Can you write Python code for it?

def dot_product(A, B):
    "Compute the dot product between two vectors of equal length,"
    # Check if A and B are vectors
    if len(np.shape(A)) == 1 and len(np.shape(B)) == 1:
        # Check if A and B have the same length
        if len(A) == len(B):
            # Initialize product
            P = 0
            # Calculate dot product iterating over each element
            for i in range(len(A)):
                P += A[i]*B[i]
        else:
            raise ValueError('Vectors must be of the same length')
    else:
        raise ValueError('A and B must be vectors')

    return P

def product(A, B):
    """Compute the product between two numpy arrays:
        A and B can be a matrix of size (m,n) and a vector of length n
        or two matrices of size, respectively, (m,l) and (l,n)"""
    # Matrix-vector case
    if len(np.shape(A)) == 2 and len(np.shape(B)) == 1:
        # Check if the number of columns of A is equal to the number of elements of B
        if np.shape(A)[1] == len(B):
            # Initialize the product
            P = np.zeros(len(B))
            #Calculate product iterating over the rows of A and using dot_product function
            for i in range(np.shape(A)[0]):
                P[i] = dot_product(A[i], B)
        else:
            raise ValueError('The number of columns of A must equal the length of B')

    # Matrix-matrix case
    elif len(np.shape(A)) == 2 and len(np.shape(B)) == 2:
        # Check if the number of columns of A is equal to the number of rows of B
        if np.shape(A)[1] == np.shape(B)[0]:
            # Initialize the product
            P = np.zeros((np.shape(A)[0], np.shape(B)[1]))
            # Calculate product iterating over the rows of A and columns of B and using dot_product function
            for i in range(np.shape(A)[0]):
                for j in range(np.shape(B)[1]):
                    P[i, j] = dot_product(A[i], B[j])
        else:
            raise ValueError('The number of columns of A must equal the number of rows of B')
   ...


I am working on the file "Foundations/Python CS/Activity 11.ipynb".
The first task is:
Exercise 11.2
For the recursive factorial algorithm in Activity 04, determine the algorithmic complexity by inspecting your implementation of the algorithm. Test this against numerical experiments.
The recursive implementation calls the function n times, in each call it computes a product so the complexity should be $O(n)$
Can you write Python code for it?

def fact(n):
    "Calculate factorial recursively"
    if n == 0:
        return 1
    else:
        return n*fact(n-1)

# Test cases
print('Calculated factorial:',fact(5))


I am working on the file "Foundations/Python CS/Activity 11.ipynb".
The first task is:
Let's test this using some numerical examples:
Can you write Python code for it?

# Test cases
N = (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2056)

# Initialize times vectors
times = []

# Increase the limit on recursion
import sys
sys.setrecursionlimit(25000)

# Time executions for each n
for n in N:
    t1 = %timeit -q -n4 -r1 -o fact(n)
    times.append(t1.best)


I am working on the file "Foundations/Python CS/Activity 11.ipynb".
The first task is:
Plot the results:
Can you write Python code for it?

# Plot and label the time taken
plt.loglog(N, times, marker='o', label='Recursive factorial')
plt.xlabel('$n$')
plt.ylabel('$t$ (s)')

# Show a reference line of O(n)
plt.loglog(N, 1e-6*np.array(N), label='$O(n)$')

# Add legend
plt.legend(loc=0);


I am working on the file "Foundations/Python CS/Activity 11.ipynb".
The first task is:
and the determinant can be computed by:
Can you write Python code for it?


I am working on the file "Foundations/Python CS/Activity 12.ipynb".
The first task is:
Exercise 12.2

Create a class for holding a student record entry. It should have the following attributes:
Surname
Forename
Birth year
Tripos year
College
CRSid (optional field)
Equip your class with the method 'age' that returns the age of the student

Equip your class with the method '__repr__' such using print on a student record displays with the format
Surname: Bloggs, Forename: Andrea, College: Churchill

Equip your class with the method __lt__(self, other) so that a list of record entries can be sorted by
   (surname, forename). Create a list of entries and test the sorting. Make sure you have two entries with the same
   surname.

Hint: To get the current year:
Can you write Python code for it?

import datetime
year = datetime.date.today().year
print(year)

class Students:
    # We have 6 attributes, CRSid is optional (default value set to None)
    def __init__(self, surname, forename, birthYear, triposYear, college, CRSid = None):
        self.surname = surname
        self.forename = forename
        self.birthYear = birthYear
        self.triposYear = triposYear
        self.college = college
        self.CRSid = CRSid

    def __repr__(self):
        "Print the student in the format Surname: surname, Forename: forename, College: college"
        return 'Surname: {}, Forename: {}, College: {}'.format(self.surname, self.forename, self.college)

    def age(self):
        "Return the age of the student subtracting the year of birth from the current year"
        return datetime.date.today().year - self.birthYear

    def __lt__(self, other):
        """Return true if a student's surname is before (in alphabetical order) another student's surname;
            if the surnames are equal do the same with the forenames"""
        if self.surname == other.surname:
            return self.forename < other.forename
        else:
            return self.surname < other.surname

# Test cases
stud0 = Students('Bella' ,'Zio', 1987, 2011, 'Università degli Studi di Torino')
stud1 = Students('Nano' ,'Gongolo', 1985, 2008, 'Università degli Studi di Torino')
stud2 = Students('Nano' ,'Dotto', 1984, 2008, 'Università degli Studi di Torino')
stud3 = Students('Casto' ,'Immanuel', 1988, 2011, 'Università degli Studi di Torino')
stud4 = Students('Ciavarro' ,'Massimo', 1983, 2006, 'Università degli Studi di Torino')

print(stud0)
print(stud0.age()) # 30
print(stud0 < stud1) # True
print(stud1 < stud0) # False
print(stud2 < stud1) # True

students_list = [stud0, stud1, stud2, stud3, stud4]
print('List:')
print(students_list)
print('Sorted list:')
students_list.sort()
print(students_list)


I am working on the file "Four-way_interaction_coordinates_and_total_n-way_interaction.ipynb".
The first task is:
The latter 110 in the four_way_from_ranking call corresponds to u.
The output is a pair of truth values corresponding to the positive and negative interaction, respectively.
In the example above, the output means that the rank order implies positive interaction.
Total n-way interaction
To detect whether your rank order implies total n-way interaction, run function total_n_way_interaction on the rank order given by a list in binary format.
Example: To detect whether the rank order
00001 > 00010 > 00011 > 00100 > 00101 > 00110 > 00111 > 01000 >
01001 > 01010 > 01011 > 01100 > 01101 > 01110 > 01111 > 10000 >
10001 > 10010 > 10011 > 10100 > 10101 > 10110 > 10111 > 11000 >
11001 > 11010 > 11011 > 11100 > 11101 > 11110 > 11111 > 00000
implies total 5-way interaction, run the following:
Can you write Python code for it?


I am working on the file "Four-way_interaction_coordinates_and_total_n-way_interaction.ipynb".
The first task is:
The output is a pair of truth values corresponding to the positive and negative interaction, respectively.
In the example above, the output means that the rank order implies negative interaction.
Both False would mean that the rank order does not imply interaction.
Plasmodium vivax dihydrofolate reducatase (DHFR)
Here we analyze the DHFR data from (Ogbunugafor and Hartl 2016, Table S3).
The index i in variable ranking_i corresponds to the drug concentration.
Can you write Python code for it?

ranking_9 = [1111, 1110, 1010, 100, 1000, 1100, 111, 110, 101, 11, 1001, 10, 1101, 1011, 1, 0]

u_0011 = four_way_from_ranking(ranking_9, 11)
print(u_0011)

u_0101 = four_way_from_ranking(ranking_9, 101)
print(u_0101)

u_0110 = four_way_from_ranking(ranking_9, 110)
print(u_0110)

u_1001 = four_way_from_ranking(ranking_9, 1001)
print(u_1001)

u_1010 = four_way_from_ranking(ranking_9, 1010)
print(u_1010)

u_1100 = four_way_from_ranking(ranking_9, 1100)
print(u_1100)

u_1110 = four_way_from_ranking(ranking_9, 1110)
print(u_1110)

u_1101 = four_way_from_ranking(ranking_9, 1101)
print(u_1101)

u_0111 = four_way_from_ranking(ranking_9, 111)
print(u_0111)

u_1011 = four_way_from_ranking(ranking_9, 1011)
print(u_1011)

u_1111 = four_way_from_ranking(ranking_9, 1111)
print(u_1111)

ranking_8 = [1111, 1110, 1010, 111, 110, 11, 100, 1000, 1100, 10, 101, 1001, 1011, 1101, 1, 0]

u_0011 = four_way_from_ranking(ranking_8, 11)
print(u_0011)

u_0101 = four_way_from_ranking(ranking_8, 101)
print(u_0101)

u_0110 = four_way_from_ranking(ranking_8, 110)
print(u_0110)

u_1001 = four_way_from_ranking(ranking_8, 1001)
print(u_1001)

u_1010 = four_way_from_ranking(ranking_8, 1010)
print(u_1010)

u_1100 = four_way_from_ranking(ranking_8, 1100)
print(u_1100)

u_1110 = four_way_from_ranking(ranking_8, 1110)
print(u_1110)

u_1101 = four_way_from_ranking(ranking_8, 1101)
print(u_1101)

u_0111 = four_way_from_ranking(ranking_8, 111)
print(u_0111)

u_1011 = four_way_from_ranking(ranking_8, 1011)
print(u_1011)

u_1111 = four_way_from_ranking(ranking_8, 1111)
print(u_1111)

ranking_7 = [1111, 111, 1110, 1010, 11, 1011, 110, 1000, 10, 1100, 101, 1001, 1101, 100, 1, 0]

u_0011 = four_way_from_ranking(ranking_7, 11)
print(u_0011)

u_0101 = four_way_from_ranking(ranking_7, 101)
print(u_0101)

u_0110 = four_way_from_ranking(ranking_7, 110)
print(u_0110)

u_1001 = four_way_from_ranking(ranking_7, 1001)
print(u_1001)

u_1010 = four_way_from_ranking(ranking_7, 1010)
print(u_1010)

u_1100 = four_way_from_ranking(ranking_7, 1100)
print(u_1100)

u_1110...


I am working on the file "Fourier.ipynb".
The first task is:
Start by creating a function to generate a superimposed sine wave function:
Can you write Python code for it?


I am working on the file "Fourier/Tarea_Fourier/Ciclo.Solar.ipynb".
The first task is:
Análisis
De la grafica de amplitudes, conforme la frecuencia  se aleja del cero, se observa un maximo aproximadamente en $f\approx0.09$, el cual siguiendo la formula $$T=\frac{1}{f}$$
Se obtiene un periodo de $T\approx 11.11 [years]$ el cual es concordante con el ciclo de actividad solar medido por medio de las manchas solares, el cual tiene una duracion de aproximadamente 11 años.
Mejore la resolución en el espectro de frecuencias
Can you write Python code for it?

yinv=y[::-1] #Invertir el orden de los datos del arreglo
yinv=yinv[1:]  #Eliminar primer elemento del nuevo arreglo
yinv=yinv[:-1] #Eliminar ultimo elemento del nuevo arreglo

yf=[]
k=0
while k<50: #Ciclo while para meter en un arreglo los valores de la señal, la inversa de la señal en el tiempo el numero que deseemos repertila
    for i in range(0,len(y)):
        yf.append(y[i])#Señal
    #print len(data3)
    for i in range(0,len(yinv)):#Señal invertida en el tiempo
        yf.append(yinv[i])
    k+=1

dy = 1
t1 = np.arange(0,len(yf),dy)

fty2 = np.fft.fftshift(np.fft.fft(np.fft.fftshift(yf)))*dy
v = np.arange(-1/(2*dy),1/(2*dy),1/(dy*t1.size))
ti = 0
tf =0.1

plt.figure(figsize=(16,8))
plt.plot(v,abs(fty2)**(1/4),marker='.',color='blue',linewidth=1,markersize=6)
plt.plot((0, 0.1), (5.5, 5.5), 'r-')
plt.title('More Resolution FT Radiation cycles of the Sun', fontsize=24)
plt.xlabel('Freq.', fontsize=18)
plt.ylabel('Amp', fontsize=18)
plt.xlim(ti,tf)
plt.grid()


I am working on the file "Fourier/Tarea_Fourier/Ciclo.Solar.ipynb".
The first task is:
Lectura y grafica de los datos de 'TSI2.tx'
Can you write Python code for it?

x,y = np.loadtxt('TSI2.txt', usecols=[0,1], dtype='float', unpack='True',delimiter=None)

plt.figure(figsize=(16,8))
plt.plot(x,y,marker='.',color='blue',linewidth=1,markersize=6)
plt.title('Radiation cycles of the Sun', fontsize=24)
plt.xlabel('years', fontsize=18)
plt.ylabel('Radiation [w/m²]', fontsize=18)
plt.grid()


I am working on the file "Fourier/Tarea_Fourier/FT-2D.ipynb".
The first task is:
Interpretación de la FT de una imagen
Una imagen se puede entender como la superpocisión de funciones armónicas (senos y cocenos) bidimensionales de diferentes frecuencias y direcciónes. La FT me dará información de los senos y cocenos que se necesitan (en términos de su frecuencia, dirección y amplitud) para formar la imagen.
Formemos primero una imagen correspondiente a un seno en la dirección horizontal
Can you write Python code for it?

tam = 256 # tamaño matriz
dx = 0.01 # resolución (m/pixel)
x = np.arange(-dx*tam/2,dx*tam/2,dx) # coordenadas espaciales
X , Y = np.meshgrid(x,x) # espacio bidimensional

A1 = 1. # amplitud en unidades arbitrarias
f1 = 1. # frecuencia espacial (1/m)
g1 = A1*np.sin(2*np.pi*f1*X) # Imagen en el espacio "espacial"

ftg1 = np.fft.fftshift(np.fft.fft2(np.fft.fftshift(g1)))*dx**2 # Transformada de Fourier, espacio frecuencial

plt.figure(figsize=(15,15))
plt.subplot(1,2,1)
plt.imshow(abs(g1), cmap='gray')
plt.title('Espacio espacial')
plt.subplot(1,2,2)
plt.imshow(abs(ftg1), cmap='gray')
plt.title('Amplitud espacio frecuencial')


I am working on the file "Fourier/Tarea_Fourier/FT-2D.ipynb".
The first task is:
Note que solo aparecen aproximadamente dos deltas de Dirac en el espacio frecuencial. De forma análoga al caso unidimensional esos dos puntos corresponden a la frecuencia del seno en el espacio espacial. Note también que los puntos salen en la dirección horizontal, indicando que la dirección del seno bidimensional es horizontal.
Finalmente, observe que en el centro de la imagen está el centro del origen (para matrices cuadradas esto no es del todo exacto), mientras que la posición (0,0) de la matriz está en la esquina superior-izquierda.
Ahora, grafiquemos la superposición de un seno horizontal y uno vertical de la misma frecuencia
Can you write Python code for it?

tam = 256 # tamaño matriz
dx = 0.01 # resolución (m/pixel)
x = np.arange(-dx*tam/2,dx*tam/2,dx) # coordenadas espaciales
X , Y = np.meshgrid(x,x) # espacio bidimensional

A1 = 1. # amplitud en unidades arbitrarias
f1 = 1. # frecuencia espacial (1/m)
gx = A1*np.sin(2*np.pi*f1*X) # Seno en la dirección horizontal
gy = A1*np.sin(2*np.pi*f1*Y) # Seno en la dirección vertical

g = gx + gy # Superposición

ftg = np.fft.fftshift(np.fft.fft2(np.fft.fftshift(g)))*dx**2 # Transformada de Fourier, espacio frecuencial

plt.figure(figsize=(15,15))
plt.subplot(1,2,1)
plt.imshow(g, cmap='gray')
plt.title('Espacio espacial')
plt.subplot(1,2,2)
plt.imshow(abs(ftg), cmap='gray')
plt.title('Amplitud espacio frecuencial')


I am working on the file "Fourier/Tarea_Fourier/FT-2D.ipynb".
The first task is:
Observe que ahora aparecen unas deltas en la dirección vertical que dan cuenta del seno en la dirección vertical.
Hagamos un último ejemplo incluyendo un coseno en la dirección diagonal que tiene una amplidut dos veces superior a los otros senos. Además, el seno en la dirección horizontal tiene una frecuencia dos veces mayor al coceno, y el seno en la dirección vertical 4 veces mayor.
Can you write Python code for it?

tam = 256 # tamaño matriz
dx = 0.01 # resolución (m/pixel)
x = np.arange(-dx*tam/2,dx*tam/2,dx) # coordenadas espaciales
X , Y = np.meshgrid(x,x) # espacio bidimensional

A1 = 1. # amplitud en unidades arbitrarias
f1 = 1. # frecuencia espacial (1/m)
gx = A1*np.sin(2*np.pi*2*f1*X) # Seno en la dirección horizontal
gy = A1*np.sin(2*np.pi*4*f1*Y) # Seno en la dirección vertical
gd = 2*A1*np.cos(2*np.pi*f1*(X + Y)) # CCoceno en la dirección diagonal

g = gx + gy + gd # Superposición

ftg = np.fft.fftshift(np.fft.fft2(np.fft.fftshift(g)))*dx**2 # Transformada de Fourier, espacio frecuencial

plt.figure(figsize=(15,15))
plt.subplot(1,2,1)
plt.imshow(g, cmap='gray')
plt.title('Espacio espacial')
plt.subplot(1,2,2)
plt.imshow(abs(ftg), cmap='gray')
plt.title('Amplitud espacio frecuencial')


I am working on the file "FourierSeries.ipynb".
The first task is:
Fourier Sine Series of $x(1-x)$
The previous series converges extremely slowly due to the discontinuities at the end-points and that $f(x)=1$ does not share the same boundary conditions as the eigenfunctions $\phi_n(x)=\sin(n\pi x)$ which are zero at the boundaries.  For $C^2$ functions that share the same boundary conditions, however,  Fourier Series can converge quite quickly. Here we will calculate the Fourier Sine series of the parabola $f(x) = x(1-x)$ on the interval $[0,1]$ which satisfies these conditions.
The Fourier coefficients for this function are
$$
    a_n = 2\int_0^1 (x - x^2) sin(n\pi x) dx = \frac{8}{n^3\pi^3}
$$
for $n$ odd.  These can be found relatively easily by successive integration by parts (Homework).
So the Fourier Sine series of $f$ is
$$
    x(1-x) = \sum_{n-odd}^\infty \frac{8}{(n\pi)^3} \sin(n\pi x)
$$
Can you write Python code for it?

x = np.linspace(0,1,1000)

# small python function to define the partial sum for the truncated Fourier Series f_N
def f_N(x,N):
    na = range(1,N+1,2)
    f_N = np.zeros(x.shape)
    for n in na:
        f_N += 8./(n*np.pi)**3*np.sin(n*np.pi*x)
    return f_N

# And make a figure showing f_N for increasing values of N
Na = [ 1, 3, 5, 11, 101]

plt.figure()
for N in Na:
    plt.plot(x,f_N(x,N),label='N={}'.format(N))
plt.plot(x,x*(1-x),'k',label='$f(x)=x(1-x)$')
plt.xlabel('x')
plt.legend(loc='best')
plt.grid()
plt.show()


I am working on the file "FourierSeries.ipynb".
The first task is:
Fun with Fourier Series
GOAL: visualize some basic behavior of Fourier Series
Fourier Sine Series of 1
Here we will calculate the Fourier Sine series on the interval $[0,1]$ as
$$
    1 = \sum_{n-odd}^\infty \frac{4}{n\pi} \sin(n\pi x)
$$
Can you write Python code for it?

x = np.linspace(0,1,1000)

# small python function to define the partial sum for the truncated Fourier Series f_N
def f_N(x,N):
    na = range(1,N+1,2)
    f_N = np.zeros(x.shape)
    for n in na:
        f_N += 4./(n*np.pi)*np.sin(n*np.pi*x)
    return f_N

# And make a figure showing f_N for increasing values of N
Na = [ 1, 3, 5, 11, 101]

plt.figure()
for N in Na:
    plt.plot(x,f_N(x,N),label='N={}'.format(N))
plt.plot(x,np.ones(x.shape),'k',label='$f(x)=1$')
plt.xlabel('x')
plt.legend(loc='best')
plt.grid()
plt.show()


I am working on the file "FourierSeriesApproximation.ipynb".
The first task is:
We separate the matrix into the sin and cos coeff list
Can you write Python code for it?

n_ = int(len(coeff) / 2)
sin_coeff = coeff[:n_]
cos_coeff = coeff[n_:]


I am working on the file "FourierSeriesApproximation.ipynb".
The first task is:
the QR decomposition
Can you write Python code for it?


I am working on the file "FourierSeriesApproximation.ipynb".
The first task is:
we choose the number of armonichs that we want in this case 50 but $ n \in [1,N)$ where $N$ is len(f)
Can you write Python code for it?


I am working on the file "FourierSeriesApproximation.ipynb".
The first task is:
we convert to $c$ and $\phi$ and now we have all the coefficent ready to go
Can you write Python code for it?

mag = np.sqrt(cos_coeff**2+sin_coeff**2)
phi = np.arctan2(sin_coeff,cos_coeff)


I am working on the file "FourierSeriesApproximation.ipynb".
The first task is:
we solve the system and get the coeff vector
Can you write Python code for it?

coeff = linalg.solve_triangular(R, (np.dot(Q.transpose(), y)))
# coeff = linalg.solve_triangular(R, (np.dot(Q.transpose(), y)),check_finite=False) Alternative way


I am working on the file "FourierSeriesApproximation.ipynb".
The first task is:
we start with f that is a sawthoot wave
Can you write Python code for it?

f = np.linspace(0,1,100)
f = np.concatenate((f,f,f,f))

T = np.linspace( 0, 2 * np.pi, num=len(f), endpoint=True) - np.pi

plt.plot(T,f)
plt.show()


I am working on the file "FourierSeriesApproximation.ipynb".
The first task is:
we transforme the array into a coloumn vector
Can you write Python code for it?

x = np.matrix(T).transpose()
y = np.matrix(f).transpose()


I am working on the file "FourierTest.ipynb".
The first task is:
Call to learn number $n$ has available or calculates (maybe):
| math    | code | explanation
|---------|------|-----------------
| $o_{n-1}$ | po | The observation passed in call $n-1$.
| $r_{n-1}$ | pr | The reward passed in call $n-1$.
| $a_{n-1}$ | pa | The action returned call $n-1$.
| $\theta_{n-1}$ | | The weights as updated in call $n-1$.
| $Q_{\theta_{n-1}}(o_{n-1}, a_{n-1})$ | pQpopa |
| $r_n$   | r | The reward passed in call $n$
| $o_n$   | o | The observation passed in call $n$
| $a_n$   | a | The action that will be returned in call $n$
| $\hat{a}n$ | ga | The action that a greedy policy would return in call $n$.
| $Q{\theta_{n-1}}(o_n, a_n)$ |pQoa |
There is no equivalent for $\theta_{n-1}$ and $\theta_n$ in the code, because $\theta$ gets updated in-place by the optimizer. So before the update, theta is $\theta_{n-1}$ and after the update it's $\theta_n$.
Can you write Python code for it?

pQpopa = Qfunc(po, pa)
pQoa = Qfunc(o, a)
loss = tf.mul(tf.sub(pQpopa, tf.add(r, Qpa)), elig)
optimizer = tf.train.GradientDescentOptimizer(learning_rate=alpha)
update_model = optimizer.minimze(loss)

sess = tf.Session()

5


I am working on the file "FourierTest.ipynb".
The first task is:
I'm reimplementing my current version of Sarsa(λ) in hiora_cartpole.linfa. That was based on Sutton & Barto 10/2015, p. 211. The 09/2016 draft is quite different for some reason I don't understand at a glance.
Can you write Python code for it?

env = gym.make("CartPole-v1")

high = np.array([2.5, 4.4, 0.28, 3.9])
state_ranges = np.array([-high, high])
order = 3

state = tf.placeholder(tf.float64, high[None,:].shape)

n_dims = state_ranges.shape[1]
n_entries = (order + 1)**n_dims
intervals = np.diff(state_ranges, axis=0)

# All entries from cartesian product {0, …, order+1}^n_dims.
c_matrix = np.array(
               list( itertools.product(range(order+1), repeat=n_dims) ),
               dtype=np.int32)

C = tf.constant(c_matrix, dtype=tf.float64)
LOW = tf.constant(-high)
INTERVALS = tf.constant(intervals)
PI = tf.constant(np.pi, dtype=tf.float64)

def phi(o):
    """

    o: a placeholder
    """
    nc_o = tf.div( tf.subtract(o, LOW) , INTERVALS) # normalized, centered
    return tf.cos( tf.mul(PI, tf.matmul(C, tf.transpose(nc_o))) )


I am working on the file "FourierTest.ipynb".
The first task is:
Need to be able to get the value for one action separately.
Can you write Python code for it?

tQall = tf.matmul(vtheta, tf.transpose(phi(to)))
tQga = tf.max(tQall)
tga = tf.argmax(tQall)


I am working on the file "FourierTransforms/FourierTransforms.ipynb".
The first task is:
As we see, above is the fourier transform of the input image.
Now let us try and see if we can reconstruct the original image, by performing Inverse fourier transform on the above obtained image in the Fourier domain.
Part B.
Inverse Fourier Transform
Can you write Python code for it?

idft_rep = two_dim_inv_fourier_transform(dft_rep)
plot_input(np.abs(idft_rep), 'Inverse Fourier Image')


I am working on the file "FourierTransforms/FourierTransforms.ipynb".
The first task is:
As we see, the image obtained by performing the inverse fourier transform of the obtained fourier image, is very similar to the input image.
But let us compute the Mean Squared Error(MSE) between the original image and the reconstructed image, to verify that the images are identical or not.
Part C.
Computing the Mean Squared Error(MSE)
Can you write Python code for it?

min_sq_error = min_sqr_err(img, np.abs(idft_rep))
print "Mean squared Error between the reconstructed and original image: ", min_sq_error


I am working on the file "FourierTransforms/FourierTransforms.ipynb".
The first task is:
Let us begin the solution by loading an input image. Since the computation of Fourier transform is extremely memory intensive, we choose a very small image (40 x 40 pixels) as input testing image.
Can you write Python code for it?

img = cv2.imread('./fb_test.jpg', 0)
img = preprocess_odd_images(img)
plot_input(img,'Input image')

# Details of the input image
M, N = img.shape[:2]
print M,N


I am working on the file "FourierTransforms/FourierTransforms.ipynb".
The first task is:
The above libraries are necessary for reading image, performing array and matrix operations, visualising the output plots and for handling complex numbers generated by the fourier transform.
Next, we shall define all the necessary functions for solving the given problem.
Can you write Python code for it?

# Function to perform 2-D Discrete Fourier transform on a given image(matrix) of size M x N.
def two_dim_fourier_transform(img):
    M, N = img.shape[:2]
    dft_rep = [[0.0 for k in range(M)] for l in range(N)]
    for k in range(M):
        for l in range(N):
            temp_sum = 0.0
            for m in range(M):
                for n in range(N):
                    e = cmath.exp(- 1j * 2 * cmath.pi * (float(k * m) / M + float(l * n) / N))
                    temp_sum += img[m][n] * e
            dft_rep[l][k] = temp_sum
    return dft_rep

# Function to perform 2-D Inverse Fourier Transform on a given Fourier image matrix.
def two_dim_inv_fourier_transform(fourier):
    M = len(fourier)
    N = len(fourier[0])
    idft_rep = [[0.0 for k in range(M)] for l in range(N)]
    for k in range(M):
        for l in range(N):
            temp_sum = 0.0
            for m in range(M):
                for n in range(N):
                    e = cmath.exp(1j * 2 * cmath.pi * (float(k * m) / M + float(l * n) / N))
                    temp_sum += fourier[m][n] * e
            idft_rep[l][k] = temp_sum/(M*N)
    return idft_rep

# Function to centre the obtained Fourier transform image. Since Fourier transform is periodic, we can represent
# by relocating the centre of the image for better representation.(Analogous to fftshift)
def img_preprocess_centred_fourier(img):
    M, N = img.shape[:2]
    processed_img = np.zeros((M,N))
    for x in range(M/2):
        for y in range(N/2):
            processed_img[x][y] = img[M/2 + x][N/2 + y]
    for x in range(M/2+1, M):
        for y in range(N/2+1, N):
            processed_img[x][y] = img[x - M/2 ][y - N/2]
    for x in range(M/2+1, M):
        for y in range(N/2):
            processed_img[x][y] = img[x - M/2][y + N/2]
    for x in range(M/2):
        for y in range(N/2+1, N/2):
            processed_img[x][y] = img[x + M/2][y - N/2]
    return processed_img

# If we have an odd sized image, we convert it into an even sized image.
def preprocess_odd_images(img):
    M,...


I am working on the file "Fourier_Optics/Fourier_Transform_PSF.ipynb".
The first task is:
FT
circular and square aperture
2D projection
Zernike polynomial, measuring ; only for circular symmetric pupil
Can you write Python code for it?

# Contour plot of the intensity projection on the image plane
plt.figure(figsize=(7, 6), dpi=80, facecolor='w', edgecolor='k')
ax = fig.add_subplot(111)
CS = plt.contourf(x, y, z,cmap=plt.get_cmap('gray'))
#plt.clabel(CS, inline=1, fontsize=10)
plt.title('log(PSF) of the Airy Disk')
ax.set_aspect('equal')
plt.colorbar()
plt.show()


I am working on the file "Fremont Bridge Analysis.ipynb".
The first task is:
Comparing with Day of Week
Can you write Python code for it?

dayofweek = pd.DatetimeIndex(pivoted.columns).dayofweek

plt.scatter(X2[:, 0], X2[:, 1], c=dayofweek, cmap='rainbow')
plt.colorbar();


I am working on the file "Fremont Bridge Analysis.ipynb".
The first task is:
Get Data
Can you write Python code for it?

data = get_data()
p = data.resample('W').sum().plot()
p.set_ylim(0, None);


I am working on the file "Fremont Bridge Analysis.ipynb".
The first task is:
Shows a graph of data on a weekly basis. Let's investigate what the pattern is when we look at hourly rates on individual days...
Pivot
Plot a hourly traffic rates for all days in data.
Can you write Python code for it?

pivoted = data.pivot_table('Total', index=data.index.time, columns=data.index.date)
pivoted.plot(legend=False, alpha=0.01);


I am working on the file "Fremont Bridge Analysis.ipynb".
The first task is:
Unsupervised Clustering
Can you write Python code for it?

gmm = GaussianMixture(2).fit(X)
labels = gmm.predict(X)

plt.scatter(X2[:, 0], X2[:, 1], c=labels, cmap='rainbow')
plt.colorbar();

fig, ax = plt.subplots(1, 2, figsize=(14, 6))

pivoted.T[labels == 0].T.plot(legend=False, alpha=0.1, ax=ax[0]);
pivoted.T[labels == 1].T.plot(legend=False, alpha=0.1, ax=ax[1]);

ax[0].set_title('Purple Cluster')
ax[1].set_title('Red Cluster');


I am working on the file "Fremont_bridge_analysis/UnsupervisedAnalysis.ipynb".
The first task is:
Analyzing Outliers
The following points are weekdays with a holiday-like pattern
Can you write Python code for it?

dates = pd.DatetimeIndex(pivoted.columns)

dates[(labels==1) & (dayofweek < 5)]


I am working on the file "Fremont_bridge_analysis/UnsupervisedAnalysis.ipynb".
The first task is:
Get Data
Can you write Python code for it?

from jupyterworkflow.data import get_fremont_data
df = get_fremont_data()

pivoted = df.pivot_table('Total', index=df.index.time, columns=df.index.date)
pivoted.plot(legend=False, alpha=0.02);

X = pivoted.fillna(0).T.values
X.shape


I am working on the file "Frequency_Domain_Error_index.ipynb".
The first task is:
And what about additive uniform white noise?
Can you write Python code for it?

sm3 = sm+(np.random.random(Ns)-0.5)
se3 = sm3-sc
FDE3 = FDEindex(sc, sm3)
RMS3 = rms(se3)
print('FDE index={:.2f}, RMS error={:.2f}'.format(FDE3, RMS3))
fig, ax = plt.subplots(1, 2, figsize=(12,4))
ax[0].plot(tt, sc, label='Computed')
ax[0].plot(tt, sm3, label='Measured')
ax[0].legend()
ax[0].grid(b=True)
ax[1].plot(tt, se3, label='Error')
ax[1].legend()
ax[1].grid(b=True)


I am working on the file "Frequency_Domain_Error_index.ipynb".
The first task is:
Helper functions:
Can you write Python code for it?

def rms(a, axis=None, dtype=None, out=None, keepdims=np._NoValue):
    """Compute the root mean square along the specified axis."""
    return np.sqrt(np.mean(np.square(a), axis=axis, dtype=dtype, out=out, keepdims=keepdims))


I am working on the file "Frequency_Domain_Error_index.ipynb".
The first task is:
Let us test the significance of this index in some simple but illustrative cases. First, consider two equal harmonic waves:
Can you write Python code for it?

Ns = 128
tt = np.arange(Ns)/Ns
Ac = 2.
fc = 2.
sc = Ac*(np.sin(2.*np.pi*fc*tt)+np.sin(2.*2.*np.pi*fc*tt))
sm = sc
se = sm-sc
FDE = FDEindex(sc, sm)
RMS = rms(se)
print('FDE index={:.2f}, RMS error={:.2f}'.format(FDE, RMS))
fig, ax = plt.subplots(1, 2, figsize=(12,4))
ax[0].plot(tt, sc, label='Computed')
ax[0].plot(tt, sm, label='Measured')
ax[0].legend()
ax[0].grid(b=True)
ax[1].plot(tt, se, label='Error')
ax[1].legend()
ax[1].grid(b=True)


I am working on the file "Frequency_Domain_Error_index.ipynb".
The first task is:
Naturally, the FDE index yields 0. Next, we will use the same harmonic waves but we will delay the measured by one sample:
Can you write Python code for it?

sm1 = np.roll(sc, 1)
se1 = sm1-sc
FDE1 = FDEindex(sc, sm1)
RMS1 = rms(se1)
print('FDE index={:.2f}, RMS error={:.2f}'.format(FDE1, RMS1))
fig, ax = plt.subplots(1, 2, figsize=(12,4))
ax[0].plot(tt, sc, label='Computed')
ax[0].plot(tt, sm1, label='Measured')
ax[0].legend()
ax[0].grid(b=True)
ax[1].plot(tt, se1, label='Error')
ax[1].legend()
ax[1].grid(b=True)


I am working on the file "Frequency_Domain_Error_index.ipynb".
The first task is:
So we see that the FDE index is indeed a good indicator for the error between the computed and measured signals, with more significance than the RMS since it is bound between zero and one.
Can you write Python code for it?

data = np.array(((FDE, RMS), (FDE1, RMS1), (FDE2, RMS2), (FDE3, RMS3)))
index = ('Equal', 'Delay 1', 'Times -1', 'Add UWN')
columns = ('FDE index', 'RMS error')
df = pd.DataFrame(data, index, columns)
print(df)


I am working on the file "Fresnel_reflection.ipynb".
The first task is:
Ellipsometric Angles
At this point, we can see how the ellipsometric angles behave.
First we define the ellipsometric angles by using the previously defined Fresnel coefficients and then some similar code for plotting and handling the interactivity as for the reflectivity before.
Can you write Python code for it?

def ellipsometricAngles(n1, n2, angle):
    rp = parallelFresnelCoefficient(n1, n2, angle)
    rs = perpendicularFresnelCoefficient(n1, n2, angle)
    psi = np.arctan(np.abs(rp)/np.abs(rs))*180/np.pi
    delta = np.angle(rp, deg=True)-np.angle(rs, deg=True)

    return psi, delta

psi, delta = ellipsometricAngles(1, 1.5, angle)
source1 = ColumnDataSource(data=dict(x=angle, y=psi))
#source2 = ColumnDataSource(data=dict(x=angle, y=delta))
ellipsometryPlot = figure(title="Psi and Delta", plot_height=300, plot_width=600, y_range=(0, 50), x_range=(0,90))
ellipsometryPlot.line(angle, psi, color="#2222aa", alpha=0.5, line_width=2, source=source1, name="1")
#ellipsometryPlot.line(angle, delta, color="#222222", alpha=0.5, line_width=2, source=source1, name="2")

def updateEllipsometryPlot(n1=1, k1=0, n2=1.5, k2=0):
    source1.data['y'] = ellipsometricAngles(n1+1j*k1, n2+1j*k2, angle)[0]
    #source2.data['y'] = ellipsometricAngles(n1+1j*k1, n2+1j*k2, angle)[1]
    push_notebook()

show(ellipsometryPlot, notebook_handle=True)

interact(updateEllipsometryPlot, n1=(1,5, 0.05), k1=(0, 2, 0.01), n2=(1,5, 0.05), k2=(0, 2, 0.01))


I am working on the file "Fresnel_reflection.ipynb".
The first task is:
Now, some imports to be able to plot and handle data
Can you write Python code for it?

from bokeh.io import output_notebook, show
from bokeh.plotting import figure
output_notebook()

from bokeh.io import push_notebook
from bokeh.models import ColumnDataSource

from ipywidgets import interact


I am working on the file "Fresnel_reflection.ipynb".
The first task is:
There we have the reflectivity. But it would be very interesting if we were able to interact and explore the behavior of the reflectivity given different index of refraction for the two media defining the interface.
We add interaction capability in the following.
Can you write Python code for it?

def updateReflectivityPlot(n1=1, k1=0, n2=1.5, k2=0):
    source1.data['y'] = perpendicularReflectivity(n1, k1, n2, k2, angle)
    source2.data['y'] = parallelReflectivity(n1, k1, n2, k2, angle)
    push_notebook()

interact(updateReflectivityPlot, n1=(1, 5, 0.05), k1=(0, 2, 0.01), n2=(1, 5, 0.05), k2=(0, 2, 0.01))


I am working on the file "Fresnel_reflection.ipynb".
The first task is:
To plot the reflectivities as a function of the angle of incidence we need to do some coding!
The starting point will be an interface defined by vacuum and a material with $n=1.5$ and no absorption.
Can you write Python code for it?

angle = np.arange(0, 90.5, 0.5)
Rs = perpendicularReflectivity(1, 0, 1.5, 0, angle)
Rp = parallelReflectivity(1, 0, 1.5, 0, angle)
source1 = ColumnDataSource(data=dict(x=angle, y=Rs))
source2 = ColumnDataSource(data=dict(x=angle, y=Rp))
reflectivityPlot = figure(title="Reflectivity", plot_height=300, plot_width=600, y_range=(0, 1), x_range=(0,90))
reflectivityPlot.line(angle, Rs, color="#2222aa", alpha=0.5, line_width=2, source=source1, name="1")
reflectivityPlot.line(angle, Rp, color="#222222", alpha=0.5, line_width=2, source=source2, name="2")
show(reflectivityPlot, notebook_handle=True)