Geometry and structural losses

Polymer Clash Summary

MediumRaw PyTorchAbout 20 min1 public example plus private tests

AlphaFold3

Write and run your solution Sign in

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

ParameterShape and meaning
masksdictSupplied masks. Each field below defines what True includes or permits.
structuredictFields supplied together in this dictionary.
clash_radiusfloatDefault 1.1AF3 mode: nonnegative contact radius in angstroms; squared-distance comparison is inclusive and uses no epsilon.
min_clashesintDefault 100AF3 mode: a chain is flagged when its clashing-atom count is strictly greater than this nonnegative integer.
num_chainsintDefault 1AF3 mode: positive count of dense chain slots. Participating chain IDs must lie in [0,num_chains).
min_fractionfloatDefault 0.5AF3 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.

Write and run your solution Sign in

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.