def test_matrix_multiply(self): matrix1 = Matrix.from_cols([[1, 2], [3, 4], [5, 6]]) matrix2 = Matrix.from_cols([[1, 2, 3], [4, 5, 6]]) product = matrix1.multiply(matrix2) assert product.size() == (2, 2) assert product.all_cols() == [[22, 28], [49, 64]] product = matrix2.multiply(matrix1) assert product.size() == (3, 3) assert product.all_cols() == [[9, 12, 15], [19, 26, 33], [29, 40, 51]]
def test_lu_more_rows(self): mat_l = Matrix.from_cols([[1, 2, 3, 4, 5], [0, 1, 2, 3, 4], [0, 0, 1, 2, 3], [0, 0, 0, 1, 2], [0, 0, 0, 0, 1]]) mat_u = Matrix.from_cols([[5, 1, 2, 3, 4], [0, 4, 3, 2, 1], [0, 0, 2, 1, 0]]) matrix = mat_l.multiply(mat_u) mat_l, mat_u = compute_lu_factorization(matrix) # note LU factorization is not unique therefore we are not comparing L and U utils.assert_lower_triangular(mat_l) utils.assert_upper_triangular(mat_u) assert self.vector_all(utils.extract_diagonal(mat_l), 1) product = mat_l.multiply(mat_u) assert product.all_cols() == matrix.all_cols()
def test_reduce_to_bidiagonal(self): mat = Matrix.from_cols([[1, 2, 3], [4, 5, 6], [7, 8, 10]]) b, _, _ = reduce_to_bidiagonal(mat) utils.assert_upper_triangular(b) truncated = MatrixView.with_size( b, (0, 1), (mat.num_rows() - 1, mat.num_cols() - 1)).to_matrix() utils.assert_lower_triangular(truncated)
def test_bidiagonal_recreate_2(self): mat = Matrix.from_cols([[1, 2, 3], [2, 5, 1], [-1, 3, -2]]) b, left, right = reduce_to_bidiagonal(mat) for index, hh in list(enumerate(left))[::-1]: b = hh.multiply_left(b, index) for index, hh in list(enumerate(right))[::-1]: b = hh.multiply_right(b, index + 1) utils.assert_matrix_equal(mat, b)
def test_givens_rotation(self): givens = Givens(1, 1) product = givens.multiply_left(Matrix.from_cols([[1, 1]])) assert product.size() == (2, 1) assert product.get_col(0) == pytest.approx([math.sqrt(2), 0]) product = givens.multiply_left_column([1, 1]) assert product.size() == (2, 1) assert product.get_col(0) == pytest.approx([math.sqrt(2), 0])
def test_create_from_cols(self): matrix = Matrix.from_cols([[1, 2], [3, 4], [5, 6]]) assert matrix.size() == (2, 3) assert matrix.get_col(0) == [1, 2] assert matrix.get_col(1) == [3, 4] assert matrix.get_col(2) == [5, 6] assert matrix.get_row(0) == [1, 3, 5] assert matrix.get_row(1) == [2, 4, 6]
def test_lu(self): matrix = Matrix.from_cols([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) mat_l, mat_u = compute_lu_factorization(matrix) utils.assert_lower_triangular(mat_l) utils.assert_upper_triangular(mat_u) assert self.vector_all(utils.extract_diagonal(mat_l), 1) product = mat_l.multiply(mat_u) assert product.all_cols() == matrix.all_cols()
def test_householder_col(self): vec = [5, 4, 3, 2, 1] householder = Householder(vec) vec_as_mat = Matrix.from_cols([vec]) product = householder.multiply_left(vec_as_mat) assert product.num_cols() == 1 assert product.get(0, 0) == pytest.approx(vec_as_mat.frobenius_norm()) for elem in product.get_col(0)[1:]: assert elem == pytest.approx(0)
def test_matrix_transpose(self): matrix = Matrix.from_cols([[1, 2], [3, 4], [5, 6]]) mat_transpose = matrix.transpose() assert matrix.num_rows() == mat_transpose.num_cols() assert matrix.num_cols() == mat_transpose.num_rows() for i in range(matrix.num_rows()): assert matrix.get_row(i) == mat_transpose.get_col(i) for i in range(matrix.num_cols()): assert matrix.get_col(i) == mat_transpose.get_row(i)
def test_upper_triangular(self): mat = Matrix.from_cols([[1, 0, 0], [2, 3, 0], [4, 5, 6]]) utils.assert_upper_triangular(mat) with pytest.raises(AssertionError): utils.assert_upper_triangular(mat.transpose())
def test_svd_bidiagonal(self): mat = Matrix.from_cols([[1, 0, 0], [2, 3, 0], [0, 4, 5]]) u, s, v = compute_svd_bidiagonal(mat) self.check_svd(u, s, v, mat)
def test_create_fail(self): with pytest.raises(ValueError): Matrix.from_cols([[1, 2], [3], [5, 6]]) with pytest.raises(ValueError): Matrix.from_rows([[1, 2], [3, 4], [6]])
def test_matrix_multiply_fail(self): matrix1 = Matrix.from_cols([[1, 2], [3, 4], [5, 6]]) with pytest.raises(ValueError): matrix1.multiply(matrix1)
def test_svd_bidiagonal_2(self): mat = Matrix.from_cols([[3.742, 0, 0], [4.018, 3.511, 0], [0, -3.408, -1.979]]) u, s, v = compute_svd_bidiagonal(mat) self.check_svd(u, s, v, mat)
def test_svd_more_cols(self): mat = Matrix.from_cols([[1, 2, 3], [2, 5, 1], [-1, 3, -2], [3, 2, 1]]) u, s, v = compute_svd(mat) self.check_svd(u, s, v, mat)
def test_rectangular_triangular(self): utils.assert_upper_triangular( Matrix.from_cols([[4, 0], [1, 2], [3, 4]]))
def test_givens_matrix(self): givens = Givens(1, 1).to_matrix() product = givens.multiply(Matrix.from_cols([[1, 1]])) assert product.size() == (2, 1) assert product.get_col(0) == pytest.approx([math.sqrt(2), 0])
def test_givens_padded(self): givens = Givens(-0.8, 0.6) product = givens.multiply_left(Matrix.from_cols([[1, 2, -0.8, 0.6]]), 2) assert product.size() == (4, 1) assert product.get_col(0) == pytest.approx([1, 2, 1, 0])
def generate_matrix_normal(size: int) -> Matrix: columns = [[generate_normal() for _ in range(size)] for _ in range(size)] return Matrix.from_cols(columns)
def test_lower_triangular(self): mat = Matrix.from_cols([[1, 2, 3], [0, 4, 5], [0, 0, 6]]) utils.assert_lower_triangular(mat) with pytest.raises(AssertionError): utils.assert_lower_triangular(mat.transpose())
def compute_svd_bidiagonal(mat: Matrix) -> (Matrix, Matrix, Matrix): dims = mat.num_cols() u = Matrix.identity(dims) v = Matrix.identity(dims) while True: # while not converged # find max off-diagonal max_off_diag = 0 diag_sum = 0 for i in range(dims - 1): max_off_diag = max(max_off_diag, abs(mat.get(i, i + 1))) for i in range(dims): diag_sum += abs(mat.get(i, i)) diag_sum /= dims if max_off_diag < diag_sum * 1e-6 and max_off_diag < 1e-8: break # introduce the bulge givens = Givens( mat.get(0, 0)**2 - mat.get(dims - 1, dims - 1)**2 - mat.get(dims - 2, dims - 1)**2, mat.get(0, 1) * mat.get(0, 0)).transpose() mat = givens.multiply_right(mat) v = givens.transpose().multiply_left(v) # chase the bulge for iteration in range(0, dims - 1): # zero subdiagonal givens_lower = Givens(mat.get(iteration, iteration), mat.get(iteration + 1, iteration)) mat = givens_lower.multiply_left(mat, pad_top=iteration) u = givens_lower.transpose().multiply_right(u, pad_top=iteration) # zero above superdiagonal if iteration != dims - 2: givens_upper = Givens(mat.get(iteration, iteration + 1), mat.get(iteration, iteration + 2)).transpose() mat = givens_upper.multiply_right(mat, pad_top=iteration + 1) v = givens_upper.transpose().multiply_left(v, pad_top=iteration + 1) v = v.transpose() # Ensure singular values are non-negative for i in range(dims): if mat.get(i, i) < 0: MatrixView.with_size(mat, (i, i), (1, 1)).scale(-1) MatrixView(u, (0, i), (u.num_rows() - 1, i)).scale(-1) # reorder columns sv = [(mat.get(i, i), i) for i in range(dims)] sv.sort() sv = sv[::-1] sorted_v_cols = [v.get_col(index) for value, index in sv] sorted_u_cols = [u.get_col(index) for value, index in sv] v = Matrix.from_cols(sorted_v_cols) u = Matrix.from_cols(sorted_u_cols) mat = Matrix.zeroes(dims, dims) for index, (value, _) in enumerate(sv): MatrixView.with_size(mat, (index, index), (1, 1)).set_element(0, 0, value) return u, mat, v