RDKit → chematic Feature Support Matrix
Honest, feature-by-feature capability-transfer guidance for teams coming from RDKit. This page classifies each area as Supported, Partially supported, or Not currently supported, names the real chematic API alongside RDKit's, and states known residuals — it is not a marketing document, and it does not claim general superiority over RDKit.
See also: rdkit_cheatsheet.md (side-by-side API
snippets for common tasks) and rdkit-comparison.md
(prose comparison of chematic vs. RDKit for teams evaluating which library
to use). This page's added value over both: a per-feature-area
Supported/Partial/Not-supported classification with explicit RDKit-API ↔
chematic-API rows, sourced against this repository's own code and
CHANGELOG rather than general impressions.
What "verified" means on this page: every chematic function name below
was checked against crates/chematic-py/python/chematic/__init__.pyi or
crates/chematic-py/src/*.rs directly (grep + read, not memory). RDKit
function names are its well-documented, stable public API (Chem.*,
AllChem.*, rdMolDescriptors.*, ...) — this page does not assert
anything about RDKit's internal implementation it has not verified against
its public interface.
Legend
- Supported — chematic has a direct, tested equivalent.
- Partially supported — chematic has an equivalent, but with a narrower scope, a different default, or a documented residual gap.
- Not currently supported — no chematic equivalent exists today.
SMILES parsing
Supported.
| RDKit | chematic | |
|---|---|---|
| Parse | Chem.MolFromSmiles(smiles) |
chematic.from_smiles(smiles) (Python); chematic_smiles::parse (Rust); parse_smiles (WASM) |
| Validate only | Chem.MolFromSmiles(smiles) is not None |
chematic.is_valid_smiles(smiles) |
| CXSMILES | Chem.MolFromSmiles(s, params) with Chem.SmilesParserParams |
chematic.from_cxsmiles(s) / chematic_smiles::parse_cxsmiles |
Migration note: chematic's parser is a from-scratch Rust implementation, not a port of RDKit's — expect the same molecule for valid SMILES, but do not assume identical error messages or identical handling of edge-case/ malformed input.
Canonical SMILES
Partially supported — known residual, do not treat as a safe dedup key today.
| RDKit | chematic | |
|---|---|---|
| Canonicalize | Chem.MolToSmiles(mol, canonical=True) |
mol.smiles / chematic.canonical_smiles(...) (chematic_smiles::canonical_smiles) |
Structural correctness of canonical SMILES round-tripping is measured at 100% (0/5000) on a 5,000-mol ChEMBL corpus and 0/33 on a dedicated acyclic-polyene corpus (tretinoin/β-carotene/lycopene-class molecules), per README's "Known Limitations" section — an earlier corruption bug (two independent parser bugs, both ring-closure-specific) is fixed.
The residual gap is narrower but real: canonical_smiles() can still emit
two different, individually-valid //\ spellings for the same E/Z
double-bond system depending on input traversal order, in roughly 1 in
18 stereo-bearing molecules (measured worst-of-10 on the same 5,000-mol
corpus — 275/5000 unstable, confirmed 100% cosmetic, not structural
corruption). Do not use canonical_smiles() as a dedup or cache key
until this closes; use apply_aromaticity()-normalized output as your own
dedup key in the meantime if this matters for your use case. Full figures
and root-cause detail: README.md's "Known Limitations" section.
SMARTS matching
Supported.
| RDKit | chematic | |
|---|---|---|
| Match | mol.GetSubstructMatch(patt) / GetSubstructMatches(patt) |
mol.has_substructure(smarts) / mol.find_matches(smarts) (Python); chematic_smarts::find_matches (Rust); smarts_match_atoms (WASM) |
| Validate | Chem.MolFromSmarts(smarts) is not None |
chematic.is_valid_smarts(smarts) |
| Bulk | [mol.HasSubstructMatch(patt) for mol in mols] |
chematic.bulk.substructure_search(smarts, smiles_list) / chematic.bulk.substructure_match(smarts, mols) (Rayon-parallel) |
Fingerprints
Supported for the common bit-vector families; partially supported
for exact-parity claims against RDKit's implementation (not independently
re-verified on this pass — see docs/verification_coverage.md for what has
been measured).
| RDKit | chematic | |
|---|---|---|
| ECFP4 (Morgan, radius 2) | AllChem.GetMorganFingerprintAsBitVect(mol, 2, nBits=2048) |
mol.ecfp4() (bytes) / mol.ecfp4_numpy() (NumPy (2048,) uint8) |
| ECFP6 | AllChem.GetMorganFingerprintAsBitVect(mol, 3, nBits=2048) |
mol.ecfp6() |
| Chiral ECFP4 | useChirality=True |
mol.ecfp4_chiral() |
| FCFP4 | useFeatures=True |
mol.fcfp4() |
| MACCS 166-bit | MACCSkeys.GenMACCSKeys(mol) |
mol.maccs() / mol.maccs_numpy() |
| Atom-pair | Pairs.GetAtomPairFingerprintAsBitVect(mol) |
mol.atom_pair_fp() (bytes) |
| Topological torsion | Torsions.GetTopologicalTorsionFingerprintAsIntVect(mol) |
mol.torsion_fp() |
| Layered | Chem.LayeredFingerprint(mol, layerFlags=0x7F) |
mol.layered_fp_layers() — 7-layer list, documented as equivalent to RDKit's layerFlags=0x7F |
| MAP4 (not in RDKit core) | — | mol.map4() / mol.map4_numpy() |
| Tanimoto similarity | DataStructs.TanimotoSimilarity(fp1, fp2) |
chematic.tanimoto(fp1, fp2) |
| Bulk fingerprints | list comprehension over mols |
chematic.bulk.ecfp4(smiles_list) (NumPy (N, 2048) uint8, Rayon-parallel) |
Performance note: batch ECFP4 was measured at ~54.7 µs/mol vs. RDKit's
~94.3 µs/mol (1.7×) on a diverse 5,000-mol ChEMBL corpus, and
6.76 µs/mol vs. ~44.5 µs/mol (6.6×) on a small repeated-fixture
10,000-mol batch — both numbers from docs/benchmark.md (measured Python
3.13.6, Apple M4, chematic v0.18.0, RDKit 2026.03.4, 2026-08-23). Cite these
exact, already-measured figures if you cite speed at all — do not
extrapolate to other batch sizes or fingerprint types not in that table.
Descriptors
Supported for the commonly-used physicochemical set.
| RDKit | chematic | |
|---|---|---|
| One descriptor | Descriptors.MolWt(mol), rdMolDescriptors.CalcTPSA(mol), etc. |
mol.mw, mol.tpsa, ... (property access) |
| All at once | manual loop over Descriptors._descList |
mol.descriptors() — dict of 70+ descriptor functions in one call (190+ individual values, since a few functions such as MQN/BCUT2D/autocorr2d return multi-value arrays — see docs/rdkit-comparison.md's descriptor accuracy caveat) |
| Bulk / DataFrame | manual loop + pd.DataFrame(...) |
chematic.bulk.descriptors(smiles_list) / chematic.descriptors_df(smiles_list) (Rayon-parallel, returns a list of dicts / DataFrame directly) |
Accuracy vs. RDKit, per docs/benchmark.md and README's badge comment
(4,999-mol ChEMBL subset, chematic v0.18.0 vs. RDKit 2026.03.4, measured
2026-08-23): HBA/HBD/ARC 100%, MW 99.82% (±0.01 Da — a genuine
corpus-wide check, added this release), TPSA 100% within ±0.1 Ų
(README's "TPSA edge cases" bullet notes a residual 0.3%/16-molecule gap in
exotic phosphazene/S=N=P chemistry), LogP (Crippen) 100%* (max Δ =
1.1×10⁻¹³). These are the only descriptor-accuracy figures this page
cites, and only because README/CHANGELOG already document them.
Aromaticity
Partially supported — documented, root-caused gap.
chematic applies Hückel 4n+2 per SSSR ring independently; RDKit uses
fused-ring electron delocalization. Per README's "Aromaticity model"
bullet: aromaticity-flag parity on Kekulized input is measured at 96.3%
worst-of-10 (5,000-mol ChEMBL); visible differences concentrate in
N-heterocycles (pyridone, quinolone, indolizine) and non-alternant/
bridgehead-heavy structures (azulene, purine). Root cause is documented as
an aromatic_context bypass mechanism, not yet fixed.
Stereocenter / CIP assignment
Partially supported.
Per README's badge comment: stereocenter count 99.96% (legacy) /
98.6% (new CIP FindPotentialStereo-equivalent path); CIP R/S label
96.30% vs. modern RDKit rdCIPLabeler, 96.83% vs. legacy RDKit CIP
assignment. Square-planar (@SP1/@SP2/@SP3-equivalent) stereo is read
automatically from MOL/SDF; write is opt-in only via 3 specific _checked
functions — see format-capabilities.md.
Conformer generation
Partially supported — real gap in generation quality, not just parity measurement.
| RDKit | chematic | |
|---|---|---|
| Single conformer | AllChem.EmbedMolecule(mol) (ETKDGv3) |
mol.generate_3d() — distance geometry + DREIDING minimization |
| Multiple conformers | AllChem.EmbedMultipleConfs(mol, numConfs=N) |
mol.conformer_ensemble(n, rmsd_threshold=0.5) — RMSD-based pruning |
| Torsion-knowledge-aware pipeline | ETKDGv3's built-in torsion preferences | mol.embed_pipeline_v2(config) — opt-in v2 pipeline: torsion-knowledge-aware distance geometry + stereo verification/repair + policy-gated force field |
README's "Use RDKit if" section states this directly: RDKit's ETKDGv3 includes ML-assisted torsion corrections chematic does not have. The feature-maturity table in README.md marks 3D conformer generation (distance geometry + MMFF94) as Experimental.
Correction (2026-08-23): an earlier version of this page said no
RDKit-comparison figure for conformer RMSD/TFD existed in this
repository's docs. That was wrong — validation/results/mmff94_bci_gap_
227_phase2_report.md already measures RMSD (mean 1.685 Å) and TFD (mean
0.2228) against RDKit's ETKDGv3+MMFF94 on the project's 265-molecule
corpus (pipeline_v2_mmff94_strict, last re-measured v0.17.0, 241/265
success). This page still does not attempt a deeper quantitative
characterization of the conformer-quality gap than that one summary
figure — see docs/rfcs/etkdg_3d_gap_rfc.md and
docs/rfcs/openeye_materials_advantage_rfc.md for the fuller picture,
including a live defect found in the public Mol.conformer_ensemble()
API (distinct from the sound embed_pipeline_v2 path measured above).
Force-field optimization
Partially supported.
| RDKit | chematic | |
|---|---|---|
| MMFF94 | AllChem.MMFFOptimizeMolecule(mol) |
mol.minimize_mmff94(coords); energy via mol.mmff94_total_energy(coords) / mol.mmff94_energy_breakdown(coords) |
| UFF | AllChem.UFFOptimizeMolecule(mol) |
mol.minimize_uff(coords) — per its own docstring, UFF covers all elements including metals, unlike chematic's MMFF94, which is limited |
| DREIDING (not in RDKit core) | — | mol.minimize_dreiding(coords) |
Known residual: MMFF94 atom-typing issue #337 — as of CHANGELOG [0.18.0],
one sub-bug (aryl isothiocyanate cumulated-double-bond CSP carbon) is
fixed; 6 of the original 8 affected molecules remain an honestly-disclosed
residual, root-caused to a genuine RDKit Kekulization/MMFF-aromaticity-
perception artifact for a specific fused, macrocyclic ring topology (a
pyridinium-conjugated exocyclic-amine scaffold) rather than a locally-
statable atom-typing rule gap — 32/6,693 type-mismatched and 56/6,693
charge-mismatched atoms remain on the 264-molecule reference corpus. See
CHANGELOG.md's [0.18.0] entry and scripts/mmff94_provenance/PROVENANCE.md
for the full writeup; this page does not re-derive it.
Molecular depiction (2D)
Supported for SVG; not currently supported for PNG-only workflows
without the optional png feature.
| RDKit | chematic | |
|---|---|---|
| Single molecule SVG | Draw.MolToImage(mol) / rdMolDraw2D.MolDraw2DSVG |
mol._repr_svg_() (Jupyter auto-render) / chematic-depict::depict_svg(mol) (Rust) |
| Grid of molecules | Draw.MolsToGridImage(mols) |
chematic.depict_grid(mols, cols) |
| Reaction depiction | Draw.ReactionToImage(rxn) |
chematic.reaction_svg(reaction_smiles) |
InChI
Partially supported — two distinct code paths with different accuracy characteristics.
| RDKit | chematic | |
|---|---|---|
| Standard InChI | Chem.MolToInchi(mol) (vendored InChI C library) |
mol.standard_inchi / mol.standard_inchikey — bit-exact, via the vendored InChI C library (v1.07.5), requires the native-inchi Cargo feature |
| Default (no C dependency) | — | mol.inchi / mol.inchikey — pure-Rust approximation, not bit-exact |
Migration note: if your pipeline depends on bit-exact standard InChI
without enabling native-inchi, chematic's default path is an
approximation, not a drop-in replacement — README's "Use RDKit if" section
states this explicitly as a reason to prefer RDKit.
Substructure search
Supported — see the SMARTS matching row above; this row exists
separately only because RDKit users often look up "substructure search" as
its own topic. Same functions apply: mol.has_substructure/
mol.find_matches (single), chematic.bulk.substructure_search/
substructure_match (bulk, Rayon-parallel).
Reactions / SMIRKS
Supported for template-based reaction application; not currently supported for RDKit's full reaction-standardization/validation toolkit beyond what's listed.
| RDKit | chematic | |
|---|---|---|
| Apply a reaction | rxn = AllChem.ReactionFromSmarts(smirks); rxn.RunReactants(reactants) |
chematic.run_smirks(smirks, reactants) |
| Combinatorial library enumeration | manual loop over RunReactants |
chematic.enumerate_library(smirks, fragment_sets) |
| Reaction fingerprint similarity | (community recipes, not core RDKit) | chematic.tanimoto_reaction_fp(rxn1, rxn2) |
| Query a reaction by SMARTS | manual matching | chematic.query_reaction(reaction_smiles, smarts) / chematic.batch_query_reactions(reactions, smarts) |
| Atom economy / mass balance | manual computation | chematic.atom_economy(reaction_smiles) / chematic.balance_check(reaction_smiles) |
Maximum Common Substructure (MCS)
Supported, single-function scope.
| RDKit | chematic | |
|---|---|---|
| MCS of a set of molecules | rdFMCS.FindMCS(mols) |
chematic.find_mcs(mols) → Optional[Mol] |
Migration note: RDKit's rdFMCS.FindMCS exposes tunable parameters
(atom/bond comparison mode, timeout, ring-matching strictness, ...) via
MCSParameters. chematic.find_mcs is a single-call function with no
documented equivalent tuning surface in __init__.pyi as of this pass —
if your RDKit usage depends on non-default MCSParameters, verify the
chematic result matches your needs before switching.
CIF / materials & simulation formats
Supported, broader than RDKit's out-of-the-box coverage for this
category — to our knowledge, RDKit's core Python package does not ship
native mmCIF/PQR/QCSchema/ORCA/Cube/OpenDX/LAMMPS readers (some may be
reachable indirectly via other tools in the wider ecosystem, which this
page does not attempt to catalogue or verify).
See format-capabilities.md for the full
15-format matrix, including which of these formats has zero WASM
exposure (plain CIF) and which Python bindings are read-only (plain CIF).
This is a real area where chematic covers formats RDKit's core package
does not — stated narrowly, without a general "chematic beats RDKit on
formats" claim.
Python batch processing
Supported.
| RDKit | chematic | |
|---|---|---|
| Bulk parse | [Chem.MolFromSmiles(s) for s in smiles_list] |
chematic.bulk.parse(smiles_list) (Rayon-parallel) |
| Bulk fingerprints / descriptors | manual for loop, optionally with multiprocessing |
chematic.bulk.ecfp4(...), chematic.bulk.maccs(...), chematic.bulk.descriptors(...), chematic.descriptors_df(...) — Rayon-parallel inside a single PyO3 call, no multiprocessing boilerplate needed |
| Bulk Tanimoto | DataStructs.BulkTanimotoSimilarity |
chematic.bulk.tanimoto(...) / chematic.bulk.tanimoto_matrix(...) / chematic.bulk.tanimoto_search(query, library) |
WASM / browser usage
Not applicable to RDKit's core package — RDKit has no first-party
Python-style WASM bindings; RDKit.js is a separate community project.
chematic ships chematic-wasm directly from the same Rust source as the
Python bindings. Measured 2026-08-21 (see docs/rdkit-comparison.md's WASM
deployment table for the full methodology): chematic's WASM bundle is
2.94 MB raw / 1.10 MB gzip, versus RDKit.js's RDKit_minimal.wasm at
6.91 MB raw (gzip not independently measured) — about 2.3× smaller on a
raw-to-raw basis. See format-capabilities.md
for exactly which formats are and are not exposed at the WASM layer (plain
CIF, notably, is not).
What this page deliberately does not claim
- No "full compatibility" claim anywhere on this page — every row is scoped to what was actually verified against source.
- No performance claim beyond the specific, already-measured figures in
docs/benchmark.md/CHANGELOG.md, cited with their measurement context (environment, corpus, version) intact. - No claim of general superiority over RDKit. Where chematic has a real, narrow advantage (WASM bundle size, native mmCIF/PQR/QCSchema/ORCA/Cube/ OpenDX/LAMMPS I/O), it is stated as exactly that — narrow and specific — not generalized.
- Known residuals (canonical-SMILES E/Z direction-normalization gap,
aromaticity
aromatic_contextgap, MMFF94 issue #337 residual, InChI approximation withoutnative-inchi) are stated here, not hidden, and are sourced from README.md's "Known Limitations" section and CHANGELOG.md rather than invented for this page.