Пример #1
0
def power_iteration(A, max_iter=1000):
    v = np.random.randn(A.shape[0])
    vs = [v.copy()]
    for i in range(max_iter):
        v = A @ v
        v /= utils.l2_norm(v)
        vs.append(v.copy())
    return vs
Пример #2
0
def rayleigh_quotient_iteration(A, mu, max_iter=1000):
    v = np.random.randn(A.shape[0])
    vs = [v.copy()]
    for i in range(max_iter):
        v = solve(A - mu * np.eye(A.shape[0]), v)
        v /= utils.l2_norm(v)
        vs.append(v.copy())
        mu = single.rayleigh_quotient(A, v)
    return vs
Пример #3
0
  def gram_schmidt_modified(self):
    """Computes QR using the modified Gram-Schmidt method.

    More numerically stable than the naive Gram-Schmidt method,
    but there should be no reason to use this over the Householder
    method.
    """
    self.A = np.array(self.backup)
    M, N = self.A.shape
    self.R = np.array(self.A)
    for i in range(N):
      self.A[:, i] /= utils.l2_norm(self.A[:, i])
      for j in range(i+1, N):
        self.A[:, j] -= utils.projection(self.A[:, j], self.A[:, i])
    self.Q = self.A
    self.R = self.Q.T @ self.R
    return self.Q, self.R
Пример #4
0
def hessenberg(A, calc_q=False):
    """Reduce a square matrix to upper Hessenberg form using Householder reflections.

  If the input matrix is symmetric, the resulting Hessenberg form is
  reduced to tridiagonal form.

  Args:
    A: A square matrix of shape (M, M).
    calc_q (bool): Whether to explicitly compute the product of
      similarity transform Householder matrices.

  Returns:
    A: The upper Hessenberg form of the matrix of shape (M, M).
    Q: The product of Householder matrices of shape (M, M). Only
      returned if `calc_q=True`.
  """
    assert utils.is_square(A), "[!] Matrix must be square."
    is_symm = utils.is_symmetric(A)
    A = np.array(A)
    M, _ = A.shape
    vs = []
    for i in range(M - 2):
        a = A[i + 1:, i]
        c = utils.l2_norm(a)
        s = utils.sign(a[0])
        e = utils.basis_vec(0, len(a), flat=True)
        v = a + s * c * e
        vs.append(v)
        # left transform
        for j in range(i, M):
            A[i + 1:,
              j] = A[i + 1:, j] - (2 * v.T @ A[i + 1:, j]) / (v.T @ v) * v
        # right transform
        for j in range(i if is_symm else 0, M):
            A[j, i + 1:M] = A[j, i + 1:M] - 2 * ((A[j, i + 1:M].T @ v) /
                                                 (v.T @ v)) * v.T
    if calc_q:
        Q = np.eye(M)
        for i in range(M):
            for j, v in enumerate(reversed(vs)):
                Q[M - j - 2:,
                  i] -= (2 * v.T @ Q[M - j - 2:, i]) / (v.T @ v) * v
        return A, Q
    return A
Пример #5
0
  def gram_schmidt(self):
    """Computes QR using the Gram-Schmidt method.

    Suffers from numerical instabilities when 2 vectors
    are nearly orthogonal which may cause loss of
    orthogonality between the columns of Q.

    Since we compute a unique QR decomposition, we force
    the diagonal elements of R to be positive.
    """
    self.A = np.array(self.backup)
    M, N = self.A.shape
    self.R = np.array(self.A)
    self.A[:, 0] /= utils.l2_norm(self.A[:, 0])
    for i in range(1, N):
      for j in range(i):
        self.A[:, i] -= utils.projection(self.A[:, i], self.A[:, j])
      utils.normalize(self.A[:, i], inplace=True)
    self.Q = self.A
    self.R = np.dot(self.Q.T, self.R)
    return self.Q, self.R
Пример #6
0
  def householder(self, ret=True):
    """Computes QR using the Householder method.
    """
    self.A = np.array(self.backup)
    M, N = self.A.shape
    K = min(M, N)

    vs = []
    for i in range(K):
      # extract subdiagonal entries of column i
      a = self.A[i:, i]

      # construct reflection vector
      c = utils.l2_norm(a)
      s = utils.sign(a[0])
      e = utils.basis_vec(0, len(a), flat=True)
      v = a + s*c*e
      vs.append(v)

      # annihlate subdiagonal entries of all columns to the right
      if not np.isclose(v.T @ v, 0):
        for j in range(i, K):
          self.A[i:, j] -= (2 * v.T @ self.A[i:, j]) / (v.T @ v) * v

    # construct Q implicitly
    self.Q = np.eye(M)
    for i in range(M):
      for j, v in enumerate(reversed(vs)):
        if not np.isclose(v.T @ v, 0):
          self.Q[K-j-1:, i] -= (2 * v.T @ self.Q[K-j-1:, i]) / (v.T @ v) * v

    self.R = self.A
    if self.reduce:
      self.Q = self.Q[:, :K]
      self.R = self.R[:K, :]
    if ret:
      return self.Q, self.R