Exemplo n.º 1
0
 def uniform_cost_search(
     g: AbstractGraph,
     start: AbstractNode,
     goal: AbstractNode,
     filter_fn: Callable[
         [Set[AbstractEdge], str], Set[AbstractEdge]
     ] = lambda es, n: set([e for e in es if e.start().id() == n]),
     costfn: Callable[[AbstractEdge, float], float] = lambda x, y: y + 1.0,
     is_min=True,
     problem_set: Optional[Set[AbstractEdge]] = None,
 ) -> Tuple[
     Dict[str, Union[int, AbstractNode, AbstractEdge, str]],
     Tuple[AbstractEdge],
 ]:
     """!
     Apply uniform cost search to given problem set
     """
     if not BaseGraphOps.is_in(g, start) or not BaseGraphOps.is_in(g, goal):
         raise ValueError("Start node or goal node is not in graph")
     problem_set = g.E if problem_set is None else problem_set
     pnode = {"cost": 0, "state": start.id(), "parent": None, "edge": None}
     frontier = PriorityQueue(is_min=is_min)
     frontier.insert(key=pnode["cost"], val=pnode)
     explored: Set[str] = set()
     while len(frontier) != 0:
         key, pn = frontier.pop()
         if pn["state"] == goal.id():
             return BaseGraphSearcher.from_ucs_result(pn), pn
         explored.add(pn["state"])
         for child_edge in filter_fn(problem_set, pn["state"]):
             child: AbstractNode = child_edge.get_other(pn["state"])
             cnode = {
                 "cost": costfn(child_edge, pn["cost"]),
                 "state": child.id(),
                 "parent": pn,
                 "edge": child_edge,
             }
             if (child.id() not in explored) or (
                 frontier.is_in(child, cmp_f=lambda x: x["state"]) is False
             ):
                 frontier.insert(cnode["cost"], cnode)
             elif frontier.is_in(child, cmp_f=lambda x: x["state"]) is True:
                 # node is already in frontier
                 ckey = frontier.key(child, f=lambda x: x["state"])
                 if ckey > cnode["cost"]:
                     frontier.insert(
                         cnode["cost"], cnode, f=lambda x: x["state"]
                     )
Exemplo n.º 2
0
 def markov_blanket(self, t: NumCatRVariable) -> Set[NumCatRVariable]:
     """!
     get markov blanket of a node from K. Murphy, 2012, p. 662
     """
     if BaseGraphOps.is_in(self, t) is False:
         raise ValueError("Node not in graph: " + str(t))
     ns: Set[NumCatRVariable] = BaseGraphOps.neighbours_of(self, t)
     return ns
Exemplo n.º 3
0
 def added_edge_between_if_none(
     g: AbstractGraph,
     n1: AbstractNode,
     n2: AbstractNode,
     is_directed: bool = False,
 ) -> BaseGraph:
     """!
     Add edge between nodes. If there are no edges in between.
     The flag is_directed specifies if the edge is directed or not
     """
     if not BaseGraphOps.is_in(g, n1) or not BaseGraphOps.is_in(g, n2):
         raise ValueError("one of the nodes is not present in graph")
     n1id = n1.id()
     n2id = n2.id()
     gdata = BaseGraphOps.to_edgelist(g)
     first_eset = set(gdata[n1id])
     second_eset = set(gdata[n2id])
     common_edge_ids = first_eset.intersection(second_eset)
     if len(common_edge_ids) == 0:
         # there are no edges between the nodes
         if isinstance(g, AbstractUndiGraph):
             edge = Edge.undirected(eid=str(uuid4()),
                                    start_node=n1,
                                    end_node=n2)
             return BaseGraphAlgOps.add(g, edge)
         elif isinstance(g, AbstractDiGraph):
             edge = Edge.directed(eid=str(uuid4()),
                                  start_node=n1,
                                  end_node=n2)
             return BaseGraphAlgOps.add(g, edge)
         elif is_directed is True:
             edge = Edge.directed(eid=str(uuid4()),
                                  start_node=n1,
                                  end_node=n2)
             return BaseGraphAlgOps.add(g, edge)
         elif is_directed is False:
             edge = Edge.undirected(eid=str(uuid4()),
                                    start_node=n1,
                                    end_node=n2)
             return BaseGraphAlgOps.add(g, edge)
         else:
             raise ValueError("Must specify an edge type to be added")
     else:
         # there is already an edge in between
         return g
Exemplo n.º 4
0
 def extract_path(
     self,
     start: Node,
     end: Node,
     filter_fn: Callable[[Set[Edge], str], Set[Edge]] = lambda es, n: set(
         [e for e in es if e.start().id() == n]),
     costfn: Callable[[Edge, float], float] = lambda x, y: y + 1.0,
     is_min=True,
 ):
     """"""
     if (BaseGraphOps.is_in(self, start) is False
             or BaseGraphOps.is_in(self, end) is False):
         raise ValueError("start or end node is not inside tree")
     #
     upset = self.upset_of(start)
     if end not in upset:
         raise ValueError("end node is not in upset of start.")
     downset = self.downset_of(end)
     upset_edges = set()
     for u in upset:
         for e in BaseGraphOps.outgoing_edges_of(self, u):
             upset_edges.add(e)
     downset_edges = set()
     for d in downset:
         for e in BaseGraphOps.outgoing_edges_of(self, d):
             downset_edges.add(e)
     problem_set = upset_edges.intersection(downset_edges)
     ucs_path = Path.from_ucs(
         g=self,
         goal=end,
         start=start,
         filter_fn=filter_fn,
         costfn=costfn,
         is_min=is_min,
         problem_set=problem_set,
     )
     return ucs_path
