Skip to main content

RiemannMol: properties-guided molecule generation over the atom (plain-SMILES) and fragment (SAFE) latent backends

Project description

RiemannMol

Properties-guided molecule generation, with two latent-space backends — and a built-in way to tell which generated molecules are actually trustworthy, not just plausible-looking.

Why

Most latent-space molecule generators will happily decode any point you give them into some molecule. But not every point in latent space is equally trustworthy: points near real training data decode confidently and reproducibly; points far from it are often ambiguous — sampling the same point repeatedly can yield several unrelated molecules, or nothing valid at all. RiemannMol's census command surfaces this directly, so you know which candidates to actually trust.

Install

pip install riemannmol

Checkpoints are hosted on the Hugging Face Hub (QuantaBricks/riemannmol) and downloaded automatically on first use — no separate setup step.

Features

atom backend (plain-SMILES latent model):

  • encode / decode — greedy, beam-search, or sampled decoding.
  • generate — analogs of a seed molecule via noise-based latent sampling, deduplicated and ranked by similarity to the seed.
  • optimize — property-guided generation: CMA-ES search in latent space, decoding and scoring every candidate against a real property function (QED by default; bring your own scoring function for anything else).
  • interpolate — walk the latent path between two molecules.
  • arithmetic — add/subtract two molecules' latent vectors and decode the result.
  • extend — complete an incomplete (open-valence) SMILES fragment.
  • project / distance — compare molecules through a pluggable metric head (structural similarity, or a custom property-similarity head you train yourself).
  • census — the confidence-state diagnostic described above: samples many points and classifies each as pure (confident, single-answer), entangled (ambiguous, multiple candidates), or dead/idle (decoding breaks down).

fragment backend (SAFE-fragment-encoded model):

  • grow — grow new structure off a fixed anchor fragment.
  • edit — fix a prefix of fragments, freely regenerate the rest.

Usage

Load the model once and reuse it across calls (avoids reloading weights every time) — every task function below takes an optional model=.

from RiemannMol.atom import load_model

model = load_model()

Generate analogs of a seed molecule (noise-based sampling)

from RiemannMol.atom import generate

# std < ~0.6 barely changes anything; std >= ~1.0 jumps to mostly-unrelated
# molecules -- there is no smooth "slightly different" middle ground.
for r in generate("CC(C)Cc1ccc(cc1)C(C)C(=O)O", n_samples=12, std=1.0, model=model):
    print(f"{r['similarity']:.3f}  {r['smiles']}")

generate deduplicates, canonicalizes, and ranks by Tanimoto similarity to the seed for you; pass min_similarity=/max_mw= to filter results.

Property-guided generation (CMA-ES optimization)

from RiemannMol.atom import optimize

history = optimize(seed, property="qed", n_steps=30, popsize=20, model=model)
for h in history:  # each entry is a strictly-improving candidate found
    print(h["generation"], h["score"], h["smiles"])
print("best:", history[-1])

Bring your own objective instead of the qed/logp builtins:

from rdkit import Chem
from rdkit.Chem import Descriptors

def my_scorer(smiles: str) -> float:
    m = Chem.MolFromSmiles(smiles)
    return -abs(Descriptors.MolWt(m) - 300)  # e.g. target MW ~300

history = optimize(seed, scoring_fn=my_scorer, n_steps=30, model=model)

Interpolate between two molecules

from RiemannMol.atom import interpolate

results = interpolate("CCO", "c1ccccc1", n_steps=9, mode="sample", model=model)
for r in results:
    print(f"t={r['t']:.2f}  top={r['top_smiles']}  confidence={r['top_frac']:.2f}")

mode="sample" (not greedy) is what reveals the ambiguous crossing zone between the two molecules — see census below for why that matters.

Latent arithmetic

from RiemannMol.atom import arithmetic

result = arithmetic("CCO", "c1ccccc1", op="+", model=model)
print(result["top_smiles"], result["top_frac"])

Complete an incomplete SMILES fragment

from RiemannMol.atom import extend

for r in extend("CC(C)Cc1ccc(", n_samples=20, temperature=1.2, model=model):
    print(r["smiles"], r["frac"])

Compare molecules through a metric head

from RiemannMol.atom import distance

print(distance("CCO", "CCN", head="tanimoto"))

Check whether a point is actually trustworthy (confidence census)

from RiemannMol.atom import census

result = census(n_points=200, n_samples_per_point=100, model=model)
print(result["state_counts"])  # e.g. {'pure': 190, 'entangled': 10}

Fragment backend: scaffold growth and local editing

from RiemannMol.fragment import load_model as load_fragment_model, grow_scaffold, edit_locally

fmodel = load_fragment_model()
print(grow_scaffold("c1ccccc12", n_samples=10, model=fmodel))       # grow off an anchor
print(edit_locally("CC(=O)Nc1ccc(", n_samples=10, model=fmodel))    # fix a prefix, regenerate the rest

Command line

riemannmol encode "CCO"
riemannmol decode --smiles "CCO"
riemannmol generate "CC(C)Cc1ccc(cc1)C(C)C(=O)O" --n-samples 20 --std 1.0
riemannmol optimize "CC(C)Cc1ccc(cc1)C(C)C(=O)O" --property qed --steps 30
riemannmol interpolate "CCO" "c1ccccc1" --steps 5
riemannmol arithmetic "CCO" "c1ccccc1" --op +
riemannmol extend "CC(C)Cc1ccc(" --n-samples 20
riemannmol distance "CCO" "CCN" --head tanimoto
riemannmol census --n-points 200
riemannmol grow "c1ccccc12" --n-samples 10    # fragment backend
riemannmol edit "CC(=O)Nc1ccc(" --n-samples 10  # fragment backend

Run riemannmol --help (or riemannmol <command> --help) for the full list of subcommands and options.

License

Apache License 2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

riemannmol-0.1.1.tar.gz (33.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

riemannmol-0.1.1-py3-none-any.whl (46.4 kB view details)

Uploaded Python 3

File details

Details for the file riemannmol-0.1.1.tar.gz.

File metadata

  • Download URL: riemannmol-0.1.1.tar.gz
  • Upload date:
  • Size: 33.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for riemannmol-0.1.1.tar.gz
Algorithm Hash digest
SHA256 280b81daf55004511bbf61f9d8d76dff9fd30cb9b703fcb8ea7121124fdd6075
MD5 d2d702cddfd882cc4923620cc0205a30
BLAKE2b-256 73400586efab7ade5afa1968e566e04ffba5fc3b00150d328de40ae71c406bf1

See more details on using hashes here.

File details

Details for the file riemannmol-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: riemannmol-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 46.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for riemannmol-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 2b4947bfee5ac6a2d43f22963b3bae50cae81dcba1ebc2f75f59bd84790c968b
MD5 34b4b1593ac7642b0493382c3a51b4de
BLAKE2b-256 142c0bfb78838d8c882a0f1be8222d808b659b9c143e6a6297cfee9aa06dcab5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page