Geometry and structural losses
Polymer Clash Summary
Free account with email, Google or GitHub. Your code runs in an isolated PyTorch sandbox.
Your task
Identify polymer atoms that clash with non-neighboring residues and summarize clashes per chain and per structure.
Function signature
polymer_clash_summary(
masks: dict,
structure: dict,
clash_radius: float = 1.1,
min_clashes: int = 100,
num_chains: int = 1,
min_fraction: float = 0.5,
) -> dict[str, torch.Tensor]Worked example
Count each clashing atom once
Atoms 0 and 2 are same-chain sequence neighbors and do not clash with each other, but both contact atom 1 at the inclusive radius. Chain 0 therefore has 2 clashing atoms out of 3, giving 2/3; chain 1 has 1/1 and empty chain 2 has 0. Atom 3 is not polymer and never contributes.
import torch
masks = {
'atom_mask': torch.tensor([[True, True, True, True, True]], dtype=torch.bool),
'polymer_mask': torch.tensor([[True, True, True, False, True]], dtype=torch.bool),
}
structure = {
'positions': torch.tensor([[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [8.0, 0.0, 0.0]]], dtype=torch.float64),
'residue_index': torch.tensor([[10, 10, 11, 13, 99]], dtype=torch.int64),
'chain_id': torch.tensor([[0, 1, 0, 0, 0]], dtype=torch.int64),
}
clash_radius = 1.0
min_clashes = 1
num_chains = 3
min_fraction = 0.75
result = polymer_clash_summary(masks=masks, structure=structure, clash_radius=clash_radius, min_clashes=min_clashes, num_chains=num_chains, min_fraction=min_fraction)Expected return
{
'atom_clash_mask': torch.tensor([[True, True, True, False, False]], dtype=torch.bool),
'chain_clash_counts': torch.tensor([[2, 1, 0]], dtype=torch.int64),
'chain_atom_counts': torch.tensor([[3, 1, 0]], dtype=torch.int64),
'chain_clash_fraction': torch.tensor([[0.6666666666666666, 1.0, 0.0]], dtype=torch.float64),
'has_clash': torch.tensor([True], dtype=torch.bool),
}Parameters
| Parameter | Shape and meaning |
|---|---|
masksdict | Supplied masks. Each field below defines what True includes or permits. |
structuredict | Fields supplied together in this dictionary. |
clash_radiusfloatDefault 1.1 | AF3 mode: nonnegative contact radius in angstroms; squared-distance comparison is inclusive and uses no epsilon. |
min_clashesintDefault 100 | AF3 mode: a chain is flagged when its clashing-atom count is strictly greater than this nonnegative integer. |
num_chainsintDefault 1 | AF3 mode: positive count of dense chain slots. Participating chain IDs must lie in [0,num_chains). |
min_fractionfloatDefault 0.5 | AF3 mode: a chain is flagged when its clashing-atom fraction is strictly greater than this value in [0,1]. |
Return
dict[str, torch.Tensor]
Return exactly the named fields applicable to this operation.
Required behavior
- An eligible atom has atom_mask and polymer_mask both True. Compare atoms in different chains, or in the same chain with absolute residue_index separation >1; immediate neighbors and same-residue pairs are excluded.
- A clash uses the inclusive boundary squared_distance ≤ clash_radius² (default radius 1.1). No distance epsilon is added. Count an atom once if it has any eligible clashing partner, regardless of partner count.
- num_chains is a positive integer (default 1); output chain slots correspond to IDs 0…num_chains−1. chain_atom_counts counts eligible polymer atoms; fractions divide clash counts by total.clamp_min(1), so an empty chain has fraction 0.
- has_clash is True when ANY chain has count > min_clashes OR fraction > min_fraction. These comparisons are strict; defaults are100 and 0.5. min_clashes is a nonnegative integer; min_fraction lies in[0,1].
- Return exact integer counts and boolean flags alongside the floating fractions; this thresholding task does not require differentiating the discrete decisions.
- Use CPU float32/float64 tensors with one shared floating dtype/device. Preserve strided layouts and do not mutate supplied tensors.
- Use raw tensor operations, not a ready-made implementation of the requested primitive. Supplied parameters and random variates must not be reinitialized.
Why this matters
AF3’s clash summary counts polymer atoms with at least one implausibly close non-neighbor partner. It reports per-chain fractions and a structure-level flag rather than a differentiable repulsion loss.
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 polymer_clash_summary(
masks: dict,
structure: dict,
clash_radius: float = 1.1,
min_clashes: int = 100,
num_chains: int = 1,
min_fraction: float = 0.5,
) -> dict[str, torch.Tensor]:
"""Return dict[str, torch.Tensor]:
atom_clash_mask: (B, A).
chain_clash_counts: (B, C).
chain_atom_counts: (B, C).
chain_clash_fraction: (B, C).
has_clash: (B,)."""
# Implement the operation. Inputs and test setup are supplied by BioTorch.
raise NotImplementedError("Implement polymer_clash_summary")
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.
Related exercises
Sources and further reading
A primitive exercise, not an end-to-end reproduction of the named models. No affiliation or endorsement is implied.