Skip to content

Molecular Verifier

The MolecularVerifier is the main orchestrator for reward computation across all molecular tasks. It automatically routes completions to the appropriate task-specific verifier based on metadata.

Overview

The MolecularVerifier provides:

  • Unified Interface: Single entry point for all reward computations
  • Automatic Routing: Routes completions to the correct verifier based on metadata
  • Parallel Processing: Uses Ray for efficient batch processing
  • GPU Support: Supports GPU-accelerated molecular docking

Architecture

MolecularVerifier
├── GenerationVerifier  → De novo molecular generation
├── MolPropVerifier     → Property prediction (regression/classification)
└── ReactionVerifier    → Chemical reactions & retro-synthesis

Usage

Basic Example

from mol_gen_docking.reward import (
    MolecularVerifier,
    MolecularVerifierConfigModel,
)
from mol_gen_docking.reward.verifiers import (
    GenerationVerifierConfigModel,
    ReactionVerifierConfigModel,
    MolPropVerifierConfigModel
)

# Configure the verifier
config = MolecularVerifierConfigModel(
    generation_verifier_config=GenerationVerifierConfigModel(
        path_to_mappings="data/molgendata",
        reward="property"
    ),
    mol_prop_verifier_config=MolPropVerifierConfigModel(),
    reaction_verifier_config=ReactionVerifierConfigModel()
)

# Create verifier
verifier = MolecularVerifier(config)

# Compute rewards for generation task
completions = ["<answer>CCO</answer>"]
metadata = [{"properties": ["QED"], "objectives": ["maximize"], "target": [0.0]}]

results = verifier(completions, metadata)
print(f"Rewards: {results.rewards}")
# Output:
# >>> Rewards: [0.1127273579103326]

Mixed Batch Processing

The verifier can handle batches with different task types:

completions = [
    "<answer>CCO</answer>",
    "<answer>0.75</answer>",
    "<answer>CCN(CC)C(N)=S + NNC(=O)Cc1ccc(F)cc1 -> C[CH]N(CC)c1nnc(Cc2ccc(F)cc2)[nH]1</answer>"
]

metadata = [
    {"properties": ["QED"], "objectives": ["maximize"], "target": [0.0]},
    {"objectives": ["regression"], "target": [0.8], "norm_var": 0.1},
    {"objectives": ["full_path"], "target": ["C[CH]N(CC)c1nnc(Cc2ccc(F)cc2)[nH]1"]}
]

results = verifier(completions, metadata)

print(results.rewards)
# Output:
# >>> Rewards: [0.1127273579103326, 0.7499999999999996, 1.0]

MolecularVerifierConfigModel

Bases: BaseModel

Pydantic model for molecular verifier configuration.

This model defines the configuration parameters for the MolecularVerifier class, providing validation and documentation for all configuration options.

The reward field is automatically propagated to all sub-verifier configurations, ensuring consistent reward type usage across all verifiers.

Attributes:

Name Type Description
parsing_method Literal['none', 'answer_tags', 'boxed']

Method to parse model completions:

  • "none": No parsing, use full completion (not recommended, risks of ambiguity in the answer extraction)
  • "answer_tags": Extract content within ... tags
  • "boxed": Extract content within answer tags and boxed in the 'oxed{...}' LaTeX command
reward Literal['valid_smiles', 'property']

Type of reward to compute. Affects all sub-verifiers:

  • "property": Computes property-based rewards (docking scores, molecular properties)
  • "valid_smiles": Computes validity rewards (1.0 for valid single SMILES, 0.0 otherwise)
generation_verifier_config Optional[GenerationVerifierConfigModel]

Configuration for de novo molecular generation tasks. Required if handling generation tasks. Contains settings for molecular property optimization, docking oracle configuration, and SMILES extraction.

mol_prop_verifier_config Optional[MolPropVerifierConfigModel]

Configuration for molecular property prediction tasks. Required if handling property prediction tasks. Contains settings for regression and classification objective handling.

reaction_verifier_config Optional[ReactionVerifierConfigModel]

Configuration for chemical reaction and retro-synthesis tasks. Required if handling reaction tasks. Contains settings for synthesis path validation and reaction SMARTS matching.

Notes
  • At least one sub-verifier configuration should be provided for the verifier to work
  • The propagate_reward_to_subconfigs validator automatically sets the reward type and parsing_method flag in all sub-verifier configurations
  • Invalid configurations will raise Pydantic ValidationError with detailed messages
Example
from mol_gen_docking.reward import MolecularVerifierConfigModel
from mol_gen_docking.reward.verifiers import (
    GenerationVerifierConfigModel,
    MolPropVerifierConfigModel,
    ReactionVerifierConfigModel
)

# Minimal configuration with generation verifier
config = MolecularVerifierConfigModel(
    generation_verifier_config=GenerationVerifierConfigModel(
        path_to_mappings="data/molgendata"
    )
)

