Exercises#

::: {note} You don’t need to worry about using Interactive Jupyter Notebooks for these exercises. You can simply ignore the rocket icon () and go ahead to answer the questions using the knowledge you’ve gained from the chapter. Have fun! :::

Exercise 2.1.1#

In the code cell bellow you can see a function that finds the greatest common divisor of any two numbers using the math module.

import math

def find_greatest_common_divisor(a, b):
    greatest_common_divisor = math.gcds(a, b)
    return greatest_common_divisor

print('The greatest common divisor is:', find_greatest_common_divisor(2, 4))

(Searching) Exercise 2.1.2#

We can only take and store measurements at a limited number of locations and/or times. But what if we are interested in a value in between, i.e., at a location/time where we do not have a measurement? Then we can use interpolation to estimate that value. A popular, and simple, interpolation technique is linear interpolation. Your task is to use the module scipy to perform a 1D linear interpolation between a set of known points, where x_known and y_known are arrays with the measured $x$ and $y$ values. Use Google to look up the 1D interpolation function in scipy.

In the code below there is something missing after return (look the three dots). What should be the correct missing code for the function to give us the desired result?

from scipy import interpolate

def interpolate_inbetween(x_known, y_known, x_predict):
    f = interpolate.interp1d(x_known, y_known)
    return ...

(Searching) Exercise 2.1.3#

Now, let’s try to measure the running time of a function, for that we will need the time module. Use it to measure the working time of the cool_function() below.

# you do not need to change anything in this cell
def cool_function():
    x = 0
    for i in range(100000000):
        x += 1

Which of the following functions will give us the working time of the cool_function()?

  • Option A

def measure_time(func):
    t0 = time.time()
    t1 = time.time()
    return t1 - t0
  • Option B

def measure_time(func):
    t0 = time.time()
    func()
    t1 = time.time()
    return t1 - t0
  • Option C

def measure_time(func,t0,t1):
    t0 = time.time()
    func()
    t1 = time.time()
    return func

Exercise 2.2.1#

One of the most crucial applications of if statements is filtering the data from errors and checking whether an error is within a certain limit.

For example, checking whether the difference between an estimated value and the actual value are within a certain range.

Mathematically speaking, this can be expressed as $|\hat{y} - y| < \epsilon$

where $\hat{y}$ is your estimated value, $y$ is the actual value and $\epsilon$ is a certain error threshold.

The function check_error_size() below must do the same — it should return True if the error is within the acceptable range eps and False if it is not.

def check_error_size(estimated_value, true_value, eps):
    if abs(estimated_value - true_value) <= eps:
        return True

Exercise 2.2.2#

You have used the knowledge obtained to write your very own function to classify soil samples based on the average grain size.

def classify_soil(avg_grain_size):
    if avg_grain_size < 0.002:
        return 'Clay'
    elif avg_grain_size >= 0.002 and avg_grain_size < 0.063:
        return 'Silt'
    elif avg_grain_size >= 0.063 and avg_grain_size < 2:
        return 'Sand'
    elif avg_grain_size >= 2:
        return 'Gravel'

print(classify_soil(1.5))

(Searching) Exercise 2.2.4#

Conditional expression is a way how one can compress an if statement to a more compact (and logical) statement. Your task is to rewrite the below if statement by using the ’conditional expression’ technique.

y = 0
x = 5

if x % 2 == 0:
    y = x ** 2
else:
    y = x % 3

Exercise 2.4.1#

The function celsius_to_fahrenheit is not working properly, can you detect the error?

def celsius_to_fahrenheit(temp_celsius):
    temp_fahrenheit = 0
    for i in range(len(temp_celsius)):
        temp_fahrenheit.append(temp_celsius[i] * 9 / 5 + 32) 
    return temp_fahrenheit

temp_celsius = [-1, -1.2, 1.3, 6.4, 11.2, 14.8, 17.8, 17.7, 13.7, 8.5, 4.1, 0.9]
print(celsius_to_fahrenheit(temp_celsius))

Exercise 2.4.3#

Here you need to write a function that is able to sort any list consisting only of real numbers, in the descending order. For example, the list $[19, 5, 144, 6]$ becomes $[144, 19, 6, 5]$. However there are three possible options to complete correctly the code where the dots ... are placed.

def sort_list(unsorted_list):
    return sorted(unsorted_list)...

Exercise 2.4.5#

In this exercise you will perform downsampling of a provided ‘regular’ 2D list. Downsampling is a procedure where only a subset of the data is sampled (to reduce its size, for example). Below a visual aid of what downsampling of a 2D list is. Instead of using all the data available, your task is to downsample the 2D list to keep only the data of every $a$-th row and every $b$-th column, including the first element $(a_{0,0})$.

$$A = \left[\begin{array}{ccccc} a_{0,0} & \dots & a_{0,b} & \dots & a_{0,2b} & \dots & \dots & a_{0,nb} & \dots\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots\ a_{a,0} & \dots & a_{a,b} & \dots & a_{a,2b} & \dots & \dots & a_{a,nb} & \dots\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots\ a_{2a,0} & \dots & a_{2a,b} & \dots & a_{2a,2b} & \dots & \dots & a_{2a,nb} & \dots\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots\ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots\ a_{ma,0} & \dots & a_{ma,b} & \dots & a_{ma,2b} & \dots & \dots & a_{ma,nb} & \dots \ \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots & \vdots \end{array}\right]$$

Notice the ... you need to fill with the correct code. Additionally there are some errors in the functions can you detect the errors?

  • Option A


def downsample(data, a, b):
    downsample_data = [0]
    
    for i in range(len(data)):
        row = []
        # create a for loop over len(data[i]), which is the number of columns
        for ...
            if i % a == 0 and j % b == 0:
                row.append(data[i][j])
        if len(row) > 0:
            downsample_data.append(row)
            
    return downsample_data

  • Option B


def downsample(data, a, b):
    downsample_data = []

    for i in range(len(data)):
        row = []

        # create a for loop over len(data[i]), which is the number of columns
        for ...
            if i % a == 0 and j % b == 0:
                row.append(data[i][j])
        if len(row) > 0:
            downsample_data.append(row)
            
    return downsample_data
  • Option C


def downsample(data, a, b):
    downsample_data = 0
    
    for i in range(len(data)):
        row = []
        # create a for loop over len(data[i]), which is the number of columns
        for ...
            if i % a == 0 and j % b == 0:
                row.append(data[i][j])
        if len(row) > 0:
            downsample_data.append(row)
            
    return downsample_data