schrodinger.application.transforms.alpareto module

Active learning with Pareto selection for multi-objective molecule selection.

Combines ML model training (TrainModel/PredictProperties) with Pareto ranking (ParetoRank) for iterative, multi-objective molecule selection. Each cycle scores a batch of molecules, trains an ML model on all scored data, uses predictions + Pareto ranking to select the next batch, and repeats.

class schrodinger.application.transforms.alpareto.ObjectivePropertyConfig(*, prefer_smaller_values: bool = True)

Bases: BaseModel

Per-property optimization metadata.

Parameters:

prefer_smaller_values – Whether smaller values are better for this property. Used by Pareto ranking to orient objectives.

prefer_smaller_values: bool
model_config: ClassVar[ConfigDict] = {'frozen': True}

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

class schrodinger.application.transforms.alpareto.ScoringStage

Bases: StrEnum

When in the pipeline a scorer runs.

PRE_AL = 'pre_active_learning'
AL = 'active_learning'
POST_AL = 'post_active_learning'
class schrodinger.application.transforms.alpareto.GenMLConfig(*, mode: Literal['once', 'every_cycle'], train_prior: TrainPriorConfig = TrainPriorConfig(num_epoch_smiles=2000000, batch_size=128), generate_from_prior: GenerateFromPriorConfig = GenerateFromPriorConfig(profile={}, required_smarts=[], cpu_hours=20, n_steps=200, n_compounds=20000, config_override={}), rdesign_config_path: Optional[Path] = None)

Bases: BaseModel

Configuration for generative ML in the AL loop.

Parameters:
  • mode – When to generate molecules — 'once' (after cycle 0 only) or 'every_cycle'.

  • train_prior – Configuration for prior training.

  • generate_from_prior – Configuration for molecule generation.

  • rdesign_config_path – Optional path to an rdesign config YAML for post-processing generated molecules.

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

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

mode: Literal['once', 'every_cycle']
train_prior: TrainPriorConfig
generate_from_prior: GenerateFromPriorConfig
rdesign_config_path: Optional[Path]
class schrodinger.application.transforms.alpareto.ScorerSpec(*, scorer_id: str, stage: ~schrodinger.application.transforms.alpareto.ScoringStage = ScoringStage.AL, config: dict[str, typing.Any] = <factory>, objectives: dict[typing.Annotated[str, AfterValidator(func=<function _number_property_validator at 0x77a3d50accc0>)], schrodinger.application.transforms.alpareto.ObjectivePropertyConfig] = <factory>, filter_ranges: dict[typing.Annotated[str, AfterValidator(func=<function _number_property_validator at 0x77a3d50accc0>)], typing.Annotated[tuple[int | float, int | float], AfterValidator(func=<function _range_validator at 0x77a3d50acb80>)]] = <factory>)

Bases: BaseModel

Specification for a single scoring endpoint.

Co-locates scorer identity, configuration, the objective properties used for Pareto ranking, and optional filter ranges.

Parameters:
  • scorer_id – Scorer identifier from SCORER_REGISTRY.

  • stage – When in the pipeline this scorer runs. active_learning (default) scores the selected batch each cycle, pre_active_learning scores the full pool upfront, post_active_learning re-scores the post-active-learning selection at higher fidelity.

  • config – Scorer-specific configuration passed to the scorer.

  • objectives – Map of property names to optimization metadata for Pareto ranking. Keys must be valid r_ or i_ prefixed property names that the scorer’s getProperties() returns.

  • filter_ranges – Map of property names to allowed ranges for filtering. Keys must be valid property names from the scorer.

scorer_id: str
stage: ScoringStage
config: dict[str, Any]
objectives: dict[typing.Annotated[str, AfterValidator(func=<function _number_property_validator at 0x77a3d50accc0>)], schrodinger.application.transforms.alpareto.ObjectivePropertyConfig]
filter_ranges: dict[typing.Annotated[str, AfterValidator(func=<function _number_property_validator at 0x77a3d50accc0>)], typing.Annotated[tuple[int | float, int | float], AfterValidator(func=<function _range_validator at 0x77a3d50acb80>)]]
model_config: ClassVar[ConfigDict] = {'frozen': True}

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

validate_spec() ScorerSpec

Validate the scorer spec.

  • At least one of objectives or filter_ranges must be set.

  • The scorer must exist in SCORER_REGISTRY.

  • All declared property names must be available from the scorer.

class schrodinger.application.transforms.alpareto.PreprocessorSpec(*, id: str, before: list[str], config: dict[str, typing.Any] = <factory>)

Bases: BaseModel

Specification for a single preprocessor.

A preprocessor is a transform that runs before its dependent scorers. It may run a side effect (e.g. force-field parameterization) or modify the structures it passes downstream; either way its dependent scorers are gated on its completion. It runs once before each stage and, in active_learning, before every round, on the batch about to be scored.

Parameters:
  • id – Preprocessor identifier from PREPROCESSOR_REGISTRY.

  • before – Scorer ids this preprocessor must precede. The preprocessor runs whenever any of these scorers is scheduled.

  • config – Preprocessor-specific configuration.

id: str
before: list[str]
config: dict[str, Any]
model_config: ClassVar[ConfigDict] = {'frozen': True}

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

validate_spec() PreprocessorSpec

Validate the preprocessor id and that its config constructs.

class schrodinger.application.transforms.alpareto.ParetoActiveLearningConfig(*, preprocessors: list[schrodinger.application.transforms.alpareto.PreprocessorSpec] = <factory>, scorers: list[schrodinger.application.transforms.alpareto.ScorerSpec], num_cycles: int = 3, sample_size: int = 100, train_time_hr: float = 1.0, frac_train: float = 0.9, seed: int | None = None, post_al_filters: dict[typing.Annotated[str, AfterValidator(func=<function _number_property_validator at 0x77a3d50accc0>)], typing.Annotated[tuple[int | float, int | float], AfterValidator(func=<function _range_validator at 0x77a3d50acb80>)]] | None = None, post_al_select_size: ~typing.Optional[int] = None, final_select_size: ~typing.Optional[int] = None, genml: schrodinger.application.transforms.alpareto.GenMLConfig | None = None)

Bases: BaseModel

Configuration for ParetoActiveLearning.

Parameters:
  • preprocessors – List of preprocessor specifications. Each runs before its dependent scorers (declared via before).

  • scorers – List of scorer specifications, each with its own objectives and stage.

  • num_cycles – Number of active learning cycles to run. Defaults to 3.

  • sample_size – Structures to select per round. Defaults to 100.

  • train_time_hr – Training time limit in hours. Defaults to 1.0.

  • frac_train – Fraction for training vs holdout. Defaults to 0.9.

  • seed – Random seed for initial sample. Defaults to None.

  • post_al_filters – Optional property-to-range filters applied after all active learning cycles complete. Independent of re-ranking. Defaults to None.

  • post_al_select_size – If set, Pareto re-rank all scored structures after active learning and select this many for post_active_learning rescoring. Defaults to None.

  • final_select_size – If set, apply a final Pareto re-rank and select this many structures as the pipeline output. Defaults to None.

  • genml – Optional generative ML configuration. When set, molecules are generated and merged into the remaining pool during active learning cycles.

preprocessors: list[PreprocessorSpec]
scorers: list[ScorerSpec]
num_cycles: int
sample_size: int
train_time_hr: float
frac_train: float
seed: int | None
post_al_filters: dict[typing.Annotated[str, AfterValidator(func=<function _number_property_validator at 0x77a3d50accc0>)], typing.Annotated[tuple[int | float, int | float], AfterValidator(func=<function _range_validator at 0x77a3d50acb80>)]] | None
post_al_select_size: Optional[int]
final_select_size: Optional[int]
genml: GenMLConfig | None
model_config: ClassVar[ConfigDict] = {'frozen': True}

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

classmethod validate_scorers_nonempty(v)

Validate that at least one scorer is specified.

validate_properties() ParetoActiveLearningConfig

Validate property declarations across scorers.

  • Duplicate objectives within the same stage are rejected.

  • Cross-stage objective duplicates are allowed only if they declare identical ObjectivePropertyConfig.

  • POST_AL objectives must be a subset of earlier stages.

  • At least one objective must be declared across all scorers.

  • post_al_filters keys must be declared by some scorer.

