MolecularDiffusion.modules.models.equifm.eot¶
Equivariant Optimal Transport coupling – EquiFM paper Algorithm 3, p. 18.
1: initialise R = I, tau = inf 2: repeat 3: Pi = argmin_Pi ||Pi (R z)^T - y^T||_2 {Jonker-Volgenant} 4: R = argmin_R ||R (Pi z)^T - y^T||_2 {Kabsch} 5: tau = ||Pi (R z)^T - y^T||_2 6: until tau converges
Pi is a permutation of the noise nodes, R a rotation. Jonker-Volgenant
is exactly scipy.optimize.linear_sum_assignment (scipy is already a declared
dependency, pyproject.toml, and is already used this way at
runmodes/data/preparation.py:231-261). Kabsch is an SVD of the 3x3
cross-covariance. Neither needs a new dependency.
Table 4 of the paper reports 4.67 iterations / 1.10 ms per QM9 sample, so the per-molecule Python loop below is affordable at the paper’s batch size of 64.
ponytail: plain per-molecule loop. The assignment problem is inherently per-molecule (different node counts) and scipy’s LSA has no batched form; batch it with a C-level solver only if profiling shows this dominates a training step.
Functions¶
|
Align prior noise to data under the EOT plan (paper Eq. 7 / Algorithm 3). |
Module Contents¶
- MolecularDiffusion.modules.models.equifm.eot.solve_eot(eps_x: torch.Tensor, x_0: torch.Tensor, node_mask: torch.Tensor, max_iters: int = 20, tol: float = 0.0001) torch.Tensor¶
Align prior noise to data under the EOT plan (paper Eq. 7 / Algorithm 3).
- Parameters:
eps_x –
(B, N, 3)zero-CoM Gaussian noise, padded rows zeroed.x_0 –
(B, N, 3)zero-CoM data coordinates, padded rows zeroed.node_mask –
(B, N, 1)1 for real atoms.max_iters – cap on the alternating loop (paper needs ~5).
tol – relative change in
taubelow which the loop stops.
- Returns:
(B, N, 3)–pi*(R* eps_x), i.e.eps_xpermuted and rotated ontox_0. Same distribution aseps_x(a permutation and rotation of an isotropic zero-CoM Gaussian is that same Gaussian), which is what makes Eq. 8 a valid conditional path; only the coupling changes.