--- title: MolOpt Environment colorFrom: blue colorTo: green sdk: docker app_port: 8000 pinned: false license: bsd-3-clause suggested_hardware: cpu-basic short_description: OpenEnv benchmark for iterative molecule optimization. tags: - openenv - chemistry - drug-discovery - reinforcement-learning - rdkit --- # MolOpt Environment MolOpt is an OpenEnv-compatible environment for iterative molecule optimization. It models a real medicinal chemistry workflow: start from a lead compound, propose a structural edit, recompute drug-relevant properties, and continue improving toward a task objective. This is a benchmark environment, not a chemistry chatbot. The core value is repeated `reset()` / `step()` interaction with dense rewards, deterministic grading, and reproducible trajectories. ## Why This Is Real-World Medicinal chemists routinely optimize molecules for multiple competing objectives: - QED: a normalized estimate of overall drug-likeness from `0.0` to `1.0` - logP: a lipophilicity measure that affects permeability and exposure - SA score: an estimate of synthetic accessibility from `1` (easy) to `10` (hard) - Lipinski violations: simple oral-drug heuristics around mass, lipophilicity, and hydrogen bonding MolOpt turns that loop into a deterministic RL/agent benchmark using only RDKit and a programmatic grader. ## Tasks 1. `logp_targeting` (easy) Move the molecule into the medicinal-chemistry-friendly logP window `[2.0, 3.0]` starting from benzene. Max `6` steps. 2. `qed_maximization` (medium) Increase QED starting from aspirin without making invalid or repetitive edits. Max `10` steps. 3. `multi_objective` (hard) Raise QED, lower SA score, reduce flexibility, and keep Lipinski violations at zero starting from a more complex lead. Max `12` steps. ## Action And Observation Spaces Primary action: - `modify_molecule(new_smiles: str)` Helper tools: - `get_properties()` - `get_task_info()` Observation (`MolOptObservation`) includes: - current task and difficulty - current step and remaining budget - canonical SMILES - computed RDKit properties - dense reward breakdown (`RewardModel`) - `last_action_error` - terminal `final_score` Typed Pydantic models live in `models.py`. Core environment logic is in `env.py`. Deterministic scoring is in `rubrics.py`. ## Reward Design The reward is dense and deterministic. - valid progress is rewarded every step - improvements earn a bonus - invalid SMILES gets `-0.5` - repeated or unchanged molecules get `-0.1` - regressions reduce reward Episode graders always return a normalized score in `[0.0, 1.0]`. Note: for validator compatibility, final task scores are guaranteed to be strictly between `0` and `1` (never exactly `0.0` or `1.0`). ## Baseline Scores Latest measured local run with the current task budgets: | Task | Success | Final Score | Notes | |---|---:|---:|---| | `logp_targeting` | true | `0.942` | Strong easy-task baseline | | `qed_maximization` | true | `0.790` | Improves, but does not clear threshold | | `multi_objective` | true | `0.680` | Hard task; one measured run was also affected by provider credit exhaustion | Average baseline: `0.661` ## Project Structure ```text . |-- openenv.yaml |-- pyproject.toml |-- Dockerfile |-- inference.py |-- models.py |-- rubrics.py |-- env.py |-- client.py |-- README.md `-- server/ |-- app.py |-- molopt_environment.py `-- sascorer.py ``` ## Local Setup ```bash python -m venv .venv . .venv/bin/activate pip install -e . openenv validate ``` ## Docker ```bash docker build -t molopt-env:latest . docker run --rm -p 7860:8000 molopt-env:latest ``` Open: - `http://localhost:7860/` - `http://localhost:7860/web/` (interactive UI) - `http://localhost:7860/health` ### Web UI (Tasks) The web interface includes a task selector so you can run each task from the browser: 1. Open `http://localhost:7860/web/` 2. Go to the **Custom** tab ("Task Runner") 3. Select a task (`logp_targeting`, `qed_maximization`, `multi_objective`) 4. Click **Reset With Selected Task** 5. Use **get_task_info**, **get_properties**, then **modify_molecule** with a new SMILES Only `modify_molecule` consumes the step budget; helper tools do not. ## Inference The root-level `inference.py` uses the OpenAI client only and reads: - `API_BASE_URL` default: `https://router.huggingface.co/v1` - `MODEL_NAME` default: `Qwen/Qwen2.5-72B-Instruct:novita` - `HF_TOKEN` required - `LOCAL_IMAGE_NAME` optional for local Docker-backed evaluation - `DOCKER_READY_TIMEOUT_S` optional, default `90` Typical local flow: ```bash cp .env.example .env python inference.py ``` ## Hugging Face Space Deployment 1. Create a new Hugging Face Space with `SDK = Docker`. 2. Connect it to this repository. 3. Keep `CPU Basic` hardware. 4. Add Space variables or secrets: - `API_BASE_URL` - `MODEL_NAME` - `HF_TOKEN` 5. Wait for the Space to reach the `Running` state before submitting. ## Validation Checklist Before submission: 1. `openenv validate` 2. `docker build -t molopt-env:latest .` 3. `docker run --rm -p 7860:8000 molopt-env:latest` 4. `python inference.py` 5. Confirm the Hugging Face Space responds at `/health`