Notebook source code: notebooks/how_to/13_rematching.ipynb
Run it yourself on binder Binder badge

How to use ReMatching to compute a functional map?#

 In [1]:
import gsops.backend as gs

from geomfum.dataset import NotebooksDataset
from geomfum.refine import ZoomOut
from geomfum.shape import TriangleMesh
from geomfum.shape.hierarchical import HierarchicalMesh

Load meshes.

 In [2]:
dataset = NotebooksDataset()

mesh_a = TriangleMesh.from_file(dataset.get_filename("cat-00"))
mesh_b = TriangleMesh.from_file(dataset.get_filename("lion-00"))

(mesh_a.n_vertices, mesh_a.n_faces), (mesh_b.n_vertices, mesh_b.n_faces)
 Out [2]:
((7207, 14410), (5000, 9996))

Create hierarchical meshes.

 In [3]:
hmesh_a = HierarchicalMesh.from_registry(mesh_a, min_n_samples=1000)
hmesh_b = HierarchicalMesh.from_registry(mesh_b, min_n_samples=1000)

(
    (hmesh_a.low.n_vertices, hmesh_a.low.n_faces),
    (hmesh_b.low.n_vertices, hmesh_b.low.n_faces),
)
 Out [3]:
((1004, 2004), (1021, 2038))

Set Laplace eigenbasis for each low-resolution mesh.

 In [4]:
hmesh_a.low.laplacian.find_spectrum(spectrum_size=10, set_as_basis=True)
hmesh_b.low.laplacian.find_spectrum(spectrum_size=10, set_as_basis=True)

hmesh_a.low.basis.use_k = 6
hmesh_b.low.basis.use_k = 5

Extend the basis for the high-resolution meshes.

 In [5]:
hmesh_a.extend_basis(set_as_basis=True)
hmesh_b.extend_basis(set_as_basis=True)

(
    hmesh_a.high.basis.vecs.shape,
    hmesh_b.high.basis.vecs.shape,
)
 Out [5]:
((7207, 10), (5000, 10))

Assume we have a valid functional map \(C\) between hmesh_a.low and hmesh_b.low (which for demonstration purposes, we instantiate randomly).

 In [6]:
fmap_matrix = gs.random.uniform(
    size=(
        hmesh_b.low.basis.spectrum_size,
        hmesh_a.low.basis.spectrum_size,
    )
)

fmap_matrix.shape
 Out [6]:
(5, 6)

Now, this functional map can be seamlessly used with the high-resolution meshes. For example, we can upsample it with ZoomOut.

 In [7]:
upsampler = ZoomOut(nit=2, step=(2, 1))

upsampled_fmap_matrix = upsampler(
    fmap_matrix,
    hmesh_a.high.basis,
    hmesh_b.high.basis,
)

upsampled_fmap_matrix.shape
 Out [7]:
(7, 10)
 In [8]:
hmesh_a.high.basis.vecs
 Out [8]:
array([[-1.72157991,  1.63091261, -1.05690336, ...,  2.67648666,
        -1.04742672, -0.71500848],
       [-1.72157991,  1.70083536, -0.86500711, ...,  2.84924518,
        -1.43599688, -0.51465914],
       [-1.72157991,  1.69559836, -0.84127265, ...,  2.87933207,
        -1.4351918 , -0.82635609],
       ...,
       [-1.72157991,  5.0574198 ,  6.82858863, ..., -3.77463283,
         6.36453632, -0.21060378],
       [-1.72157991,  5.06379084,  6.84460851, ..., -3.8108807 ,
         6.45896302, -0.21374222],
       [-1.72157991,  1.63753198, -1.00536459, ...,  2.71484979,
        -1.10020252, -1.01029031]], shape=(7207, 10))

NB: mesh_a and hmesh_a.high are the same object, so it is indiferent which one to use.

Further reading#