Source code for geomfum.shape.hierarchical
"""Hierarchical objects."""
import abc
from geomfum._registry import HierarchicalMeshRegistry, WhichRegistryMixins
from geomfum.basis import EigenBasis
[docs]
class HierarchicalShape(abc.ABC):
"""Hierarchical shape.
Parameters
----------
low : Shape
Low-resolution shape.
high : Shape
High-resolution shape.
"""
def __init__(self, low, high):
self.low = low
self.high = high
[docs]
@abc.abstractmethod
def scalar_low_high(self, scalar):
"""Transfer scalar from low-resolution to high.
Parameters
----------
scalar : array-like, shape=[..., low.n_vertices]
Scalar map on the low-resolution shape.
Returns
-------
high_scalar : array-like, shape=[..., high.n_vertices]
Scalar map on the high-resolution shape.
"""
[docs]
def extend_basis(self, set_as_basis=True):
"""Extend basis.
See section 3.3. of [MBMR2023]_ for details.
Parameters
----------
set_as_basis : bool
Whether to set as basis.
Return
------
vecs : array-like, shape=[high.n_vertices, spectrum_size]
Eigenvectors.
References
----------
.. [MBMR2023] Filippo Maggioli, Daniele Baieri, Simone Melzi, and Emanuele Rodolà.
“ReMatching: Low-Resolution Representations for Scalable Shape
Correspondence.” arXiv, October 30, 2023.
https://doi.org/10.48550/arXiv.2305.09274.
"""
hvecs = self.scalar_low_high(self.low.basis.full_vecs.T).T
if set_as_basis:
basis = EigenBasis(self.low.basis.full_vals, hvecs)
self.high.set_basis(basis)
return hvecs
[docs]
class HierarchicalMesh(WhichRegistryMixins, HierarchicalShape):
"""Hierarchical mesh.
Parameters
----------
low : TriangleMesh
Low resolution shape.
high : TriangleMesh
High resolution shape.
"""
_Registry = HierarchicalMeshRegistry
[docs]
class NestedHierarchicalShape:
"""Nested hierachical shape.
Parameters
----------
hshapes : list[HierarchicalShape]
Hierarchical shapes from low to high resolution.
"""
def __init__(self, hshapes):
self.hshapes = hshapes
@property
def shapes(self):
"""Shapes from low to high resolution.
Remarks
-------
shapes : list[Shape]
List of shapes from low to high resolution.
"""
return [hshape.low for hshape in self.hshapes] + [self.hshapes[-1].high]
@property
def lowest(self):
"""Lowest resolution shape.
Returns
-------
shape : Shape.
"""
return self.hshapes[0].low
@property
def highest(self):
"""Highest resolution shape.
Returns
-------
shape : Shape.
"""
return self.hshapes[-1].high
[docs]
@classmethod
def from_hierarchical_shape(cls, shape, HierarchicalShape, **kwargs):
"""Create nested from hierarchical.
Parameters
----------
shape : Shape.
High-resolution shape.
HierarchicalShape : HierarchicalShape object
Class for the mapping between two resolutions.
Signature: `(high_res_shape, **kwargs).
kwargs: dict
Each must be a list with the proper number of resolution levels.
"""
n_levels = len(kwargs[list(kwargs.keys())[0]])
hshapes = []
for n_level in range(n_levels):
level_kwargs = {}
for key, value in kwargs.items():
level_kwargs[key] = value[n_level]
hshapes.append(HierarchicalShape(shape, **level_kwargs))
shape = hshapes[-1].low
hshapes.reverse()
return cls(hshapes)
[docs]
def scalar_low_high(self, scalar, n_levels=None):
"""Transfer scalar from low-resolution to high.
Parameters
----------
scalar : array-like, shape=[..., low.n_vertices]
Scalar map on the low-resolution shape.
n_levels : int
Number of levels to transfer scalar.
If ``None`` transfer up to maximum resolution.
Returns
-------
high_scalar : list[array-like], shape=[..., level.n_vertices]
Scalar map on the shape at corresponding level.
As many as number of levels.
"""
n_levels = n_levels or len(self.hshapes)
scalars = [scalar]
for _, hshape in zip(range(n_levels), self.hshapes):
scalars.append(hshape.scalar_low_high(scalars[-1]))
return scalars
[docs]
def extend_basis(self, set_as_basis=True, n_levels=None):
"""Extend basis.
See section 3.3. of [MBMR2023]_ for details.
Parameters
----------
set_as_basis : bool
Whether to set as basis.
n_levels : int
Number of levels to transfer scalar.
If ``None`` transfer up to maximum resolution.
Return
------
vecs : list[array-like], shape=[level.n_vertices, spectrum_size]
Eigenvectors.
As many as number of levels.
References
----------
.. [MBMR2023] Filippo Maggioli, Daniele Baieri, Simone Melzi, and Emanuele Rodolà.
“ReMatching: Low-Resolution Representations for Scalable Shape
Correspondence.” arXiv, October 30, 2023.
https://doi.org/10.48550/arXiv.2305.09274.
"""
n_levels = n_levels or len(self.hshapes)
vecs = [self.hshapes[0].low.basis.full_vecs]
for _, hshape in zip(range(n_levels), self.hshapes):
vecs.append(hshape.extend_basis(set_as_basis=set_as_basis))
return vecs
[docs]
class NestedHierarchicalMesh(NestedHierarchicalShape):
"""Nested hierachical mesh."""
@property
def hmeshes(self):
"""Meshes from low to high resolution.
Remarks
-------
hshapes : list[HierarchicalMesh]
Hierarchical meshes from low to high resolution.
"""
return self.hshapes
@property
def meshes(self):
"""Meshes from low to high resolution.
Remarks
-------
meshes : list[Mesh]
List of meshes from low to high resolution.
"""
return self.shapes
@property
def n_vertices(self):
"""Number of vertices at each level.
Returns
-------
n_vertices : list[int]
"""
return [mesh_.n_vertices for mesh_ in self.meshes]
@property
def n_faces(self):
"""Number of faces at each level.
Returns
-------
n_faces : list[int]
"""
return [mesh_.faces for mesh_ in self.meshes]