Quick Start
Python
"""RENKIN Python quickstart. Runs as part of CI so this example can never
silently drift from the real API (see .github/workflows/ci.yml)."""
import json
import renkin
result = json.loads(
renkin.find_routes(
target="CC(=O)Oc1ccccc1C(=O)O", # Aspirin
depth=5,
max_routes=3,
)
)
print(f"Routes found: {result['routes_found']}")
for route in result["routes"]:
print(f"Route (depth {route['depth']}):")
for step in route["steps"]:
print(f" {step['target']} -> {' + '.join(step['precursors'])}")
print(f" via {step['rule']}")
Output, captured from an actual run of the example above (CI executes the example on every change to confirm it still runs without error, but does not diff its output against the text below):
Routes found: 3
Route (depth 1):
OC(=O)c1ccccc1OC(=O)C -> O=CC + c1cccc(c1O)C(O)=O
via co_aliphatic_cleavage
Route (depth 1):
OC(=O)c1ccccc1OC(=O)C -> OC(=O)C + c1cccc(c1O)C(O)=O
via ester_cleavage
Route (depth 1):
OC(=O)c1ccccc1OC(=O)C -> c1cccc(c1O)C(O)=O + OC(=O)C
via aryl_ether_retro
find_routes returns a JSON string — always json.loads() it before
accessing fields; see Python API for the full parameter
list (custom templates, evidence metadata, constraints, pricing, etc.).
Custom Building Blocks
You can supply your own building block library:
import renkin, json
my_stock = [
"CC(=O)O", # acetic acid
"Oc1ccccc1", # phenol
"c1ccccc1", # benzene
"Brc1ccccc1", # bromobenzene
"OB(O)c1ccccc1", # phenylboronic acid
]
result = json.loads(renkin.find_routes(
target="c1ccc(-c2ccccc2)cc1", # biphenyl
building_blocks=my_stock,
depth=3,
))
print(f"Routes found: {result['routes_found']}")
# Routes found: 1 (bromobenzene + benzene via suzuki_retro, the only rule
# this small 5-compound stock can support)
Rust
//! RENKIN Rust quickstart. Compiled and run as part of CI (see
//! .github/workflows/ci.yml) so this example can never silently drift from
//! the real `find_routes` API.
use renkin::chem_env::{ChemEnv, default_rules};
use renkin::search::{SearchConfig, find_routes};
fn main() -> anyhow::Result<()> {
let env = ChemEnv::load("data/building_blocks.smi")?;
let rules = default_rules();
let config = SearchConfig {
max_depth: 5,
max_routes: 3,
..Default::default()
};
let (routes, _stats) = find_routes("CC(=O)Oc1ccccc1C(=O)O", &env, &rules, &config)?;
println!("Routes found: {}", routes.len());
for route in &routes {
println!("Route (depth {}):", route.depth);
for step in &route.steps {
println!(" {} -> {}", step.target, step.precursors.join(" + "));
println!(" via {}", step.rule);
}
}
Ok(())
}
find_routes returns Result<(Vec<Route>, SearchStats)> — destructure the
tuple, and note route.depth/route.steps are plain fields, not methods. See
Rust API for the full signature and SearchConfig fields.
CLI Benchmark
# Run retrosynthesis on a list of targets
renkin-bench \
--input targets.smi \
--building-blocks data/building_blocks.smi \
--depth 3 \
--beam-width 50 \
> results.json
The input file should be a SMILES file (one SMILES per line, optional name after whitespace).
SMILES File Format
Building blocks and target files use the standard .smi format: