diff --git a/api.py b/api.py index 3b64327..f1d4eb6 100644 --- a/api.py +++ b/api.py @@ -1,6 +1,7 @@ -from dotenv import load_dotenv -from os import environ import json +import networkx as nx +from os import environ +from dotenv import load_dotenv from rdkit import Chem from rdkit import RDLogger @@ -31,43 +32,94 @@ def read_vec2(data) -> tuple[float, float]: return (data['x'] / 100, data['y'] / 100) -def read_mol(data) -> Chem.rdchem.RWMol: - mol = Chem.rdchem.RWMol() +def json_to_graph(data) -> nx.Graph: + g = nx.Graph() - for atom in data['atoms']: - a = Chem.rdchem.Atom(atom['symbol']) - if 'formal_charge' in atom: - a.SetFormalCharge(atom['formal_charge']) - mol.AddAtom(a) + for v, atom in enumerate(data['atoms']): + g.add_node(v, **{ + 'symbol': atom['symbol'], + 'position': read_vec2(atom['position']), + 'formal_charge': atom.get('formal_charge', 0), + 'non_bonded_ve': atom.get('non_bonded_ve', 0) + }) for bond in data['bonds']: - mol.AddBond( - bond['from'], - bond['to'], - bond_type[bond['type']]) + g.add_edge(bond['from'], bond['to'], type=bond['type']) - mol = mol.GetMol() + return g + + +def graph_to_mol(g: nx.Graph) -> Chem.rdchem.RWMol: + mol = Chem.rdchem.RWMol() + index = {} + + for v in g.nodes: + a = Chem.rdchem.Atom(g.nodes[v]['symbol']) + a.SetFormalCharge(g.nodes[v]['formal_charge']) + index[v] = mol.AddAtom(a) + + for u, v in g.edges: + mol.AddBond(index[u], index[v], bond_type[g.edges[(u,v)]['type']]) + + # Build 2D conformer. conf = Chem.Conformer(mol.GetNumAtoms()) - for i, atom in enumerate(data['atoms']): - conf.SetAtomPosition(i, read_vec2(atom['position']) + (0,)) + for v in g.nodes: + # Note that we add a Z-coordinate with value 0. + conf.SetAtomPosition(index[v], g.nodes[v]['position'] + (0,)) + + # Assign conformer and compute stereochemistry. + mol = mol.GetMol() mol.AddConformer(conf) + Chem.AssignStereochemistryFrom3D(mol) return mol -def compare(data1, data2) -> bool: - # TODO: Graph isomorphism; https://stackoverflow.com/a/60211992 - mol1 = read_mol(data1) - mol2 = read_mol(data2) - Chem.AssignStereochemistryFrom3D(mol1) - Chem.AssignStereochemistryFrom3D(mol2) - smiles1 = Chem.rdmolfiles.MolToSmiles(mol1, isomericSmiles=True) - smiles2 = Chem.rdmolfiles.MolToSmiles(mol2, isomericSmiles=True) - return smiles1 == smiles2 +def json_to_mol(data) -> Chem.rdchem.RWMol: + return graph_to_mol(json_to_graph(data)) + + +def _node_match(v1, v2): + props = ['symbol', 'formal_charge', 'non_bonded_ve'] + return all(map(lambda p: v1[p] == v2[p], props)) + + +def _edge_match(e1, e2): + return e1['type'] == e2['type'] + + +def _graph_to_smiles(g: nx.Graph) -> str: + mol = graph_to_mol(g) + return Chem.rdmolfiles.MolToSmiles(mol, isomericSmiles=True) + + +def compare_components(g1: nx.Graph, g2: nx.Graph) -> bool: + return ( + nx.is_isomorphic(g1, g2, _node_match, _edge_match) and + _graph_to_smiles(g1) == _graph_to_smiles(g2)) + + +def compare(diagram1, diagram2) -> bool: + g1 = json_to_graph(diagram1) + g2 = json_to_graph(diagram2) + cs1 = list(map(lambda c: g1.subgraph(c), nx.connected_components(g1))) + cs2 = list(map(lambda c: g2.subgraph(c), nx.connected_components(g2))) + + # Check if every component in g1 matches a unique component in g2. + for c1 in cs1: + match = (i for i, c2 in enumerate(cs2) if compare_components(c1, c2)) + index = next(match, None) + if index is None: + return False + else: + # Every component can only be matched once. + cs2.pop(index) + + return len(cs2) == 0 def validate(diagram) -> bool: - mol = read_mol(diagram) + mol = json_to_mol(diagram) try: Chem.SanitizeMol(mol) return True diff --git a/requirements.txt b/requirements.txt index 87b1092..f751fe0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ rdkit +networkx numpy===1.26.4 python-dotenv===1.0.1 \ No newline at end of file diff --git a/test.ipynb b/test.ipynb index 4f12fcf..4f2f013 100644 --- a/test.ipynb +++ b/test.ipynb @@ -25,9 +25,9 @@ "outputs": [ { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ - "" + "" ] }, "execution_count": 2, @@ -36,7 +36,7 @@ } ], "source": [ - "api.read_mol(read('test/author.json'))" + "api.json_to_mol(read('test/author.json'))" ] }, { @@ -47,7 +47,7 @@ { "data": { "text/plain": [ - "False" + "(False, True)" ] }, "execution_count": 3, @@ -56,7 +56,7 @@ } ], "source": [ - "api.validate(read('test/invalid.json'))" + "api.validate(read('test/invalid.json')), api.validate(read('test/author.json'))" ] }, { @@ -87,7 +87,7 @@ { "data": { "text/plain": [ - "True" + "False" ] }, "execution_count": 5,