Пример #1
0
def compute_svd(mat: Matrix) -> (Matrix, Matrix, Matrix):
    if mat.num_cols() > mat.num_rows():
        u, s, v = compute_svd(mat.transpose())
        return v, s.transpose(), u
    elif mat.num_rows() > mat.num_cols():
        # mat is m x n, m > n
        # q should be m x m, r should be m x n
        q, r = compute_qr_factorization(mat)
        # truncate r to be n x n, truncate q to be m x n
        r_truncated = MatrixView.with_size(
            r, (0, 0), (mat.num_cols(), mat.num_cols())).to_matrix()
        u, s, v = compute_svd(r_truncated)
        u_padded = Matrix.identity(mat.num_rows())
        MatrixView.with_size(u_padded, (0, 0),
                             (mat.num_cols(), mat.num_cols())).set(
                                 MatrixView.whole(u))
        u = q.multiply(u_padded)
        s_padded = Matrix.zeroes(mat.num_rows(), mat.num_cols())
        MatrixView.with_size(s_padded, (0, 0),
                             (mat.num_cols(), mat.num_cols())).set(
                                 MatrixView.whole(s))
        s = s_padded
        return u, s, v
    else:
        # matrix is square
        b, left, right = reduce_to_bidiagonal(mat)
        u, s, v = compute_svd_bidiagonal(b)
        for index, hh in list(enumerate(left))[::-1]:
            u = hh.multiply_left(u, index)
        v_transpose = v.transpose()
        for index, hh in list(enumerate(right))[::-1]:
            v_transpose = hh.multiply_right(v_transpose, index + 1)
        return u, s, v_transpose.transpose()
Пример #2
0
def compute_qr_factorization(mat: Matrix) -> (Matrix, Matrix):
    # Do not overwrite original matrix
    mat = mat.copy()
    householders = []  # store householder transformations
    iterations = min(mat.num_rows(), mat.num_cols())
    for iteration in range(iterations):
        col = mat.get_col(iteration)
        # Zero out the entries below the diagonal
        hh = Householder(col[iteration:])
        householders.append((iteration, hh))
        mat = hh.multiply_left(mat, pad_top=iteration)
    # Accumulate the householder transformations
    q_mat = Matrix.identity(mat.num_rows())
    for iteration, hh in householders[::-1]:
        q_mat = hh.multiply_left(q_mat, pad_top=iteration)
    return (q_mat, mat)
Пример #3
0
def reduce_to_bidiagonal(
        mat: Matrix) -> (Matrix, List[Householder], List[Householder]):
    mat = mat.copy()
    if mat.num_rows() != mat.num_cols():
        raise ValueError("Matrix should be square")
    iterations = mat.num_rows() - 1
    acc_left = []
    acc_right = []
    for iteration in range(iterations):
        # clear zeroes below diagonal
        col = mat.get_col(iteration)[iteration:]
        householder_left = Householder(col)
        mat = householder_left.multiply_left(mat, pad_top=iteration)
        acc_left.append(householder_left)
        if iteration != iterations - 1:
            # clear zeroes above superdiagonal
            row = mat.get_row(iteration)[iteration + 1:]
            householder_right = Householder(row)
            mat = householder_right.multiply_right(mat, pad_top=iteration + 1)
            acc_right.append(householder_right)
    return mat, acc_left, acc_right