def insert_eval(self, x, y, T, na_y_x): """Evaluates bump for adding edge x->y given conditioning sets T and na_y_x""" assert (x is not y) _na_y_x = set(na_y_x) _na_y_x.update(T) _na_y_x.update(graph_util.get_parents(self.graph, y)) return self.score_graph_change(y, _na_y_x, x)
def undirect_unforced_edges_func(self, node, graph): """Removes directed edges that are not forced by an unshielded collider about node""" node_parents = graph_util.get_parents(graph, node) parents_to_undirect = set(node_parents) # Find any unshielded colliders in node_parents, and orient them for (p1, p2) in itertools.combinations(node_parents, 2): if not graph_util.adjacent(graph, p1, p2): # Have an unshielded collider p1 -> node <- p2, which forces orientation self.oriented.update([(p1, node), (p2, node)]) parents_to_undirect.difference_update([p1, p2]) did_unorient = False for parent in parents_to_undirect: if self.knowledge is not None: must_orient = self.knowledge.is_required(parent, node) or \ self.knowledge.is_forbidden(node, parent) else: must_orient = False if not (parent, node) in self.oriented and not must_orient: # Undirect parent -> node graph_util.remove_dir_edge(graph, parent, node) graph_util.add_undir_edge(graph, parent, node) self.visited.add(node) self.visited.add(parent) # print(f"unorienting {parent} -> {node}") did_unorient = True if did_unorient: for adjacent in graph_util.adjacent_nodes(graph, node): self.direct_stack.append(adjacent) self.direct_stack.append(node)
def delete_eval(self, x, y, diff, na_y_x): """Evaluates the bump of removing edge X-->Y""" a = set(diff) a.update(graph_util.get_parents(self.graph, y)) a = a - {x} return -1 * self.score_graph_change(y, a, x)