def test_make_reaction_from_smiles(): smiles = "CCCCOc1ccc(CC(=O)N(C)O)cc1>>CCCCOc1ccc(CC(=O)Cl)cc1.CNO" rxn = RetroReaction.from_reaction_smiles(smiles, smarts="") assert rxn.mol.smiles == "CCCCOc1ccc(CC(=O)N(C)O)cc1" assert len(rxn.reactants[0]) == 2 assert rxn.reactants[0][0].smiles == "CCCCOc1ccc(CC(=O)Cl)cc1" assert rxn.reactants[0][1].smiles == "CNO"
def wrapper(mol): actions = { "CCCCOc1ccc(CC(=O)N(C)O)cc1": [ "([#8:4]-[N;H0;D3;+0:5](-[C;D1;H3:6])-[C;H0;D3;+0:1](-[C:2])=[O;D1;H0:3])" ">>(Cl-[C;H0;D3;+0:1](-[C:2])=[O;D1;H0:3]).([#8:4]-[NH;D2;+0:5]-[C;D1;H3:6])", "([C:2]-[CH2;D2;+0:1]-[O;H0;D2;+0:3]-[c:4])>>(Br-[CH2;D2;+0:1]-[C:2]).([OH;D1;+0:3]-[c:4])", "([C:4]-[N;H0;D3;+0:5](-[C:6])-[C;H0;D3;+0:1](-[C:2])=[O;D1;H0:3])>>" "(O-[C;H0;D3;+0:1](-[C:2])=[O;D1;H0:3]).([C:4]-[NH;D2;+0:5]-[C:6])", ] } action1, action2, action3 = actions[mol.smiles] action_list = [ RetroReaction(mol, action1, metadata={"dummy": 1}), RetroReaction(mol, action2, metadata={"dummy": 2}), RetroReaction(mol, action3, metadata={"dummy": 3}), ] prior_list = [0.7, 0.5, 0.3] return action_list, prior_list
def setup_graphviz_graph(): mol1 = TreeMolecule(smiles="CCCO", parent=None) reaction = RetroReaction(mol=mol1, smarts="") graph = image.GraphvizReactionGraph() graph.add_molecule(mol1, "green") graph.add_reaction(reaction) graph.add_edge(mol1, reaction) return graph
def serialize_action( action: RetroReaction, molecule_store: MoleculeSerializer ) -> StrDict: """ Serialize a retrosynthesis action :param action: the (re)action to serialize :param molecule_store: the molecule serialization object :return: the action as a dictionary """ dict_ = action.to_dict() dict_["mol"] = molecule_store[dict_["mol"]] dict_["class"] = f"{action.__class__.__module__}.{action.__class__.__name__}" return dict_
def __init__(self, dict_, config, molecules, tree): self.tree = tree self.config = config self._children = [ AndOrNode(child, config, molecules, tree) for child in dict_["children"] ] if "reaction" in dict_: self._obj = RetroReaction( molecules[dict_["reaction"]["mol"]], dict_["reaction"]["smarts"], dict_["reaction"]["index"], dict_["reaction"].get("metadata", {}), ) self._solved = all(child.prop["solved"] for child in self._children) else: self.tree._mol_nodes.append(self) self._obj = molecules[dict_["mol"]] self._solved = self._obj in self.config.stock
def get_actions( self, molecules: Sequence[TreeMolecule] ) -> Tuple[List[RetroReaction], List[float]]: """ Get all the probable actions of a set of molecules, using the selected policies and given cutoffs :param molecules: the molecules to consider :return: the actions and the priors of those actions :raises: PolicyException: if the policy isn't selected """ if not self.selection: raise PolicyException("No expansion policy selected") possible_actions = [] priors = [] for mol in molecules: if mol in self._stock: continue for policy_key in self.selection: model = self[policy_key]["model"] templates = self[policy_key]["templates"] all_transforms_prop = self._predict(mol, model) probable_transforms_idx = self._cutoff_predictions( all_transforms_prop) possible_moves = templates.iloc[probable_transforms_idx] probs = all_transforms_prop[probable_transforms_idx] priors.extend(probs) for idx, (move_index, move) in enumerate(possible_moves.iterrows()): metadata = dict(move) del metadata[self._config.template_column] metadata["policy_probability"] = float(probs[idx].round(4)) metadata["policy_probability_rank"] = idx metadata["policy_name"] = policy_key metadata["template_code"] = move_index possible_actions.append( RetroReaction(mol, move[self._config.template_column], metadata=metadata)) return possible_actions, priors
def from_dict( cls, dict_: StrDict, tree: SearchTree, config: Configuration, molecules: MoleculeDeserializer, parent: "Node" = None, ) -> "Node": """ Create a new node from a dictionary, i.e. deserialization :param dict_: the serialized node :param tree: the search tree :param config: settings of the tree search algorithm :param molecules: the deserialized molecules :param parent: the parent node :return: a deserialized node """ state = State.from_dict(dict_["state"], config, molecules) node = Node(state=state, owner=tree, config=config, parent=parent) node.is_expanded = dict_["is_expanded"] node.is_expandable = dict_["is_expandable"] node._children_values = dict_["children_values"] node._children_priors = dict_["children_priors"] node._children_visitations = dict_["children_visitations"] node._children_actions = [] for action in dict_["children_actions"]: mol = molecules.get_tree_molecules([action["mol"]])[0] node._children_actions.append( RetroReaction( mol, action["smarts"], action["index"], action.get("metadata", {}), ) ) node._children = [ Node.from_dict(child, tree, config, molecules, parent=node) if child else None for child in dict_["children"] ] return node
def get_actions(self, molecules): """ Get all the probable actions of a set of molecules, using the selected policies and given cutoffs :param molecules: the molecules to consider :type molecules: list of Molecule :return: the actions and the priors of those actions :rtype: tuple (list of RetroReaction, numpy.ndarray) """ possible_actions = [] priors = [] for mol in molecules: if mol in self._stock: continue for policy_key in self.selection: model = self[policy_key]["model"] templates = self[policy_key]["templates"] all_transforms_prop = self._predict(mol, model) probable_transforms_idx = self._cutoff_predictions( all_transforms_prop) possible_moves = templates.iloc[probable_transforms_idx] probs = all_transforms_prop[probable_transforms_idx] priors.extend(probs) for idx, (move_index, move) in enumerate(possible_moves.iterrows()): metadata = dict(move) del metadata[self._config.template_column] metadata["policy_probability"] = float(probs[idx]) metadata["policy_name"] = policy_key metadata["template_code"] = move_index possible_actions.append( RetroReaction(mol, move[self._config.template_column], metadata=metadata)) return possible_actions, priors
def from_dict(cls, dict_, tree, config, molecules, parent=None): """ Create a new node from a dictionary, i.e. deserialization :param dict_: the serialized node :type dict_: dict :param tree: the search tree :type tree: SearchTree :param config: settings of the tree search algorithm :type config: Configuration :param molecules: the deserialized molecules :type molecules: MoleculeDeserializer :param parent: the parent node :type parent: Node :return: a deserialized node :rtype: Node """ state = State.from_dict(dict_["state"], config, molecules) node = Node(state=state, owner=tree, config=config, parent=parent) node.is_expanded = dict_["is_expanded"] node.is_expandable = dict_["is_expandable"] node._children_values = dict_["children_values"] node._children_priors = dict_["children_priors"] node._children_visitations = dict_["children_visitations"] node._children_actions = [ RetroReaction( molecules[action["mol"]], action["smarts"], action["index"], action.get("metadata", {}), ) for action in dict_["children_actions"] ] node._children = [ Node.from_dict(child, tree, config, molecules, parent=node) if child else None for child in dict_["children"] ] return node
def setup_graphviz_graph(): mol1 = TreeMolecule(smiles="CCCO", parent=None) reaction = RetroReaction(mol=mol1, smarts="") return [mol1], [reaction], [(mol1, reaction)], ["green"]
def setup_complete_tree(fresh_tree, mocker, mock_stock): tree = fresh_tree state1 = mocker.MagicMock() state1.mols = [ TreeMolecule( parent=None, transform=0, smiles="CN1CCC(C(=O)c2cccc(NC(=O)c3ccc(F)cc3)c2F)CC1", ) ] state1.in_stock_list = [False] state1.score = 0.049 state1.is_solved = False state1.max_transforms = state1.mols[0].transform node1 = mocker.MagicMock() node1.state = state1 node1.parent = None node1.tree = tree node1.is_expanded = True action1 = ( "([C:2]-[CH;D3;+0:1](-[C:3])-[C;H0;D3;+0:4](=[O;H0;D1;+0:6])-[c:5])" ">>(Cl-[CH;D3;+0:1](-[C:2])-[C:3]).(N#[C;H0;D2;+0:4]-[c:5]).([OH2;D0;+0:6])" ) reaction1 = RetroReaction(state1.mols[0], action1) reaction1.apply() node1.__getitem__.return_value = {"action": reaction1} tree.root = node1 state2 = mocker.MagicMock() state2.mols = [ TreeMolecule(parent=state1.mols[0], smiles=smiles) for smiles in ["CN1CCC(Cl)CC1", "N#Cc1cccc(NC(=O)c2ccc(F)cc2)c1F", "O"] ] state2.max_transforms = state2.mols[0].transform state2.in_stock_list = [True, False, True] state2.score = 0.68 state2.is_solved = False node2 = mocker.MagicMock() node2.parent = node1 node2.is_expanded = True node2.state = state2 node2.tree = tree node1.promising_child.return_value = node2 node1.children.return_value = [node2] action2 = ( "([O;D1;H0:2]=[C;H0;D3;+0:1](-[c:3])-[NH;D2;+0:4]-[c:5])" ">>(Cl-[C;H0;D3;+0:1](=[O;D1;H0:2])-[c:3]).([NH2;D1;+0:4]-[c:5])" ) reaction2 = RetroReaction(state2.mols[1], action2) reaction2.apply() node2.__getitem__.return_value = {"action": reaction2} state3 = mocker.MagicMock() state3.mols = [ TreeMolecule(parent=state2.mols[1], smiles=smiles) for smiles in ["N#Cc1cccc(N)c1F", "O=C(Cl)c1ccc(F)cc1"] ] state3.max_transforms = state3.mols[0].transform state3.in_stock_list = [True, True] state3.stock = mocker.MagicMock() state3.stock.__contains__.side_effect = [False, True, False, True, True, True] state3.score = 0.99 state3.is_solved = True node3 = mocker.MagicMock() node3.parent = node2 node3.tree = tree node3.state = state3 node2.promising_child.return_value = node3 node2.children.return_value = [node3] node3.children.return_value = [] return tree, [node1, node2, node3]