# some definitions *without* using comprehensions


def dot_prod(u, v):
    """
    Return the dot product of u and v

    @param list[float] u: vector
    @param list[float] v: vector
    @rtype: float

    >>> dot_prod([1.0, 2.0], [3.0, 4.0])
    11.0
    """
    # sum of products of pairs of corresponding coordinates of u and v
    assert len(u) == len(v)
    total = 0
    for i in range(len(u)):
        total += u[i] * v[i]
    return total


def matrix_vector_prod(m, v):
    """
    Return the matrix-vector product of m x v

    @param list[list[float]] m: matrix
    @param list[float] v: vector
    @rtype: list[float]

    >>> matrix_vector_prod([[1.0, 2.0], [3.0, 4.0]], [5.0, 6.0])
    [17.0, 39.0]
    """
    # list of dot products of vectors in m with v
    assert all([len(row) == len(m[0]) for row in m])
    assert len(m[0]) == len(v)
    lst = []
    for row in m:
        lst.append(dot_prod(row, v))
    return lst


def pythagorean_triples(n):
    """
    Return list of pythagorean triples with elements from 1 to n.

    @param int n: positive integer
    @rtype: list[(int, int, int)]

    >>> pythagorean_triples(5)
    [(3, 4, 5)]
    """
    # helper to check whether a triple is pythagorean and non_descending
    # you could also use a lambda instead of this...
    def ascending_pythagorean(t):
        """
        Return whether t is pythagorean and non-descending

        @param (int, int, int) t: tuple to check for pythagorean triple
        @rtype: bool
        """
        return (t[0] <= t[1] <= t[2]) and (t[0]**2 + t[1]**2) == t[2]**2
    # filter just the ones that satisfy ascending_pythagorean
    lst = []
    for i in range(1, n + 1):
        for j in range(1, n + 1):
            for k in range(1, n + 1):
                if ascending_pythagorean((i, j, k)):
                    lst.append((i, j, k))
    return lst


if __name__ == '__main__':
    import doctest
    doctest.testmod()
