Source code for geomfum.basis

"""Basis implementations."""

import abc

import geomstats.backend as gs

import geomfum.linalg as la


[docs] class Basis(abc.ABC): """Basis."""
[docs] class EigenBasis(Basis): """Eigenbasis. Parameters ---------- vals : array-like, shape=[full_spectrum_size] Eigenvalues. vecs : array-like, shape=[dim, full_spectrum_size] Eigenvectors. use_k : int Number of values to use on computations. """ def __init__(self, vals, vecs, use_k=None): self.full_vals = vals self.full_vecs = vecs self.use_k = use_k # NB: assumes sorted self._n_zeros = gs.sum(gs.isclose(vals, 0.0)) @property def vals(self): """Eigenvalues. Returns ------- vals : array-like, shape=[spectrum_size] Eigenvalues. """ return self.full_vals[: self.use_k] @property def vecs(self): """Eigenvectors. Returns ------- vecs : array-like, shape=[dim, spectrum_size] Eigenvectors. """ return self.full_vecs[:, : self.use_k] @property def nonzero_vals(self): """Nonzero eigenvalues. Returns ------- vals : array-like, shape=[spectrum_size - n_zeros] Eigenvalues. """ return self.vals[self._n_zeros :] @property def nonzero_vecs(self): """Eigenvectors corresponding to nonzero eigenvalues. Returns ------- vecs : array-like, shape=[dim, spectrum_size - n_zeros] Eigenvectors. """ return self.vecs[:, self._n_zeros :] @property def spectrum_size(self): """Spectrum size. Returns ------- spectrum_size : int Spectrum size. """ return len(self.vals) @property def full_spectrum_size(self): """Full spectrum size. Returns ------- spectrum_size : int Spectrum size. """ return len(self.full_vals)
[docs] def truncate(self, spectrum_size): """Truncate basis. Parameters ---------- spectrum_size : int Spectrum size. Returns ------- basis : Eigenbasis Truncated eigenbasis. """ if spectrum_size == self.spectrum_size: return self return EigenBasis(self.vals[:spectrum_size], self.vecs[:, :spectrum_size])
[docs] class LaplaceEigenBasis(EigenBasis): """Laplace eigenbasis. Parameters ---------- shape : Shape Shape. vals : array-like, shape=[spectrum_size] Eigenvalues. vecs : array-like, shape=[dim, spectrum_size] Eigenvectors. use_k : int Number of values to use on computations. """ def __init__(self, shape, vals, vecs, use_k=None): super().__init__(vals, vecs, use_k) self._shape = shape self._pinv = None @property def use_k(self): """Number of values to use on computations. Returns ------- use_k : int Number of values to use on computations. """ return self._use_k @use_k.setter def use_k(self, value): """Set number of values to use on computations. Parameters ---------- use_k : int Number of values to use on computations. """ self._pinv = None self._use_k = value @property def pinv(self): """Inverse of the eigenvectors matrix. Return ------ pinv : array-like, shape=[spectrum_size, n_vertices] Inverse of the eigenvectors matrix. """ if self._pinv is None: self._pinv = self.vecs.T @ self._shape.laplacian.mass_matrix return self._pinv
[docs] def truncate(self, spectrum_size): """Truncate basis. Parameters ---------- spectrum_size : int Spectrum size. Returns ------- basis : LaplaceEigenBasis Truncated eigenbasis. """ if spectrum_size == self.spectrum_size: return self return LaplaceEigenBasis( self._shape, self.full_vals[:spectrum_size], self.full_vecs[:, :spectrum_size], )
[docs] def project(self, array): """Project on the eigenbasis. Parameters ---------- array : array-like, shape=[..., n_vertices] Array to project. Returns ------- projected_array : array-like, shape=[..., spectrum_size] Projected array. """ return la.matvecmul( self.vecs.T, la.matvecmul(self._shape.laplacian.mass_matrix, array), )