Robust fragment-aware molecular language with SELFIES-compatible fragment bodies.
Project description
Fragment-SELFIES
Fragment-SELFIES is a robust, fragment-aware molecular language with validity-preserving decoding and explicit fragment structure. It records the BRICS fragment tree with a small set of structural tokens, while each fragment body is encoded as SELFIES-like tokens plus non-atomic Dummy attachment placeholders.
The current format is vocabulary-free at encode/decode time. It does not emit
large corpus-specific IDs such as [F:F000001]. Instead, it emits tokens like
[Frag], [Frag@0], [Attach:0], [pop], and SELFIES-compatible
fragment-body tokens such as [C], [=C], [Branch1], [Ring1], and [Dummy].
Full technical details are in docs/fragment_selfies.md.
Why This Format Exists
The fragment-token approach required a huge BRICS fragment vocabulary. For large molecular corpora, that produces large JSONL vocabulary artifacts and many rare fragment-ID tokens. The compact representation keeps the chemically meaningful BRICS decomposition but avoids fragment IDs by encoding each fragment body with SELFIES-compatible tokens.
This gives molecular language-model workflows a representation with:
- Explicit BRICS fragment tree structure.
- SELFIES-compatible tokens for fragment internals.
- A small fixed set of Fragment-SELFIES structural tokens.
- Canonical and randomized encoding modes.
- Randomized implicit-anchor augmentation for design pretraining.
- Direct decoding back to RDKit molecules.
- No required fragment vocabulary file for normal encode/decode.
Installation
Fragment-SELFIES supports Python 3.11 and newer.
python -m pip install fragment-selfies
RDKit is a runtime dependency. If a compatible RDKit wheel is unavailable for
your platform, install RDKit from conda-forge first, then install
Fragment-SELFIES with pip in the same environment.
Development install:
git clone https://github.com/fairydance/Fragment-SELFIES.git
cd Fragment-SELFIES
conda create -n fragment_selfies python=3.13
conda activate fragment_selfies
conda install -c conda-forge rdkit
python -m pip install -e ".[test]"
Verify the installation:
python -m pytest -q
Build and validate release artifacts:
python -m pip install --upgrade build twine
python -m build
python -m twine check dist/*
Token Grammar
Fragment-SELFIES strings are strict bracketed-token strings.
In one sentence: current compact Fragment-SELFIES starts root fragments with
[Frag], starts child fragments with [Frag@N], stores each fragment body as
SELFIES-compatible tokens, connects explicit BRICS tree edges with
[Attach:N][Frag@M], and represents implicit anchors as adjacent root
[Frag] blocks.
Example:
[Frag][C][C][O][C][Branch1][C][N][=C][Branch1][C][Dummy][C][=Ring1][#Branch1][C][Attach:0][Frag@1][O][=C][Branch1][C][Dummy][Dummy][Attach:0][Frag@0][C][O][Dummy][pop][pop]
Structural Fragment-SELFIES tokens:
| Token | Meaning |
|---|---|
[Frag] |
Start a root BRICS fragment. Adjacent root fragments are disconnected anchors unless an explicit attachment edge is emitted. |
[Frag@N] |
Start a child fragment and connect through child attachment N. |
[Attach:N] |
Select parent attachment N on the current fragment. |
[pop] |
Return traversal state to the parent fragment. |
[.] |
Legacy disconnected molecule component marker. |
[SELFIES]...[ENDSELFIES] |
Optional whole-molecule SELFIES fallback block. |
Everything between a fragment marker and the next structural token is the SELFIES-compatible body for that fragment.
The [Dummy...] tokens are non-atomic attachment placeholders. They are used
because the standard SELFIES encoder cannot encode RDKit dummy atoms (*)
directly, and they avoid colliding with real elements such as xenon.
Explicit And Implicit Anchor Semantics
Fragment-SELFIES uses only tokens that can be learned from the compact molecular corpus. This lets a pretrained tokenizer accept implicit-anchor prompts without adding new vocabulary.
There are no special implicit tokens. An implicit string is normal compact Fragment-SELFIES whose selected cut edge appears as adjacent roots:
Use adjacent root fragments as disconnected anchors:
[Frag]anchor_A[Frag]anchor_B
A concrete two-anchor shape is:
[Frag][C][=C][C][=C][C][=C][Ring1][=Branch1][Dummy][Frag][O][=C][Dummy]
Both anchors contain [Dummy] placeholders, which are the open attachment sites
used during implicit repair.
Use explicit attachment tokens when two fragments should be connected by the serialized tree itself:
[Frag]fragment_A[Attach:0][Frag@0]fragment_B
Do not use [.] for implicit-anchor prompts:
[Frag]anchor_A[.][Frag]anchor_B
That syntax means legacy disconnected components rather than adjacent anchors in the same repair group.
Decoding repairs implicit-anchor prompts by connecting adjacent root-anchor
components through unused [Dummy...] attachment points when possible. If no
valid attachment-based connection is possible, strict decoding raises and
non-strict decoding falls back to the largest valid component.
For linker-design generations that consume every generated-side [Dummy] but
still leave the first anchor disconnected, decoding can optionally repair one
missing return attachment. Enable repair_missing_return_attachment=True in the
API or --repair-missing-return-attachment in the CLI. The repair chooses the
farthest topologically suitable atom from the second anchor, tests the synthetic
single-bond return connection with RDKit sanitization, and leaves decoding
unchanged when no strictly valid site exists.
Encoding Modes
Default encoding is deterministic for the input order but not canonicalized:
from fragment_selfies import FragmentSelfiesCodec
codec = FragmentSelfiesCodec()
encoded = codec.encode("COC(=O)c1c(N)oc(C)c1C")
Canonical encoding gives a stable canonical string:
canonical = codec.encode("COC(=O)c1c(N)oc(C)c1C", canonical=True)
Randomized encoding changes atom order and fragment traversal for augmentation:
augmented = codec.encode("COC(=O)c1c(N)oc(C)c1C", randomized=True, seed=0)
Randomized encoding also supports implicit-anchor augmentation. With probability
implicit_probability, up to max_implicit_cuts BRICS edges in each connected component are
serialized as adjacent root anchors instead of an explicit [Attach:N][Frag@M]
edge. The default max_implicit_cuts=1 preserves the two-root implicit behavior;
set it to 2 or higher to produce multi-root implicit samples for multi-fragment
design training:
implicit_augmented = codec.encode(
"COC(=O)c1c(N)oc(C)c1C",
randomized=True,
seed=0,
implicit_probability=1.0,
max_implicit_cuts=2,
)
The default probability is 0.15 for randomized encoding. Set
implicit_probability=0.0 to disable implicit-anchor augmentation.
canonical=True and randomized=True are mutually exclusive.
CLI Usage
Encode one SMILES string:
conda run -n fragment_selfies fragment-selfies encode \
--smiles 'COC(=O)c1c(N)oc(C)c1C' \
--canonical
Encode a randomized augmentation:
conda run -n fragment_selfies fragment-selfies encode \
--smiles 'COC(=O)c1c(N)oc(C)c1C' \
--randomized \
--seed 0 \
--implicit-probability 0.15 \
--max-implicit-cuts 2
Force explicit one-root serialization:
conda run -n fragment_selfies fragment-selfies encode \
--smiles 'COC(=O)c1c(N)oc(C)c1C' \
--randomized \
--style explicit
Force implicit adjacent-root serialization when a BRICS edge exists:
conda run -n fragment_selfies fragment-selfies encode \
--smiles 'COC(=O)c1c(N)oc(C)c1C' \
--canonical \
--style implicit \
--max-implicit-cuts 2
Re-serialize an existing Fragment-SELFIES string into another style:
conda run -n fragment_selfies fragment-selfies reserialize \
--fragment-selfies '[Frag][O][=CH0][Branch1][C][Dummy][Dummy][Frag][C][OH0][Dummy]' \
--style explicit \
--canonical
Decode a compact Fragment-SELFIES string:
conda run -n fragment_selfies fragment-selfies decode \
--fragment-selfies '[Frag][C][=C][C][=C][C][=C][Ring1][=Branch1]' \
--canonical
Decoding uses non-strict recovery mode by default for generated strings. Add
--strict to require exact Fragment-SELFIES decoding for validation.
For linker-design outputs missing a final return attachment, add the opt-in repair flag:
conda run -n fragment_selfies fragment-selfies decode \
--fragment-selfies '<generated-linker-fragment-selfies>' \
--repair-missing-return-attachment \
--canonical
API Usage
from rdkit import Chem
from fragment_selfies import FragmentSelfiesCodec
codec = FragmentSelfiesCodec()
encoded = codec.encode("COC(=O)c1c(N)oc(C)c1C", canonical=True)
mol = codec.decode(encoded)
smiles = Chem.MolToSmiles(mol, canonical=True, isomericSmiles=False)
codec.decode(...) is non-strict by default. Pass strict=True when validation
should fail on malformed Fragment-SELFIES instead of recovering a molecule.
Pass repair_missing_return_attachment=True to enable the conservative linker
return-attachment repair described above.
SMILES fragments with dummy attachment atoms can be encoded as a single Fragment-SELFIES fragment and decoded with dummy atoms preserved:
fragment = codec.encode_fragment("[*]C(=O)O", canonical=True)
fragment_mol = codec.decode_fragment(fragment)
fragment_smiles = Chem.MolToSmiles(fragment_mol, canonical=True, isomericSmiles=False)
Use the CLI commands fragment-selfies encode-fragment and
fragment-selfies decode-fragment for the same fragment-specific conversion.
Example
Input SMILES:
COC(=O)c1c(N)oc(C)c1C
Canonical compact Fragment-SELFIES:
[Frag][C][C][O][C][Branch1][C][N][=C][Branch1][C][Dummy][C][=Ring1][#Branch1][C][Attach:0][Frag@1][O][=C][Branch1][C][Dummy][Dummy][Attach:0][Frag@0][C][O][Dummy][pop][pop]
The string has 31 tokens and 3 BRICS fragments. It decodes back to:
COC(=O)c1c(N)oc(C)c1C
Optional Fragment Statistics
Normal compact encode/decode does not need a BRICS fragment vocabulary. The
historical build-vocab command remains available as a BRICS fragment counting
and analysis utility.
conda run --live-stream -n fragment_selfies fragment-selfies build-vocab \
--input /path/to/molecules.smi \
--output /path/to/fragment_vocab.jsonl \
--min-count 1 \
--workers 8 \
--canonical \
--progress
Verification
conda run --live-stream -n fragment_selfies python -m py_compile src/fragment_selfies/*.py tests/test_fragment_selfies.py
conda run --live-stream -n fragment_selfies python -m pytest -q
Current expected result:
37 passed, 1 skipped
An optional corpus roundtrip test runs when FRAGMENT_SELFIES_SAMPLE_SMI points
to a local .smi file.
Molecular Language Model Integration
A downstream model should train its tokenizer directly on compact Fragment-SELFIES corpus files. The tokenizer should learn bracketed tokens from the generated corpus: Fragment-SELFIES structural tokens, SELFIES-compatible fragment-body tokens, and any task-specific control tokens. No large BRICS fragment-ID vocabulary is required.
Recommended integration path:
- Convert molecule corpora from SMILES to compact Fragment-SELFIES.
- Train a WordLevel tokenizer on the compact Fragment-SELFIES corpus.
- Use
FragmentSelfiesCodec.encode()for SMILES to Fragment-SELFIES conversion. - Use
FragmentSelfiesCodec.decode()plusChem.MolToSmiles()for generated molecule recovery.
Fragment-SELFIES is the molecular language used by Molexar, a unified multimodal molecular foundation model for drug design.
Citation
@misc{lin2026molexarunifiedmultimodalmolecular,
title={Molexar: A Unified Multimodal Molecular Foundation Model for Drug Design},
author={Haoyu Lin and Yiyan Liao and Jinmei Pan and Xinliao Ling and Luhua Lai and Jianfeng Pei},
year={2026},
eprint={2606.25865},
archivePrefix={arXiv},
primaryClass={q-bio.BM},
url={https://arxiv.org/abs/2606.25865},
}
License
Fragment-SELFIES is released under the MIT License. See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fragment_selfies-1.0.0.tar.gz.
File metadata
- Download URL: fragment_selfies-1.0.0.tar.gz
- Upload date:
- Size: 337.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c9b3e5d77bc8d11e04c979ce7af069ac5a7e23ed9892b88279875bb92bfdb3c6
|
|
| MD5 |
7df245b9ddb2a20456c213573423f0a0
|
|
| BLAKE2b-256 |
d3add5521721d9a5910f133252f3f01092d8a5cd3ff1722124c0d260970a3244
|
File details
Details for the file fragment_selfies-1.0.0-py3-none-any.whl.
File metadata
- Download URL: fragment_selfies-1.0.0-py3-none-any.whl
- Upload date:
- Size: 24.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4b51dd85726139a3ca57ac63a2d407234aebcf22f61296342a0a8b1b89ab57b9
|
|
| MD5 |
b529b9aa0f52b8f65373745c679d8c85
|
|
| BLAKE2b-256 |
58a3e3a8a5c7445ad18e9fe3162baf73e0c1787a003016fd1edf0fa9b7018eb0
|