neurosnap.chemistry.landscape module#
Topology-aware chemical-library characterization.
Reimplementation of the ChemManifold chemical-landscape algorithm by Danial Gharaie Amirabadi. A molecular library is represented as a multi-resolution traversable chemical graph:
nodes: compounds, Bemis-Murcko scaffolds, fragments
edges: compound -> scaffold, compound -> fragment, compound <-> compound Tanimoto similarity, scaffold hierarchy (general -> specific), fragment sharing through a common ring system
from neurosnap.chemistry import ChemicalLandscape
landscape = ChemicalLandscape(“library.csv”, smiles_column=”smiles”) landscape.build_all() report = landscape.characterize() print(report.summary()) landscape.path_between(“aspirin”, “naproxen”)
- class neurosnap.chemistry.landscape.CharacterizationReport(diversity, network, islands, frontier=<factory>, counts=<factory>, metadata=<factory>)[source]#
Bases:
objectEverything the engine can say about a library.
-
diversity:
DiversityMetrics#
-
islands:
IslandResult#
-
network:
NetworkMetrics#
-
diversity:
- class neurosnap.chemistry.landscape.ChemicalGraph(node_type, smiles, compound_id, level, frequency, n_atoms, n_rings, mw, method, murcko, src, dst, edge_type, weight)[source]#
Bases:
objectColumn-store heterogeneous chemical graph.
Nodes: compounds, scaffolds, fragments. Edges: compound-scaffold, compound-fragment, similarity, scaffold hierarchy, fragment sharing. Flat NumPy arrays plus a cached SciPy CSR adjacency for graph algorithms.
- adjacency(edge_types=None)[source]#
Unweighted undirected CSR adjacency, optionally restricted to types.
- Return type:
csr_matrix
- average_path_length(sources)[source]#
Average shortest-path length estimated from BFS trees of
sources.
- class neurosnap.chemistry.landscape.ChemicalLandscape(source=None, smiles_column='smiles', id_column=None, config=None, *, compound_ids=None, **overrides)[source]#
Bases:
objectA molecular library and the chemical landscape built from it.
The source may be a path or an in-memory SMILES sequence:
landscape = ChemicalLandscape(“library.csv”, smiles_column=”smiles”) landscape.build_all() report = landscape.characterize() print(report.summary()) landscape.save(“out/”) reloaded = ChemicalLandscape.from_store(“out/”)
- Parameters:
source (
Union[str,Path,Sequence[str],None]) – Input path or in-memory SMILES sequence.smiles_column (
str) – SMILES column for delimited input files.id_column (
Optional[str]) – Optional compound identifier column.config (
Optional[LandscapeConfig]) – Optional complete landscape configuration.compound_ids (
Optional[Sequence[str]]) – IDs corresponding to an in-memory SMILES sequence.**overrides (
Any) – Configuration field overrides.
- build_fragments()[source]#
Fragment every compound (BRICS, rotatable bonds, linkers).
When
FragmentConfig.reversibleis enabled, each compound also keeps aReverseFragmentRecord(attachment points + cut orders) so it can be rebuilt withreassemble().- Return type:
- build_scaffolds()[source]#
Annotate Bemis-Murcko scaffolds and build the scaffold network.
- Return type:
- characterize(n_samples=512, seed=0, resolution=1.0)[source]#
Run the full characterization and cache the report.
- Return type:
- decompose(core_smiles=None, *, params=None)[source]#
Decompose the library into a core + per-position R-groups.
If
core_smilesis omitted, the most frequent scaffold is used.- Parameters:
- Return type:
- Returns:
Per-molecule R-group decomposition.
- enumerate(core_smiles, rgroups_by_label, *, max_products=100000)[source]#
Enumerate all products of a labeled core with R-groups per position.
rgroups_by_labelmaps an attachment label to a list of R-group SMILES (each carrying a matching labeled dummy, e.g.CO[*:1]).
- property fingerprints: FingerprintBlock | None#
Packed Morgan fingerprints, if the library has been loaded.
- classmethod from_store(path)[source]#
Load a previously persisted landscape.
- Parameters:
path (
Union[str,Path]) – Landscape directory created bysave().- Return type:
- Returns:
Restored
ChemicalLandscapeinstance.
- property graph: ChemicalGraph#
The heterogeneous chemical graph (assembled on first access).
- island_of(compound_id)[source]#
Island id of a compound (-1 if it was not part of the analysis).
- Return type:
- neighbors(compound_id, edge_types=None)[source]#
Return labels of the direct neighbours of a compound.
- reassemble(compound_id)[source]#
Rebuild a compound’s canonical SMILES from its fragments.
Uses the reversible fragment record (attachment points + cut orders) captured during
build_fragments(). Returns""if the compound was not fragmented reversibly.- Return type:
- property report: CharacterizationReport#
Return the cached characterization report, building it if needed.
- save(path)[source]#
Persist the landscape as JSON plus an optional NPZ fingerprint store.
- Return type:
- swap_rgroup(compound_id, position, new_rgroup, core_smiles=None)[source]#
Replace an R-group at
positionand return the new molecule.new_rgroupshould carry a dummy labeled forposition(e.g.CO[*:1]for position 1). The compound is decomposed against a core, the labelled position is substituted, and the product is reassembled with the other R-groups left in place.- Return type:
- class neurosnap.chemistry.landscape.DiversityMetrics(n_compounds=0, n_scaffold_nodes=0, n_populated_scaffolds=0, n_murcko_scaffolds=0, n_fragments=0, scaffold_entropy=0.0, scaffold_entropy_normalized=0.0, scaffold_gini=0.0, fragment_entropy=0.0, fragment_entropy_normalized=0.0, chemical_coverage=0.0, scaffold_redundancy=0.0, fragment_coverage=0.0, singleton_scaffold_fraction=0.0, compounds_per_scaffold=0.0, scaffold_levels=<factory>, top_scaffolds=<factory>, top_fragments=<factory>)[source]#
Bases:
objectDiversity summary of a library.
- class neurosnap.chemistry.landscape.EdgeType(*values)[source]#
Bases:
IntEnumEdge types of the heterogeneous chemical graph.
- COMPOUND_FRAGMENT = 2#
- COMPOUND_SCAFFOLD = 1#
- COMPOUND_SIMILARITY = 3#
- FRAGMENT_SHARED = 5#
- SCAFFOLD_HIERARCHY = 4#
- class neurosnap.chemistry.landscape.FingerprintBlock(packed, popcounts, n_bits)[source]#
Bases:
objectPacked Morgan fingerprints for the whole library.
- class neurosnap.chemistry.landscape.FingerprintConfig(radii=(2, 3), n_bits=2048, use_chirality=False, use_features=False)[source]#
Bases:
objectMorgan fingerprint settings.
radiimay hold several radii; bits of all radii are OR-ed into one packed vector, which keeps one fingerprint per compound while still covering multiple resolutions (radius 2 and 3 by default).
- class neurosnap.chemistry.landscape.FragmentConfig(use_brics=True, use_rotatable_bonds=True, use_linkers=True, min_fragment_atoms=3, max_fragments_per_molecule=32, max_rotatable_cuts=8, shared_links_per_fragment=4, reversible=True)[source]#
Bases:
objectFragmentation settings, in priority order.
- class neurosnap.chemistry.landscape.FragmentMethod(*values)[source]#
Bases:
IntEnumProvenance of a fragment node.
- BRICS = 1#
- LINKER = 3#
- ROTATABLE_BOND = 2#
- UNKNOWN = 0#
- class neurosnap.chemistry.landscape.FragmentResult(fragments=None, methods=None, frequencies=None, ring_systems=None, compound_fragment_src=None, compound_fragment_dst=None, compound_fragment_method=None, n_compounds=0)[source]#
Bases:
objectFragment nodes plus compound->fragment edges for a chunk.
- class neurosnap.chemistry.landscape.GraphBuilder[source]#
Bases:
objectIncremental builder that deduplicates scaffold and fragment nodes.
- add_edge(src, dst, edge_type, weight=1.0)[source]#
Add a single edge (convenience wrapper around
add_edges()).
- class neurosnap.chemistry.landscape.IslandResult(labels, compound_nodes, islands=<factory>, bridges=<factory>, method='louvain_local_moving', modularity=0.0, resolution=1.0)[source]#
Bases:
objectCommunity structure of the compound similarity graph.
- class neurosnap.chemistry.landscape.LandscapeConfig(smiles_column='smiles', id_column=None, delimiter=None, chunk_size=20000, workers=1, limit=None, fingerprints=<factory>, scaffolds=<factory>, fragments=<factory>, similarity=<factory>)[source]#
Bases:
objectTop-level build settings.
-
fingerprints:
FingerprintConfig#
-
fragments:
FragmentConfig#
-
scaffolds:
ScaffoldConfig#
-
similarity:
SimilarityConfig#
-
fingerprints:
- class neurosnap.chemistry.landscape.NetworkMetrics(n_nodes=0, n_edges=0, density=0.0, mean_degree=0.0, median_degree=0.0, max_degree=0, degree_histogram=<factory>, n_components=0, largest_component_size=0, largest_component_fraction=0.0, n_singletons=0, component_size_distribution=<factory>, average_path_length=0.0, path_sample_pairs=0, path_length_exact=False, edge_type_counts=<factory>, node_type_counts=<factory>, central_nodes=<factory>)[source]#
Bases:
objectTopology summary of the chemical graph.
- class neurosnap.chemistry.landscape.NodeType(*values)[source]#
Bases:
IntEnumNode types of the heterogeneous chemical graph.
- COMPOUND = 0#
- FRAGMENT = 2#
- SCAFFOLD = 1#
- class neurosnap.chemistry.landscape.RGroupDecompositionResult(core_smiles='', rows=<factory>, n_failed=0)[source]#
Bases:
objectA library decomposed into a core plus per-position R-groups.
rowsis a list of per-molecule dicts keyed by R-group label ('Core','R1','R2', …) mapping to the group SMILES.- property positions#
Sorted integer attachment labels present (excluding the core).
- class neurosnap.chemistry.landscape.ReverseFragmentRecord(pieces=None, cut_orders=None, methods=None)[source]#
Bases:
objectA compound’s fragments kept with their attachment points so the molecule can be rebuilt.
Cutting a set of bonds produces pieces whose cut ends are capped with dummy atoms carrying a unique cut-id isotope.
piecesstores those reactive SMILES;cut_orders[k]is the bond order of the cut that produced thek-th isotope pair. Reassembly matches the two dummies of each cut id and reconnects their neighbours with the recorded bond order.
- class neurosnap.chemistry.landscape.ScaffoldConfig(max_level=6, include_generic=False, flatten_chirality=True, keep_only_first_fragment=True, strip_attachments=True, max_nodes_per_molecule=64)[source]#
Bases:
objectScaffold network settings (Bemis-Murcko is only the entry point).
- class neurosnap.chemistry.landscape.ScaffoldNetworkResult(scaffolds=None, levels=None, compound_scaffold=None, hierarchy_parent=None, hierarchy_child=None, hierarchy_relation=None, murcko=None)[source]#
Bases:
objectScaffold nodes, per-compound Murcko links and hierarchy edges.
- class neurosnap.chemistry.landscape.SimilarityConfig(threshold=0.55, k=8, n_permutations=128, n_bands=32, bucket_cap=64, max_candidate_pairs=20000000, mutual_only=False, seed=12648430, metric='tanimoto', exact_below=2000)[source]#
Bases:
objectSparse similarity graph settings (never all-vs-all above a size cap).
- neurosnap.chemistry.landscape.apply_reversible_cut(mol, bond_ids)[source]#
Cut
bond_idsand cap both ends with cut-id dummy atoms.Returns
(pieces, cut_orders)wherepiecesare reactive SMILES in which cutkexplains isotopek + 1andcut_orders[k]holds the original bond order of that cut.
- neurosnap.chemistry.landscape.attach_rgroup(core_smiles, rgroup_smiles, label)[source]#
Connect an R-group onto a core at the labeled attachment point.
Both the core and the R-group carry a matching labeled dummy (isotope or map-number form). The two dummies are removed and a single bond joins their neighbours. Returns the product SMILES (still carrying any other labels).
- neurosnap.chemistry.landscape.build_similarity_edges(fps, cfg=None)[source]#
Build compound-compound similarity edges
(src, dst, score).Exact scan for small libraries, MinHash/LSH + exact rescoring above
cfg.exact_below. Returned pairs satisfysrc < dstand are unique.- Parameters:
fps (
FingerprintBlock) – Packed fingerprints for the library.cfg (
Optional[SimilarityConfig]) – Optional similarity graph settings.
- Return type:
- Returns:
Unique source indices, destination indices, and Tanimoto scores.
- neurosnap.chemistry.landscape.characterize(graph, n_samples=512, seed=0, resolution=1.0, min_frontier_support=1, metadata=None)[source]#
Run every analysis block over a built chemical graph.
- Parameters:
graph (
ChemicalGraph) – Built chemical graph.n_samples (
int) – Maximum number of path-length source nodes.seed (
int) – Random generator seed.resolution (
float) – Island community resolution.min_frontier_support (
int) – Maximum direct support for frontier scaffolds.metadata (
Optional[Mapping[str,Any]]) – Optional metadata copied into the report.
- Return type:
- Returns:
Complete characterization report.
- neurosnap.chemistry.landscape.decompose_molecules(mol_smiles, core_smiles, *, params=None)[source]#
Decompose a set of molecules into a core + R-groups (R-group linkage).
core_smilesmay be labeled ([*:1],[*:2], …) or unlabeled; an unlabeled core is matched and its attachment points detected automatically.- Parameters:
- Return type:
- Returns:
Decomposition rows and the matched core SMILES.
- neurosnap.chemistry.landscape.detect_islands(graph, resolution=1.0, top_scaffolds=3)[source]#
Detect chemical islands and describe their chemistry.
- Parameters:
graph (
ChemicalGraph) – Chemical graph to analyze.resolution (
float) – Local-moving community resolution.top_scaffolds (
int) – Number of representative scaffolds per island.
- Return type:
- Returns:
Island labels and per-island summaries.
- neurosnap.chemistry.landscape.diversity_metrics(graph, top_n=10)[source]#
Compute the diversity block of a characterization report.
- Parameters:
graph (
ChemicalGraph) – Chemical graph to summarize.top_n (
int) – Number of top scaffolds and fragments to retain.
- Return type:
- Returns:
Diversity metrics for the graph.
- neurosnap.chemistry.landscape.enumerate_core(core_smiles, rgroups_by_label, *, max_products=100000, dedupe=True)[source]#
Enumerate all products of a labeled core with lists of R-groups per label.
rgroups_by_labelmaps an attachment label to a list of R-group SMILES (each carrying a matching dummy). Returns the cartesian product as SMILES.- Parameters:
- Return type:
- Returns:
Enumerated product SMILES.
- neurosnap.chemistry.landscape.export_graphml(graph, path, node_types=None, edge_types=None)[source]#
Streaming GraphML export (no NetworkX).
- Return type:
- neurosnap.chemistry.landscape.export_json(graph, path, indent=None, **kwargs)[source]#
Write a node-link JSON representation of
graph.- Return type:
- neurosnap.chemistry.landscape.fragment_cut_bonds(mol, cfg=None)[source]#
Bond indices each enabled method would cut, with their FragmentMethod.
Returns
[(bond_idx, method), ...]with duplicates removed and the per-molecule budget respected.- Parameters:
mol (
Mol) – RDKit molecule to inspect.cfg (
Optional[FragmentConfig]) – Optional fragmentation settings.
- Return type:
- Returns:
Unique bond indices paired with their cut method.
- neurosnap.chemistry.landscape.fragment_library(smiles, cfg=None)[source]#
Fragment a chunk of compounds into deduplicated fragment nodes.
- Parameters:
cfg (
Optional[FragmentConfig]) – Optional fragmentation settings.
- Return type:
- Returns:
Fragment nodes and compound-to-fragment edges for the input chunk.
- neurosnap.chemistry.landscape.fragment_molecule(smiles, cfg=None)[source]#
Fragment one molecule into
(fragment_smiles, method)pairs.- Parameters:
smiles (
Union[str,Mol]) – SMILES string or RDKit molecule to fragment.cfg (
Optional[FragmentConfig]) – Optional fragmentation settings.
- Return type:
- Returns:
Fragment SMILES paired with their
FragmentMethodvalue. Invalid molecules return an empty list.
- neurosnap.chemistry.landscape.frontier_scaffolds(graph, min_support=1, limit=20)[source]#
Unexplored regions: general scaffolds whose descendants are populated.
A frontier scaffold has at most
min_supportcompounds of its own while its children in the hierarchy carry many compounds. Ranked by descendant support.
- neurosnap.chemistry.landscape.load_landscape(path)[source]#
Load a landscape written by
save_landscape().- Parameters:
- Return type:
tuple[ChemicalGraph,Optional[FingerprintBlock],LandscapeConfig,dict[str,Any]]- Returns:
Graph, optional fingerprints, configuration, and extra metadata.
- neurosnap.chemistry.landscape.louvain_local_moving(A, resolution=1.0, n_iter=20)[source]#
Modularity local-moving (first Louvain phase) in pure NumPy.
Community-detection fallback used because igraph/leidenalg are not Neurosnap dependencies. Returns a community label per node.
- neurosnap.chemistry.landscape.minhash_signatures(offsets, indices, a, b)[source]#
Compute MinHash signatures over on-bit CSR data.
- neurosnap.chemistry.landscape.morgan_packed(smiles, cfg)[source]#
Generate packed Morgan fingerprints.
- Parameters:
cfg (
FingerprintConfig) – Fingerprint settings.
- Return type:
- Returns:
A packed fingerprint block. Unparsable SMILES produce all-zero rows.
- neurosnap.chemistry.landscape.murcko_smiles(smiles_or_mol)[source]#
Return the canonical Bemis-Murcko scaffold SMILES.
- neurosnap.chemistry.landscape.network_metrics(graph, n_samples=512, seed=0, top_central=10)[source]#
Compute the network block of a characterization report.
- Parameters:
graph (
ChemicalGraph) – Chemical graph to summarize.n_samples (
int) – Maximum number of source nodes for path-length sampling.seed (
int) – Random generator seed.top_central (
int) – Number of PageRank-central nodes to retain.
- Return type:
- Returns:
Network metrics for the graph.
- neurosnap.chemistry.landscape.popcount_rows(packed)[source]#
Count set bits row-wise in a packed fingerprint matrix.
- neurosnap.chemistry.landscape.reassemble_fragments(pieces, cut_orders)[source]#
Join reactive fragment pieces back into the original molecule.
Two dummies sharing a cut-id isotope are reconnected with the recorded bond order, then all dummies are removed and the result is sanitized.
- neurosnap.chemistry.landscape.reversible_fragment_record(smiles, cfg=None)[source]#
Fragment a molecule reversibly.
- Parameters:
smiles (
Union[str,Mol]) – SMILES string or RDKit molecule to fragment.cfg (
Optional[FragmentConfig]) – Optional fragmentation settings.
- Return type:
- Returns:
A reversible fragment record, or
Nonewhen no reversible cut applies.
- neurosnap.chemistry.landscape.save_landscape(graph, fingerprints, config, path, extra=None)[source]#
Persist the landscape as JSON plus an optional NPZ fingerprint store.
- Parameters:
graph (
ChemicalGraph) – Chemical graph to persist.fingerprints (
Optional[FingerprintBlock]) – Optional packed fingerprint block.config (
Optional[LandscapeConfig]) – Optional landscape configuration.extra (
Optional[Mapping[str,Any]]) – Optional JSON-serializable metadata.
- Return type:
- Returns:
The destination directory.
- neurosnap.chemistry.landscape.scaffold_network(smiles, cfg=None)[source]#
Build the scaffold network for a list of compounds.
Unique Murcko scaffolds are expanded once, so cost scales with the number of distinct scaffolds rather than the number of compounds.
- Parameters:
cfg (
Optional[ScaffoldConfig]) – Optional scaffold network settings.
- Return type:
- Returns:
Scaffold nodes, compound links, and hierarchy edges.
Fragment-fragment edges for fragments sharing a ring system.
Each fragment links to the
links_per_fragmentmost frequent other fragments carrying the same ring system, keeping the edge count linear.- Parameters:
- Return type:
- Returns:
Two arrays containing the source and destination fragment indices.
- neurosnap.chemistry.landscape.stream_chunks(path, smiles_column='smiles', id_column=None, chunk_size=20000, limit=None, delimiter=None)[source]#
Stream a molecular library in bounded chunks.
- Parameters:
path (
Union[str,Path]) – CSV, TSV, SMI, or SDF input path, optionally compressed.smiles_column (
str) – Name of the SMILES column for delimited inputs.id_column (
Optional[str]) – Optional compound identifier column.chunk_size (
int) – Maximum number of records yielded per chunk.limit (
Optional[int]) – Optional maximum number of records to read.delimiter (
Optional[str]) – Optional delimiter override for delimited inputs.
- Yields:
RecordChunkinstances containing compound IDs and SMILES.- Raises:
FileNotFoundError – If
pathdoes not exist.ValueError – If the input format or chunk size is invalid.
- Return type:
Iterator[RecordChunk]