Skip to content

laplacian_smooth

laplacian_smoothing(coords, is_fixed, edge_index, tolerance=1e-07, max_iter=10000, verbose=False, damping_factor=0.5, laplacian=None)

Smooth free-node coordinates towards a uniform Laplacian equilibrium via explicit mean curvature flow.

Parameters:

Name Type Description Default
coords Tensor[N, D]

node coordinates, updated in place for the free (non-fixed) nodes.

required
is_fixed (Tensor[N], bool)

mask of nodes to keep fixed.

required
edge_index Tensor[2, E]

edge connectivity.

required
tolerance float

convergence threshold on the per-iteration displacement norm.

1e-07
max_iter int

maximum number of iterations.

10000
verbose bool

if True, print a convergence summary.

False
damping_factor float

fraction of the Laplacian step to damp; 0 is a full explicit step, values closer to 1 slow convergence.

0.5
laplacian Laplacian

a precomputed Laplacian operator; if None, one is built from edge_index.

None

Returns:

Type Description

tuple[torch.Tensor, int, bool]: the (in-place updated) coords,

the number of iterations run, and whether the loop converged.

Source code in src/torch_structure/formfinding/laplacian_smooth.py
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def laplacian_smoothing(
    coords,
    is_fixed,
    edge_index,
    tolerance=1e-7,
    max_iter=10000,
    verbose=False,
    damping_factor = 0.5,
    laplacian=None,
):
    """Smooth free-node coordinates towards a uniform Laplacian equilibrium via explicit mean curvature flow.

    Args:
        coords (torch.Tensor [N, D]): node coordinates, updated in place for
            the free (non-fixed) nodes.
        is_fixed (torch.Tensor [N], bool): mask of nodes to keep fixed.
        edge_index (torch.Tensor [2, E]): edge connectivity.
        tolerance (float): convergence threshold on the per-iteration
            displacement norm.
        max_iter (int): maximum number of iterations.
        verbose (bool): if ``True``, print a convergence summary.
        damping_factor (float): fraction of the Laplacian step to damp;
            ``0`` is a full explicit step, values closer to ``1`` slow
            convergence.
        laplacian (Laplacian, optional): a precomputed
            [Laplacian][torch_structure.message_passing.laplace.Laplacian]
            operator; if ``None``, one is built from ``edge_index``.

    Returns:
        tuple[torch.Tensor, int, bool]: the (in-place updated) ``coords``,
        the number of iterations run, and whether the loop converged.
    """
    is_fixed = is_fixed.view(-1)

    if laplacian is None:
        laplacian = Laplacian(edge_index, num_nodes=coords.size(0))

    converged = False
    for i in range(max_iter):
        # Explicit time-stepping associated with mean curvature flow
        updated_coords = coords - (1 - damping_factor) * laplacian(coords)
        updated_coords = updated_coords[~is_fixed]
        delta = coords[~is_fixed] - updated_coords
        delta_norm = torch.norm(delta)
        coords[~is_fixed] = updated_coords
        if delta_norm < tolerance:
            converged = True
            break

    if verbose:
        print(
            f"Laplacian Smoothing finished in {i} iterations. Converged: {converged}."
        )

    return coords, i, converged