Esempio n. 1
0
    def reevaluate_forward(self, to_process, arrow):
        # print("Re-evaluate forward with " + str(to_process) + " " + str(arrow))
        for node in to_process:
            if self.mode == "heuristic":
                nzero_effect_nodes = self.effect_edges_graph.get(node)
                # print("Re-evaluate forward. Currently on node: " + str(node))
                # print("nzero-effect-nodes: " + str(nzero_effect_nodes))
            elif self.mode == "covernoncolliders":
                g = set()
                for n in graph_util.adjacent_nodes(self.graph, node):
                    for m in graph_util.adjacent_nodes(self.graph, n):
                        if graph_util.adjacent(self.graph, n, m):
                            continue

                        if graph_util.is_def_collider(self.graph, m, n, node):
                            continue

                        g.update(m)

                nzero_effect_nodes = list(g)
            if nzero_effect_nodes is not None:
                for w in nzero_effect_nodes:
                    if w == node:
                        continue
                    if not graph_util.adjacent(self.graph, node, w):
                        self.clear_arrow(w, node)
                        self.calculate_arrows_forward(w, node)
Esempio n. 2
0
    def initialize_two_step_edges(self, nodes):
        for node in nodes:

            g = set()

            for n in graph_util.adjacent_nodes(self.graph, node):
                for m in graph_util.adjacent_nodes(self.graph, n):

                    if node == m:
                        continue

                    if graph_util.adjacent(self.graph, node, m):
                        continue

                    if graph_util.is_def_collider(self.graph, m, n, node):
                        continue

                    g.update(m)

            for x in g:
                assert (x is not node)
                if self.knowledge is not None:
                    if self.knowledge.is_forbidden(
                            node, x) or self.knowledge.is_forbidden(x, node):
                        continue
                    # again, what's the point?
                    if not self.valid_set_by_knowledge(node, set()):
                        continue

                # TODO: Adjacencies

                if (x, node) in self.removed_edges:
                    continue

                self.calculate_arrows_forward(x, node)
Esempio n. 3
0
    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)
Esempio n. 4
0
    def orient_using_meek_rules_locally(self, graph):
        """Orient graph using the four Meek rules"""
        if self.undirect_unforced_edges:
            for node in self.node_subset:
                self.undirect_unforced_edges_func(node, graph)
                self.direct_stack.extend(graph_util.adjacent_nodes(
                    graph, node))

        # TODO: Combine loops
        for node in self.node_subset:
            self.run_meek_rules(node, graph)
        if self.direct_stack != []:
            last_node = self.direct_stack.pop()
        else:
            last_node = None

        while last_node is not None:
            # print(last_node)
            if self.undirect_unforced_edges:
                self.undirect_unforced_edges_func(last_node, graph)

            self.run_meek_rules(last_node, graph)
            # print("past run_meek_rules")
            if len(self.direct_stack) > 0:
                last_node = self.direct_stack.pop()
            else:
                last_node = None
Esempio n. 5
0
    def run_meek_rule_four(self, a, graph):
        if self.knowledge is None:
            return

        adjacent_nodes = graph_util.adjacent_nodes(graph, a)

        for (b, c, d) in itertools.permutations(adjacent_nodes, 3):
            if (graph_util.has_undir_edge(graph, a, b)
                    and graph_util.has_dir_edge(graph, b, c)
                    and graph_util.has_dir_edge(graph, c, d)
                    and graph_util.has_undir_edge(graph, d, a)
                    and self.is_arrowpoint_allowed(a, d)):
                self.direct(a, d, graph)
Esempio n. 6
0
 def run_meek_rule_two(self, node_b, graph):
     # print("Running meek rule two", node_b)
     adjacencies = graph_util.adjacent_nodes(graph, node_b)
     if len(adjacencies) < 2:
         return
     all_combinations = itertools.combinations(range(0, len(adjacencies)),
                                               2)
     for (index_one, index_two) in all_combinations:
         node_a = adjacencies[index_one]
         node_c = adjacencies[index_two]
         self.r2_helper(node_a, node_b, node_c, graph)
         self.r2_helper(node_b, node_a, node_c, graph)
         self.r2_helper(node_a, node_c, node_b, graph)
         self.r2_helper(node_c, node_a, node_b, graph)
Esempio n. 7
0
    def reevaluate_backward(self, to_process):
        for node in to_process:
            self.stored_neighbors[node] = graph_util.neighbors(
                self.graph, node)
            adjacent_nodes = graph_util.adjacent_nodes(self.graph, node)

            for adj_node in adjacent_nodes:
                if graph_util.has_dir_edge(self.graph, adj_node, node):
                    self.clear_arrow(adj_node, node)
                    self.clear_arrow(node, adj_node)

                    self.calculate_arrows_backward(adj_node, node)
                elif graph_util.has_undir_edge(self.graph, adj_node, node):
                    self.clear_arrow(adj_node, node)
                    self.clear_arrow(node, adj_node)
                    self.calculate_arrows_backward(adj_node, node)
                    self.calculate_arrows_backward(node, adj_node)
Esempio n. 8
0
    def run_meek_rule_one(self, node, graph):
        """
                Meek's rule R1: if a-->b, b---c, and a not adj to c, then a-->c
                """
        # print("Running meek rule one", node)
        adjacencies = graph_util.adjacent_nodes(graph, node)
        if len(adjacencies) < 2:
            return
        all_combinations = itertools.combinations(range(0, len(adjacencies)),
                                                  2)
        for (index_one, index_two) in all_combinations:
            node_a = adjacencies[index_one]
            node_c = adjacencies[index_two]

            # TODO: Parallelize these flipped versions?
            self.r1_helper(node_a, node, node_c, graph)
            self.r1_helper(node_c, node, node_a, graph)
Esempio n. 9
0
    def run_meek_rule_three(self, node, graph):
        """
        A --- B, A --- X, A --- C, B --> X <-- C, B -/- C => A --> X
        The parameter node = X
        """
        # print("Running meek rule three", node)
        adjacencies = graph_util.adjacent_nodes(graph, node)

        if len(adjacencies) < 3:
            return

        for node_a in adjacencies:
            if graph_util.has_undir_edge(graph, node, node_a):
                copy_adjacencies = [a for a in adjacencies if a != node_a]
                all_combinations = itertools.combinations(copy_adjacencies, 2)

                for node_b, node_c in all_combinations:
                    if graph_util.is_kite(graph, node, node_a, node_b, node_c) and \
                            self.is_arrowpoint_allowed(node_a, node) and \
                            graph_util.is_unshielded_non_collider(graph, node_c, node_a, node_b):
                        # print("R3: " + str(node_a) + " " + str(node))
                        self.direct(node_a, node, graph)