# Assignment 2

## Deadline: 1st Oct - 15:00 - After this time, don't change your notebook. It'll be automatically collected by CoCalc.

### We will use this assignment to simulate how a graded assignment works. On the deadline, we'll automatically collect your assignment and calculate the points. As an answer, you will receive a report showing the test cases where you succeeded and the final number of points. However, remember, as this is a non-graded assignment, those points won't count for your grade.

##### What to do if you get stuck with a task?
• Ask for help in the Monday session
• Ask for help in the Friday session
• Ask for help on the course forum
• Ask for help on Stack Overflow. Before asking there you should read the following links, or your question will probably be closed. There is a high chance you can find a solution for your problem in one of the many existing answers on the site.
Write code that prints the string 'Hello world'.
In [1]:
### BEGIN SOLUTION
print("Hello world")
### END SOLUTION

Hello world
##### How to read error messages and debug on CoCalc
There will be times when you see an error message because of something being wrong in your code.
###### This is completely normal!
A lot of the time when programming is spent fixing errors in the code or looking for more efficient solutions. So there will definitely be times during this course when you run into errors. But how can you understand and fix them?
In [1]:
number = 3 * 5
print(num)

--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-1-57dabf8ad525> in <module> 1 number = 3 * 5 ----> 2 print(num) NameError: name 'num' is not defined 

The cell above shows such an example. The stack trace / traceback is shown. The last line tells you that a NameError was encountered when your code was executed. We can check the Python documentation to see what this error means - link to the documentation: NameError - or we can read the message that is included with it: name 'number' is not defined.

Above the error we can see the code that caused the error. In this case the error happened in line 2. Based on the code in that line and the error message we can see that the variable $number$ was not defined. When we tried to print it the error happened. To fix it can we can rename the variable $num$ in line 1 to $number$ or change the $number$ in line 2 to $num$.

In [2]:
num = 3 * 5
print(num)

15
Define a variable s1.
In [8]:
### BEGIN SOLUTION
s1 = None
### END SOLUTION

In [9]:
# If you see no errors under this cell then your solution is correct!
# You don't have to do anything with the code in this cell. It's just here to check your answer.

from nose.tools import assert_true
assert_true("s1" in locals(), msg="You did not define a variable called 's1'.")
print("\x1b[6;30;42mSuccess!\x1b[0m")

Success! 

# The following cell contains an example of what you see when your solution is wrong.

Big red scary box = something is wrong!

This is just here as an example to show you what it looks like. You don't have to change the code in the box to make it work or anything.

Test your code from above here(0 points), ID: test_fail_example
In [3]:
from nose.tools import assert_true
assert_true(False)

--------------------------------------------------------------------------- AssertionError Traceback (most recent call last) <ipython-input-3-eedc3f8f4569> in <module> 1 from nose.tools import assert_true ----> 2 assert_true(False) /usr/lib/python3.8/unittest/case.py in assertTrue(self, expr, msg) 763 if not expr: 764 msg = self._formatMessage(msg, "%s is not true" % safe_repr(expr)) --> 765 raise self.failureException(msg) 766 767 def _formatMessage(self, msg, standardMsg): AssertionError: False is not true 

Here we see that the error is an AssertionError. The lower half of the stack trace shows us code that is called by the code that we have written. This useful when we are using code from other projects in our own projects. In this case we don't need it though.

The structure of the stack trace is that at the bottom it shows the line of code that caused the error, and then above that code block there can be more code blocks, with code that has caused the code in the lower block to be called.

In our example (from top to bottom): 'assert_true(False)' was executed in line 2, which caused the code in the lower half to be executed, where in line 765 an error happened.

The error further tells us that 'False is not true'. In the upper half we see that 'assert_true(False)' was executed in line 2. This means that the value inside 'assert_true()' should have been 'True' and not 'False'.

The tests that check your code will usually check that the value that your code calculated is the same as the correct answer. That way you can find out which value is wrong and by looking at your code then figure out why. Another example is given below.

