Notebook source code:
notebooks/how_to/07_functional_map.ipynb
Run it yourself on binder
How to compute a functional map?#
In [1]:
import geomstats.backend as gs
from geomfum.dataset import NotebooksDataset
from geomfum.descriptor.pipeline import (
ArangeSubsampler,
DescriptorPipeline,
L2InnerNormalizer,
)
from geomfum.descriptor.spectral import HeatKernelSignature, WaveKernelSignature
from geomfum.functional_map import (
FactorSum,
LBCommutativityEnforcing,
OperatorCommutativityEnforcing,
SpectralDescriptorPreservation,
)
from geomfum.numerics.optimization import ScipyMinimize
from geomfum.shape import TriangleMesh
In [2]:
dataset = NotebooksDataset()
mesh_a = TriangleMesh.from_file(dataset.get_filename("cat-00"))
mesh_b = TriangleMesh.from_file(dataset.get_filename("lion-00"))
Set Laplace eigenbasis for each mesh.
In [3]:
mesh_a.laplacian.find_spectrum(spectrum_size=10, set_as_basis=True)
mesh_b.laplacian.find_spectrum(spectrum_size=10, set_as_basis=True)
# I decide to visualize just the first 8 eigenfunctions
mesh_b.basis.use_k = 8
Set a descriptor pipeline and apply it to both shapes.
In [4]:
steps = [
HeatKernelSignature.from_registry(n_domain=4),
ArangeSubsampler(subsample_step=2),
WaveKernelSignature.from_registry(n_domain=3),
L2InnerNormalizer(),
]
pipeline = DescriptorPipeline(steps)
In [5]:
descr_a = pipeline.apply(mesh_a)
descr_b = pipeline.apply(mesh_b)
Create objective function:
The optimization of the functional map can be performed considering different constraints, for example:
SpectralDescriptorPreservation: the functional map needs to align spectral coefficients of descriptors.
LBCommutativityEnforcing: the functional map needs to commute with the Laplace Beltrami operator.
OperatorCommutativityEnforcing: the functional map needs to commute with a chosen operator defined on meshes.
Details about these energies can be found in https://dl.acm.org/doi/10.1145/3084873.3084877.
In [6]:
factors = [
SpectralDescriptorPreservation(
mesh_a.basis.project(descr_a),
mesh_b.basis.project(descr_b),
weight=1.0,
),
LBCommutativityEnforcing.from_bases(
mesh_a.basis,
mesh_b.basis,
weight=1e-2,
),
OperatorCommutativityEnforcing.from_multiplication(
mesh_a.basis, descr_a, mesh_b.basis, descr_b, weight=1e-1
),
OperatorCommutativityEnforcing.from_orientation(
mesh_a, descr_a, mesh_b, descr_b, weight=1e-1
),
]
objective = FactorSum(factors)
Instantiate an Optimizer
and solve for the functional map matrix.
In [7]:
optimizer = ScipyMinimize(
method="L-BFGS-B",
)
In [8]:
x0 = gs.zeros((mesh_b.basis.spectrum_size, mesh_a.basis.spectrum_size))
res = optimizer.minimize(
objective,
x0,
fun_jac=objective.gradient,
)
fmap = res.x.reshape(x0.shape)
fmap.shape
Out [8]:
(8, 10)