lab5

New topics: default argument values, tests

std_dev(x)

Compute the standard deviation as a data processing exercise

A function std_dev(x) which takes a list x of floating point numbers, and computes and returns the standard deviation of the sample of the floating point numbers in the list x.

For clarity, if the list x with N elements is defined as \(x = [x_1, x_2, x_3, \ldots, x_N]\), then the standard deviation is given by

\[\sigma = \sqrt{\frac{(x_1 - \mu)^2 + (x_2 - \mu)^2 + \ldots + (x_N - \mu)^2}{N}}\]

where \(\mu\) is the (arithmetic) mean

\[\mu = \frac{1}{N}\sum_{i=1}^N x_i\]

Examples:

In [ ]: std_dev([1.0, 1.0])
Out[ ]: 0.0

In [ ]: std_dev([1.0, 2.0])
Out[ ]: 0.5

box_volume_UPS(a, b, c)

Write a function box_volume_UPS(a, b, c) that returns the volume of a box with edge lengths a, b and c. Inputs should be provided in inch, and the output should be expressed in inch^3.

The standard dimensions of the UPS express box (small) in the US are a=13 inch, b=11 inch and c=2 inch.

Your function should use these values for a, b and c unless others are provided.

Examples:

In [ ]: box_volume_UPS()
Out[ ]: 286

In [ ]: box_volume_UPS(a=10, b=10, c=10)
Out[ ]: 1000

In [ ]: box_volume_UPS(c=5)
Out[ ]: 715

rps_winner()

Copy the following test functions into your file lab5.py

def test_rps_winner_player1_wins():
    assert rps_winner("rock", "scissors") == "player 1 wins"
    assert rps_winner("scissors", "paper") == "player 1 wins"
    assert rps_winner("paper", "rock") == "player 1 wins"

def test_rps_winner_player2_wins():
    assert rps_winner("scissors", "rock") == "player 2 wins"
    assert rps_winner("paper", "scissors") == "player 2 wins"
    assert rps_winner("rock", "paper") == "player 2 wins"

def test_rps_winner_draw():
    assert rps_winner("rock", "rock") == "draw"
    assert rps_winner("paper", "paper") == "draw"
    assert rps_winner("scissors", "scissors") == "draw"
  1. Write the function rps_winner so that the tests pass after reading the following instructions:

    To focus on only problem at the time, you can and should call pytest like this: pytest -v -x lab5.py (where we assume the test-functions above and the source of rps_winner are in file lab5.py).

    With the -x flag, pytest will only report the first failing test and then stop. You can program until that test passes, and then pytest will move past this test. The -v flag increases the verbosity of the pytest output a little - it is not important.

  2. When all the tests pass, step back from your work, and consider if you want to modify or rewrite (“refactor”) your implementation of rps_winner.

    Things to consider:

    • would a different logical structure be better for some reason?

    • can I make the code easier to read?

    • can I name variables better?

    You can and should run the tests on your refactored code.


compress(s)

In this exercise, we ask you to use the tests provided as the guidance for what you need to implement.

In contrast to task rps_winner, the specifications of the functionality is not complete for compress: even if all the given tests pass, it is possible that your implementation is not correct. While working through the tests, try to identify the general expected behaviour, and implement that.

Copy the following test code into your file lab5.py

import base64


def test_compress_incompressible():
    assert compress("") == ""
    assert compress("a") == "a"
    assert compress("aa") == "aa"
    assert compress("abc") == "abc"
    assert compress("a message") == "a message"

def test_compress_max():
    assert compress("aaaaaa") == base64.standard_b64decode(b'YTY=').decode()
    assert (
      compress("aaabbb") == base64.standard_b64decode(b"YTNiMw==").decode()
    )

def test_compress_partial():
    assert compress("aaabab") == ''.join(map(chr, [97, 51, 98, 97, 98]))
    assert compress("aaabba") == ''.join(map(chr, [97, 51, 98, 98, 97]))
    assert compress("bbcaaa") == ''.join(map(chr, [98, 98, 99, 97, 51]))
  1. Write the function compress so that the tests pass after reading the instructions:

    The source code of the tests is hard to read. In particular, the comparisons in the assert statements in test_compress_max() and test_compress_partial() are somewhat obfuscated here for educational reasons.

    Instead of attempting to decipher what they mean, please run the tests: The command pytest will show you the assert lines that fail, and will also evaluate the cryptic looking statements such as base64.standard_b64decode(b'YTY=').decode() for you.

    To focus on only problem at the time, you can call and should call pytest like this: pytest -v -x lab5.py (where we assume the test-functions above and the source of compress() are in file lab5.py).

  2. When all the tests pass, step back from your work, and consider if you want to modify or rewrite (“refactor”) your implementation of compress.

    You can and should run the tests again on your refactored code if you make any changes.

Hints

Here are some string manipulations you may(!) find useful for this task:

In [ ]: a = "hello"

In [ ]: len(a)
Out[ ]: 5

In [ ]: a[0:2]  # first two characters
Out[ ]: 'he'

In [ ]: a[3:4]  # one character starting at index 3
Out[ ]: 'l'

In [ ]: for i in range(len(a)):  # use index to iterate over string
   ...:     print(f"at index {i} there is letter {a[i]}")
   ...:
at index 0 there is letter h
at index 1 there is letter e
at index 2 there is letter l
at index 3 there is letter l
at index 4 there is letter o

In [ ]: for i in range(1, len(a)):  # detect where letters change
   ...:     if a[i] != a[i-1]:
   ...:         print(f"character {a[i]} at index {i} is different from {a[i-1]} at index {i-1}.")
   ...:
character e at index 1 is different from h at index 0.
character l at index 2 is different from e at index 1.
character o at index 4 is different from l at index 3.

In [ ]: a + str(42)  # concatenating a string and a string of a number
Out[ ]: 'hello42'

In [ ]: f"{a}{42}"   # another way of concatenating string a and number 42
Out[ ]: 'hello42'

In [1]: b = "one"    # extend a string with name `b`
In [2]: b = b + " two"
In [3]: b
Out[3]: 'one two'

In [4]: b = b + " three"
In [5]: b
Out[5]: 'one two three'

Please submit your file lab5.py for this assignment.

Additional (voluntary) tasks are available in lab5-extra.

End of lab5.