Exercise 1: Documentation and Testing

The following little program needs some documentation and some tests. Since you didn't write it, I'll tell you what it's supposed to do. You'll need to document it. Feel free to test for additional exceptions if you have time but start with it as it is.

The point of the program is to compute the $L_{2}$ norm of a vector $v$. A second argument, if provided, will be interpreted as a vector of weights. The second argument must have the same length as the input vector.

NOTE: The input type of the vectors for this program should be a list of numbers.

As a reminder, the weighted $L_2$ norm of a vector $v$ is given by \begin{align*} \|v\|_{W} = \sqrt{\sum_{i=1}^{N}{\left(w_{i}v_{i}\right)^2}} \end{align*} where $N$ is the length of the vector $v$, $v_{i}$ is the i-th component of the vector $v$ and $w_{i}$ is the i-th component of the weight vector.

You must write the documentation and a decent test suite. Try to include some doctests as well!

Next, use the pytest module to run the doctests and unit tests and to assess the code coverage.

If you don't already have pytest, you can install it using pip install pytest. If you have trouble installing, here's the website: pytest installation.


In [3]:
import numpy as np

def L2(v, *args):
    """Returns the norm of a vector v
    
    INPUTS
    ======
    v: list of float, vector
    args:list of float, weight vector
        
    RETURNS
    ======
    norm: float
          if the dimension of w and v is not the same, an error is raised
    
    EXAMPLES
       >>L2([1,1,1,1,1],[1,2,3,4,5])
        7.416198487095663
        
    
    """
    ======
    
    
    """
    s = 0.0 # Initialize sum
    if len(args) == 0: # No weight vector
        for vi in v:
            s += vi * vi
    else: # Weight vector present
        w = args[0] # Get the weight vector
        if (len(w) != len(v)): # Check lengths of lists
            raise ValueError("Length of list of weights must match length of target list.")
        for i, vi in enumerate(v):
            s += w[i] * w[i] * vi * vi
    return np.sqrt(s)

In [5]:
L2([1,1,1,1,1],[1,2,3,4,5])


Out[5]:
7.416198487095663

In [6]:
import doctest
doctest.testmod(verbose=True)


2 items had no tests:
    __main__
    __main__.L2
0 tests in 2 items.
0 passed and 0 failed.
Test passed.
Out[6]:
TestResults(failed=0, attempted=0)

In [20]:
%%file L2.py
import numpy as np
def vector_len(v, *args):
    """Returns the norm of a vector v
    
    INPUTS
    ======
    v: list of float, vector
    args:list of float, weight vector
        
    RETURNS
    ======
    norm: float
          if the dimension of w and v is not the same, an error is raised
    
    EXAMPLES
       >>L2([1,1,1,1,1],[1,2,3,4,5])
        7.416198487095663
        
    
    """

    s = 0.0 # Initialize sum
    if len(args) == 0: # No weight vector
        for vi in v:
            s += vi * vi
    else: # Weight vector present
        w = args[0] # Get the weight vector
        if (len(w) != len(v)): # Check lengths of lists
            raise ValueError("Length of list of weights must match length of target list.")
        for i, vi in enumerate(v):
            s += w[i] * w[i] * vi * vi
    return np.sqrt(s)


Overwriting L2.py

In [28]:
L2([1,1,1,1,1])


Out[28]:
2.2360679774997898

In [29]:
%%file test_L2.py
import L2

def test_L2_result():
    assert L2.vector_len([1,1,1,1,1],[1,2,3,4,5])==7.416198487095663

def test_L2_no_weight():
    assert L2.vector_len([1,1,1,1,1])==2.2360679774997898
def test_L2_dimensions():
    try: 
        L2.vector_len([1,1,1,1,1,1],[1,2,3])
    except ValueError as err:
        assert(type(err)==ValueError)


Overwriting test_L2.py

In [30]:
!pytest --cov


============================= test session starts ==============================
platform darwin -- Python 3.6.1, pytest-3.0.7, py-1.4.33, pluggy-0.4.0
rootdir: /Users/zhaiyi/cs207_yi_zhai/lectures/L7, inifile:
plugins: cov-2.5.1
collected 3 items 

test_L2.py ...

---------- coverage: platform darwin, python 3.6.1-final-0 -----------
Name         Stmts   Miss  Cover
--------------------------------
L2.py           12      0   100%
test_L2.py      10      0   100%
--------------------------------
TOTAL           22      0   100%


=========================== 3 passed in 0.29 seconds ===========================

In [31]:
!pytest --cov --cov-report term-missing


============================= test session starts ==============================
platform darwin -- Python 3.6.1, pytest-3.0.7, py-1.4.33, pluggy-0.4.0
rootdir: /Users/zhaiyi/cs207_yi_zhai/lectures/L7, inifile:
plugins: cov-2.5.1
collected 3 items 

test_L2.py ...

---------- coverage: platform darwin, python 3.6.1-final-0 -----------
Name         Stmts   Miss  Cover   Missing
------------------------------------------
L2.py           12      0   100%
test_L2.py      10      0   100%
------------------------------------------
TOTAL           22      0   100%


=========================== 3 passed in 0.29 seconds ===========================

In [ ]: