AssemblyTheoryTools (ATT) provides a unified Python interface for assembly-index calculations across molecules, strings, and arbitrary graphs.
Documentation · Examples · API reference · PyPI · Issues · Releases
What is assembly theory?
Assembly theory quantifies the complexity of an object by the smallest number of joining steps needed to build it from elementary parts, while allowing previously created intermediates to be reused. The reuse rule captures internal structure and repetition rather than size alone.
For molecules, the elementary parts are bonds and the calculation is performed on the molecular graph. ATT exposes the parallelassemblycpp C++ calculator, the assembly-theory Rust calculator, and assemblycfg for fast approximate string calculations through one Python package.
See the concepts guide and theory overview for more background.
ATT requires Python 3.12 or newer. Install the current release from PyPI:
python -m pip install assemblytheorytoolsPlatform note: The C++ calculator is not distributed as a binary. The first calculation that needs it builds parallelassemblycpp from source into
~/.cache/assemblytheorytools, which takes a few minutes and needsgitand a C++20 compiler. To use a build you already have, setASS_PATHinstead; see Use your own parallelassemblycpp build below.
Calculate and plot the assembly pathway for caffeine:
import matplotlib.pyplot as plt
import assemblytheorytools as att
smi = "CN1C=NC2=C1C(=O)N(C(=O)N2C)C"
graph = att.smi_to_nx(smi)
ai, virtual_objects, pathway = att.calculate_assembly_index(
graph,
strip_hydrogen=True,
)
print(f"Assembly index: {ai}")
fig, ax = att.plot_pathway(pathway, plot_type="graph")
plt.show()Assembly index: 9
Understanding the result
aiis the assembly index.virtual_objectscontains reusable intermediates found along the pathway. The collection is unordered; do not rely on positional order.pathwayis a NetworkXDiGraphwhose nodes are the virtual objects and the joining steps. Each node carries its object in avoattribute; the node ids themselves are labels such asvirtual_object_3andstep_5.
Convert the virtual-object graphs back to SMILES with:
virtual_smiles = [
att.nx_to_smi(obj, add_hydrogens=False)
for obj in virtual_objects
]Most published molecular assembly indices exclude hydrogens. Use strip_hydrogen=True when comparing against those
values. ATT strips a copy, leaving the original graph unchanged.
Which function computes which quantity. The route map carries the full table — every quantity ATT computes, with its inputs, its outputs, and what it is used for.
| Quantity | Function | Input | Output |
|---|---|---|---|
| Assembly index | calculate_assembly_index |
NetworkX graph or RDKit Mol |
Index, virtual objects, pathway |
| Assembly index without the pathway | calculate_assembly_index_rust |
NetworkX graph or RDKit Mol |
Index (hydrogens always stripped) |
| String assembly index | calculate_string_assembly_index |
String or list of strings | Index, virtual objects, pathway |
| Joint assembly index | calculate_assembly_index on a joined graph |
Graphs merged with join_graphs |
Index for the whole set |
| Shared-assembly score | calculate_assembly_index_similarity |
List of graphs | Score; 0 to 1 for a pair |
| Semi-metric distance | calculate_assembly_index_semi_metric |
Two graphs | Distance; larger means less shared motifs |
Assembly A |
calculate_assembly |
Graphs and their copy numbers | Ensemble assembly value |
| Assembly depth | calculate_assembly_depth_rust |
NetworkX graph or RDKit Mol |
Minimum depth under concurrent joins |
| Bounds | calculate_assembly_index_upper_bound, calculate_assembly_index_lower_bound |
NetworkX graph or RDKit Mol |
Instant bounds for screening |
| Many indices at once | calculate_assembly_index_parallel |
List of graphs plus a settings dictionary (required; pass None for the defaults) |
Indices, virtual objects, pathways |
| Assembly index estimated from tandem MS | MAEstimator |
Fragmentation tree and molecular weight | Monte Carlo samples of MA |
| Assembly index estimated from IR peaks | estimate_ai_from_ir_peaks |
Peak counts, reference indices, a model function and a starting parameter guess | Fitted model and predicted indices |
The last two rows are heuristic estimates from measured spectra, not exact calculations; report their spread.
| Other complexity scores | bertz_complexity, bottcher, wiener_index, and more | RDKit Mol | Score, for comparison against the index |
- Exact assembly-index calculations for molecules, arbitrary labelled graphs, and directed or undirected strings.
The search is exponential in the worst case, so a default 100-second timeout applies; on a timeout the calculation
returns the best upper bound it reached, and
exact=Truemakes it return-1instead. - Default C++ and alternative Rust search interfaces, plus fast graph bounds and CFG-based string approximations.
- Joint assembly, parallel execution, pathway parsing, pathway visualisation, and alternative-path enumeration.
- Molecular complexity metrics, structure conversion, reassembly, crystal-cell, spectroscopy, and mass-spectrometry utilities.
Calculator backends and important differences
| Backend | Main interface | Best suited to | Result |
|---|---|---|---|
| parallelassemblycpp (C++) | calculate_assembly_index |
Default molecule and graph calculations | Index, virtual objects, and pathway |
| assembly-theory (Rust) | calculate_assembly_index_rust |
Fast molecular index calculations | Index |
| assembly-theory search (Rust) | calculate_assembly_index_rust_search |
Search statistics, options, and pathway reconstruction | Structured search result |
| assemblycfg | calculate_string_assembly_index(..., mode="cfg") |
Fast approximate string calculations | Upper bound and pathway |
The analytic bounds calculate_assembly_index_upper_bound and
calculate_assembly_index_lower_bound are not a backend: they are pure Python
formulas that invoke no calculator at all.
The Rust backend always strips hydrogens. For a meaningful comparison, compare it with
calculate_assembly_index(..., strip_hydrogen=True).
The Rust backend is unavailable on Windows, where assembly-theory cannot be installed; its four functions raise
ImportError there, and every other backend works.
The PyPI distribution ships no parallelassemblycpp binary. ATT checks ASS_PATH, then looks for ParallelAssemblyCpp
(or the older AssemblyCpp) on PATH, then in its own cache, and builds one from source if it finds none. A single executable covers molecules,
graphs and strings. See configuration for
all backend options and environment variables.
The one-line PyPI install above resolves ATT's runtime dependencies. The authoritative dependency list and minimum
versions live in
pyproject.toml.
Two dependencies need more than pip can supply on its own: assembly-theory is not installed on Windows at all,
because it has no wheel there and its Rust source distribution does not build with MSVC (Intel macOS does build it,
and needs a Rust toolchain), and cairosvg needs the Cairo system library. The
installation guide covers both, along with conda,
HPC and build-from-source instructions.
Install from source for development
git clone https://github.com/ELIFE-ASU/assemblytheorytools.git
cd assemblytheorytools
python -m pip install --upgrade "pip>=25.1"
python -m pip install -e ".[dev]"
python -m pip install --group build --group lint
pytestInstall .[docs] instead of .[dev], or install both extras, to build the documentation:
python -m pip install -e ".[dev,docs]"
make -C docs strictSee
CONTRIBUTING.md
for the full development workflow.
Use a Conda environment
From the root of a repository checkout, create an environment with Python, Git, a C++ compiler and Cairo. The environment uses only conda-forge and Python 3.12–3.14; pip installs ATT's Python dependencies from its package metadata:
conda env create -f build_tools/environment.yml
conda activate att_envFor an editable development installation, use build_tools/environment_dev.yml and activate att_dev_env instead.
See build_tools/README.md for the build tools and checks.
Install on an HPC system (including SOL)
Module names vary between systems. On SOL, run these commands from the root of a repository checkout:
module load mamba/latest
mamba env create -f build_tools/environment.yml
source activate att_envWhen submitting a scheduled job, use the environment's Python executable explicitly:
srun "$HOME/.conda/envs/att_env/bin/python3" my_script.pyUse your own parallelassemblycpp build
ATT builds parallelassemblycpp on demand, but a build you control is worth having: it skips the wait on first use, and an optimised build is faster on supported hardware. Build it once:
git clone https://github.com/ELIFE-ASU/parallelassemblycpp.git
cmake -S parallelassemblycpp -B parallelassemblycpp/build/release -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF
cmake --build parallelassemblycpp/build/release --parallelThen set ASS_PATH to the full path of the executable, not its containing directory:
export ASS_PATH=$PWD/parallelassemblycpp/build/release/ParallelAssemblyCppOlder upstream revisions name this executable AssemblyCpp; ATT accepts both names and keeps the historical name
for its own cached build. The same executable computes molecular, graph and string assembly indices. ASS_STR_PATH is only needed to point
string calculations at a different build; it falls back to ASS_PATH when unset.
To build a specific revision on demand instead, set ATT_ASSEMBLYCPP_REF to a branch, tag or commit. For the
optimised and parallel build presets, see the
installation guide.
parallelassemblycpp is licensed CC BY-NC 4.0, which is more restrictive than this package's MIT licence. That is why ATT builds it on demand rather than distributing it.
Optional: configure ORCA
ORCA is only required by energy and geometry-optimisation helpers in
assemblytheorytools.tools_atoms; ordinary assembly-index calculations do not use it. ORCA is free for academic use but
requires registration.
After downloading and extracting the appropriate ORCA build, point ATT at the executable:
export ORCA_PATH=/absolute/path/to/orcaSee the installation guide for the complete setup.
Verify the installation
import assemblytheorytools as att
print(att.__version__)
print(
att.calculate_assembly_index(
att.smi_to_nx("CCO"),
strip_hydrogen=True,
)[0]
)The second line prints 1, the assembly index of hydrogen-stripped ethanol.
| Resource | Description |
|---|---|
| Installation | Platform notes, conda, HPC and building the C++ calculator |
| Route map | Every ATT quantity with its inputs, outputs, and applications |
| Concepts | Assembly indices, virtual objects, pathways, joint assembly, and backends |
| User guide | Molecules, strings, graphs, pathways, parallel runs, complexity, and mass spectrometry |
| Runnable examples | Basic and advanced scripts included with the repository |
| Published protocols | Jupyter notebooks reproducing published workflows end to end, committed with their outputs |
| Configuration | Environment variables, binaries, graph requirements, and search options |
| API reference | Complete module and function documentation |
Found a bug or have a feature request? Open an issue in the GitHub tracker. Bug reports should include the ATT version, Python version, operating system, and a minimal reproducible example.
Contributions are welcome. Read
CONTRIBUTING.md
before opening a pull request.
Contributors and acknowledgements
- Louie Slocombe — orchestration, development, and conceptualisation
- Gage Siebert — string assembly-index calculations and CFG integration
- Estelle Janin — bonding and joint assembly-index calculations
- Joey Fedrow — development, maintenance, and documentation
- Veronica Mierzejewski — integration of reassembly calculations
- Mohammadreza Shahjahan — branding and development
- Marina Fernandez-Ruz — visualisation and circle plots
- Sebastian Pagel — reassembly calculations and visualisation
- Amit Kahana — recursive MA integration
- Stuart Marshall — debugging and optimisation
- Ian Seet — joining-operations index calculations
- Keith Patarroyo — assembly-path reconstruction and visualisation
- Michael Jirasek — mass-spectrometry measurement pipeline
- Abhishek Sharma — administrative support
- Lee Cronin — concept, funding, and administrative support
- Sara Walker — concept, funding, and administrative support
If ATT contributes to published work, cite the papers associated with the methods you use. The repository also includes
an att.bib bibliography for ATT and its scientific
Python dependencies.
References
- Sharma, A., Czégel, D., Lachmann, M., Kempes, C. P., Walker, S. I., & Cronin, L. (2023). Assembly theory explains and quantifies selection and evolution. Nature, 622(7982), 321–328. doi:10.1038/s41586-023-06600-9
- Seet, I., Patarroyo, K. Y., Siebert, G., Walker, S. I., & Cronin, L. (2025). Rapid exploration of the assembly chemical space of molecular graphs. Journal of Chemical Information and Modeling, 65(24), 13203–13214. doi:10.1021/acs.jcim.5c01964
- Vimal, D., Parzych, G., Smith, O. M., Parkar, D., Bergen, H., Daymude, J. J., & Mathis, C. (2026). assembly-theory: Open, reproducible calculation of assembly indices. Journal of Open Source Software, 11(117), 9318. doi:10.21105/joss.09318
Method-specific references for spectroscopy and mass-spectrometry workflows are listed in the citing guide.
AssemblyTheoryTools is available under the MIT License.

