Source code for geomfum.operator

"""Functional operators."""

import abc

from geomfum._registry import (
    FaceDivergenceOperatorRegistry,
    FaceOrientationOperatorRegistry,
    FaceValuedGradientRegistry,
    WhichRegistryMixins,
)
from geomfum.laplacian import LaplacianFinder, LaplacianSpectrumFinder

# TODO: remove functional; simply use operator


[docs] class FunctionalOperator(abc.ABC): """Functional operator.""" # TODO: move to operator def __init__(self, shape): self._shape = shape @abc.abstractmethod def __call__(self, point): """Apply operator. Parameters ---------- point : array-like, shape=[..., n_vertices] """
# TODO: update docstrings
[docs] class VectorFieldOperator(abc.ABC): """Vector field operator.""" # TODO: really needed? def __init__(self, shape): self._shape = shape @abc.abstractmethod def __call__(self, vector): """Apply operator. Parameters ---------- point : array-like, shape=[..., n_faces, 3] """
# TODO: update docstrings
[docs] class Laplacian(FunctionalOperator): """Laplacian. Check [P2016]_ for representation choice. Parameters ---------- stiffness_matrix : array-like, shape=[n_vertices, n_vertices] Stiffness matrix. mass_matrix : array-like, shape=[n_vertices, n_vertices] Diagonal lumped mass matrix. References ---------- .. [P2016] Giuseppe Patané. “STAR - Laplacian Spectral Kernels and Distances for Geometry Processing and Shape Analysis.” Computer Graphics Forum 35, no. 2 (2016): 599–624. https://doi.org/10.1111/cgf.12866. """ def __init__(self, shape, stiffness_matrix=None, mass_matrix=None): super().__init__(shape) self._stiffness_matrix = stiffness_matrix self._mass_matrix = mass_matrix self._basis = None @property def stiffness_matrix(self): """Stiffness matrix. Returns ------- stiffness_matrix : array-like, shape=[n_vertices, n_vertices] Stiffness matrix. """ if self._stiffness_matrix is None: self.find() return self._stiffness_matrix @property def mass_matrix(self): """Mass matrix. Returns ------- mass_matrix : array-like, shape=[n_vertices, n_vertices] Mass matrix. """ if self._mass_matrix is None: self.find() return self._mass_matrix @property def basis(self): """Laplace eigenbasis. Returns ------- basis : LaplaceEigenBasis Laplace eigenbasis. """ if self._basis is None: self.find_spectrum() return self._basis
[docs] def find(self, laplacian_finder=None, recompute=False): """Find Laplacian. Parameters ---------- laplacian_finder : BaseLaplacianFinder Algorithm to find the Laplacian. recompute : bool Whether to recompute Laplacian if information is cached. Returns ------- stiffness_matrix : array-like, shape=[n_vertices, n_vertices] Stiffness matrix. mass_matrix : array-like, shape=[n_vertices, n_vertices] Diagonal lumped mass matrix. """ if ( not recompute and self._stiffness_matrix is not None and self._mass_matrix is not None ): return self._stiffness_matrix, self._mass_matrix if laplacian_finder is None: laplacian_finder = LaplacianFinder.from_registry( mesh=self._shape.is_mesh, which="robust" ) self._stiffness_matrix, self._mass_matrix = laplacian_finder(self._shape) return self._stiffness_matrix, self._mass_matrix
[docs] def find_spectrum( self, spectrum_size=100, laplacian_spectrum_finder=None, set_as_basis=True, recompute=False, ): """Find Laplacian spectrum. Parameters ---------- spectrum_size : int Spectrum size. Ignored if ``laplacian_spectrum_finder`` is not None. laplacian_spectrum_finder : LaplacianSpectrumFinder Algorithm to find Laplacian spectrum. set_as_basis : bool Whether to set spectrum as basis. recompute : bool Whether to recompute spectrum if information is cached in basis. Returns ------- eigenvals : array-like, shape=[spectrum_size] Eigenvalues. eigenvecs : array-like, shape=[n_vertices, spectrum_size] Eigenvectors. """ if not recompute and self._basis is not None: if set_as_basis: self._shape.set_basis(self.basis) return self.basis.full_vals, self.basis.full_vecs if laplacian_spectrum_finder is None: laplacian_spectrum_finder = LaplacianSpectrumFinder( spectrum_size=spectrum_size, nonzero=False, fix_sign=False, ) self._basis = laplacian_spectrum_finder(self._shape, as_basis=True) if set_as_basis: self._shape.set_basis(self.basis) return self.basis.full_vals, self.basis.full_vecs
def __call__(self, point): """Apply operator. Parameters ---------- point : array-like, shape=[..., n_vertices] """ raise NotImplementedError("Not implemented yet.")
[docs] class FaceValuedGradient(WhichRegistryMixins, FunctionalOperator): """Gradient of a function on a mesh. Computes the gradient of a function on f using linear interpolation between vertices. """ _Registry = FaceValuedGradientRegistry
[docs] class FaceDivergenceOperator(WhichRegistryMixins, VectorFieldOperator): """Divergence of a function on a mesh.""" _Registry = FaceDivergenceOperatorRegistry
[docs] class FaceOrientationOperator(WhichRegistryMixins, VectorFieldOperator): r"""Orientation operator associated to a gradient field. For a given function :math:`g` on the vertices, this operator linearly computes :math:`< \grad(f) x \grad(g)`, n> for each vertex by averaging along the adjacent faces. In practice, we compute :math:`< n x \grad(f), \grad(g) >` for simpler computation. """ _Registry = FaceOrientationOperatorRegistry