# Full configuration with all verifiers
config = MolecularVerifierConfigModel(
    parsing_method="answer_tags",
    reward="property",
    generation_verifier_config=GenerationVerifierConfigModel(
        path_to_mappings="data/molgendata",
        rescale=True,
        oracle_kwargs={
            "exhaustiveness": 8,
            "n_cpu": 8,
            "docking_oracle": "autodock_gpu",
            "vina_mode": "autodock_gpu_256wi"
        },
        docking_concurrency_per_gpu=2
    ),
    mol_prop_verifier_config=MolPropVerifierConfigModel(
        reward="property"
    ),
    reaction_verifier_config=ReactionVerifierConfigModel(
        reaction_matrix_path="data/rxn_matrix.pkl",
        reaction_reward_type="tanimoto"
    )
)
See Also
  • GenerationVerifierConfigModel: Configuration for generation tasks
  • MolPropVerifierConfigModel: Configuration for property prediction tasks
  • ReactionVerifierConfigModel: Configuration for reaction tasks
  • MolecularVerifier: Main orchestrator class using this config
Source code in mol_gen_docking/reward/molecular_verifier_pydantic_model.py
class MolecularVerifierConfigModel(BaseModel):
    """Pydantic model for molecular verifier configuration.

    This model defines the configuration parameters for the MolecularVerifier class,
    providing validation and documentation for all configuration options.

    The reward field is automatically propagated to all sub-verifier configurations,
    ensuring consistent reward type usage across all verifiers.

    Attributes:
        parsing_method: Method to parse model completions:

            - "none": No parsing, use full completion (not recommended, risks of ambiguity in the answer extraction)
            - "answer_tags": Extract content within <answer>...</answer> tags
            - "boxed": Extract content within answer tags and boxed in the '\boxed{...}' LaTeX command
        reward: Type of reward to compute. Affects all sub-verifiers:

            - "property": Computes property-based rewards (docking scores, molecular properties)
            - "valid_smiles": Computes validity rewards (1.0 for valid single SMILES, 0.0 otherwise)
        generation_verifier_config: Configuration for de novo molecular generation tasks.
            Required if handling generation tasks. Contains settings for molecular property
            optimization, docking oracle configuration, and SMILES extraction.
        mol_prop_verifier_config: Configuration for molecular property prediction tasks.
            Required if handling property prediction tasks. Contains settings for regression
            and classification objective handling.
        reaction_verifier_config: Configuration for chemical reaction and retro-synthesis tasks.
            Required if handling reaction tasks. Contains settings for synthesis path validation
            and reaction SMARTS matching.

    Notes:
        - At least one sub-verifier configuration should be provided for the verifier to work
        - The propagate_reward_to_subconfigs validator automatically sets the reward type
          and parsing_method flag in all sub-verifier configurations
        - Invalid configurations will raise Pydantic ValidationError with detailed messages

    Example:
        ```python
        from mol_gen_docking.reward import MolecularVerifierConfigModel
        from mol_gen_docking.reward.verifiers import (
            GenerationVerifierConfigModel,
            MolPropVerifierConfigModel,
            ReactionVerifierConfigModel
        )

        # Minimal configuration with generation verifier
        config = MolecularVerifierConfigModel(
            generation_verifier_config=GenerationVerifierConfigModel(
                path_to_mappings="data/molgendata"
            )
        )

        # Full configuration with all verifiers
        config = MolecularVerifierConfigModel(
            parsing_method="answer_tags",
            reward="property",
            generation_verifier_config=GenerationVerifierConfigModel(
                path_to_mappings="data/molgendata",
                rescale=True,
                oracle_kwargs={
                    "exhaustiveness": 8,
                    "n_cpu": 8,
                    "docking_oracle": "autodock_gpu",
                    "vina_mode": "autodock_gpu_256wi"
                },
                docking_concurrency_per_gpu=2
            ),
            mol_prop_verifier_config=MolPropVerifierConfigModel(
                reward="property"
            ),
            reaction_verifier_config=ReactionVerifierConfigModel(
                reaction_matrix_path="data/rxn_matrix.pkl",
                reaction_reward_type="tanimoto"
            )
        )
        ```

    See Also:
        - GenerationVerifierConfigModel: Configuration for generation tasks
        - MolPropVerifierConfigModel: Configuration for property prediction tasks
        - ReactionVerifierConfigModel: Configuration for reaction tasks
        - MolecularVerifier: Main orchestrator class using this config
    """

    parsing_method: Literal["none", "answer_tags", "boxed"] = Field(
        default="boxed",
        description="Method to parse model completions for SMILES or property values.",
    )
    reward: Literal["valid_smiles", "property"] = Field(
        default="property",
        description="Type of reward to use for molecular verification.",
    )
    generation_verifier_config: Optional[GenerationVerifierConfigModel] = Field(
        None,
        description="Configuration for generation verifier, required if reward is 'valid_smiles'.",
    )
    mol_prop_verifier_config: Optional[MolPropVerifierConfigModel] = Field(
        None,
        description="Configuration for molecular property verifier, required if reward is 'property'.",
    )
    reaction_verifier_config: Optional[ReactionVerifierConfigModel] = Field(
        None,
        description="Configuration for reaction verifier, required if reward is 'reaction'.",
    )

    @model_validator(mode="after")
    def propagate_fields_to_subconfigs(self) -> "MolecularVerifierConfigModel":
        """Propagate the fields shared to all sub-verifier configurations."""
        if self.generation_verifier_config is not None:
            self.generation_verifier_config.reward = self.reward
            self.generation_verifier_config.parsing_method = self.parsing_method
        if self.mol_prop_verifier_config is not None:
            self.mol_prop_verifier_config.parsing_method = self.parsing_method
            self.mol_prop_verifier_config.reward = self.reward
        if self.reaction_verifier_config is not None:
            ### FOR REACTION VERIFIER, SPECIAL BEHAVIOR:
            ###     - if parsing_method is "none", set it to "none" for reaction verifier
            ###     - else, set it to "answer_tags" for reaction verifier (boxed not supported)
            if self.parsing_method == "none":
                self.reaction_verifier_config.parsing_method = "none"
            else:
                self.reaction_verifier_config.parsing_method = "answer_tags"
            self.reaction_verifier_config.reward = self.reward
        return self

    class Config:
        """Pydantic configuration for the MolecularVerifierConfigModel."""

        arbitrary_types_allowed = True
        json_schema_extra = {
            "example": {
                "parsing_method": "answer_tags",
                "reward": "property",
                "generation_verifier_config": {
                    "path_to_mappings": "data/molgendata",
                    "rescale": True,
                    "oracle_kwargs": {
                        "exhaustiveness": 8,
                        "n_cpu": 8,
                        "docking_oracle": "autodock_gpu",
                        "vina_mode": "autodock_gpu_256wi",
                    },
                    "docking_concurrency_per_gpu": 2,
                },
                "mol_prop_verifier_config": {},
                "reaction_verifier_config": {
                    "reaction_matrix_path": "data/rxn_matrix.pkl",
                    "reaction_reward_type": "tanimoto",
                },
            }
        }

Config

Pydantic configuration for the MolecularVerifierConfigModel.

Source code in mol_gen_docking/reward/molecular_verifier_pydantic_model.py
class Config:
    """Pydantic configuration for the MolecularVerifierConfigModel."""

    arbitrary_types_allowed = True
    json_schema_extra = {
        "example": {
            "parsing_method": "answer_tags",
            "reward": "property",
            "generation_verifier_config": {
                "path_to_mappings": "data/molgendata",
                "rescale": True,
                "oracle_kwargs": {
                    "exhaustiveness": 8,
                    "n_cpu": 8,
                    "docking_oracle": "autodock_gpu",
                    "vina_mode": "autodock_gpu_256wi",
                },
                "docking_concurrency_per_gpu": 2,
            },
            "mol_prop_verifier_config": {},
            "reaction_verifier_config": {
                "reaction_matrix_path": "data/rxn_matrix.pkl",
                "reaction_reward_type": "tanimoto",
            },
        }
    }

propagate_fields_to_subconfigs()

Propagate the fields shared to all sub-verifier configurations.

Source code in mol_gen_docking/reward/molecular_verifier_pydantic_model.py
@model_validator(mode="after")
def propagate_fields_to_subconfigs(self) -> "MolecularVerifierConfigModel":
    """Propagate the fields shared to all sub-verifier configurations."""
    if self.generation_verifier_config is not None:
        self.generation_verifier_config.reward = self.reward
        self.generation_verifier_config.parsing_method = self.parsing_method
    if self.mol_prop_verifier_config is not None:
        self.mol_prop_verifier_config.parsing_method = self.parsing_method
        self.mol_prop_verifier_config.reward = self.reward
    if self.reaction_verifier_config is not None:
        ### FOR REACTION VERIFIER, SPECIAL BEHAVIOR:
        ###     - if parsing_method is "none", set it to "none" for reaction verifier
        ###     - else, set it to "answer_tags" for reaction verifier (boxed not supported)
        if self.parsing_method == "none":
            self.reaction_verifier_config.parsing_method = "none"
        else:
            self.reaction_verifier_config.parsing_method = "answer_tags"
        self.reaction_verifier_config.reward = self.reward
    return self

BatchMolecularVerifierOutputModel

Bases: BaseModel

Output model for molecular verifier batch results.

This model encapsulates the results from batch verification across multiple tasks and completions. It provides both the computed rewards and detailed metadata about each verification process, enabling comprehensive analysis of model performance.

The output is structured as parallel lists where each index corresponds to a single completion from the input batch, allowing easy correlation between inputs and outputs.

Attributes:

Name Type Description
rewards list[float]

List of computed reward scores, one per input completion. Each reward is a float value typically in the range [0.0, 1.0], though values may exceed 1.0 for maximize objectives depending on the input values. The reward value depends on the task type and objective:

  • Generation tasks: Geometric mean of per-property rewards
  • Property prediction: 0-1 for classification, 0-1 (clipped) for regression
  • Reaction tasks: 0-1 for ground truth, 0-1 for path validation
parsed_answer list[float]

The parsed answer extracted from the model completion.

verifier_metadatas list[MolecularVerifierOutputMetadataModel]

List of metadata objects from each verification process. Each element corresponds to the reward at the same index. The metadata type depends on which verifier processed the completion:

  • GenerationVerifierMetadataModel: For generation tasks (SMILES extraction, properties)
  • MolPropVerifierMetadataModel: For property prediction (extracted values)
  • ReactionVerifierMetadataModel: For reaction tasks (validation results)
Notes
  • The length of rewards and verifier_metadatas must always match the number of input completions
  • The order of outputs corresponds to the order of inputs
  • Metadata provides detailed diagnostic information about failures (extraction errors, invalid molecules, validation failures, etc.)
  • All numeric reward values are finite (not NaN or inf)
Example
from mol_gen_docking.reward import MolecularVerifier, MolecularVerifierConfigModel
from mol_gen_docking.reward.verifiers import GenerationVerifierConfigModel

config = MolecularVerifierConfigModel(
    generation_verifier_config=GenerationVerifierConfigModel(
        path_to_mappings="data/molgendata"
    )
)
verifier = MolecularVerifier(config)

# Verify multiple completions
completions = [
    "<answer>CCO</answer>",
    "<answer>c1ccccc1</answer>",
    "<answer>invalid_smiles</answer>"
]
metadata = [
    {"properties": ["QED"], "objectives": ["maximize"], "target": [0.0]},
    {"properties": ["QED"], "objectives": ["maximize"], "target": [0.0]},
    {"properties": ["QED"], "objectives": ["maximize"], "target": [0.0]}
]

results = verifier(completions, metadata)

# Access results
print(f"Number of completions: {len(results.rewards)}")
for i, (reward, meta) in enumerate(zip(results.rewards, results.verifier_metadatas)):
    print(f"Completion {i}: reward={reward:.3f}")
    print(f"  Properties: {meta.properties}")
    print(f"  All SMILES: {meta.all_smi}")
    if meta.smiles_extraction_failure:
        print(f"  Failure reason: {meta.smiles_extraction_failure}")

#  Output:
# >>> Number of completions: 3
# Completion 0: reward=0.113
#   Properties: ['QED']
#   All SMILES: ['CCO']
# Completion 1: reward=0.173
#   Properties: ['QED']
#   All SMILES: ['c1ccccc1']
# Completion 2: reward=0.000
#   Properties: []
#   All SMILES: []
#   Failure reason: no_smiles
See Also
  • MolecularVerifier: Main class that returns this model
  • GenerationVerifierMetadataModel: Metadata for generation tasks
  • MolPropVerifierMetadataModel: Metadata for property prediction tasks
  • ReactionVerifierMetadataModel: Metadata for reaction tasks
Source code in mol_gen_docking/reward/molecular_verifier_pydantic_model.py
class BatchMolecularVerifierOutputModel(BaseModel):
    """Output model for molecular verifier batch results.

    This model encapsulates the results from batch verification across multiple tasks
    and completions. It provides both the computed rewards and detailed metadata about
    each verification process, enabling comprehensive analysis of model performance.

    The output is structured as parallel lists where each index corresponds to a single
    completion from the input batch, allowing easy correlation between inputs and outputs.

    Attributes:
        rewards: List of computed reward scores, one per input completion.
            Each reward is a float value typically in the range [0.0, 1.0], though values
            may exceed 1.0 for maximize objectives depending on the input values.
            The reward value depends on the task type and objective:

            - Generation tasks: Geometric mean of per-property rewards
            - Property prediction: 0-1 for classification, 0-1 (clipped) for regression
            - Reaction tasks: 0-1 for ground truth, 0-1 for path validation
        parsed_answer: The parsed answer extracted from the model completion.
        verifier_metadatas: List of metadata objects from each verification process.
            Each element corresponds to the reward at the same index. The metadata type
            depends on which verifier processed the completion:

            - GenerationVerifierMetadataModel: For generation tasks (SMILES extraction, properties)
            - MolPropVerifierMetadataModel: For property prediction (extracted values)
            - ReactionVerifierMetadataModel: For reaction tasks (validation results)

    Notes:
        - The length of rewards and verifier_metadatas must always match the number
          of input completions
        - The order of outputs corresponds to the order of inputs
        - Metadata provides detailed diagnostic information about failures (extraction errors,
          invalid molecules, validation failures, etc.)
        - All numeric reward values are finite (not NaN or inf)

    Example:
        ```python
        from mol_gen_docking.reward import MolecularVerifier, MolecularVerifierConfigModel
        from mol_gen_docking.reward.verifiers import GenerationVerifierConfigModel

        config = MolecularVerifierConfigModel(
            generation_verifier_config=GenerationVerifierConfigModel(
                path_to_mappings="data/molgendata"
            )
        )
        verifier = MolecularVerifier(config)

        # Verify multiple completions
        completions = [
            "<answer>CCO</answer>",
            "<answer>c1ccccc1</answer>",
            "<answer>invalid_smiles</answer>"
        ]
        metadata = [
            {"properties": ["QED"], "objectives": ["maximize"], "target": [0.0]},
            {"properties": ["QED"], "objectives": ["maximize"], "target": [0.0]},
            {"properties": ["QED"], "objectives": ["maximize"], "target": [0.0]}
        ]

        results = verifier(completions, metadata)

        # Access results
        print(f"Number of completions: {len(results.rewards)}")
        for i, (reward, meta) in enumerate(zip(results.rewards, results.verifier_metadatas)):
            print(f"Completion {i}: reward={reward:.3f}")
            print(f"  Properties: {meta.properties}")
            print(f"  All SMILES: {meta.all_smi}")
            if meta.smiles_extraction_failure:
                print(f"  Failure reason: {meta.smiles_extraction_failure}")

        #  Output:
        # >>> Number of completions: 3
        # Completion 0: reward=0.113
        #   Properties: ['QED']
        #   All SMILES: ['CCO']
        # Completion 1: reward=0.173
        #   Properties: ['QED']
        #   All SMILES: ['c1ccccc1']
        # Completion 2: reward=0.000
        #   Properties: []
        #   All SMILES: []
        #   Failure reason: no_smiles
        ```


    See Also:
        - MolecularVerifier: Main class that returns this model
        - GenerationVerifierMetadataModel: Metadata for generation tasks
        - MolPropVerifierMetadataModel: Metadata for property prediction tasks
        - ReactionVerifierMetadataModel: Metadata for reaction tasks
    """

    rewards: list[float] = Field(
        ...,
        description="List of computed rewards for the molecular verification.",
    )
    parsed_answers: list[str] = Field(
        ..., description="The parsed answer extracted from the model completion."
    )
    verifier_metadatas: list[MolecularVerifierOutputMetadataModel] = Field(
        ...,
        description="List of metadata from each verifier used in the molecular verification.",
    )

Molecular verifier module for computing rewards across different task types.

This module provides the MolecularVerifier class which orchestrates reward computation for molecular generation, property prediction, and chemical reaction tasks. It uses Ray for parallel processing and supports GPU-accelerated docking calculations.

MolecularVerifier

Main orchestrator for molecular verification and reward computation.

This class provides a unified interface for computing rewards across different molecular tasks: de novo generation, property prediction, and chemical reactions. It automatically routes inputs to the appropriate verifier based on metadata.

The verifier uses Ray for parallel processing and supports GPU-accelerated molecular docking calculations when configured.

Attributes:

Name Type Description
verifier_config

Configuration model containing settings for all verifiers.

logger

Logger instance for the verifier.

Example
from mol_gen_docking.reward import MolecularVerifier, MolecularVerifierConfigModel
from mol_gen_docking.reward.verifiers import GenerationVerifierConfigModel

config = MolecularVerifierConfigModel(
    generation_verifier_config=GenerationVerifierConfigModel(
        path_to_mappings="data/molgendata",
        reward="property"
    )
)
verifier = MolecularVerifier(config)

# Compute rewards
completions = ["<answer>CCO</answer>", "<answer>c1ccccc1</answer>"]
metadata = [
    {"properties": ["QED"], "objectives": ["maximize"], "target": [0.0]},
    {"properties": ["SA"], "objectives": ["minimize"], "target": [0.0]}
]
results = verifier(completions, metadata)
print(f"Rewards: {results.rewards}")
Source code in mol_gen_docking/reward/molecular_verifier.py
class MolecularVerifier:
    """Main orchestrator for molecular verification and reward computation.

    This class provides a unified interface for computing rewards across different
    molecular tasks: de novo generation, property prediction, and chemical reactions.
    It automatically routes inputs to the appropriate verifier based on metadata.

    The verifier uses Ray for parallel processing and supports GPU-accelerated
    molecular docking calculations when configured.

    Attributes:
        verifier_config: Configuration model containing settings for all verifiers.
        logger: Logger instance for the verifier.

    Example:
        ```python
        from mol_gen_docking.reward import MolecularVerifier, MolecularVerifierConfigModel
        from mol_gen_docking.reward.verifiers import GenerationVerifierConfigModel

        config = MolecularVerifierConfigModel(
            generation_verifier_config=GenerationVerifierConfigModel(
                path_to_mappings="data/molgendata",
                reward="property"
            )
        )
        verifier = MolecularVerifier(config)

        # Compute rewards
        completions = ["<answer>CCO</answer>", "<answer>c1ccccc1</answer>"]
        metadata = [
            {"properties": ["QED"], "objectives": ["maximize"], "target": [0.0]},
            {"properties": ["SA"], "objectives": ["minimize"], "target": [0.0]}
        ]
        results = verifier(completions, metadata)
        print(f"Rewards: {results.rewards}")
        ```
    """

    def __init__(
        self,
        verifier_config: MolecularVerifierConfigModel,
    ):
        """Initialize the MolecularVerifier.

        Args:
            verifier_config: Configuration model containing settings for all
                sub-verifiers (generation, property prediction, reaction).
        """
        self.verifier_config = verifier_config
        self.__name__ = "RewardScorer/MolecularVerifier"
        self.remote_tqdm = ray.remote(tqdm_ray.tqdm)

        self._generation_verifier: None | GenerationVerifier = None
        self._mol_prop_verifier: None | MolPropVerifier = None
        self._reaction_verifier: None | ReactionVerifier = None
        self.logger = logging.getLogger("RewardScorer")

        if not ray.is_initialized():
            ray.init()

    @property
    def generation_verifier(self) -> GenerationVerifier:
        """Lazy-loaded generation verifier instance.

        Returns:
            GenerationVerifier: The generation verifier for de novo molecular generation tasks.

        Raises:
            AssertionError: If generation_verifier_config is not set in the config.
        """
        if self._generation_verifier is not None:
            return self._generation_verifier
        assert self.verifier_config.generation_verifier_config is not None
        self._generation_verifier = GenerationVerifier(
            verifier_config=self.verifier_config.generation_verifier_config
        )
        return self._generation_verifier

    @property
    def mol_prop_verifier(self) -> MolPropVerifier:
        """Lazy-loaded molecular property verifier instance.

        Returns:
            MolPropVerifier: The verifier for molecular property prediction tasks.

        Raises:
            AssertionError: If mol_prop_verifier_config is not set in the config.
        """
        if self._mol_prop_verifier is not None:
            return self._mol_prop_verifier
        assert self.verifier_config.mol_prop_verifier_config is not None
        self._mol_prop_verifier = MolPropVerifier(
            verifier_config=self.verifier_config.mol_prop_verifier_config
        )
        return self._mol_prop_verifier

    @property
    def reaction_verifier(self) -> ReactionVerifier:
        """Lazy-loaded reaction verifier instance.

        Returns:
            ReactionVerifier: The verifier for chemical reaction and retro-synthesis tasks.

        Raises:
            AssertionError: If reaction_verifier_config is not set in the config.
        """
        if self._reaction_verifier is not None:
            return self._reaction_verifier
        assert self.verifier_config.reaction_verifier_config is not None
        self._reaction_verifier = ReactionVerifier(
            verifier_config=self.verifier_config.reaction_verifier_config
        )

        return self._reaction_verifier

    def _get_generation_score(
        self,
        inputs: BatchVerifiersInputModel,
        debug: bool = False,
        use_pbar: bool = False,
    ) -> List[GenerationVerifierOutputModel]:
        """Compute rewards for molecular generation tasks.

        Args:
            inputs: Batch of completions and metadata for generation verification.
            debug: If True, enables debug mode with additional logging.
            use_pbar: If True, displays a progress bar during computation.

        Returns:
            List of GenerationVerifierOutputModel containing rewards and metadata.
        """
        if debug:  # Testing purposes
            self.generation_verifier.debug = True
        elif self._generation_verifier is not None:
            self.generation_verifier.debug = False
        return self.generation_verifier.get_score(inputs)

    def _get_prop_pred_score(
        self,
        inputs: BatchVerifiersInputModel,
        debug: bool = False,
        use_pbar: bool = False,
    ) -> List[MolPropVerifierOutputModel]:
        """Compute rewards for molecular property prediction tasks.

        Args:
            inputs: Batch of completions and metadata for property verification.
            debug: If True, enables debug mode with additional logging.
            use_pbar: If True, displays a progress bar during computation.

        Returns:
            List of MolPropVerifierOutputModel containing rewards and metadata.
        """
        return self.mol_prop_verifier.get_score(inputs)

    def _get_reaction_score(
        self,
        inputs: BatchVerifiersInputModel,
        debug: bool = False,
        use_pbar: bool = False,
    ) -> List[ReactionVerifierOutputModel]:
        """Compute rewards for chemical reaction tasks.

        Args:
            inputs: Batch of completions and metadata for reaction verification.
            debug: If True, enables debug mode with additional logging.
            use_pbar: If True, displays a progress bar during computation.

        Returns:
            List of ReactionVerifierOutputModel containing rewards and metadata.
        """
        return self.reaction_verifier.get_score(inputs)

    def get_score(
        self,
        completions: List[Any],
        metadata: List[Dict[str, Any]],
        debug: bool = False,
        use_pbar: bool = False,
    ) -> BatchMolecularVerifierOutputModel:
        """Compute rewards for a batch of completions.

        This method automatically routes each completion to the appropriate verifier
        based on its metadata. It supports mixed batches containing generation,
        property prediction, and reaction tasks.

        Args:
            completions: List of model completions (strings or structured outputs).
            metadata: List of metadata dictionaries, one per completion. The metadata
                determines which verifier is used for each completion.
            debug: If True, enables debug mode with additional logging.
            use_pbar: If True, displays a progress bar during computation.

        Returns:
            BatchMolecularVerifierOutputModel containing:
                - rewards: List of float rewards for each completion
                - verifier_metadatas: List of metadata from each verification

        Raises:
            AssertionError: If completions and metadata have different lengths.

        Example:
            ```python
            completions = ["<answer>CCO</answer>"]
            metadata = [{"properties": ["QED"], "objectives": ["maximize"], "target": [0.0]}]
            results = verifier.get_score(completions, metadata)
            ```
        """
        assert len(completions) == len(metadata)
        obj_to_fn: Dict[
            str,
            Callable[
                [
                    BatchVerifiersInputModel,
                    bool,
                    bool,
                ],
                List[Any],
            ],
        ] = {
            "generation": self._get_generation_score,
            "mol_prop": self._get_prop_pred_score,
            "reaction": self._get_reaction_score,
        }
        idxs: Dict[str, List[int]] = {"generation": [], "mol_prop": [], "reaction": []}
        completions_per_obj: Dict[str, List[str]] = {
            "generation": [],
            "mol_prop": [],
            "reaction": [],
        }
        metadata_per_obj: Dict[str, List[Dict[str, Any]]] = {
            "generation": [],
            "mol_prop": [],
            "reaction": [],
        }
        for i, (completion, meta) in enumerate(zip(completions, metadata)):
            assigned = assign_to_inputs(completion, meta)
            idxs[assigned].append(i)
            completions_per_obj[assigned].append(completion)
            metadata_per_obj[assigned].append(meta)

        rewards = [0.0 for _ in range(len(metadata))]
        metadata_output = [
            MolecularVerifierOutputMetadataModel() for _ in range(len(metadata))
        ]
        parsed_answers: List[str] = ["" for _ in range(len(metadata))]
        for key, fn in obj_to_fn.items():
            if len(completions_per_obj[key]) > 0:
                outputs_obj = fn(
                    BatchVerifiersInputModel(
                        completions=completions_per_obj[key],
                        metadatas=metadata_per_obj[key],
                    ),
                    debug,
                    use_pbar,
                )
                for i, output in zip(idxs[key], outputs_obj):
                    rewards[i] = output.reward
                    metadata_output[i] = (
                        MolecularVerifierOutputMetadataModel.model_validate(
                            {f"{key}_verifier_metadata": output.verifier_metadata}
                        )
                    )
                    parsed_answers[i] = output.parsed_answer
        return BatchMolecularVerifierOutputModel(
            rewards=rewards,
            parsed_answers=parsed_answers,
            verifier_metadatas=metadata_output,
        )

    def __call__(
        self,
        completions: List[Any],
        metadata: List[Dict[str, Any]],
        debug: bool = False,
        use_pbar: bool = False,
    ) -> BatchMolecularVerifierOutputModel:
        """Call the verifier to compute rewards.

        This is a convenience method that calls get_score().

        Args:
            completions: List of model completions.
            metadata: List of metadata dictionaries.
            debug: If True, enables debug mode.
            use_pbar: If True, displays a progress bar.

        Returns:
            BatchMolecularVerifierOutputModel with rewards and metadata.
        """
        return self.get_score(
            completions=completions, metadata=metadata, debug=debug, use_pbar=use_pbar
        )

generation_verifier property

Lazy-loaded generation verifier instance.

Returns:

Name Type Description
GenerationVerifier GenerationVerifier

The generation verifier for de novo molecular generation tasks.

Raises:

Type Description
AssertionError

If generation_verifier_config is not set in the config.

mol_prop_verifier property

Lazy-loaded molecular property verifier instance.

Returns:

Name Type Description
MolPropVerifier MolPropVerifier

The verifier for molecular property prediction tasks.

Raises:

Type Description
AssertionError

If mol_prop_verifier_config is not set in the config.

reaction_verifier property

Lazy-loaded reaction verifier instance.

Returns:

Name Type Description
ReactionVerifier ReactionVerifier

The verifier for chemical reaction and retro-synthesis tasks.

Raises:

Type Description
AssertionError

If reaction_verifier_config is not set in the config.

__call__(completions, metadata, debug=False, use_pbar=False)

Call the verifier to compute rewards.

This is a convenience method that calls get_score().

Parameters:

Name Type Description Default
completions List[Any]

List of model completions.

required
metadata List[Dict[str, Any]]

List of metadata dictionaries.

required
debug bool

If True, enables debug mode.

False
use_pbar bool

If True, displays a progress bar.

False

Returns:

Type Description
BatchMolecularVerifierOutputModel

BatchMolecularVerifierOutputModel with rewards and metadata.

Source code in mol_gen_docking/reward/molecular_verifier.py
def __call__(
    self,
    completions: List[Any],
    metadata: List[Dict[str, Any]],
    debug: bool = False,
    use_pbar: bool = False,
) -> BatchMolecularVerifierOutputModel:
    """Call the verifier to compute rewards.

    This is a convenience method that calls get_score().

    Args:
        completions: List of model completions.
        metadata: List of metadata dictionaries.
        debug: If True, enables debug mode.
        use_pbar: If True, displays a progress bar.

    Returns:
        BatchMolecularVerifierOutputModel with rewards and metadata.
    """
    return self.get_score(
        completions=completions, metadata=metadata, debug=debug, use_pbar=use_pbar
    )

__init__(verifier_config)

Initialize the MolecularVerifier.

Parameters:

Name Type Description Default
verifier_config MolecularVerifierConfigModel

Configuration model containing settings for all sub-verifiers (generation, property prediction, reaction).

required
Source code in mol_gen_docking/reward/molecular_verifier.py
def __init__(
    self,
    verifier_config: MolecularVerifierConfigModel,
):
    """Initialize the MolecularVerifier.

    Args:
        verifier_config: Configuration model containing settings for all
            sub-verifiers (generation, property prediction, reaction).
    """
    self.verifier_config = verifier_config
    self.__name__ = "RewardScorer/MolecularVerifier"
    self.remote_tqdm = ray.remote(tqdm_ray.tqdm)

    self._generation_verifier: None | GenerationVerifier = None
    self._mol_prop_verifier: None | MolPropVerifier = None
    self._reaction_verifier: None | ReactionVerifier = None
    self.logger = logging.getLogger("RewardScorer")

    if not ray.is_initialized():
        ray.init()

