C++ Bindings
Grouper bindings for Python
- class Grouper._Grouper.Atom
Bases:
pybind11_objectRepresents an atom in an AtomGraph.
from Grouper import Atom # Create a carbon atom carbon = Atom("C", 4)
- property type
The type of the atom (e.g., ‘C’, ‘O’).
- property valency
The valency of the atom.
- class Grouper._Grouper.AtomGraph
Bases:
pybind11_objectRepresents a graph of atoms.
from Grouper import AtomGraph # Create an empty atom graph atom_graph = AtomGraph()
- add_edge(self: Grouper._Grouper.AtomGraph, src: SupportsInt | SupportsIndex, dst: SupportsInt | SupportsIndex, order: SupportsFloat | SupportsIndex = 1.0, validate: bool = True) None
Adds a bond to the graph.
- add_node(*args, **kwargs)
Overloaded function.
add_node(self: Grouper._Grouper.AtomGraph, type: str, valency: typing.SupportsInt | typing.SupportsIndex = -1) -> None
Adds an atom to the graph.
add_node(self: Grouper._Grouper.AtomGraph, atom: Grouper._Grouper.Atom) -> None
Adds an atom to the graph from an Atom object.
- property edges
The bonds in the graph.
- free_valency(self: Grouper._Grouper.AtomGraph, arg0: SupportsInt | SupportsIndex) int
Get the free valency of the graph.
- from_smarts(self: Grouper._Grouper.AtomGraph, arg0: str) None
Creates an AtomGraph from a SMARTS string.
- from_smiles(self: Grouper._Grouper.AtomGraph, arg0: str) None
Creates an AtomGraph from a SMILES string.
from Grouper import AtomGraph atom_graph = AtomGraph() atom_graph.from_smiles("CCO")
- property nodes
The atoms in the graph.
- substructure_search(self: Grouper._Grouper.AtomGraph, arg0: Grouper._Grouper.AtomGraph, arg1: collections.abc.Sequence[SupportsInt | SupportsIndex]) list[list[tuple[int, int]]]
Performs a substructure search on the graph.
from Grouper import AtomGraph graph = AtomGraph() graph.from_smiles("CCO") sub = AtomGraph() sub.from_smiles("CO") matches = graph.substructure_search(sub)
- class Grouper._Grouper.Group
Bases:
pybind11_objectRepresents a chemical group with a SMARTS pattern and connection ports.
from Grouper import Group # Create a methyl group methyl = Group("methyl", "[CH3]", [0])
- property hubs
The hub atoms of the group.
- property pattern
The SMARTS pattern of the group.
- property pattern_type
The type of the pattern (e.g., SMILES, SMARTS).
- property ports
The connection ports of the group.
- possible_attachments(self: Grouper._Grouper.Group, arg0: SupportsInt | SupportsIndex) list[list[int]]
Get the number of possible attachments for the group.
- property type
The type of the group.
- class Grouper._Grouper.GroupGraph
Bases:
pybind11_objectRepresents a graph of chemical groups.
from Grouper import GroupGraph # Create an empty graph graph = GroupGraph()
- add_edge(self: Grouper._Grouper.GroupGraph, src: tuple[SupportsInt | SupportsIndex, SupportsInt | SupportsIndex] = (0, 0), dst: tuple[SupportsInt | SupportsIndex, SupportsInt | SupportsIndex] = (0, 0), order: SupportsFloat | SupportsIndex = 1.0, strict: bool = True) bool
Adds an edge to the graph.
graph = GroupGraph() graph.add_node("methyl", "[CH3]", [0]) graph.add_node("hydroxyl", "[OH]", [0]) graph.add_edge((0, 0), (1, 0))
- add_node(*args, **kwargs)
Overloaded function.
add_node(self: Grouper._Grouper.GroupGraph, type: str = ‘’, pattern: str = ‘’, hubs: collections.abc.Sequence[typing.SupportsInt | typing.SupportsIndex] = [], pattern_type: str = ‘SMILES’) -> None
Adds a node to the graph.
graph = GroupGraph() graph.add_node("methyl", "[CH3]", [0])
add_node(self: Grouper._Grouper.GroupGraph, group: Grouper._Grouper.Group) -> None
Adds a node to the graph from a Group object.
- clear_edges(self: Grouper._Grouper.GroupGraph) None
Remove all edges from the graph.
- compute_orbits(self: Grouper._Grouper.GroupGraph, edge_list: collections.abc.Sequence[tuple[SupportsInt | SupportsIndex, SupportsInt | SupportsIndex]], node_colors: collections.abc.Sequence[SupportsInt | SupportsIndex]) tuple[list[int], list[int], list[list[int]]]
Compute the orbits of the graph.
graph = GroupGraph() graph.add_node("ester", "C(O)=O", [0, 1]) graph.add_node("ester", "C(O)=O", [0, 1]) graph.add_node("ester", "C(O)=O", [0, 1]) graph.add_node("not-ester", "C", [0, 0]) edge_list = [ (0, 2),(0, 3),(1, 2),(1, 3) ] node_colors = [0,0,0,1] node_orbits, edge_orbits, _ = graph.compute_orbits(edge_list, node_colors)
- property edges
The edges of the graph.
- from_json(self: Grouper._Grouper.GroupGraph, arg0: str) None
Deserialize a GroupGraph from a JSON string.
graph = GroupGraph() graph.add_node("type1", "C", [0, 0]) graph.add_node("type1", "C", [0, 0]) graph.add_edge((0, 0), (1, 0)) json_str = graph.to_json() graph2 = GroupGraph() graph2.from_json(json_str)
- property is_coarse_grained
Whether the graph is coarse-grained.
- is_port_free(self: Grouper._Grouper.GroupGraph, node_id: SupportsInt | SupportsIndex, port: SupportsInt | SupportsIndex) bool
Check if a port is free.
- n_free_ports(self: Grouper._Grouper.GroupGraph, arg0: SupportsInt | SupportsIndex) int
Get the number of free ports in the graph.
- property node_types
The types of the nodes in the graph.
- property nodes
The nodes of the graph.
- to_3d(**kw)
Generate 3D coordinates via ETKDG + force-field minimization. Returns an RDKit Mol with explicit hydrogens. See Grouper.exports.to_3d_mol for parameters.
- to_atom_graph(self: Grouper._Grouper.GroupGraph) AtomGraph
Convert GroupGraph to AtomGraph.
graph = GroupGraph() graph.add_node(type="carbon", pattern= "C", hubs = [0,0,0,0]) graph.add_node(type="nitrogen", pattern = "N", hubs = [0,0,0]) graph.add_edge((0, 0), (1, 0)) atom_graph = graph.to_atom_graph()
- to_canonical(self: Grouper._Grouper.GroupGraph) list[int]
Return a canonical form of the GroupGraph as a list of nauty setwords followed by the canonical color sequence.
Two graphs return equal lists iff they are isomorphic with group ntype, port hub label, and bond order preserved. The canonical form is what exhaustive_generate’s dedup uses internally and is suitable as a hash key for cross-run deduplication.
from Grouper import GroupGraph g1 = GroupGraph() g1.add_node("methyl", "C", [0]) g1.add_node("hydroxyl", "O", [0]) g1.add_edge((0, 0), (1, 0)) # Same molecule, nodes added in the reverse order: g2 = GroupGraph() g2.add_node("hydroxyl", "O", [0]) g2.add_node("methyl", "C", [0]) g2.add_edge((1, 0), (0, 0)) assert g1.to_canonical() == g2.to_canonical()
- to_inchi()
Return the IUPAC InChI string (cross-tool deterministic identifier).
- to_inchi_key()
Return the 27-character InChIKey — primary-key form used by most chemistry databases (PubChem, ChEMBL, NIST).
- to_json(self: Grouper._Grouper.GroupGraph) str
Serialize the GroupGraph to a JSON string.
graph = GroupGraph() graph.add_node("type1", "C", [0, 0]) graph.add_node("type1", "C", [0, 0]) graph.add_edge((0, 0), (1, 0)) json_str = graph.to_json()
- to_mol(path=None, **kw)
Render as a V2000 MOL block (single-molecule).
- to_pdb(path=None, **kw)
Render as PDB (always 3D).
- to_sdf(path=None, **kw)
Render as SDF. Pass path to write to disk; otherwise returns the SDF as a string. See Grouper.exports.to_sdf for parameters.
- to_smarts()
Return the SMARTS pattern for this molecule. Useful as a query pattern in substructure searches downstream.
- to_smiles(self: Grouper._Grouper.GroupGraph) str
Convert GroupGraph to SMILES string.
graph = GroupGraph() graph.add_node("methyl", "[CH3]", [0]) graph.add_node("hydroxyl", "[OH]", [0]) graph.add_edge((0, 0), (1, 0)) # print(graph.to_smiles()) # Output: CO
- to_vector(self: Grouper._Grouper.GroupGraph) dict[str, int]
Convert GroupGraph to group vector.
graph = GroupGraph() graph.add_node("methyl", "[CH3]", [0]) graph.add_node("hydroxyl", "[OH]", [0]) graph.add_edge((0, 0), (1, 0)) # print(graph.to_vector()) # Output: {'methyl': 1, 'hydroxyl': 1}
- to_xyz(path=None, **kw)
Render as XYZ (always 3D).
- visualize(figsize=(10, 5), structure_size=(400, 400))
Render a side-by-side view of the molecule for this GroupGraph.
Two panels:
- Left — 2D chemical structure (atoms and bonds), via RDKit’s
Draw.MolToImage on the SMILES of this graph.
- Right — port-graph (groups as colored nodes, ports as edges),
via Grouper.visualization.visualize_graph.visualize.
The two views answer different questions: the left tells you what molecule this is in chemistry terms; the right tells you how Grouper sees it — which groups, which ports, which edges. Together they’re the easiest way to sanity-check a generated structure in a notebook.
Returns the matplotlib Figure so callers can plt.show(), fig.savefig(…), or embed it.
- exception Grouper._Grouper.GrouperFragmentationError
Bases:
Exception
- exception Grouper._Grouper.GrouperNotYetImplementedException
Bases:
Exception
- exception Grouper._Grouper.GrouperParseException
Bases:
Exception
- Grouper._Grouper.exhaustive_fragment(smiles: str, node_defs: collections.abc.Set[Grouper._Grouper.Group]) list[Grouper._Grouper.GroupGraph]
Fragment a molecule into a set of GroupGraphs based on a given set of group definitions.
from Grouper import Group, exhaustive_fragment node_defs = set() node_defs.add(Group("hydroxyl", "O", [0])) node_defs.add(Group("alkene", "C=C", [0, 0, 1, 1])) smiles = "C=CO" fragmented_graphs = exhaustive_fragment(smiles, node_defs)
- Grouper._Grouper.exhaustive_generate(n_nodes: SupportsInt | SupportsIndex, node_defs: collections.abc.Set[Grouper._Grouper.Group], num_procs: SupportsInt | SupportsIndex = -1, vcolg_output_file: str = '', positive_constraints: collections.abc.Mapping[str, SupportsInt | SupportsIndex] = {}, negative_constraints: collections.abc.Set[str] = set(), config_path: str = '') set
Exhaustively generate all possible GroupGraphs with a given number of nodes and a set of allowed groups.
- n_nodesint
Number of group nodes per generated graph.
- node_defsset[Group]
The palette of groups the enumeration is allowed to use.
- num_procsint, default -1
OpenMP worker count for the colored-graph processing stage. -1 binds to all available cores.
- vcolg_output_filestr, default “”
Path to a pre-computed vcolg
-Toutput file. When empty (the default), the call pipesgeng -c n | vcolg -T -m|node_defs|internally. Set this to feed in your own filtered or externally-generated colored-graph list (e.g. when sweeping a custom subset of colorings, or when reusing a large vcolg run across multiple invocations).- positive_constraintsdict[str, int], default {}
Map from group
typeto a minimum required count. Graphs that don’t meet every floor are dropped.- negative_constraintsset[str], default set()
SMILES substrings that disqualify a generated graph.
- config_pathstr, default “”
Optional path to a
key=valueconfig file with PostgreSQL connection settings (table_name,dbname,user,password,hostaddr,port). When set, generated graphs are also persisted to the named table.
from Grouper import Group, exhaustive_generate node_defs = [ {"type": "t2", "smarts": "N", "hubs": [0, 0, 0]}, {"type": "Methyl", "smarts": "C", "hubs": [0, 0, 0]}, {"type": "ester", "smarts": "C(=O)O", "hubs": [0, 2]}, {"type": "extra1", "smarts": "O", "hubs": [0, 0]}, ] node_defs = set( Group(n["type"], n["smarts"], n["hubs"], pattern_type="SMILES") for n in node_defs ) generated_graphs = exhaustive_generate(2, node_defs)
- Grouper._Grouper.random_generate(n_nodes: SupportsInt | SupportsIndex, node_defs: collections.abc.Set[Grouper._Grouper.Group], num_graphs: SupportsInt | SupportsIndex = 100, num_procs: SupportsInt | SupportsIndex = -1, positive_constraints: collections.abc.Mapping[str, SupportsInt | SupportsIndex] = {}, negative_constraints: collections.abc.Set[str] = set()) set
Randomly generate a specified number of GroupGraphs.
from Grouper import Group, random_generate node_defs = [ {"type": "t2", "smarts": "N", "hubs": [0, 0, 0]}, {"type": "Methyl", "smarts": "C", "hubs": [0, 0, 0]}, {"type": "ester", "smarts": "C(=O)(O)", "hubs": [0, 2]}, {"type": "extra1", "smarts": "O", "hubs": [0, 0]}, ] node_defs = set( Group(n["type"], n["smarts"], n["hubs"], pattern_type="SMILES") for n in node_defs ) generated_graphs = random_generate(2, node_defs, 5)