Protein sequence and inverse folding
Arbitrary-order autoregressive graph mask
ProteinMPNNLigandMPNN
Free account with email, Google or GitHub. Your code runs in an isolated PyTorch sandbox.
Your task
Convert a supplied decoding permutation into neighbor visibility masks. Distinguish already decoded sequence information from structure-only information without assuming left-to-right residue order.
Function signature
permuted_autoregressive_mask(
permutation: torch.Tensor,
neighbors: torch.Tensor,
node_mask: torch.Tensor,
design_mask: torch.Tensor,
edge_mask: torch.Tensor,
fixed_first: bool = True,
) -> dict[str, torch.Tensor]Worked example
Decode residues in order 2, 0, 3, 1
The inverse ranks are [1,3,0,2]. For target residue 0, only source residue 2 has a lower rank, so only that edge is backward. The self edge and the later residues are forward. fixed_first=False keeps the supplied order.
import torch
permutation = torch.tensor([[2, 0, 3, 1]], dtype=torch.int64)
neighbors = torch.tensor([[[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]], dtype=torch.int64)
node_mask = torch.tensor([[True, True, True, True]], dtype=torch.bool)
design_mask = torch.tensor([[True, True, True, False]], dtype=torch.bool)
edge_mask = torch.full((1, 4, 4), True, dtype=torch.bool)
fixed_first = False
result = permuted_autoregressive_mask(permutation=permutation, neighbors=neighbors, node_mask=node_mask, design_mask=design_mask, edge_mask=edge_mask, fixed_first=fixed_first)Expected return
{
'rank': torch.tensor([[1, 3, 0, 2]], dtype=torch.int64),
'backward': torch.tensor([[[[False], [False], [True], [False]], [[True], [False], [True], [True]], [[False], [False], [False], [False]], [[True], [False], [True], [False]]]], dtype=torch.bool),
'forward': torch.tensor([[[[True], [True], [False], [True]], [[False], [True], [False], [False]], [[True], [True], [True], [True]], [[False], [True], [False], [True]]]], dtype=torch.bool),
}Parameters
| Parameter | Shape and meaning |
|---|---|
permutationtorch.Tensor | [B, L]Residue IDs in earliest-to-latest order; a bijection per batch. |
neighborstorch.Tensor | [B, L, K]Source residue IDs, K may be zero. |
node_masktorch.Tensor | [B, L]True for valid residues. |
design_masktorch.Tensor | [B, L]True for designed/unknown residues, False for fixed residues. |
edge_masktorch.Tensor | [B, L, K]True for enabled directed edge slots. |
fixed_firstboolDefault True | When True, stably place fixed residues before designed residues before deriving visibility ranks. |
Return
dict[str, torch.Tensor]
Return exactly the named fields applicable to this operation.
Required behavior
- Build directed graph masks for arbitrary-order sequence decoding.
permutation[B,L]is integer and each row contains every residue ID0..L-1exactly once, EARLIEST to LATEST.neighbors[B,L,K]gives source residuejfor each targeti; indices are in[0,L),B,L\ge 1,K\ge 0. node_mask[B,L],design_mask[B,L],edge_mask[B,L,K]are bool.Truemeans valid residue, residue to design (unknown sequence), and enabled edge slot, respectively. Masks are selection data, not differentiable weights. Configfixed_firstis bool, defaultTrue, and is the only option.- If
False, use the supplied order unchanged;design_maskdoes not alter it. IfTrue, stably partition the supplied order into VALID FIXED residues (node_maskand notdesign_mask), then VALID DESIGNED residues, then invalid residues; preserve the original order within each group. - Return
rank[B,L], the inversepermutationof this effective schedule, including ranks for invalid residues. No random ordering or argsort is required: inverse ranks can be built frompermutationequality, and stable partition ranks by pairwise comparisons. - For a target
i/sourcejedge,\mathrm{active} = \mathrm{edge\_mask}[i,k]ANDnode_mask[i]ANDnode_mask[j].\mathrm{backward}[i,k,0] = \mathrm{active}AND\mathrm{rank}[j]<\mathrm{rank}[i].\mathrm{forward}[i,k,0] = \mathrm{active}AND\mathrm{rank}[j]\ge \mathrm{rank}[i]. - Return these BOOL
[B,L,K,1]masks. Self edges are strictly excluded frombackwardand included inforwardwhen active. The masks are disjoint and their union equals the active edges; inactive slots are false in both.K=0returns correctly shaped empty masks. - Backward enables earlier SEQUENCE information only;
forwardenables STRUCTURE-ONLY information and must never be multiplied by a future sequence embedding. This primitive constructs masks, not a decoder or feature tensor, and therefore cannot make an already-leaking hidden representation causal. - When
fixed_first=True, all valid fixed residues precede all designed residues. WhenFalse, even fixed residues obey the supplied schedule.
Why this matters
The order says when each residue becomes known; a target can read sequence information only from neighbors decoded strictly earlier.
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 permuted_autoregressive_mask(
permutation: torch.Tensor, # (B, L)
neighbors: torch.Tensor, # (B, L, K)
node_mask: torch.Tensor, # (B, L)
design_mask: torch.Tensor, # (B, L)
edge_mask: torch.Tensor, # (B, L, K)
fixed_first: bool = True,
) -> dict[str, torch.Tensor]:
"""Return dict[str, torch.Tensor]:
rank: (B, L).
backward: (B, L, K, 1).
forward: (B, L, K, 1)."""
# Implement the operation. Inputs and test setup are supplied by BioTorch.
raise NotImplementedError("Implement permuted_autoregressive_mask")
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.