def sorted_eig(mat, thresh=0.0, n=None, sps=True): """ Returns n eigenvalues and vectors sorted from largest to smallest eigenvalue """ if sps: from scipy.sparse.linalg import eigs as speig if n is None: k = mat.shape[0] - 1 else: k = n val, vec = speig(mat, k=k, tol=thresh) val = np.real(val) vec = np.real(vec) idx = sorted(range(len(val)), key=lambda i: -val[i]) val = val[idx] vec = vec[:, idx] else: val, vec = np.linalg.eigh(mat) val = np.flip(val, axis=0) vec = np.flip(vec, axis=1) if n is not None and len(val[val < thresh]) < n: vec[:, val < thresh] = 0 val[val < thresh] = 0 else: vec = vec[:, val >= thresh] val = val[val >= thresh] return val[:n], vec[:, :n]
def eig_solver(matrix, n_components=None, tol=1e-12, add_null=False): """ This function returns the eigenpairs corresponding to the `n_components` largest eigenvalues. :param matrix: Matrix to decompose :type matrix: ndarray :param n_components: number of eigenpairs to return. If None, full eigendecomposition will be computed / returned :type n_components: int, None :param tol: value below which to assume an eigenvalue is 0 :type tol: float :param add_null: when the rank of matrix < n_components, whether to add (n_components - rank(matrix)) eigenpairs, defaults to False :type add_null: boolean """ if n_components is not None and n_components < matrix.shape[0]: v, U = speig(matrix, k=n_components, tol=tol) else: v, U = np.linalg.eig(matrix) U = np.real(U[:, np.argsort(-v)]) v = np.real(v[np.argsort(-v)]) if tol is not None: U = U[:, v > tol] v = v[v > tol] if len(v) == 1: U = U.reshape(-1, 1) if n_components is not None and n_components > len(v): if not add_null: warnings.warn(f"There are fewer than {n_components} " "significant eigenpair(s). Resulting decomposition" f"will be truncated to {len(v)} eigenpairs.") else: for i in range(len(v), n_components): v = np.array([*v, 0]) U = np.array([*U.T, np.zeros(U.shape[0])]).T return v[:n_components], U[:, :n_components]
def pcovr_select(A, n, Y, alpha, k=1, idxs=None, sps=False, **kwargs): """ Selection function which computes the CUR indices using the PCovR `Covariance` matrix """ Acopy = A.copy() Ycopy = Y.copy() if(idxs is None): idxs = [] # indexA is initially empty. else: idxs = list(idxs) try: for nn in tqdm(range(n)): if(len(idxs) <= nn): Ct = get_Ct(Acopy, Ycopy, alpha=alpha) if(not sps): v_Ct, U_Ct = sorted_eig(Ct, n=k) else: v_Ct, U_Ct = speig(Ct, k) U_Ct = U_Ct[:, np.flip(np.argsort(v_Ct))] pi = (np.real(U_Ct)[:, :k]**2.0).sum(axis=1) pi[idxs] = 0 # eliminate possibility of selecting same column twice j = pi.argmax() idxs.append(j) v = np.linalg.pinv( np.matmul(Acopy[:, idxs[:nn+1]].T, Acopy[:, idxs[:nn+1]])) v = np.matmul(Acopy[:, idxs[:nn+1]], v) v = np.matmul(v, Acopy[:, idxs[:nn+1]].T) Ycopy -= np.matmul(v, Ycopy) v = Acopy[:, idxs[nn]] / \ np.sqrt(np.matmul(Acopy[:, idxs[nn]], Acopy[:, idxs[nn]])) for i in range(Acopy.shape[1]): Acopy[:, i] -= v * np.dot(v, Acopy[:, i]) except: print("INCOMPLETE AT {}/{}".format(len(idxs), n)) return list(idxs)
def select(self, n): """Method for CUR select based upon a product of the input matrices Parameters ---------- n : number of selections to make, must be > 0 Returns ------- idx: list of n selections """ if n <= 0: raise ValueError("You must call select(n) with n > 0.") if len(self.idx) > n: return self.idx[:n] for i in self.report_progress(range(len(self.idx), n)): if self.iter: v, U = speig(self.product, k=self.k, tol=self.tol) U = U[:, np.flip(np.argsort(v))] pi = (np.real(U)[:, :self.k]**2.0).sum(axis=1) pi[self.idx] = 0.0 self.idx.append(pi.argmax()) self.pi.append(max(pi)) self.orthogonalize() self.product = self.get_product() if np.isnan(self.product).any(): print(f"The product matrix has rank {i}. " + f"n_select reduced from {n} to {i}.") return self.idx return self.idx
def _eigWrapper(A: spmatrix, k: int): # Take magnitude and sort according to largest k eigenvalues keigs, vectors = speig(A, k, which="LM", return_eigenvectors=True) keigs = keigs.real ix = keigs.argsort()[::-1] return vectors[:, ix].real, keigs[ix]