Skip to content

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:

CC(=O)O         acetic_acid
c1ccccc1        benzene
# Comments start with #
Brc1ccccc1      bromobenzene