In [10]:
# Task: Divide 'a' by 'b' and store the value in the variable 'c'.
a = 10
b = 5
c = 0

a / b  # Divide a by b (but we forget to store the value in 'c')

from nose.tools import assert_equal
assert_equal(c, 2)  # check that 'c' has the value 2

--------------------------------------------------------------------------- AssertionError Traceback (most recent call last) <ipython-input-10-6bf482eb6108> in <module> 7 8 from nose.tools import assert_equal ----> 9 assert_equal(c, 2) # check that 'c' has the value 2 /usr/lib/python3.8/unittest/case.py in assertEqual(self, first, second, msg) 910 """ 911 assertion_func = self._getAssertEqualityFunc(first, second) --> 912 assertion_func(first, second, msg=msg) 913 914 def assertNotEqual(self, first, second, msg=None): /usr/lib/python3.8/unittest/case.py in _baseAssertEqual(self, first, second, msg) 903 standardMsg = '%s != %s' % _common_shorten_repr(first, second) 904 msg = self._formatMessage(msg, standardMsg) --> 905 raise self.failureException(msg) 906 907 def assertEqual(self, first, second, msg=None): AssertionError: 0 != 2 

We get another 'AssertionError'. '0 != 2'. Again the lower half of the stack trace doesn't really help us. In the first block (from the top) we see our code, where we are checking that 'c' is equal to '2'. Because we get an 'AssertionError' we know that this is not the case, so 'c' is not equal to '2'. The error further tells us that apparently 'c' must be 0.

We can then look at our calculation code again and we see that we forgot to save the value of 'a / b' in the variable c! If we save the the value correctly in 'c' and run the cells again then the error will disappear, as our solution is now correct.

Play around with the code in the next cell and see how the error changes if you change the value for 'c'.

In [4]:
# This cell is here for you to experiment with how the test cases work
# This cell (the box that this text and the code are in) is not part of the assignment, it is just here so you can experiment easier.
# You can add your own cells if you want to experiment by moving your mouse to the upper "edge" of the cell (it should turn blue) and clicking
# This is useful when you want to try something!

# Task: Divide 'a' by 'b' and store the value in the variable 'c'.
a = 10
b = 5
c = 0

c = a / b  # Divide a by b (we fixed our code)

from nose.tools import assert_equal
assert_equal(c, 2)  # check that 'c' has the value 2

Change the type of the variable 'rating' to int.
In [5]:
rating = "5"
t = type(rating)
print("The variable 'rating' has the type: ", t)  # You can also do: print("The variable 'rating' has the type: ", type(rating))
### BEGIN SOLUTION
rating = int(rating)
x = type(rating)
### END SOLUTION
# The type should now be 'int' instead of 'str'
print("The variable 'rating' has the type: ", x)

Enter an integer rating between 1 and 10
In [16]:
# If you see no errors under this cell your solution is correct!

from nose.tools import assert_equal, assert_true

# Two ways to check the type of a variable: with type() or with isinstance()
assert_equal(type(rating), int)
assert_true(isinstance(rating, int))

print("\x1b[6;30;42mSuccess!\x1b[0m")

Success! 
For a circle of radius 3, display the diameter, circumference and area. Use the value 3.14159 for $\pi$. Use the following formulas (r is the radius):
• $diameter = 2 r$
• $circumference = 2 \pi r$
• $area = \pi r^{2}$
Create variables called $diameter$, $circumference$ and $area$ that contain the calculated values for the circle of radius 3. Calculate the values in your code, don't calculate the values by hand and create variables that are assigned the values.
In [11]:
### BEGIN SOLUTION
r = 3
pi = 3.14159
diameter = 2 * r
circumference = 2 * pi * r
area = pi * (r ** 2)
print(diameter, circumference, area)
### END SOLUTION

6 18.849539999999998 28.27431
In [12]:
# Tests for Task 3
from nose.tools import assert_true
assert_true("diameter" in locals(), msg="You did not define a variable called 'diameter'!")
assert_true("circumference" in locals(), msg="You did not define a variable called 'circumference'!")
assert_true("area" in locals(), msg="You did not define a variable called 'area'!")

print("\x1b[6;30;42mSuccess!\x1b[0m")

Success! 
In [13]:
# Tests for Task 3
from nose.tools import assert_equal
assert_equal(diameter, 6, msg="Diameter was calculated incorrectly!")
assert_equal(circumference, 18.849539999999998, msg="Circumference was calculated incorrectly!")
assert_equal(area, 28.27431, msg="Area was calculated incorrectly!")

Use $if$ statements that change the value of the variable $check$ to $True$ if the variable $num$ is even and changes the value of the variable $check$ to $False$ if the variable $num$ is odd. You should use $True$ and $False$ for this task. Set the value of $check$ to $True$ or $False$ in your if-condition. You can use $else$ and $elif$ if you need them, not just $if$.

Hint: Use the remainder operator (%, also known as modulo).

In [14]:
# An example of True and False:
t = True
f = False

# They are not strings!
print("Is True the same as the string 'True'?", True == "True")
print("Is False the same as the string 'False'?", False == "False")

Is True the same as the string 'True'? False Is False the same as the string 'False'? False
In [1]:
def is_even(num):
check = None
# Put your if-conditions down there!
### BEGIN SOLUTION
if num % 2 == 0: #num is even
check = True
else: #num is odd
check = False
### END SOLUTION
# Put your if-conditions up there!
return check

In [2]:
is_even(2)

True
In [16]:
from nose.tools import assert_true, assert_false
import inspect
assert_true(inspect.isfunction(is_even), msg="The 'is_even' function does not exist anymore. Did you overwrite it by using 'is_even' as a variable name?")
print("\x1b[6;30;42mSuccess!\x1b[0m")

Success! 
In [17]:
# If you see no errors under this cell then your solution is correct!

from nose.tools import assert_true, assert_false
assert_false(is_even(2) is None, msg="You do not have a 'return' statement in your function. Did you delete it? The last line of your function should be 'return check'.")

assert_true(is_even(2))
assert_true(is_even(42))
assert_true(is_even(23218232))
assert_false(is_even(1))
assert_false(is_even(41))
assert_false(is_even(21832831))
print("\x1b[6;30;42mSuccess!\x1b[0m")

Success! 
Instructor only (will be removed from student version), ID: 04196a

This cell should only be visible to tutors (hopefully).

The goal of Task 5 and 6 is to teach the students debugging / reading the stack traces.

##### Task 5 (4 Points, 1 Point per question)

What caused the error in the following code samples? Store your solution in a variable called $solution$. There is always only one correct solution.

This task uses hidden>hidden tests. You won't know if your solution is correct or not until it is graded and returned.

In [18]:
a = 5
b = a - 5
a / b

--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) <ipython-input-18-f76d16b615ef> in <module> 1 a = 5 2 b = a - 5 ----> 3 a / b ZeroDivisionError: division by zero 
In [19]:
# a) We forgot to define the variable 'c'.
# b) We divide by zero.
# c) We forgot to convert the type to 'int'.
# d) We tried to do a calculation with an 'int' and with a 'str'.
solution = "a)"  # enter your solution here in this format
### BEGIN SOLUTION
solution = "b)"
### END SOLUTION

In [20]:
# Tests for Task 5a)
# There is a hidden test that checks if your solution is correct

# Checks that your chosen answer is one of the four possible options
from nose.tools import assert_equal, assert_true
assert_true(solution in ["a)", "b)", "c)", "d)"], msg="Your solution must be 'a)', 'b)', 'c)' or 'd)'.")

### BEGIN HIDDEN TESTS
# students will NOT see these extra tests
assert_equal(solution, "b)")
### END HIDDEN TESTS

