예제 #1
0
def projected_iteration(A, k, max_iter=1000, sort=True):
    """Sequentially find the k eigenpairs of a symmetric matrix.

  Concretely, combines power iteration and deflation to find
  eigenpairs in order of decreasing magnitude.

  Args:
    A: a square symmetric array of shape (N, N).
    k (int): the number of eigenpairs to return.
    sort (bool): Whether to sort by decreasing eigenvalue magnitude.

  Returns:
    e, v: eigenvalues and eigenvectors. The eigenvectors are
      stacked column-wise.
  """
    assert utils.is_symmetric(A), "[!] Matrix must be symmetric."
    assert k > 0 and k <= A.shape[0], "[!] k must be between 1 and {}.".format(
        A.shape[0])

    eigvecs = np.zeros((A.shape[0], k))
    eigvals = np.zeros(A.shape[0])
    for i in range(k):
        v = np.random.randn(A.shape[0])
        for _ in range(max_iter):
            # project out computed eigenvectors
            proj_sum = np.zeros_like(v)
            for j in range(i):
                proj_sum += utils.projection(v, eigvecs[:, j])
            v -= proj_sum

            v_new = A @ v
            v_new = utils.normalize(v_new)
            if np.all(np.abs(v_new - v) < 1e-8):
                break
            v = v_new
        e = single.rayleigh_quotient(A, v)

        # store eigenpair
        eigvecs[:, i] = np.array(v)
        eigvals[i] = e

    # sort by largest absolute eigenvalue
    if sort:
        idx = np.abs(eigvals).argsort()[::-1]
        eigvecs = eigvecs[:, idx]
        eigvals = eigvals[idx]

    return eigvals, eigvecs
예제 #2
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
예제 #3
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