schrodinger.application.transforms.enumerators.synthesize module

class schrodinger.application.transforms.enumerators.synthesize.DeprotectConfig(*, reaction_tags: frozenset[str] = <factory>)

Bases: BaseModel

Configuration for Deprotect.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

reaction_tags: frozenset[str]
validateReactionTags() → Self

Validate deprotection reaction tags.

getReactions() → tuple[Reaction, ...]

Return deprotection reactions selected by reaction_tags.

class schrodinger.application.transforms.enumerators.synthesize.Deprotect(*, _config: pydantic.main.BaseModel | None = None, **kwargs)

Bases: PTransformWithConfig

Exhaustively apply tagged deprotection reactions to molecules.

Configured Pathfinder reactions are applied until no selected protecting groups remain. Molecule properties are copied from the input molecule to each deprotected output.

Parameters:

reaction_tags – Pathfinder reaction tags selecting deprotection reactions to apply.

config_class

alias of DeprotectConfig

class schrodinger.application.transforms.enumerators.synthesize.SynthesizeConfig(*, frozen_smarts: str, depth: int = 1, dedupe_routes: bool = False, max_routes: Optional[int] = None, max_products_per_route: int = 100, max_tries_per_route: Optional[int] = None, reagent_libraries: list[typing.Annotated[pathlib.Path, PathType(path_type='dir')]] | None = None, seed: int | None = None)

Bases: BaseModel

Configuration for Synthesize.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

frozen_smarts: str
depth: int
dedupe_routes: bool
max_routes: Optional[int]
max_products_per_route: int
max_tries_per_route: Optional[int]
reagent_libraries: list[typing.Annotated[pathlib.Path, PathType(path_type='dir')]] | None
seed: int | None
class schrodinger.application.transforms.enumerators.synthesize.Synthesize(*, _config: pydantic.main.BaseModel | None = None, **kwargs)

Bases: PTransformWithConfig

A PTransform that generates sanitized molecules by:

  • Enumerating all retrosynthetic routes available in the default reaction dictionary of up to a maximum depth for all molecules with fixed heavy atoms based on frozen_smarts.

  • Optionally deduplicating the routes based on their one-line representation (dedupe_routes).

  • Optionally sampling the number of routes to retain (max_routes).

  • Evaluating each route either systematically or randomly. Products are generated systematically if max_products_per_route is 0, max_tries_per_route is 0, or the combinations of reagents less than max_products_per_route.

Note that random sampling may yield fewer products than requested.

The resulting products may not be unique since only unqiue products per route are guaranteed. Consider using beam.Distinct() after this transform if unique products are desired.

Example usage:

>>> import apache_beam as beam
>>> from rdkit import Chem
>>> from schrodinger.application.transforms.enumerators import Synthesize
>>> from schrodinger.seam.io import chemio
>>> with beam.Pipeline() as p:
...     products = (
...      p
...      | beam.Create([Chem.MolFromSmiles('Cc1ccccc1')])
...      | Synthesize(frozen_smarts='c1ccccc1',
...                   max_products_per_route=100)
...     )
Parameters:
  • frozen_smarts – The SMARTS whose heavy atoms the products should have.

  • depth – The maximum depth of the retrosynthetic routes to use.

  • dedupe_routes – Whether to deduplicate the routes.

  • max_routes – The number of routes to retain. If ‘None’, all routes will be kept.

  • max_products_per_route – The maximum number of products to try to synthesize for each input molecule per route. Use 0 to force exhaustive synthesis.

  • max_tries_per_route – The maximum number of tries to synthesize products for each input molecule per route. If None, the number of tries is automatically determined. If 0, the synthesis will be exhaustive.

  • reagent_libraries – Optional custom reagent-library directories, searched in order before the standard libraries. Pathfinder uses the first matching file for each class. The directories must be accessible during pipeline construction, when the reagent files used for distributed execution are captured.

  • seed – seed for random number generator. If None, the random number generator will not be seeded.

config_class

alias of SynthesizeConfig

class schrodinger.application.transforms.enumerators.synthesize.EnumerateRoutesConfig(*, frozen_smarts: str, depth: int = 1, dedup: bool = False)

Bases: BaseModel

Configuration for EnumerateRoutes.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