In [7]:
a = 5
b = a - "5"
c = a / b

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-7-2b1c8c0f7ecc> in <module> 1 a = 5 ----> 2 b = a - "5" 3 c = a / b TypeError: unsupported operand type(s) for -: 'int' and 'str' 
In [22]:
# a) We forgot to define the variable 'c'.
# b) We divide by zero.
# c) We forgot to convert the type to 'int'.
# d) We tried to do a calculation with an 'int' and with a 'str'.
solution = "a)"  # enter your solution here in this format
### BEGIN SOLUTION
solution = "d)"
### END SOLUTION

In [23]:
# Tests for Task 5b)
# There is a hidden test that checks if your solution is correct

# Checks that your chosen answer is one of the four possible options
from nose.tools import assert_equal, assert_true
assert_true(solution in ["a)", "b)", "c)", "d)"], msg="Your solution must be 'a)', 'b)', 'c)' or 'd)'.")

### BEGIN HIDDEN TESTS
# students will NOT see these extra tests
assert_equal(solution, "d)")
### END HIDDEN TESTS

In [21]:
a = 5
b = a - 3
c = int(a - b) #now it's correct, change str to int
print("The value of c is", c)   # check that c is actually a number

from nose.tools import assert_equal
assert_equal(type(c), int)

The value of c is 3
In [22]:
# a) We forgot to define the variable 'c'.
# b) We divide by zero.
# c) We forgot to convert the type to 'int'.
# d) We tried to do a calculation with an 'int' and with a 'str'.
solution = "a)"  # enter your solution here in this format
### BEGIN SOLUTION
solution = "c)"
### END SOLUTION

In [26]:
# Tests for Task 5c)
# There is a hidden test that checks if your solution is correct

# Checks that your chosen answer is one of the four possible options
from nose.tools import assert_equal, assert_true
assert_true(solution in ["a)", "b)", "c)", "d)"], msg="Your solution must be 'a)', 'b)', 'c)' or 'd)'.")

### BEGIN HIDDEN TESTS
# students will NOT see these extra tests
assert_equal(solution, "c)")
### END HIDDEN TESTS

In [27]:
a = 5
b = a - 3  # 2
cc = a - b  # 3
print("The value is ", cc)  # checking that the value is really 3

from nose.tools import assert_equal
assert_equal(c, 3)

