Source code for rbfenetmap.core.meta.intermediates

"""The intermediate-generator contract: invent a molecule to bridge a gap."""

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Any, ClassVar, Mapping

from rbfenetmap.core.intermediates import IntermediateOptions, IntermediateProposal
from rbfenetmap.core.models import Ligand
from rbfenetmap.core.options import MappingOptions

__all__ = ("AbstractIntermediateGenerator",)


[docs] class AbstractIntermediateGenerator(ABC): """Propose molecules that split one hard transformation into two easier ones. The fifth plugin kind, and the only one whose output changes the *ligand set* rather than the network over it. That is why the contract is narrow: a generator proposes, and nothing else. It does not pose its molecules -- :mod:`rbfenetmap.core.posing` does, once, for everyone -- it does not decide whether the resulting edges are feasible, and it does not price them. Each of those already has an owner, and a generator that took any of them over would make an intermediate's quality depend on which generator happened to invent it. Attributes ---------- name : str The registered plugin name, recorded on every ligand the generator's proposals become. Notes ----- A generator that cannot help with a pair returns an :class:`~rbfenetmap.core.intermediates.IntermediateProposal` with no molecules and a ``rejection`` string. It does **not** raise: an intermediate is an optimisation, and one gap that cannot be bridged is an ordinary outcome rather than an impossible request. This is the same rule that keeps a rejected edge out of :mod:`rbfenetmap.core.exceptions`. """ name: ClassVar[str] = "abstract"
[docs] @abstractmethod def propose( self, source: Ligand, target: Ligand, options: IntermediateOptions, mapping_options: MappingOptions ) -> IntermediateProposal: """Suggest molecules bridging the gap between *source* and *target*. Parameters ---------- source, target : Ligand The two real ligands, each with explicit hydrogens and one 3D conformer. options : IntermediateOptions How many molecules may be proposed, and the posing budget that will be spent on them. mapping_options : MappingOptions The same settings the mappers run under, so a generator that needs an MCS finds the one the pipeline would have found. Returns ------- IntermediateProposal Possibly empty, with ``rejection`` set to say why. Every proposed molecule must carry no conformer; a :class:`~rbfenetmap.core.intermediates.ProposedMolecule` strips any it is given, so this is enforced rather than merely asked for. """
[docs] def supports_pair(self, source: Ligand, target: Ligand) -> bool: """Whether this generator can attempt the pair at all. Cheap pre-check, called before :meth:`propose`. The default accepts everything. """ del source, target return True
[docs] def describe_parameters(self) -> Mapping[str, Any]: """Return the generator's own settings, for the run record. Returns ------- Mapping[str, Any] JSON-friendly values. The default is empty. Notes ----- Generators are the plugin kind most likely to carry knobs of their own -- how far to search, which transformations to consider -- and those knobs change what molecules a run invents. Reporting them alongside the network is what makes an invented ligand reproducible by someone who was not there when it was invented. """ return {}
def __repr__(self) -> str: # pragma: no cover - trivial return f"{type(self).__name__}(name={self.name!r})"