frozen_smarts: str
depth: int
dedup: bool
class schrodinger.application.transforms.enumerators.synthesize.EvaluateRoutesConfig(*, max_products_per_route: int = 100, max_tries_per_route: Optional[int] = None, reagent_libraries: list[typing.Annotated[pathlib.Path, PathType(path_type='dir')]] | None = None, seed: int | None = None)

Bases: BaseModel

Configuration for EvaluateRoutes.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

max_products_per_route: int
max_tries_per_route: Optional[int]
reagent_libraries: list[typing.Annotated[pathlib.Path, PathType(path_type='dir')]] | None
seed: int | None
class schrodinger.application.transforms.enumerators.synthesize.SystematicSynthesizeConfig(*, frozen_smarts: str, max_routes: Optional[int] = None, max_reactions_per_route: Optional[int] = None, depth: int = 1, reagent_libraries: list[typing.Annotated[pathlib.Path, PathType(path_type='dir')]] | None = None)

Bases: BaseModel

Configuration for SystematicSynthesize.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

frozen_smarts: str
max_routes: Optional[int]
max_reactions_per_route: Optional[int]
depth: int
reagent_libraries: list[typing.Annotated[pathlib.Path, PathType(path_type='dir')]] | None
class schrodinger.application.transforms.enumerators.synthesize.SystematicSynthesize(*, _config: pydantic.main.BaseModel | None = None, **kwargs)

Bases: PTransformWithConfig

A PTransform that generates unique sanitized molecules by:

  • Enumerating unique retrosynthetic routes up to a maximum depth for all molecules with fixed heavy atoms based on frozen_smarts.

  • Optionally sampling the number of routes to retain (max_routes).

  • Evaluating each route systematically, optionally limiting the number of reactions per route (max_reactions_per_route).

Example usage:

>>> import apache_beam as beam
>>> from rdkit import Chem
>>> from schrodinger.application.transforms.enumerators import SystematicSynthesize
>>> from schrodinger.seam.io import chemio
>>> with beam.Pipeline() as p:
...     products = (
...      p
...      | beam.Create([Chem.MolFromSmiles('Cc1ccccc1')])
...      | SystematicSynthesize(frozen_smarts='c1ccccc1')
...     )
Parameters:
  • frozen_smarts – The SMARTS whose heavy atoms the products should have.

  • max_routes – The number of routes to retain. If None, all routes will be kept.

  • max_reactions_per_route – The maximum number of reactions to try to synthesize products for each input molecule per route. If None, the number of reactions is unlimited.

  • depth – The maximum depth of the retrosynthetic routes to use.

  • reagent_libraries – Optional custom reagent-library directories, searched in order before the standard libraries. Pathfinder uses the first matching file for each class. The directories must be accessible during pipeline construction, when the reagent files used for distributed execution are captured.

config_class

alias of SystematicSynthesizeConfig

class schrodinger.application.transforms.enumerators.synthesize.SystematicEvaluateRoutesConfig(*, max_reactions_per_route: Optional[int] = None, reagent_libraries: list[typing.Annotated[pathlib.Path, PathType(path_type='dir')]] | None = None)

Bases: BaseModel

Configuration for SystematicEvaluateRoutes.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

max_reactions_per_route: Optional[int]
reagent_libraries: list[typing.Annotated[pathlib.Path, PathType(path_type='dir')]] | None
class schrodinger.application.transforms.enumerators.synthesize.SystematicEvaluateRoutes(*, _config: pydantic.main.BaseModel | None = None, **kwargs)

Bases: PTransformWithConfig

A PTransform that exhaustively generates sanitized molecules by:

  • Evaluating each input route systematically, optionally limiting the number of reactions per route (max_reactions_per_route).

  • Distributing large route evaluations into fixed-size slices.

Products are not deduplicated so that each output can keep the reactant provenance assigned during route evaluation.

Example usage:

>>> import apache_beam as beam
>>> from rdkit import Chem
>>> from schrodinger.application.transforms import enumerators
>>> from schrodinger.seam.io import chemio
>>> with beam.Pipeline() as p:
...     products = (
...      p
...      | beam.Create([Chem.MolFromSmiles('Cc1ccccc1')])
...      | enumerators.EnumerateRoutes(frozen_smarts='c1ccccc1')
...      | enumerators.SystematicEvaluateRoutes(
...          max_reactions_per_route=1)
...     )
Parameters:
  • max_reactions_per_route – The maximum number of reactions to try to synthesize products for each input route. If None, the number of reactions is unlimited.

  • reagent_libraries – Optional custom reagent-library directories, searched in order before the standard libraries. Pathfinder uses the first matching file for each class. The directories must be accessible during pipeline construction, when the reagent files used for distributed execution are captured.

