def getHKS(mesh, num_samples=3, num_components=50, feature_name='hks', tau=1, eps=1e-5, normalize=True, **kwargs): try: from scipy.sparse.linalg import eigsh as sp_eigs from scipy.sparse import diags except ModuleNotFoundError: raise ModuleNotFoundError("The dependency 'SciPy' is required for this functionality!") # compute eigenvalues and eigenvectors of Laplace-Beltrami operator L = -mesh.cot_matrix M = mesh.mass_matrix try: evals, evecs = sp_eigs(L, k=num_components, M=M, which='LM', sigma=0, **kwargs) except RuntimeError: # add small value to cot matrix to try and make it invertable D = diags(eps*np.ones(L.shape[0])) L = L + D evals, evecs = sp_eigs(L, k=num_components, M=M, which='LM', sigma=0, **kwargs) if normalize: evals = evals/evals.sum() scale = mesh.area else: scale = 1 # determine time samples tmin = tau/min(evals.max(), 1e+1) tmax = tau/max(evals.min(), 1e-3) tsamps = np.exp(np.linspace(np.log(tmin), np.log(tmax), num_samples)) # compute heat kernel signatures evecs = evecs**2 feature_names = [] for i, t in enumerate(tsamps): fn = "{}{}".format(feature_name, i+1) HKS = scale*np.sum(np.exp(-t*evals)*evecs, axis=1) mesh.vertex_attributes[fn] = clipOutliers(HKS) feature_names.append(fn) return feature_names
def cond(A, M=None): 'Get the condition number of A or inv(B)*A' if __method__ == 'scipy': large, _ = sp_eigs(A, k=2, M=M, which='LM') small, _ = sp_eigs(A, k=4, M=M, which='LM', sigma=1E-8, tol=1E-10) l_max = np.max(large) l_min = np.min(small) print 'Lambda_max', l_max, 'Lambda_min', l_min return abs(l_max)/abs(l_min) elif __method__ == 'matlab': # Dump the matrix to A.m dump_matrix('A.m', 'A', A) # Call matlab to get eigs for problem B*u = a*u, stored in cond.m os.system('matlab -nodesktop < run_A.m') # Parse the file to get condition number with open('cond.m') as f: for line in f: print float((line.strip().split())[0])
def segment(img_brightness): ''' Compute and return the two segments of the image as described in the text. Compute L, the laplacian matrix. Then compute D^(-1/2)LD^(-1/2),and find the eigenvector corresponding to the second smallest eigenvalue. Use this eigenvector to calculate a mask that will be usedto extract the segments of the image. Inputs: img_brightness (array): an array of brightnesses given by the function getImage(). Returns: seg1 (array): an array the same size as img_brightness, but with 0's for each pixel not included in the positive segment (which corresponds to the positive entries of the computed eigenvector) seg2 (array): an array the same size as img_brightness, but with 0's for each pixel not included in the negative segment. ''' m, n = img_brightness.shape W, D_vals = adjacency(img_brightness, radius=6.0) temp_D = np.diagflat(D_vals) L = temp_D - W L = csc_matrix(L) D_vals = 1. / np.sqrt(D_vals) sqrD_matrix = np.diagflat(D_vals) sqrD_matrix = csc_matrix(sqrD_matrix) DLD = sqrD_matrix.dot(L.dot(sqrD_matrix)) k, v = sp_eigs(DLD, which="SR") e_val = k[1] e_vec = v[:, 1] mask1 = e_vec > 0 mask2 = e_vec <= 0 mask1 = np.reshape(mask1, (m, n)) mask2 = np.reshape(mask2, (m, n)) seg1 = np.multiply(img_brightness, mask1) seg2 = np.multiply(img_brightness, mask2) return seg1, seg2
def segment(img_brightness): ''' Compute and return the two segments of the image as described in the text. Compute L, the laplacian matrix. Then compute D^(-1/2)LD^(-1/2),and find the eigenvector corresponding to the second smallest eigenvalue. Use this eigenvector to calculate a mask that will be usedto extract the segments of the image. Inputs: img_brightness (array): an array of brightnesses given by the function getImage(). Returns: seg1 (array): an array the same size as img_brightness, but with 0's for each pixel not included in the positive segment (which corresponds to the positive entries of the computed eigenvector) seg2 (array): an array the same size as img_brightness, but with 0's for each pixel not included in the negative segment. ''' m,n = img_brightness.shape W,D_vals = adjacency(img_brightness, radius=6.0) temp_D = np.diagflat(D_vals) L = temp_D-W L = csc_matrix(L) D_vals = 1./np.sqrt(D_vals) sqrD_matrix = np.diagflat(D_vals) sqrD_matrix = csc_matrix(sqrD_matrix) DLD = sqrD_matrix.dot(L.dot(sqrD_matrix)) k,v = sp_eigs(DLD, which="SR") e_val = k[1] e_vec = v[:,1] mask1 = e_vec > 0 mask2 = e_vec <= 0 mask1 = np.reshape(mask1, (m,n)) mask2 = np.reshape(mask2, (m,n)) seg1 = np.multiply(img_brightness,mask1) seg2 = np.multiply(img_brightness,mask2) return seg1, seg2
def getHKS(mesh, num_samples=3, num_components=50, feature_name='hks', tau=1, **kwargs): # compute eigenvalues and eigenvectors of Laplace-Beltrami operator L = -mesh.cot_matrix M = mesh.mass_matrix evals, evecs = sp_eigs(L, k=num_components, M=M, which='LM', sigma=0, **kwargs) # determine time samples tmin = tau/min(evals.max(), 1e+1) tmax = tau/max(evals.min(), 1e-3) tsamps = np.exp(np.linspace(np.log(tmin), np.log(tmax), num_samples)) # compute heat kernel signatures evecs = evecs**2 feature_names = [] for i, t in enumerate(tsamps): fn = "{}{}".format(feature_name, i+1) HKS = np.sum(np.exp(-t*evals)*evecs, axis=1) mesh.vertex_attributes[fn] = clipOutliers(HKS) feature_names.append(fn) return feature_names
def eigs(self, neigs=None, symmetric=False, niter=None, uselobpcg=False, **kwargs_eig): r"""Most significant eigenvalues of linear operator. Return an estimate of the most significant eigenvalues of the linear operator. If the operator has rectangular shape (``shape[0]!=shape[1]``), eigenvalues are first computed for the square operator :math:`\mathbf{A^H}\mathbf{A}` and the square-root values are returned. Parameters ---------- neigs : :obj:`int` Number of eigenvalues to compute (if ``None``, return all). Note that for ``explicit=False``, only :math:`N-1` eigenvalues can be computed where :math:`N` is the size of the operator in the model space symmetric : :obj:`bool`, optional Operator is symmetric (``True``) or not (``False``). User should set this parameter to ``True`` only when it is guaranteed that the operator is real-symmetric or complex-hermitian matrices niter : :obj:`int`, optional Number of iterations for eigenvalue estimation uselobpcg : :obj:`bool`, optional Use :func:`scipy.sparse.linalg.lobpcg` **kwargs_eig Arbitrary keyword arguments for :func:`scipy.sparse.linalg.eigs`, :func:`scipy.sparse.linalg.eigsh`, or :func:`scipy.sparse.linalg.lobpcg` Returns ------- eigenvalues : :obj:`numpy.ndarray` Operator eigenvalues. Raises ------- ValueError If ``uselobpcg=True`` for a non-symmetric square matrix with complex type Notes ----- Depending on the size of the operator, whether it is explicit or not and the number of eigenvalues requested, different algorithms are used by this routine. More precisely, when only a limited number of eigenvalues is requested the :func:`scipy.sparse.linalg.eigsh` method is used in case of ``symmetric=True`` and the :func:`scipy.sparse.linalg.eigs` method is used ``symmetric=False``. However, when the matrix is represented explicitly within the linear operator (``explicit=True``) and all the eigenvalues are requested the :func:`scipy.linalg.eigvals` is used instead. Finally, when only a limited number of eigenvalues is required, it is also possible to explicitly choose to use the ``scipy.sparse.linalg.lobpcg`` method via the ``uselobpcg`` input parameter flag. Most of these algorithms are a port of ARPACK [1]_, a Fortran package which provides routines for quickly finding eigenvalues/eigenvectors of a matrix. As ARPACK requires only left-multiplication by the matrix in question, eigenvalues/eigenvectors can also be estimated for linear operators when the dense matrix is not available. .. [1] http://www.caam.rice.edu/software/ARPACK/ """ if self.explicit and isinstance(self.A, np.ndarray): if self.shape[0] == self.shape[1]: if neigs is None or neigs == self.shape[1]: eigenvalues = eigvals(self.A) else: if not symmetric and np.iscomplexobj(self) and uselobpcg: raise ValueError( 'cannot use scipy.sparse.linalg.lobpcg ' 'for non-symmetric square matrices of ' 'complex type...') if symmetric and uselobpcg: X = np.random.rand(self.shape[0], neigs) eigenvalues = \ sp_lobpcg(self.A, X=X, maxiter=niter, **kwargs_eig)[0] elif symmetric: eigenvalues = sp_eigsh(self.A, k=neigs, maxiter=niter, **kwargs_eig)[0] else: eigenvalues = sp_eigs(self.A, k=neigs, maxiter=niter, **kwargs_eig)[0] else: if neigs is None or neigs == self.shape[1]: eigenvalues = np.sqrt( eigvals(np.dot(np.conj(self.A.T), self.A))) else: if uselobpcg: X = np.random.rand(self.shape[1], neigs) eigenvalues = np.sqrt( sp_lobpcg(np.dot(np.conj(self.A.T), self.A), X=X, maxiter=niter, **kwargs_eig)[0]) else: eigenvalues = np.sqrt( sp_eigsh(np.dot(np.conj(self.A.T), self.A), k=neigs, maxiter=niter, **kwargs_eig)[0]) else: if neigs is None or neigs >= self.shape[1]: neigs = self.shape[1] - 2 if self.shape[0] == self.shape[1]: if not symmetric and np.iscomplexobj(self) and uselobpcg: raise ValueError( 'cannot use scipy.sparse.linalg.lobpcg for ' 'non symmetric square matrices of ' 'complex type...') if symmetric and uselobpcg: X = np.random.rand(self.shape[0], neigs) eigenvalues = \ sp_lobpcg(self, X=X, maxiter=niter, **kwargs_eig)[0] elif symmetric: eigenvalues = sp_eigsh(self, k=neigs, maxiter=niter, **kwargs_eig)[0] else: eigenvalues = sp_eigs(self, k=neigs, maxiter=niter, **kwargs_eig)[0] else: if uselobpcg: X = np.random.rand(self.shape[1], neigs) eigenvalues = np.sqrt( sp_lobpcg(self.H * self, X=X, maxiter=niter, **kwargs_eig)[0]) else: eigenvalues = np.sqrt( sp_eigs(self.H * self, k=neigs, maxiter=niter, **kwargs_eig)[0]) return -np.sort(-eigenvalues)
def eigs(self, neigs=None, symmetric=False, niter=None, **kwargs_eig): r"""Most significant eigenvalues of linear operator. Return an estimate of the most significant eigenvalues of the linear operator. If the operator has rectangular shape (``shape[0]!=shape[1]``), eigenvalues are first computed for the square operator :math:`\mathbf{A^H}\mathbf{A}` and the square-root values are returned. Parameters ---------- neigs : :obj:`int` Number of eigenvalues to compute (if ``None``, return all). Note that for ``explicit=False``, only :math:`N-1` eigenvalues can be computed where :math:`N` is the size of the operator in the model space symmetric : :obj:`bool`, optional Operator is symmetric (``True``) or not (``False``). User should set this parameter to ``True`` only when it is guaranteed that the operator is real-symmetric or complex-hermitian matrices niter : :obj:`int`, optional Number of iterations for eigenvalue estimation **kwargs_eig Arbitrary keyword arguments for :func:`scipy.sparse.linalg.eigs` or :func:`scipy.sparse.linalg.eigsh` Returns ------- eigenvalues : :obj:`numpy.ndarray` Operator eigenvalues. Notes ----- Eigenvalues are estimated using :func:`scipy.sparse.linalg.eigs` (``explicit=True``) or :func:`scipy.sparse.linalg.eigsh` (``explicit=False``). This is a port of ARPACK [1]_, a Fortran package which provides routines for quickly finding eigenvalues/eigenvectors of a matrix. As ARPACK requires only left-multiplication by the matrix in question, eigenvalues/eigenvectors can also be estimated for linear operators when the dense matrix is not available. .. [1] http://www.caam.rice.edu/software/ARPACK/ """ if self.explicit and isinstance(self.A, np.ndarray): if self.shape[0] == self.shape[1]: if neigs is None or neigs == self.shape[1]: eigenvalues = eigvals(self.A) else: if symmetric: eigenvalues = sp_eigsh(self.A, k=neigs, maxiter=niter, **kwargs_eig)[0] else: eigenvalues = sp_eigs(self.A, k=neigs, maxiter=niter, **kwargs_eig)[0] else: if neigs is None or neigs == self.shape[1]: eigenvalues = np.sqrt( eigvals(np.dot(np.conj(self.A.T), self.A))) else: eigenvalues = np.sqrt( sp_eigsh(np.dot(np.conj(self.A.T), self.A), k=neigs, maxiter=niter, **kwargs_eig)[0]) else: if neigs is None or neigs >= self.shape[1]: neigs = self.shape[1] - 2 if self.shape[0] == self.shape[1]: if symmetric: eigenvalues = sp_eigsh(self, k=neigs, maxiter=niter, **kwargs_eig)[0] else: eigenvalues = sp_eigs(self, k=neigs, maxiter=niter, **kwargs_eig)[0] else: eigenvalues = np.sqrt( sp_eigs(self.H * self, k=neigs, maxiter=niter, **kwargs_eig)[0]) return -np.sort(-eigenvalues)