The value is 3
--------------------------------------------------------------------------- AssertionError Traceback (most recent call last) <ipython-input-27-c7f455dea594> in <module> 5 6 from nose.tools import assert_equal ----> 7 assert_equal(c, 3) /usr/lib/python3.8/unittest/case.py in assertEqual(self, first, second, msg) 910 """ 911 assertion_func = self._getAssertEqualityFunc(first, second) --> 912 assertion_func(first, second, msg=msg) 913 914 def assertNotEqual(self, first, second, msg=None): /usr/lib/python3.8/unittest/case.py in _baseAssertEqual(self, first, second, msg) 903 standardMsg = '%s != %s' % _common_shorten_repr(first, second) 904 msg = self._formatMessage(msg, standardMsg) --> 905 raise self.failureException(msg) 906 907 def assertEqual(self, first, second, msg=None): AssertionError: '3' != 3 
In [28]:
# a) We forgot to define the variable 'c'.
# b) We divide by zero.
# c) We forgot to convert the type to 'int'.
# d) We tried to do a calculation with an 'int' and with a 'str'.
solution = "a)"  # enter your solution here in this format
### BEGIN SOLUTION
solution = "a)"
### END SOLUTION

In [29]:
# Tests for Task 5d)
# There is a hidden test that checks if your solution is correct

# Checks that your chosen answer is one of the four possible options
from nose.tools import assert_equal, assert_true
assert_true(solution in ["a)", "b)", "c)", "d)"], msg="Your solution must be 'a)', 'b)', 'c)' or 'd)'.")

### BEGIN HIDDEN TESTS
# students will NOT see these extra tests
assert_equal(solution, "a)")
### END HIDDEN TESTS


What caused the error in the following code samples? Store your solution in a variable called $solution$. There is always only one correct solution.

This task uses hidden tests. You won't know if your solution is correct or not until it is graded and returned.

In [24]:
# Task: Write code that checks if variable 'a' is less than 10 and less than 6 and stores that information in two variables.
a = 5
less_than_10 = False
less_than_6 = False
if a < 10:
less_than_10 = True
elif a < 6:
less_than_6 = True

from nose.tools import assert_true
assert_true(a < 10)
assert_true(a < 6)
assert_true(less_than_10)
assert_true(less_than_6)

--------------------------------------------------------------------------- AssertionError Traceback (most recent call last) <ipython-input-24-dc6fb09ca06e> in <module> 13 assert_true(a < 6) 14 assert_true(less_than_10) ---> 15 assert_true(less_than_6) /usr/lib/python3.8/unittest/case.py in assertTrue(self, expr, msg) 763 if not expr: 764 msg = self._formatMessage(msg, "%s is not true" % safe_repr(expr)) --> 765 raise self.failureException(msg) 766 767 def _formatMessage(self, msg, standardMsg): AssertionError: False is not true 
In [25]:
#Bei If... elif... hört der Test beim ersten True auf und somit schon bei <10 --> deshalb elif zu if ändern

In [31]:
# a) We used incorrect variable names. Numbers in variable names cause undefined, random behaviour and that is why the 'assert_true' failed.
# b) Only one variable can have the value 'True'. We used up the 'True' for 'less_than_10', so we can't put it in 'less_than_6'.
# c) We should have used an 'else' instead of 'elif'.
# d) We should have used another 'if' instead of 'elif'.
solution = "a)"  # enter your solution here in this format
### BEGIN SOLUTION
solution = "d)"
### END SOLUTION

In [32]:
# Tests for Task 6a)
# There is a hidden test that checks if your solution is correct

# Checks that your chosen answer is one of the four possible options
from nose.tools import assert_equal, assert_true
assert_true(solution in ["a)", "b)", "c)", "d)"], msg="Your solution must be 'a)', 'b)', 'c)' or 'd)'.")

### BEGIN HIDDEN TESTS
# students will NOT see these extra tests
assert_equal(solution, "d)")
### END HIDDEN TESTS

In [27]:
# Task: Write code that checks if the variable 'a' is equal to '5' (integer 5, not string 5) and if it is, sets the value of the variable 'equal_5' to 'True'.
a = int("5")
equal_5 = False
if a = 5:
equal_5 = True

from nose.tools import assert_true
assert_true(equal_5)

 File "<ipython-input-27-7a45abec651c>", line 4 if a = 5: ^ SyntaxError: invalid syntax 
In [34]:
# a) We used a single equals sign. Single equals signs are used for value assignment instead of equality checking.
# b) 'a' is a 'str' (string), not an 'int'. We can't check if an 'int' and a 'str' are the same.
# c) We forgot to use brackets in the if-condition.
# d) We forgot to add an 'else' or 'elif'. An 'if' without 'else' or 'elif' is invalid.
solution = "a)"  # enter your solution here in this format
### BEGIN SOLUTION
solution = "a)"
### END SOLUTION

In [35]:
# Tests for Task 6b)
# There is a hidden test that checks if your solution is correct

# Checks that your chosen answer is one of the four possible options
from nose.tools import assert_equal, assert_true
assert_true(solution in ["a)", "b)", "c)", "d)"], msg="Your solution must be 'a)', 'b)', 'c)' or 'd)'.")

### BEGIN HIDDEN TESTS
# students will NOT see these extra tests
assert_equal(solution, "a)")
### END HIDDEN TESTS

Store every letter of the string 'Programming' in the variable $s7$. Add a space character after every letter.

In the end, the variable $s7$ should contain the value 'P r o g r a m m i n g '.

Don't forget the space character the final 'g'!

Hint: Use a for-loop for this task.

Hint: You can combine strings, or add characters to them, with "+". An example is given in the cell below.

In [36]:
tmp1 = "Hello"
tmp2 = "World"
tmp3 = tmp1 + " " + tmp2
print(tmp3)
print("----------------------------")
print(tmp3 + "!")  # adding the '!' at the end

Hello World ---------------------------- Hello World!
In [33]:
p = "Programming"
s7 = ""  # this is called an empty string - a string with no characters in it
### BEGIN SOLUTION
for c in p:
s7 += c + " "

print(s7)
### END SOLUTION

P r o g r a m m i n g
In [38]:
# Tests for Task 7

from nose.tools import assert_equal, assert_not_equal
# this test checks that you didn't forget the space character at the end
assert_not_equal(s7, "P r o g r a m m i n g", msg="You forgot the space character at the end.")

# this test checks that you didn't add a space character at the beginning
assert_not_equal(s7, " P r o g r a m m i n g ", msg="You have a space character before the 'P' that you don't need.")

# this test checks that your solution is correct
# the other two tests are just there to help you find out where you made a mistake
assert_equal(s7, "P r o g r a m m i n g ")

print("\x1b[6;30;42mSuccess!\x1b[0m")

Success! 
Store every second letter of the string 'Programming' (starting at 'P') in the variable $s7$. Add a space character after every letter.

In the end, the variable $s7$ should contain the value 'P o r m i g '.

HINT: Use a for-loop for this task.

HINT: Count how many iterations of the for-loop have been executed and use that information to check whether you should include the character of the current iteration in the result or not.

Don't forget the space character the final 'g'!

In [35]:
p = "Programming"
s7 = ""  # this is called an empty string - a string with no characters in it
### BEGIN SOLUTION
count = 0
for c in p:
if count % 2 == 0:
s7 += c + " "
count += 1

print(s7)
### END SOLUTION

P o r m i g
In [40]:
# Tests for Task 8

from nose.tools import assert_equal, assert_not_equal
# this test checks that you didn't forget the space character at the end
assert_not_equal(s7, "P o r m i g", msg="You forgot the space character at the end.")

# this test checks that you didn't add a space character at the beginning
assert_not_equal(s7, " P o r m i g ", msg="You have a space character before the 'P' that you don't need.")

# this test checks that your solution is correct
# the other two tests are just there to help you find out where you made a mistake
assert_equal(s7, "P o r m i g ")

print("\x1b[6;30;42mSuccess!\x1b[0m")

Success! 
Write code that counts how many operations you need to perform to reach 1 with the Collatz conjecture sequence, for $n=11$. The example below has 6 steps. Store the number of steps required in a variable called $steps$.

According to the Collatz conjecture the following sequence will always reach 1 for any positive integer:

• if the integer is even then the next term in the sequence is half of the previous term
• if the integer is odd then the next term in the sequence is 3 times the previous term plus 1

Example for n=10:

Step Current term Next term
1 10 5 (even, halve it)
2 5 16 (uneven, multiply by 3 and add 1): $next = (5 * 3) + 1 = 16$
3 16 8 (even, halve it)
4 8 4 (even, halve it)
5 4 2 (even, halve it)
6 2 1 (we are finished)

This sequence can be described like this, perform this operation until you reach 1:

$f(n) = \begin{cases} \frac{n}{2} &\text{if } n \equiv 0 \pmod{2}\\[4px] 3n+1 & \text{if } n\equiv 1 \pmod{2} .\end{cases}$

Hint: Use a while-loop.

Hint: Use if-conditions inside the while-loop.

Hint: Use the remainder operator (%, also known as modulo).

Hint: Update the value of the variable $n$ in every loop-iteration (halve it if it is even, multiply by 3 and add 1 if it is odd).

Hint: You do not have to define new variables for this task. You can solve it with only $n$ and $steps$.

Hint: If you fail the test that checks your number of steps try replacing the example from above with $n=10$. Add print() statements to check which steps your code is executing and how many steps it needs! The test cases don't care about whether or not you have print()s in your solution, they won't break a correct solution but it can be helpful to figure out what your code does.

In [37]:
n = 11
steps = 0
### BEGIN SOLUTION
while n != 1:
steps += 1
if n % 2 == 0:
n = n / 2
else:
n = (3 * n) + 1

print(n)
print(steps)
### END SOLUTION

1.0 14
# Tests for task 9

Success!