classmethod fromYaml(path: str) ParetoActiveLearningConfig

Load a configuration from a YAML file.

Parameters:

path – Path to the YAML configuration file.

Returns:

Parsed ParetoActiveLearningConfig instance.

scorers_for(stage: ScoringStage) list[ScorerSpec]

Scorers matching the given stage.

preprocessors_for(scorer_specs: list[ScorerSpec]) list[PreprocessorSpec]

Preprocessors that must precede any of the given scorers.

Returned in configuration order, which is the order they run in.

objective_properties_for(stage: ScoringStage) set[str]

Objective property names for scorers matching the given stage.

property objectives: dict[str, ObjectivePropertyConfig]

All objectives across all scorers.

Cross-stage duplicates are guaranteed identical by validation, so the merge order does not matter.

property properties: set[str]

All declared property names (objectives + filter_ranges).

class schrodinger.application.transforms.alpareto.ParetoSelectConfig(*, objectives: dict[typing.Annotated[str, AfterValidator(func=<function _number_property_validator at 0x77a3d50accc0>)], schrodinger.application.transforms.alpareto.ObjectivePropertyConfig], select_size: int)

Bases: BaseModel

Configuration for ParetoSelect.

Parameters:
  • objectives – Map of property names to optimization metadata.

  • select_size – Number of top structures to select after ranking.

objectives: dict[typing.Annotated[str, AfterValidator(func=<function _number_property_validator at 0x77a3d50accc0>)], schrodinger.application.transforms.alpareto.ObjectivePropertyConfig]
select_size: int
model_config: ClassVar[ConfigDict] = {'frozen': True}

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

class schrodinger.application.transforms.alpareto.ParetoSelect(**kwargs)

Bases: PTransformWithConfig

Pareto-rank structures and select the top N.

Ranks by Pareto front with deterministic within-front ordering and selects the top select_size structures.

Returns a (picked, notpicked) tuple of Structure PCollections.

config_class

alias of ParetoSelectConfig

class schrodinger.application.transforms.alpareto.ScoreAndFilter(scorer_specs: list[ScorerSpec])

Bases: PTransform

Score all structures with the given scorers, applying property filters.

For each scorer spec, runs the scorer on all input structures, then drops structures whose property values fall outside the spec’s filter_ranges. Scorers are applied sequentially, so earlier scorers can reduce the pool for later ones.

Parameters:

scorer_specs – Scorer specifications to run.

__init__(scorer_specs: list[ScorerSpec])
class schrodinger.application.transforms.alpareto.Preprocess(preprocessor_specs: list[PreprocessorSpec])

Bases: PTransform

Run the given preprocessors on the input structures, in the order the specs are given.

Each preprocessor either runs a side effect or modifies the structures it passes downstream, with the next preprocessor (and the downstream scorers) gated on its completion. With no specs, the structures pass through unchanged.

Parameters:

preprocessor_specs – Preprocessor specifications to run.

__init__(preprocessor_specs: list[PreprocessorSpec])
class schrodinger.application.transforms.alpareto.ParetoActiveLearning(genml_post_process: apache_beam.transforms.ptransform.PTransform | None = None, **kwargs)

Bases: PTransformWithConfig

Active learning pipeline with Pareto-based selection.

Iteratively selects molecules for scoring using a multi-objective Pareto strategy. Round 0 uses random selection; subsequent rounds train an ML model on all scored data and use Pareto ranking of predicted properties to select the next batch.

When genml is configured, a generative prior is trained on the input molecules before the AL loop. During configured cycles, novel molecules are generated and merged into the remaining pool.

Parameters:

genml_post_process – Optional PTransform applied to generated molecules (e.g., rdesign’s StrictFilterCascade). Passed through to MoleculeGenerator as post_process.

config_class

alias of ParetoActiveLearningConfig

__init__(genml_post_process: apache_beam.transforms.ptransform.PTransform | None = None, **kwargs)

Initialize the transform with configuration.

All keyword arguments are passed to the config_class constructor to create a validated configuration instance stored as self.config.

Parameters:

kwargs – Configuration parameters for the config_class

Raises:
  • AttributeError – If config_class is not defined on the subclass

  • ValidationError – If the configuration parameters are invalid