Exercise 1

To write a function that accepts two lists-of-lists of numbers and returns one list-of-lists with each of the corresponding numbers in the two given lists-of-lists added together.

It should work something like this:

> >> matrix1 = [[1, -2], [-3, 4]]
>>> matrix2 = [[2, -1], [0, -1]]
>>> add(matrix1, matrix2)
[[3, -3], [-3, 3]]
>>> matrix1 = [[1, -2, 3], [-4, 5, -6], [7, -8, 9]]
>>> matrix2 = [[1, 1, 0], [1, -2, 3], [-2, 2, -2]]
>>> add(matrix1, matrix2)
[[2, -1, 3], [-3, 3, -3], [5, -6, 7]]

Try to solve this excise without using any 3rd-party libraries (for those need to use conda or pip to install)

There's two bonuses:## Bonus 1Modify your add() function to accept non-fixed length argument (*args)

> >> matrix1 = [[1, 9], [7, 3]]
>>> matrix2 = [[5, -4], [3, 3]]
>>> matrix3 = [[2, 3], [-3, 1]]
>>> add(matrix1, matrix2, matrix3)
[[8, 8], [7, 7]]

Bonus 2

Raise ValueError if the given matrices is not the same shape.

>>> add([[1, 9], [7, 3]], [[1, 2], [3]])
Traceback (most recent call last):File "<stdin>", line 1, in <module>  File "add.py", line 10, in add
    raise ValueError("Given matrices are not the same size.")
ValueError: Given matrices are not the same size.
# test case
from copy import deepcopy
import unittest

class AddTests(unittest.TestCase):

    """Tests for add."""

    def test_single_items(self):
        self.assertEqual(add([[5]], [[-2]]), [[3]])

    def test_two_by_two_matrixes(self):
        m1 = [[6, 6], [3, 1]]
        m2 = [[1, 2], [3, 4]]
        m3 = [[7, 8], [6, 5]]
        self.assertEqual(add(m1, m2), m3)

    def test_two_by_three_matrixes(self):
        m1 = [[1, 2, 3], [4, 5, 6]]
        m2 = [[-1, -2, -3], [-4, -5, -6]]
        m3 = [[0, 0, 0], [0, 0, 0]]
        self.assertEqual(add(m1, m2), m3)

    def test_input_unchanged(self):
        m1 = [[6, 6], [3, 1]]
        m2 = [[1, 2], [3, 4]]
        m1_original = deepcopy(m1)
        m2_original = deepcopy(m2)
        add(m1, m2)
        self.assertEqual(m1, m1_original)
        self.assertEqual(m2, m2_original)

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_any_number_of_matrixes(self):
        m1 = [[6, 6], [3, 1]]
        m2 = [[1, 2], [3, 4]]
        m3 = [[2, 1], [3, 4]]
        m4 = [[9, 9], [9, 9]]
        m5 = [[31, 32], [27, 24]]
        self.assertEqual(add(m1, m2, m3), m4)
        self.assertEqual(add(m2, m3, m1, m1, m2, m4, m1), m5)

    # To test the Bonus part of this exercise, comment out the following line
    @unittest.expectedFailure
    def test_different_matrix_size(self):
        m1 = [[6, 6], [3, 1]]
        m2 = [[1, 2], [3, 4], [5, 6]]
        m3 = [[6, 6], [3, 1, 2]]
        with self.assertRaises(ValueError):
            add(m1, m2)
        with self.assertRaises(ValueError):
            add(m1, m3)
        with self.assertRaises(ValueError):
            add(m1, m1, m1, m3, m1, m1)
        with self.assertRaises(ValueError):
            add(m1, m1, m1, m2, m1, m1)

unittest.main(argv=['first-arg-is-ignored'], verbosity=2, exit=False)