The complete library for molecular reasoning: question generation, property computation, and answer evaluation
Everything you need for molecular reasoning benchmarks in one package
Installation • Quick Start • API Overview • MolecularIQ Family
MolecularIQ Core is the central library for the MolecularIQ benchmark ecosystem:
- MolecularIQD: High-level API for dynamic question generation and evaluation
- Molecule Pools: Access training molecules (validation pools hidden to prevent leakage)
- SymbolicSolver: Compute 100+ molecular properties from SMILES
- Reward Functions: Evaluate model predictions against ground truth
- NaturalLanguageFormatter: Convert between technical keys and natural language
# From GitHub
pip install git+https://github.com/ml-jku/moleculariq-core.git
# From source (for development)
pip install -e ".[dev]"Requirements: Python 3.9+ and RDKit
For most users, MolecularIQD is the recommended entry point:
from moleculariq_core import MolecularIQD
mqd = MolecularIQD(seed=42)
# Generate a count question
question, answer, metadata = mqd.generate_count_question(
smiles="c1ccccc1",
count_properties="aromatic_ring_count"
)
print(question)
# "How many aromatic rings are in c1ccccc1? Return the result as JSON with key `aromatic_ring_count`."
print(answer)
# {'aromatic_ring_count': 1}
# Generate an index question
question, answer, metadata = mqd.generate_index_question(
smiles="CCO",
index_properties="carbon_atom_index"
)
print(answer)
# {'carbon_atom_index': [0, 1]}
# Validate predictions
score = mqd.validate_count_answer("c1ccccc1", {"aromatic_ring_count": 1})
# 1.0
# Generate a constraint question (molecule generation task)
question, metadata = mqd.generate_constraint_question(
constraints=[{"property": "ring_count", "operator": ">=", "value": 2}]
)
# "Generate a molecule with at least 2 rings..."
# Validate a generated molecule against constraints
score = mqd.validate_constraint_answer(
"c1ccc2ccccc2c1", # Naphthalene (2 fused rings)
metadata["constraints"]
)
# 1.0from moleculariq_core import load_molecule_pool
# Load training pool for development
train_smiles = load_molecule_pool("train")
print(f"Loaded {len(train_smiles)} training molecules")
# Validation pools are hidden to prevent data leakage
load_molecule_pool("val_hard") # Raises MoleculePoolHiddenErrorfrom moleculariq_core import MolecularIQD, load_molecule_pool
import random
mqd = MolecularIQD(seed=42)
train_smiles = load_molecule_pool("train")
for epoch in range(num_epochs):
smiles = random.choice(train_smiles)
question, answer, _ = mqd.generate_count_question(smiles, "ring_count")
prediction = model(question)
reward = mqd.validate_count_answer(smiles, prediction, answer)
# ... update modelFor custom pipelines, access the primitives directly:
from moleculariq_core import SymbolicSolver, evaluate_answer
solver = SymbolicSolver()
smiles = "CC(=O)Oc1ccccc1C(=O)O" # Aspirin
# Compute properties
solver.get_ring_count(smiles) # 1
solver.get_aromatic_ring_count(smiles) # 1
solver.get_carbon_atom_count(smiles) # 9
# Evaluate predictions
score = evaluate_answer(
task_type="single_count",
predicted={"ring_count": 1},
target={"ring_count": 1}
) # 1.0| Component | Description |
|---|---|
MolecularIQD |
All-in-one class for question generation and evaluation |
load_molecule_pool |
Load training molecules from HuggingFace |
| Method | Description |
|---|---|
generate_count_question() |
Generate counting questions |
generate_index_question() |
Generate atom index identification questions |
generate_constraint_question() |
Generate molecule generation questions |
validate_count_answer() |
Validate count predictions |
validate_index_answer() |
Validate index predictions |
validate_constraint_answer() |
Validate generated molecules |
generate_paired_question() |
Generate matched count/index pairs |
compute_property() |
Compute any molecular property |
| Module | Description |
|---|---|
SymbolicSolver |
Compute 100+ molecular properties from SMILES |
FunctionalGroupSolver |
SMARTS-based functional group detection |
NaturalLanguageFormatter |
Bidirectional NL ↔ technical key conversion |
evaluate_answer |
Unified reward function dispatcher |
| Category | Examples |
|---|---|
| Topology | ring_count, fused_ring_count, bridgehead_atom_count |
| Aromaticity | aromatic_ring_count, aliphatic_ring_count |
| Atoms | carbon_atom_count, hetero_atom_count, halogen_atom_count |
| Bonds | rotatable_bond_count, double_bond_count |
| H-bonding | hba_count, hbd_count |
| Stereochemistry | stereocenter_count, r_s_stereocenter_r_count |
| Functional Groups | 60+ groups (alcohol, ketone, amine, etc.) |
| Reactions | 40+ templates (bromination, oxidation, etc.) |
| Task | Output | Description |
|---|---|---|
single_count |
INTEGER | Count one property |
multi_count |
DICT | Count multiple properties |
single_index |
LIST | Identify atom indices for one property |
multi_index |
DICT | Identify indices for multiple properties |
constraint_generation |
SMILES | Generate molecule satisfying constraints |
This package is part of the MolecularIQ ecosystem:
| Repository | Purpose |
|---|---|
| moleculariq | Central hub for the MolecularIQ benchmark ecosystem |
| moleculariq-leaderboard | Leaderboard: HuggingFace space for results and submissions |
| moleculariq-core | Core library: question generation, property computation, evaluation, molecule pools |
| moleculariq-benchmark | Dataset creation pipeline |
| moleculariq-eval | Evaluation code: lm-eval-harness integration |
MIT License - see LICENSE for details.