Source code for geomfum.basis
"""Basis implementations. This module defines various function space bases used in GeomFum. A basis is a set of functionsdefined on a shape that can be used to represent other functions on that shape."""
import abc
import gsops.backend as gs
import geomfum.linalg as la
[docs]
class Basis(abc.ABC):
"""Abstract base class for function space bases."""
[docs]
class EigenBasis(Basis):
"""Basis formed by eigenvectors with dynamic truncation support.
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):
"""Currently used eigenvalues (truncated to use_k).
Returns
-------
vals : array-like, shape=[spectrum_size]
Eigenvalues.
"""
return self.full_vals[: self.use_k]
@property
def vecs(self):
"""Currently used eigenvectors (truncated to use_k).
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):
"""Number of eigenvalues/eigenvectors currently in use.
Returns
-------
spectrum_size : int
Spectrum size.
"""
return len(self.vals)
@property
def full_spectrum_size(self):
"""Total number of stored eigenvalues/eigenvectors.
Returns
-------
spectrum_size : int
Spectrum size.
"""
return len(self.full_vals)
[docs]
def truncate(self, spectrum_size):
"""Create new basis with reduced spectrum size.
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):
"""Eigenbasis of the Laplace-Beltrami operator with mass matrix projection.
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 basis functions actively used in 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 basis functions to use (invalidates cached pinv).
Parameters
----------
use_k : int
Number of values to use on computations.
"""
self._pinv = None
self._use_k = value
@property
def pinv(self):
"""L2 pseudo-inverse for projecting functions onto the basis.
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):
"""Create new basis with reduced spectrum size.
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 function onto the eigenbasis using L2 inner product.
Parameters
----------
array : array-like, shape=[..., n_vertices]
Function values to project.
Returns
-------
projected_array : array-like, shape=[..., spectrum_size]
Spectral coefficients.
"""
return la.matvecmul(
self.vecs.T,
la.matvecmul(self._shape.laplacian.mass_matrix, array),
)