config_class

alias of SystematicEvaluateRoutesConfig

class schrodinger.application.transforms.enumerators.synthesize.AttemptsBasedSynthesizeConfig(*, frozen_smarts: str, depth: int = 1, route_duplicate_policy: Literal['preserve', 'deduplicate', 'multiplicity_weighted'] = 'preserve', max_routes: Optional[int] = None, max_attempts_per_route: Optional[int] = None, attempt_range_size: int = 10000, reagent_libraries: list[typing.Annotated[pathlib.Path, PathType(path_type='dir')]] | None = None, seed: int | None = None)

Bases: BaseModel

Configuration for AttemptsBasedSynthesize.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

frozen_smarts: str
depth: int
route_duplicate_policy: Literal['preserve', 'deduplicate', 'multiplicity_weighted']
max_routes: Optional[int]
max_attempts_per_route: Optional[int]
attempt_range_size: int
reagent_libraries: list[typing.Annotated[pathlib.Path, PathType(path_type='dir')]] | None
seed: int | None
class schrodinger.application.transforms.enumerators.synthesize.EvaluateEnumeratedRouteAttemptsConfig(*, route_duplicate_policy: Literal['preserve', 'deduplicate', 'multiplicity_weighted'] = 'preserve', max_routes: Optional[int] = None, max_attempts_per_route: Optional[int] = None, attempt_range_size: int = 10000, reagent_libraries: list[typing.Annotated[pathlib.Path, PathType(path_type='dir')]] | None = None, seed: int | None = None)

Bases: BaseModel

Configuration for EvaluateEnumeratedRouteAttempts.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'frozen': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

route_duplicate_policy: Literal['preserve', 'deduplicate', 'multiplicity_weighted']
max_routes: Optional[int]
max_attempts_per_route: Optional[int]
attempt_range_size: int
reagent_libraries: list[typing.Annotated[pathlib.Path, PathType(path_type='dir')]] | None
seed: int | None
class schrodinger.application.transforms.enumerators.synthesize.AttemptsBasedSynthesize(*, _config: pydantic.main.BaseModel | None = None, **kwargs)

Bases: PTransformWithConfig

Enumerate synthesis routes and evaluate reagent-tuple attempts.

Routes are produced by EnumerateRoutes without initial deduplication, then passed to EvaluateEnumeratedRouteAttempts, which owns route sampling, duplicate handling, attempt ordering, and evaluation. See that transform for the detailed post-enumeration policy semantics.

An attempt evaluates one reagent tuple and does not repeat a tuple selected earlier within the same route evaluation. Every product from every successful attempt is emitted. Products are not deduplicated across attempts or routes, so their reagent provenance is retained.

Example usage:

>>> import apache_beam as beam
>>> from rdkit import Chem
>>> from schrodinger.application.transforms.enumerators import AttemptsBasedSynthesize
>>> with beam.Pipeline() as p:
...     products = (
...         p
...         | beam.Create([Chem.MolFromSmiles('Cc1ccccc1')])
...         | AttemptsBasedSynthesize(
...             frozen_smarts='c1ccccc1',
...             max_attempts_per_route=100,
...             seed=2793)
...     )
Parameters:
  • frozen_smarts – SMARTS whose matching heavy atoms remain fixed during route enumeration.

  • depth – Maximum retrosynthesis depth used to generate routes.

  • route_duplicate_policy – Handling of generated routes with the same compact identity. preserve evaluates every retained occurrence; deduplicate evaluates one deterministically selected representative; and multiplicity_weighted evaluates one representative but multiplies a finite attempt cap by the number of retained occurrences, up to exhaustion.

  • max_routes – Maximum generated routes to retain. preserve and multiplicity_weighted sample route occurrences before grouping, so route frequency affects selection and a group’s retained multiplicity. deduplicate samples unique route groups after grouping. None retains all routes.

  • max_attempts_per_route – Maximum reagent-tuple attempts per generated route occurrence or grouped representative. None exhausts the Cartesian space. A finite value below the space size selects tuples in random order without replacement; otherwise tuples are evaluated systematically.

  • attempt_range_size – Maximum attempts in each distributed work item. Smaller values expose more parallel work but increase range and per-worker setup overhead.

  • reagent_libraries – Optional custom reagent-library directories, searched in order before the standard libraries. Pathfinder uses the first matching file for each class. The directories must be accessible during pipeline construction, when the reagent files used for distributed execution are captured.

  • seed – Optional seed used for deterministic reagent-tuple ordering with the deduplicate and multiplicity_weighted policies when the effective attempt count is smaller than the Cartesian-space size. None selects a fresh random ordering for each route. preserve samples every occurrence independently regardless of this setting. The seed does not affect exhaustive execution or max_routes sampling.

