示例#1
0
    def test_solve_single_no_pivoting(self):
        T = np.random.randn(50, 50)
        b = np.random.randn(50)

        lu_solver = LU(T)
        lu_solver.decompose()
        actual = lu_solver.solve(b)
        expected = np.linalg.solve(T, b)

        self.assertTrue(np.allclose(actual, expected))
示例#2
0
    def test_solve_multi_full_pivoting(self):
        T = np.random.randn(50, 50)
        b = np.random.randn(50, 5)

        lu_solver = LU(T, pivoting='full')
        lu_solver.decompose()
        actual = lu_solver.solve(b)
        expected = np.linalg.solve(T, b)

        self.assertTrue(np.allclose(actual, expected))
示例#3
0
    def test_no_pivoting(self):
        T = np.random.randn(3, 3)

        L_a, U_a = LU(T).decompose()
        actual = np.dot(L_a, U_a)

        self.assertTrue(np.allclose(actual, T))
示例#4
0
    def test_partial_pivoting(self):
        T = np.random.randn(50, 50)

        actual = LU(T, pivoting='partial').decompose()
        expected = LA.lu(T)

        self.assertTrue(
            all(np.allclose(a, e) for a, e in zip(actual, expected)))
示例#5
0
def determinant(X, log=False):
    """Computes the determinant of a square matrix A.

  Concretely, first factorizes A into PLU and then computes
  the product of the determinant of P and U.

  In case where the determinant is a very small or very big
  number, the implementation may underflow or overflow. To combat
  this, we compute the log of the determinant and return the sign
  in which case:

  `det = sign * np.exp(logdet)`

  Args
  ----
  - A: a numpy array of shape (N, N).
  - log: set to True to return the log of the determinant
    and the sign.

  Returns
  -------
  If log = False, returns:

  - det: a scalar, the determinant of A.

  Else, returns a tuple:

  - sign: 1 or -1.
  - logdet: a float representing the log of the determinant.
  """
    A = np.array(X)

    # LU decomposition
    t, U = LU(A, pivoting='partial').decompose(det=True)

    # compute determinant of P
    if t % 2 == 0:
        sign = 1.
    else:
        sign = -1.

    # compute determinant of U and then A
    diagonal = diag(U)
    if log:
        logdet = 0.
        for d in diagonal:
            logdet += np.log(d)
    else:
        det_U = multi_dot(diagonal)
        det_A = sign * det_U

    if log:
        return sign, logdet
    return det_A
示例#6
0
    def test_already_factored_partial(self):
        A = np.random.randn(2, 2)
        b = np.random.randn(2)

        P, L, U = LU(A, pivoting='partial').decompose()
        actual = solve((P, L, U), b, 'partial')

        lu, piv = lu_factor(A)
        expected = lu_solve((lu, piv), b)

        self.assertTrue(np.allclose(actual, expected))
示例#7
0
def lstsq(A, b):
    """Finds the least-squares solution to a linear system Ax = b for an over-determined A.

  Solves the linear system of equations Ax = b by computing a vector
  x that minimizes the Euclidean norm ||b - Ax||^2 using QR decomposition.

  Args:
    A: a numpy array of shape (M, N).
    b: a numpy array of shape (M,).

  Returns:
    x: a numpy array of shape (N, ).
  """
    M, N = A.shape

    # if well-determined, use PLU
    if (M == N):
        solver = LU(A, pivoting='partial')
        solver.decompose()
    else:
        solver = QR(A)

    # solve for x
    x = solver.solve(b)

    return x
示例#8
0
def inverse(A):
    """Computes the inverse of a square matrix A.

  Concretely, solves the linear system Ax = I
  where x is a square matrix rather than a vector.

  The system is solved using LU decomposition with
  partial pivoting.

  Args:
    A: a numpy array of shape (N, N).

  Returns:
    A numpy array of shape (N, N).
  """
    N = A.shape[0]

    P, L, U = LU(A, pivoting='partial').decompose()

    # transpose P since LU returns A = PLU
    P = P.T

    # solve Ly = P for y
    y = np.zeros_like(L)
    for i in range(N):
        for j in range(N):
            summer = KahanSum()
            for k in range(i):
                summer.add(L[i, k] * y[k, j])
            sum = summer.result()
            y[i, j] = (P[i, j] - sum) / (L[i, i])

    # solve Ux = y for x
    x = np.zeros_like(U)
    for i in range(N - 1, -1, -1):
        for j in range(N):
            summer = KahanSum()
            for k in range(N - 1, i, -1):
                summer.add(U[i, k] * x[k, j])
            sum = summer.result()
            x[i, j] = (y[i, j] - sum) / (U[i, i])

    return x
示例#9
0
def inverse_iteration(A, max_iter=1000):
    """Finds the smallest eigenpair of a symmetric matrix.

  Args:
    A: a square symmetric array of shape (N, N).

  Returns:
    e, v: eigenvalue and right eigenvector.
  """
    assert utils.is_symmetric(A), "[!] Matrix must be symmetric."
    v = np.random.randn(A.shape[0])
    PLU = LU(A, pivoting='partial').decompose()
    for i in range(max_iter):
        v_new = solve(PLU, v)
        v_new = utils.normalize(v_new)
        if np.all(np.abs(v_new - v) < 1e-8):
            break
        v = v_new
    e = rayleigh_quotient(A, v)
    return e, v
示例#10
0
    def test_full_pivoting(self):
        T = np.random.randn(50, 50)

        actual = list(LU(T, pivoting='full').decompose())

        self.assertTrue(np.allclose(multi_dot(actual), T))
示例#11
0
def solve(A_or_plu_or_pluq, b, pivoting='partial'):
    """Solves the linear system of equations Ax = b for a well-determined A.

  Concretely, uses PLU decomposition of A followed by forward
  and back substitution to solve for x.

  Args:
    A: a numpy array of shape (N, N) or a tuple containing a
      previously computed factorization.
    b: a numpy array of shape (N,).
    pivoting: 'partial' or 'full' pivoting.

  Returns:
    x: a numpy array of shape (N, ).
  """
    if isinstance(A_or_plu_or_pluq, tuple):
        solver = LU(np.eye(A_or_plu_or_pluq[0].shape[0]), pivoting=pivoting)

        solver.set_P(A_or_plu_or_pluq[0])
        solver.set_L(A_or_plu_or_pluq[1])
        solver.set_U(A_or_plu_or_pluq[2])
        if len(A_or_plu_or_pluq) > 3:
            solver.set_Q(A_or_plu_or_pluq[3])
    else:
        M, N = A_or_plu_or_pluq.shape
        Z = len(b)

        error_msg = "[!] A must be square."
        assert (M == N), error_msg

        error_msg = "[!] b must be {}-D".format(M)
        assert (Z == N), error_msg

        solver = LU(A_or_plu_or_pluq, pivoting=pivoting)
        solver.decompose()

    x = solver.solve(b)

    return x