get_score(completions, metadata, debug=False, use_pbar=False)

Compute rewards for a batch of completions.

This method automatically routes each completion to the appropriate verifier based on its metadata. It supports mixed batches containing generation, property prediction, and reaction tasks.

Parameters:

Name Type Description Default
completions List[Any]

List of model completions (strings or structured outputs).

required
metadata List[Dict[str, Any]]

List of metadata dictionaries, one per completion. The metadata determines which verifier is used for each completion.

required
debug bool

If True, enables debug mode with additional logging.

False
use_pbar bool

If True, displays a progress bar during computation.

False

Returns:

Type Description
BatchMolecularVerifierOutputModel

BatchMolecularVerifierOutputModel containing: - rewards: List of float rewards for each completion - verifier_metadatas: List of metadata from each verification

Raises:

Type Description
AssertionError

If completions and metadata have different lengths.

Example
completions = ["<answer>CCO</answer>"]
metadata = [{"properties": ["QED"], "objectives": ["maximize"], "target": [0.0]}]
results = verifier.get_score(completions, metadata)
Source code in mol_gen_docking/reward/molecular_verifier.py
def get_score(
    self,
    completions: List[Any],
    metadata: List[Dict[str, Any]],
    debug: bool = False,
    use_pbar: bool = False,
) -> BatchMolecularVerifierOutputModel:
    """Compute rewards for a batch of completions.

    This method automatically routes each completion to the appropriate verifier
    based on its metadata. It supports mixed batches containing generation,
    property prediction, and reaction tasks.

    Args:
        completions: List of model completions (strings or structured outputs).
        metadata: List of metadata dictionaries, one per completion. The metadata
            determines which verifier is used for each completion.
        debug: If True, enables debug mode with additional logging.
        use_pbar: If True, displays a progress bar during computation.

    Returns:
        BatchMolecularVerifierOutputModel containing:
            - rewards: List of float rewards for each completion
            - verifier_metadatas: List of metadata from each verification

    Raises:
        AssertionError: If completions and metadata have different lengths.

    Example:
        ```python
        completions = ["<answer>CCO</answer>"]
        metadata = [{"properties": ["QED"], "objectives": ["maximize"], "target": [0.0]}]
        results = verifier.get_score(completions, metadata)
        ```
    """
    assert len(completions) == len(metadata)
    obj_to_fn: Dict[
        str,
        Callable[
            [
                BatchVerifiersInputModel,
                bool,
                bool,
            ],
            List[Any],
        ],
    ] = {
        "generation": self._get_generation_score,
        "mol_prop": self._get_prop_pred_score,
        "reaction": self._get_reaction_score,
    }
    idxs: Dict[str, List[int]] = {"generation": [], "mol_prop": [], "reaction": []}
    completions_per_obj: Dict[str, List[str]] = {
        "generation": [],
        "mol_prop": [],
        "reaction": [],
    }
    metadata_per_obj: Dict[str, List[Dict[str, Any]]] = {
        "generation": [],
        "mol_prop": [],
        "reaction": [],
    }
    for i, (completion, meta) in enumerate(zip(completions, metadata)):
        assigned = assign_to_inputs(completion, meta)
        idxs[assigned].append(i)
        completions_per_obj[assigned].append(completion)
        metadata_per_obj[assigned].append(meta)

    rewards = [0.0 for _ in range(len(metadata))]
    metadata_output = [
        MolecularVerifierOutputMetadataModel() for _ in range(len(metadata))
    ]
    parsed_answers: List[str] = ["" for _ in range(len(metadata))]
    for key, fn in obj_to_fn.items():
        if len(completions_per_obj[key]) > 0:
            outputs_obj = fn(
                BatchVerifiersInputModel(
                    completions=completions_per_obj[key],
                    metadatas=metadata_per_obj[key],
                ),
                debug,
                use_pbar,
            )
            for i, output in zip(idxs[key], outputs_obj):
                rewards[i] = output.reward
                metadata_output[i] = (
                    MolecularVerifierOutputMetadataModel.model_validate(
                        {f"{key}_verifier_metadata": output.verifier_metadata}
                    )
                )
                parsed_answers[i] = output.parsed_answer
    return BatchMolecularVerifierOutputModel(
        rewards=rewards,
        parsed_answers=parsed_answers,
        verifier_metadatas=metadata_output,
    )

Task Routing

The verifier automatically determines the task type based on metadata structure:

Metadata Fields Task Type Verifier
properties, objectives (maximize/minimize/above/below), target Generation GenerationVerifier
objectives (regression/classification), target, norm_var Property Prediction MolPropVerifier
objectives (full_path/smarts/...), target, reactants Reaction ReactionVerifier

Performance Considerations

  • Lazy Loading: Verifiers are instantiated on first use
  • Ray Parallelization: Long-running computations (docking) are parallelized
  • GPU Allocation: Docking uses fractional GPU allocation for concurrency
  • Caching: Oracle results are cached to avoid redundant computations