Exemplo n.º 5
0
    def breadth_first_search(
        g: AbstractGraph,
        n1: AbstractNode,
        edge_generator: Callable[[AbstractNode], Set[AbstractEdge]],
    ) -> BaseGraphBFSResult:
        """!
        \brief find shortest path from given node to all other nodes

        Applies the Breadth first search algorithm from Even and Guy Even 2012, p. 12

        \throws ValueError if given node is not found in graph instance
        """
        if not BaseGraphOps.is_in(g, n1):
            raise ValueError("argument node is not in graph")
        nid = n1.id()
        Q = [nid]
        V: Dict[str, AbstractNode] = {v.id(): v for v in g.V}
        l_vs = {v: math.inf for v in V}
        l_vs[nid] = 0
        T = set([nid])
        P: Dict[str, Dict[str, str]] = {}
        P[nid] = {}
        while Q:
            u = Q.pop(0)
            unode = V[u]
            for edge in edge_generator(unode):
                vnode = edge.get_other(unode)
                vid = vnode.id()
                if vid not in T:
                    T.add(vid)
                    l_vs[vid] = int(l_vs[u] + 1)
                    P[nid][u] = vid
                    Q.append(vid)
        #
        T = set([V[t] for t in T])
        path_props = {"bfs-tree": P, "path-set": T, "top-sort": l_vs}
        return BaseGraphBFSResult(
            props=path_props,
            result_id="bfs-result-of-" + g.id(),
            search_name="breadth_first_search",
            data={},
        )
Exemplo n.º 6
0
 def height_of(self, n: Node) -> int:
     """!"""
     if not BaseGraphOps.is_in(self, n):
         raise ValueError("node not in tree")
     nid = n.id()
     return self.topsort[nid]
Exemplo n.º 7
0
 def test_is_in_false(self):
     """"""
     n = Node("n86", {})
     b = BaseGraphOps.is_in(self.graph, n)
     self.assertFalse(b)
Exemplo n.º 8
0
 def test_is_in_true(self):
     """"""
     b = BaseGraphOps.is_in(self.graph, self.n2)
     self.assertTrue(b)
Exemplo n.º 9
0
    def depth_first_search(
        g: AbstractGraph,
        edge_generator: Callable[[AbstractNode], Set[AbstractNode]],
        check_cycle: bool = False,
        start_node: Optional[AbstractNode] = None,
    ) -> BaseGraphDFSResult:
        """!
        \brief interior visit function for depth first enumeration of graph
        instance.

        \see dfs_forest() method for more information on parameters.
        """
        V: Dict[str, AbstractNode] = {n.id(): n for n in g.V}
        if start_node is not None:
            if not BaseGraphOps.is_in(g, start_node):
                raise ValueError("Specified start node not in graph")
            #
            Vlst: List[str] = list(v for v in V.keys() if v != start_node.id())
            Vlst.insert(0, start_node.id())
            Vlst.sort()
        else:
            Vlst = list(v for v in V.keys())
            Vlst.sort()
        time = 0
        marked: Dict[str, bool] = {n: False for n in V}
        preds: Dict[str, Dict[str, str]] = {}
        Ts: Dict[str, Set[str]] = {}
        d: Dict[str, int] = {n: math.inf for n in V}
        f: Dict[str, int] = {n: math.inf for n in V}
        cycles: Dict[str, List[Dict[str, Union[str, int]]]] = {
            n: [] for n in V
        }
        component_counter = 0
        #
        for u in Vlst:
            if marked[u] is False:
                pred: Dict[str, Optional[str]] = {n: None for n in V}
                T: Set[str] = set()
                BaseGraphSearcher.dfs_forest(
                    g=g,
                    V=V,
                    u=u,
                    pred=pred,
                    cycles=cycles,
                    marked=marked,
                    d=d,
                    T=T,
                    f=f,
                    time=time,
                    check_cycle=check_cycle,
                    edge_generator=edge_generator,
                )
                component_counter += 1
                for child, parent in pred.copy().items():
                    if child != u and child is None:
                        pred.pop(child)
                Ts[u] = T
                preds[u] = pred
        #
        res = {
            "dfs-forest": BaseGraphSearcher.from_preds_to_edgeset(g, preds),
            "dfs-trees": preds,
            "first-visit-times": d,
            "last-visit-times": f,
            "components": Ts,
            "cycle-info": cycles,
            "nb-component": component_counter,
        }
        return BaseGraphDFSResult(
            props=res,
            result_id="dfs-result-of-" + g.id(),
            search_name="depth_first_search",
            data={},
        )