Diffusion and flow matching
One Lie-group Euler step for frame flow
FrameFlowRFdiffusion2
Free account with email, Google or GitHub. Your code runs in an isolated PyTorch sandbox.
Your task
Advance positions and rotation frames one step toward predicted endpoints. Leave fixed valid frames unchanged; padded positions return zero and padded rotations return the identity matrix.
Function signature
lie_euler(
x_t: torch.Tensor,
x1_hat: torch.Tensor,
R_t: torch.Tensor,
R1_hat: torch.Tensor,
t: torch.Tensor,
dt: torch.Tensor,
valid_mask: torch.Tensor,
diffuse_mask: torch.Tensor,
rotation_schedule: str = 'linear',
exp_rate: float = 10.0,
) -> tuple[torch.Tensor, torch.Tensor]Worked example
Advance only part of the remaining path
Use one valid movable residue with x_t=[0,0,0], x1_hat=[4,0,0], R_t=identity, R1_hat=[[0,-1,0],[1,0,0],[0,0,1]], t=[0.5] and dt=[0.125]. The translation fraction is 0.125/(1−0.5)=1/4, so x_next=[1,0,0]. With rotation_schedule="linear", the 90° endpoint rotation advances by 22.5° about z. With rotation_schedule="exp" and exp_rate=4, the angular fraction is 0.125×4=1/2 and R_next rotates 45°; translation still advances by one quarter.
Parameters
| Parameter | Shape and meaning |
|---|---|
x_ttorch.Tensor | [B, N, 3][B,N,3] current positions |
x1_hattorch.Tensor | [B, N, 3]Predicted clean positions |
R_ttorch.Tensor | [B, N, 3, 3]Current local-to-global rotations |
R1_hattorch.Tensor | [B, N, 3, 3]Predicted endpoint rotations |
ttorch.Tensor | [B]Current time in [0,1] |
dttorch.Tensor | [B]Nonnegative forward \mathrm{step} \le 1-t |
valid_masktorch.Tensor | [B, N]True marks usable positions; False marks padding. |
diffuse_masktorch.Tensor | [B, N]Bool; True may update |
rotation_schedulestrDefault 'linear' | Choose "linear" for the remaining-time rotation fraction or "exp" for the exp_rate-controlled fraction defined below. |
exp_ratefloatDefault 10.0 | Rate of the exponential rotational schedule. |
Return
tuple[torch.Tensor, torch.Tensor]
Return these tensors in the stated order.
Required behavior
- Inputs
x_t,x1_hat[B,N,3],R_t,R1_hat[B,N,3,3],t,dt[B], and two bool masks. - For
0\le t<1and0\le \mathrm{dt}\le 1-t,f=\mathrm{dt}/(1-t),x_{\mathrm{next}}=x_{t}+f\cdot (\mathrm{x1\_hat}-x_{t}). Evaluate this as(1-f)\cdot x_{t}+f\cdot \mathrm{x1\_hat}to avoid overflowing a residual whose endpoints are finite. - Set
\omega=\operatorname{Log}(R_{t}^{\top} \mathrm{R1\_hat})in the LOCAL/BODY frame andR_{\mathrm{next}}=R_{t} \operatorname{Exp}(g\cdot \omega).rotation_schedule='linear'(default) usesg=f. - The alternate 'exp' uses
g=\mathrm{dt}\cdot \mathrm{exp\_rate},\mathrm{exp\_rate}>0default10; translation still uses the linear factor. - This exponential rotation scaling corresponds to
\mathrm{kappa}(t)=1-\operatorname{exp}(-\mathrm{exp\_rate}\cdot t), whose kappa'/(1-\mathrm{kappa}) is constant; it need not hit the predicted rotational endpoint att=1. - In the linear variant
\mathrm{dt}=1-treaches both supplied endpoints exactly (up to roundoff) for proper rotations away from the cut locus. Att=1only\mathrm{dt}=0is valid: return the current valid frames unchanged, and never evaluate1/(1-t). - Valid fixed residues always retain their CURRENT
x_t/R_t; invalid positions become zero and invalid rotations identity. This is a positive-time flow step; do not insert the minus sign of a reverse-time diffusion integrator. No\epsilon, stochastic noise or post-update orthogonalization. - The only
keysarerotation_scheduleandexp_rate(used only for 'exp'). All masks are bool:valid_mask=Truedenotes a real residue/atom;diffuse_mask=Truedenotes a movable one. Their conjunction selects updates.B,N(orA) are positive; an all-false mask, not a zero-length tensor, represents an empty example. - All supplied numbers, including padding, are finite and share dtype/device; floating tensors are
float32orfloat64. Rotations act on column vectors and map local coordinates to the global frame. - For
v=(x,y,z),\operatorname{hat}(v)=\begin{pmatrix}0&-z&y\\z&0&-x\\-y&x&0\end{pmatrix}.\operatorname{Exp}(v)=I+A\operatorname{hat}(v)+B\operatorname{hat}(v)^2, whereq=v\cdot v,A=\frac{\sin\sqrt q}{\sqrt q},B=\frac{1-\cos\sqrt q}{q}. - For
q<10^{-4}useA=1-\frac q6+\frac{q^2}{120}-\frac{q^3}{5040}andB=\frac12-\frac q{24}+\frac{q^2}{720}-\frac{q^3}{40320}; at zero\operatorname{Exp}(0)=I. - For
\operatorname{Log}(R), setv=\frac12\operatorname{vee}(R-R^\top),q=v\cdot v,s=\sqrt{q},c=\frac{\operatorname{tr}R-1}{2},\theta=\operatorname{atan2}(s,c). Ordinarily\operatorname{Log}(R)=\frac{\theta}{s}v. Ifq<10^{-8}andc>0usev\left(1+\frac q6+\frac{3q^2}{40}+\frac{5q^3}{112}\right). - If
q<10^{-6}andc<0, recover an axis fromP=\frac{R+R^\top-2cI}{2(1-c)}: choose the largest diagonal(\mathrm{ties} x, \mathrm{then} y, \mathrm{then} z), take its positive square root, and divide its row by that component; normalize the axis. - Orient it to have nonnegative dot with
vwhenq>10^{-20}; otherwise keep the chosen component positive. Return\theta\cdot \mathrm{axis}. - For dormant branches clamp
1-cbelow by10^{-6}and diagonal square-root arguments below by10^{-12}; these floors do not alter the selected near-\piaxis. Evaluate every inactive square root/division safely beforetorch.where.Rmust be a proper\operatorname{SO}(3)matrix; no projection/repair is requested. - At
\piaxis sign is inherently ambiguous:\operatorname{exp}(\operatorname{log}(R))is the geometric invariant. No global continuous logarithm exists at the\picut locus.
Why this matters
Positions move by a linear interpolation factor. Rotations move by a local angular increment composed on the right. Translation and rotation may use different schedules, but both outputs are complete next frames.
Starter code
You write the body of this function in the BioTorch workspace. Your code runs in an isolated PyTorch sandbox; Run checks the public examples and Submit grades the full test suite, including gradients.
import torch
def lie_euler(
x_t: torch.Tensor, # (B, N, 3)
x1_hat: torch.Tensor, # (B, N, 3)
R_t: torch.Tensor, # (B, N, 3, 3)
R1_hat: torch.Tensor, # (B, N, 3, 3)
t: torch.Tensor, # (B,)
dt: torch.Tensor, # (B,)
valid_mask: torch.Tensor, # (B, N)
diffuse_mask: torch.Tensor, # (B, N)
rotation_schedule: str = 'linear',
exp_rate: float = 10.0,
) -> tuple[torch.Tensor, torch.Tensor]:
"""Return tuple[torch.Tensor, torch.Tensor]:
x_next: (B, N, 3).
R_next: (B, N, 3, 3)."""
# Implement the operation. Inputs and test setup are supplied by BioTorch.
raise NotImplementedError("Implement lie_euler")
Ready to implement it?
3 progressive hints, a solution walkthrough, and grading that checks values, shapes and gradients are waiting in the workspace.
Free account with email, Google or GitHub. Your code runs in an isolated PyTorch sandbox.
Sources and further reading
A primitive exercise, not an end-to-end reproduction of the named models. No affiliation or endorsement is implied.