config_class

alias of AttemptsBasedSynthesizeConfig

class schrodinger.application.transforms.enumerators.synthesize.EvaluateEnumeratedRouteAttempts(*, _config: pydantic.main.BaseModel | None = None, **kwargs)

Bases: PTransformWithConfig

Evaluate enumerated synthesis routes using reagent-tuple attempts.

Inputs must be routes produced by EnumerateRoutes or routes recovered from a lossless RouteNodeCoder cache of such enumerated routes.

This provenance requirement is important for deduplicate and multiplicity_weighted. Those policies group routes by the compact RouteNode.getOneLineRepresentation() identity, which records reaction names and precursor positions but omits details such as reagent-class SMILES. For routes produced by EnumerateRoutes, reaction definitions determine the reagent class at each precursor position, so the omitted details do not change route execution. Arbitrary or independently authored route files do not necessarily satisfy that invariant: routes with the same compact identity could resolve to different reagents or chemistry, and grouping them could discard an execution-distinct route. The preserve policy does not group routes, but this transform has one uniform enumerated- route input contract so changing policy cannot silently make an input unsafe.

The duplicate policies behave as follows:

  • preserve evaluates every retained route occurrence.

  • deduplicate evaluates one deterministically selected representative of each route group.

  • multiplicity_weighted evaluates one representative of each group and multiplies a finite attempt cap by the number of retained occurrences, up to exhaustion.

For each retained occurrence or representative, a finite attempt cap below the Cartesian-space size selects tuples in random order without replacement. Under the grouping policies, an integer seed makes that order reproducible and None selects a fresh order for each route. preserve always selects a fresh order independently for each occurrence. An unlimited cap, or a cap that reaches the Cartesian-space size, evaluates tuples systematically and does not use a seed.

Products are not deduplicated across attempts or routes, so their reagent provenance is retained.

Typical composition:

routes = input_mols | EnumerateRoutes(
    frozen_smarts='c1ccccc1', dedup=False)
products = routes | EvaluateEnumeratedRouteAttempts(
    max_attempts_per_route=100)
Parameters:
  • route_duplicate_policy – Handling of enumerated routes with the same one-line identity. preserve keeps occurrences independent; deduplicate evaluates one representative; and multiplicity_weighted uses retained multiplicity to increase a finite attempt budget.

  • max_routes – Maximum enumerated routes to retain. preserve and multiplicity_weighted sample route occurrences before grouping, so route frequency affects selection and retained multiplicity; deduplicate samples unique route groups after grouping. None retains all routes.

  • max_attempts_per_route – Maximum reagent-tuple attempts per retained route occurrence or grouped representative. Selection does not repeat a tuple within one route evaluation. None exhausts the Cartesian space.

  • attempt_range_size – Maximum attempts in each distributed work item. Smaller values expose more parallel work but increase range and per-worker setup overhead.

  • reagent_libraries – Optional custom reagent-library directories, searched in order before the standard libraries. Pathfinder uses the first matching file for each class. The directories must be accessible during pipeline construction, when the reagent files used for distributed execution are captured.

  • seed – Optional seed for deterministic finite attempt ordering under the deduplicate and multiplicity_weighted policies. None selects a fresh random ordering for each route. preserve samples each occurrence independently regardless of this setting. The seed does not affect exhaustive execution or max_routes sampling.

config_class

alias of EvaluateEnumeratedRouteAttemptsConfig