def test_simple_graph():
    # Prepare graph, just a 0 -> 1 arc
    g = DirectedGraph()
    u = add_vertex(g)
    v = add_vertex(g)
    e, added = add_edge(u, v, g)
    assert added
    w = 1
    map_eweight = {
        e: w,
    }

    # Call Dijkstra
    map_vpreds = defaultdict(set)
    map_vdist = dict()
    dijkstra_shortest_paths(g, u, make_assoc_property_map(map_eweight),
                            make_assoc_property_map(map_vpreds),
                            make_assoc_property_map(map_vdist))

    # Check
    assert map_vpreds == {
        v: {e},
    }

    assert map_vdist == {u: 0, v: w}
def test_parallel_edges():
    # Prepare graph, two parallel edges from 0 to 1
    g = DirectedGraph()
    u = add_vertex(g)
    v = add_vertex(g)
    (e1, added) = add_edge(u, v, g)
    assert added
    (e2, added) = add_edge(u, v, g)
    assert added
    w = 1
    map_eweight = {
        e1: w,
        e2: w,
    }

    # Call Dijkstra
    map_vpreds = defaultdict(set)
    map_vdist = dict()
    dijkstra_shortest_paths(g, u, make_assoc_property_map(map_eweight),
                            make_assoc_property_map(map_vpreds),
                            make_assoc_property_map(map_vdist))

    # Check
    assert map_vpreds == {
        v: {e1, e2},
    }

    assert map_vdist == {u: 0, v: w}
Beispiel #3
0
def test_graph_to_html_with_html_sequences():
    from collections import defaultdict
    from pybgl.property_map import make_assoc_property_map

    g = DirectedGraph(2)
    (e, _) = add_edge(0, 1, g)
    pmap_vlabel = make_assoc_property_map(defaultdict(str))
    pmap_elabel = make_assoc_property_map(defaultdict(str))
    gdp = GraphDp(g, dpv={"label": pmap_vlabel}, dpe={"label": pmap_elabel})

    for label in [
            "<b>foo</b>",
            "<foo>",
            "<",
            ">",
            "<b>foo</b><bar>",
            "<bar><b>foo</b>",
            "<font color='red'><b>foo</b></font>",
            # NB: foo.png must exists + graphviz imposes <img/> not <img>
            #"<table><tr><td><img src='foo.png'/></td></tr></table>",
    ]:
        print(f"{label} --> {graphviz_escape_html(label)}")
        pmap_vlabel[0] = pmap_vlabel[1] = pmap_elabel[e] = label
        shtml = graph_to_html(gdp)
        if in_ipynb():
            html(shtml)
            ipynb_display_graph(gdp)
Beispiel #4
0
def graph_copy(s: int,
               g: Graph,
               g_dup: Graph,
               pmap_vrelevant: ReadPropertyMap = None,
               pmap_erelevant: ReadPropertyMap = None,
               pmap_vertices: ReadWritePropertyMap = None,
               pmap_edges: ReadWritePropertyMap = None,
               callback_dup_vertex=None,
               callback_dup_edge=None):
    """
    Copy a sub-graph from a Graph according to an edge-based filtering
    starting from a given source node.
    Args:
        s: The VertexDescriptor of the source node.
        g: A Graph instance.
        pmap_vrelevant: A ReadPropertyMap{VertexDescriptor : bool} which indicates
            for each vertex whether if it must be duped or not.
            Only used if vis == None.
        pmap_erelevant: A ReadPropertyMap{EdgeDescriptor : bool} which indicates
            for each edge whether if it must be duped or not.
            Only used if vis == None.
        callback_dup_vertex: Callback(u, g, u_dup, g_dup).
            Pass None if irrelevant.
        callback_dup_edge: Callback(e, g, e_dup, g_dup).
            Pass None if irrelevant.
        vis: Pass a custom DepthFirstSearchExtractVisitor or None.
            This visitor must overload super()'s methods.
    """
    # Prepare the needed mappings.
    map_vcolor = defaultdict(int)
    pmap_vcolor = make_assoc_property_map(map_vcolor)

    if not pmap_vrelevant:
        pmap_vrelevant = make_func_property_map(lambda u: True)
    if not pmap_erelevant:
        pmap_erelevant = make_func_property_map(lambda e: True)

    # Prepare the DepthFirstSearchCopyVisitor.
    if not pmap_vertices:
        map_vertices = dict()
        pmap_vertices = make_assoc_property_map(map_vertices)
    if not pmap_edges:
        map_edges = dict()
        pmap_edges = make_assoc_property_map(map_edges)

    vis = DepthFirstSearchCopyVisitor(g_dup, pmap_vrelevant, pmap_erelevant,
                                      pmap_vertices, pmap_edges, pmap_vcolor,
                                      callback_dup_vertex, callback_dup_edge)

    # Copy g to g_copy according to pmap_erelevant using a DFS from s.
    depth_first_search(s,
                       g,
                       pmap_vcolor,
                       vis,
                       if_push=lambda e, g: pmap_erelevant[e] and
                       pmap_vrelevant[target(e, g)])
Beispiel #5
0
def strong_components(g: DirectedGraph,
                      pmap_component: ReadWritePropertyMap) -> int:
    map_vcolor = defaultdict(int)
    map_root = defaultdict(int)
    map_discover_time = defaultdict(int)

    pmap_vcolor = make_assoc_property_map(map_vcolor)
    pmap_root = make_assoc_property_map(map_root)
    pmap_discover_time = make_assoc_property_map(map_discover_time)

    stack = deque()
    vis = TarjanVisitor(pmap_component, pmap_root, pmap_discover_time, stack)

    depth_first_search_graph(g, vertices(g), pmap_vcolor, vis, None)
    return vis.total
Beispiel #6
0
def graph_extract(s: int,
                  g: Graph,
                  pmap_vrelevant=None,
                  pmap_erelevant=None,
                  callback_vertex_extract=None,
                  callback_edge_extract=None):
    """
    Extract the edges of a given Graph according to an edge-based filtering starting
    from a given source node.
    Args:
        s: The VertexDescriptor of the source node.
        g: A Graph instance.
        pmap_vrelevant: A ReadPropertyMap{VertexDescriptor : bool} which indicates
            for each vertex whether if it must be duped or not.
        pmap_erelevant: A ReadPropertyMap{EdgeDescriptor : bool} which indicates
            each edge of the Graph with a boolean equal to True iff the edge is relevant.
        callback_vertex_extract:
        callback_edge_extract:
    """
    if not pmap_vrelevant:
        pmap_vrelevant = make_func_property_map(lambda u: True)
    if not pmap_erelevant:
        pmap_erelevant = make_func_property_map(lambda e: True)

    map_vcolor = defaultdict(int)
    pmap_vcolor = make_assoc_property_map(map_vcolor)
    vis = DepthFirstSearchExtractVisitor(pmap_vrelevant, pmap_erelevant,
                                         pmap_vcolor, callback_vertex_extract,
                                         callback_edge_extract)
    depth_first_search(s,
                       g,
                       pmap_vcolor,
                       vis,
                       if_push=lambda e, g: pmap_erelevant[e] and
                       pmap_vrelevant[target(e, g)])
Beispiel #7
0
 def __init__(self, pmap_vlabel :ReadWritePropertyMap = None, num_vertices = 0):
     super().__init__(num_vertices)
     if not pmap_vlabel:
         self.map_vlabel = defaultdict()
         self.pmap_vlabel = make_assoc_property_map(self.map_vlabel)
     else:
         self.pmap_vlabel = pmap_vlabel
Beispiel #8
0
def make_gdp2() -> GraphDp:
    g = make_g()
    vlabel = {u : "v%s" % u for u in vertices(g)}
    elabel = {e : "e%s%s" % (source(e, g), target(e, g)) for e in edges(g)}
    gdp = GraphDp(
        g,
        dpv = {
            "label" : make_assoc_property_map(vlabel),
            "color" : make_func_property_map(lambda q: "red" if q % 2 else "green"),
        },
        dpe = {
            "label" : make_assoc_property_map(elabel),
            "color" : make_func_property_map(lambda e: "red" if target(e, g) % 2 else "green"),
        }
    )
    return gdp
Beispiel #9
0
def test_all():
    for directed in [True, False]:
        for (i, g) in enumerate([make_g1(directed), make_g2(directed)]):
            print("Processing G%s (directed = %s)" % (i, directed))
            vis = MyDepthFirstSearchVisitor(verbose=False)
            map_color = defaultdict(int)
            depth_first_search(0, g, make_assoc_property_map(map_color), vis)

            n = num_vertices(g)
            m = num_edges(g)
            n_ = vis.num_vertices
            m_ = vis.num_edges

            # Our graph are connected, so these assertion should be verified
            assert n_ == n, "Visited %s/%s vertices" % (n_, n)
            if directed:
                assert m_ == m, "Visited %s/%s edges" % (m_, m)
            else:
                # Undirected edges are visited forward and backward, so they are visited "twice"
                # Not that (u -> u) arc would be only visited once.
                assert m_ == 2 * m, "Visited %s/%s edges" % (m_, m)

            # Finally, all vertices should all be BLACK
            for u in vertices(g):
                assert map_color[u] == BLACK
Beispiel #10
0
def depth_first_search(
    s: int,
    g: Graph,
    pmap_vcolor: ReadWritePropertyMap = None,
    vis: DefaultDepthFirstSearchVisitor = None,
    # N.B: The following parameters does not exist in libboost:
    if_push=None  # if_push(e :EdgeDecriptor, g :Graph) -> bool returns True iff e is relevant
):
    if pmap_vcolor is None:
        map_vcolor = defaultdict(int)
        pmap_vcolor = make_assoc_property_map(map_vcolor)
    if vis is None:
        vis = DefaultDepthFirstSearchVisitor()
    if if_push is None:
        if_push = (lambda e, g: True)

    vis.start_vertex(s, g)
    pmap_vcolor[s] = GRAY
    vis.discover_vertex(s, g)
    u_edges = [e for e in out_edges(s, g) if if_push(e, g)]
    stack = deque([(s, 0, len(u_edges))])

    while stack:
        # Pop the current vertex u. Its (i-1)-th first out-edges have already
        # been visited. The out-degree of u is equal to n.
        (u, i, n) = stack.pop()
        u_edges = [e for e in out_edges(u, g) if if_push(e, g)]

        while i != n:
            # e is the current edge.
            e = u_edges[i]
            v = target(e, g)
            vis.examine_edge(e, g)
            color_v = pmap_vcolor[v]

            # (color[v] == WHITE) means that v has not yet been visited.
            if color_v == WHITE:
                # u must be re-examined later, its i-th out-edge has been visited.
                vis.tree_edge(e, g)
                i += 1
                stack.append((u, i, n))

                # v becomes the new current vertex
                u = v
                pmap_vcolor[u] = GRAY
                vis.discover_vertex(u, g)
                u_edges = [e for e in out_edges(u, g) if if_push(e, g)]
                i = 0
                n = len(u_edges)
            else:
                if color_v == GRAY:
                    vis.back_edge(e, g)
                else:
                    vis.forward_or_cross_edge(e, g)
                i += 1

        # u and all the vertices reachable from u have been visited.
        pmap_vcolor[u] = BLACK
        vis.finish_vertex(u, g)
Beispiel #11
0
def topological_sort(g :DirectedGraph, stack :deque = None) -> deque:
    stack = stack if stack else deque()
    depth_first_search_graph(
        g,
        pmap_vcolor = make_assoc_property_map(defaultdict(int)),
        vis = TopologicalSortVisitor(stack)
    )
    return stack
def test_isolated_vertices():
    # Create 10 isolated vertices
    infty = sys.maxsize
    g = DirectedGraph(10)
    map_eweight = dict()

    for s in vertices(g):
        map_vpreds = defaultdict(set)
        map_vdist = dict()
        dijkstra_shortest_paths(g, s, make_assoc_property_map(map_eweight),
                                make_assoc_property_map(map_vpreds),
                                make_assoc_property_map(map_vdist))

        # No incident arc in the shortest path DAG
        assert map_vpreds == dict()

        # Every target are at infinite distance excepted the source node.
        assert map_vdist == {u: infty if u != s else 0 for u in vertices(g)}
Beispiel #13
0
def parallel_breadth_first_search(
        g1: Automaton,
        g2: Automaton,
        source_pairs=None,
        pmap_vcolor: ReadWritePropertyMap = None,
        vis:
    ParallelBreadthFirstSearchVisitor = ParallelBreadthFirstSearchVisitor(),
        if_push=None,
        delta=delta):
    def get_edge(q, r, a, g):
        assert q is not None
        # It may be useful to consider (q, BOTTOM, a), see parallel_walk algorithm and tree_edge
        #assert r is not None
        return EdgeDescriptor(q, r, a) if q is not None and r == delta(q, a, g) else \
               EdgeDescriptor(q, BOTTOM, a)

    stack = deque()

    if source_pairs == None:
        q01 = initial(g1)
        q02 = initial(g2)
        stack.appendleft((q01, q02))
        vis.start_vertex(q01, g1, q02, g2)
    else:
        for (s1, s2) in source_pairs:
            stack.appendleft((s1, s2))
            vis.start_vertex(s1, g1, s2, g2)

    if not pmap_vcolor:
        map_vcolor = defaultdict(int)
        pmap_vcolor = make_assoc_property_map(map_vcolor)

    if not if_push:
        if_push = (lambda e1, g1, e2, g2: True)

    while stack:
        (q1, q2) = stack.pop()
        vis.examine_vertex(q1, g1, q2, g2)
        for a in sigma(q1, g1) | sigma(q2, g2):
            (r1, r2) = (delta(q1, a, g1), delta(q2, a, g2))
            vis.examine_symbol(q1, g1, q2, g2, a)
            e1 = get_edge(q1, r1, a, g1) if q1 is not BOTTOM else None
            e2 = get_edge(q2, r2, a, g2) if q2 is not BOTTOM else None
            vis.examine_edge(e1, g1, e2, g2, a)
            color = pmap_vcolor[(r1, r2)]
            if color == WHITE:
                vis.tree_edge(e1, g1, e2, g2, a)
                pmap_vcolor[(r1, r2)] = GRAY
                vis.discover_vertex(r1, g1, r2, g2)
                if if_push(e1, g1, e2, g2):
                    stack.appendleft((r1, r2))
            elif color == GRAY:
                vis.gray_target(e1, g1, e2, g2, a)
            else:
                vis.black_target(e1, g1, e2, g2, a)
        pmap_vcolor[(q1, q2)] = BLACK
        vis.finish_vertex(q1, g2, q2, g2)
def test_graph_extract_small(threshold :int = 50):
    g = DirectedGraph(5)
    (e01, _) = add_edge(0, 1, g)
    (e02, _) = add_edge(0, 2, g)
    (e04, _) = add_edge(0, 4, g)
    (e12, _) = add_edge(1, 2, g)
    (e23, _) = add_edge(2, 3, g)
    (e24, _) = add_edge(2, 4, g)
    (e40, _) = add_edge(4, 0, g)
    (e44, _) = add_edge(4, 4, g)
    pmap_eweight = make_assoc_property_map({
        e01 : 83,
        e02 : 3,
        e04 : 78,
        e12 : 92,
        e23 : 7,
        e24 : 18,
        e40 : 51,
        e44 : 84,
    })

    extracted_edges = set()
    pmap_erelevant = make_func_property_map(lambda e: pmap_eweight[e] >= threshold)
    graph_extract(
        0, g,
        pmap_erelevant        = pmap_erelevant,
        callback_edge_extract = lambda e, g: extracted_edges.add(e)
    )

    if in_ipynb():
        pmap_extracted = make_func_property_map(lambda e: e in extracted_edges)
        html(dotstr_to_html(GraphDp(
            g,
                dpe = {
                    "color" : make_func_property_map(lambda e : "darkgreen" if pmap_extracted[e] else "lightgrey"),
                    "style" : make_func_property_map(lambda e : "solid"     if pmap_extracted[e] else "dashed"),
                    "label" : pmap_eweight,
                }
            ).to_dot())
        )

    expected_edges = None

    if threshold == 0:
        expected_edges = {e for e in edges(g)}
    elif threshold == 50:
        expected_edges = {e12, e40, e44, e04, e01}
    elif threshold > 100:
        expected_edges = set()

    if expected_edges is not None:
        assert (extracted_edges == expected_edges), """Invalid edges:
            For threshold = %s:
            extracted: %s
            expected:  %s
        """ % (threshold, sorted(extracted_edges), sorted(expected_edges))
Beispiel #15
0
 def __init__(self,
              num_vertices: int = 0,
              q0: int = 0,
              pmap_final=None,
              pmap_vsymbol: ReadWritePropertyMap = None):
     # Convention: self.adjacencies[q][a] = r
     super().__init__(num_vertices, q0, pmap_final)
     if pmap_vsymbol is None:
         map_vsymbol = defaultdict(lambda: None)
         pmap_vsymbol = make_assoc_property_map(map_vsymbol)
     self.pmap_vsymbol = pmap_vsymbol
def test_directed_graph(links: list = LINKS):
    map_eweight = dict()
    pmap_eweight = make_assoc_property_map(map_eweight)
    g = make_graph(LINKS,
                   pmap_eweight,
                   directed=True,
                   build_reverse_edge=False)

    map_vpreds = defaultdict(set)
    map_vdist = dict()
    dijkstra_shortest_paths(g, 0, pmap_eweight,
                            make_assoc_property_map(map_vpreds),
                            make_assoc_property_map(map_vdist))

    infty = sys.maxsize
    E = {(source(e, g), target(e, g)): e for e in edges(g)}

    assert map_vpreds == {
        1: {E[0, 1]},
        2: {E[1, 2]},
        3: {E[1, 3]},
        4: {E[3, 4]},
        5: {E[4, 5]},
        6: {E[4, 6]},
        7: {E[6, 7]},
        8: {E[7, 8]},
        9: {E[7, 9]}
    }
    assert map_vdist == {
        0: 0,
        1: 1,
        2: 2,
        3: 4,
        4: 5,
        5: 6,
        6: 6,
        7: 14,
        8: 15,
        9: 15,
        10: infty
    }
Beispiel #17
0
def depth_first_search_graph(
        g: Graph,
        sources: set = None,  # Or a generator e.g. vertices(g)
        pmap_vcolor: ReadWritePropertyMap = None,
        vis: DefaultDepthFirstSearchVisitor = None,
        if_push: bool = None  # if_push(e :EdgeDecriptor) -> bool
):
    if pmap_vcolor is None:
        map_vcolor = defaultdict(int)
        pmap_vcolor = make_assoc_property_map(map_vcolor)
    for u in (sources if sources else vertices(g)):
        if pmap_vcolor[u] == WHITE:
            depth_first_search(u, g, pmap_vcolor, vis, if_push)
Beispiel #18
0
    def gold_make_automaton(self):
        """
        Builds an automaton from the observation table information.
        Returns:
            a tuple (b, g) where:
                b: bool, True if the operation is possible, False otherwise
                g: Automaton, an automaton that recognizes the language
                    if b is True,
                    the PTA recognizing the language otherwise
        """
        if self.fill_holes:
            if not self.try_and_fill_holes():
                return False, self.gold_make_pta()
        epsilon_idx = self.exp.index('')
        states = sorted(list(self.red_states.keys()),
                        key=lambda s: (len(s), s))

        transitions = []
        if self.fill_holes:
            for q in states:
                for a in self.sigma:
                    qa_val = self.red_states.get(
                        q + a, self.blue_states.get(q + a, None))
                    for (r, r_val) in self.red_states.items():
                        if qa_val == r_val:
                            transitions += [(q, r, a)]
                            break
        else:
            for q in states:
                for a in self.sigma:
                    if q + a in states:
                        transitions += [(q, q + a, a)]
                    else:
                        qa_val = self.blue_states.get(q + a, None)
                        r = self.choose_compatible_red_state(qa_val)
                        transitions += [(q, r, a)]
        transitions = [(states.index(q), states.index(r), a)
                       for (q, r, a) in transitions]
        final_states = defaultdict(
            bool, {
                states.index(state): True
                if self.red_states[state][epsilon_idx] == self.ONE else False
                for state in states
            })
        g = make_automaton(transitions, states.index(''),
                           make_assoc_property_map(final_states))
        if not self.fill_holes:
            if not self.is_consistent_with_samples(g):
                return False, self.gold_make_pta()
        return True, g
def find_reachable_vertices(g: Graph, sources: set) -> set:
    """
    Returns the set of vertices of a graph which are reachable
    from a set of source vertices.
    Args:
        g: Graph, an instance of `Graph`
        sources: set, a set of integers representing the source vertices
    Returns:
        The set of vertices that are reachable from the source vertices
    """
    map_vcolor = defaultdict(int)
    pmap_vcolor = make_assoc_property_map(map_vcolor)
    depth_first_search_graph(g, sources, pmap_vcolor=pmap_vcolor)
    return set(map_vcolor.keys())
Beispiel #20
0
def _test_make_assoc_property_map(with_dict: bool):
    # Build the underlying dictionary
    d = dict() if with_dict else defaultdict(
        str)  # Here we use str instead of chr, because chr() does not exists!

    # Initialize the property map (and its underlying dict)
    pmap_rot13 = make_assoc_property_map(d)
    for a in alphabet():
        pmap_rot13[a] = rot13(a)

    check_rot13(pmap_rot13)

    # This will not trigger KeyError, because we used defaultdict instead of dict.
    # This is the behavior we expect (std::map<K, V> in C++ ~ defaultdict(V) in python).
    x = pmap_rot13['!']
Beispiel #21
0
def test_strong_components():
    # Create the graph
    g = DirectedGraph(7)
    add_edge(0, 1, g)
    add_edge(1, 2, g)
    add_edge(2, 3, g)
    add_edge(3, 1, g)
    add_edge(3, 4, g)
    add_edge(4, 5, g)
    add_edge(5, 6, g)
    add_edge(6, 4, g)

    # Find strong connected components
    map_component = {u : None for u in vertices(g)}
    pmap_component = make_assoc_property_map(map_component)
    strong_components(g, pmap_component)

    # Rendering
    pmap_color = make_assoc_property_map({
        0 : "red",
        1 : "blue",
        2 : "green",
        3 : "purple"
    })
    assert map_component == {
        0 : 2,
        1 : 1,
        2 : 1,
        3 : 1,
        4 : 0,
        5 : 0,
        6 : 0,
    }

    if in_ipynb():
        html(strong_components_to_html(g, pmap_color, pmap_component).replace("\\n", ""))
Beispiel #22
0
def test_read_graphviz_custom():
    from collections import defaultdict
    from pybgl.property_map import ReadWritePropertyMap, make_assoc_property_map
    from pybgl.graphviz import ReadGraphvizVisitor

    class MyReadGraphvizVisitor(ReadGraphvizVisitor):
        def __init__(self, g: Graph, pmap_vlabel: ReadWritePropertyMap,
                     pmap_elabel: ReadWritePropertyMap):
            super().__init__(g)
            self.pmap_vlabel = pmap_vlabel
            self.pmap_elabel = pmap_elabel

        def on_install_vertex_property(self, u, g, key, value):
            if key == "label":
                self.pmap_vlabel[u] = value

        def on_install_edge_property(self, e, g, key, value):
            if key == "label":
                self.pmap_elabel[e] = value

    map_vlabel = defaultdict(str)
    map_elabel = defaultdict(str)
    g = DirectedGraph()
    dot = """digraph G {
        0 [fontsize=8 label='red'];
        1 [label='green'];
        2 [label='blue' fontsize=10];
        0->1 [label='my_label'];
    }"""
    vis = MyReadGraphvizVisitor(g, make_assoc_property_map(map_vlabel),
                                make_assoc_property_map(map_elabel))
    read_graphviz(dot.splitlines(), g, vis)
    if in_ipynb(): ipynb_display_graph(g)
    assert map_vlabel == {0: "red", 1: "green", 2: "blue"}, map_vlabel
    e_01 = next(iter(edges(g)))
    assert map_elabel == {e_01: "my_label"}, map_vlabel
Beispiel #23
0
def test_incidence_node_automaton_pmap_vlabel():
    map_vlabel = defaultdict(lambda: None)
    map_vlabel[v] = "a"
    map_vlabel[w] = "b"
    g = IncidenceNodeAutomaton(
        3, pmap_vsymbol=make_assoc_property_map(map_vlabel))
    assert num_vertices(g) == 3
    print(g.adjacencies)
    assert symbol(u, g) is None, f"Got {symbol(u, g)}"
    assert symbol(v, g) == "a"
    assert symbol(w, g) == "b"
    assert num_edges(g) == 0
    add_edge(u, v, g)
    assert num_edges(g) == 1
    add_edge(u, w, g)
    assert num_edges(g) == 2
Beispiel #24
0
def test_make_incidence_node_automaton():
    g = make_incidence_node_automaton(
        [(0, 1), (0, 2), (1, 2)],
        q0n=0,
        pmap_vlabel=make_assoc_property_map(
            defaultdict(lambda: None, {
                1: "a",
                2: "b"
            })),
        pmap_vfinal=make_func_property_map(lambda u: u in {0, 2}))
    assert num_vertices(g) == 3
    assert num_edges(g) == 3
    for u in vertices(g):
        assert is_initial(u, g) == (u == 0)
        assert is_final(u, g) == (u in {0, 2})
    assert symbol(0, g) is None
    assert symbol(1, g) == "a"
    assert symbol(2, g) == "b"
Beispiel #25
0
def test_bfs_tree():
    map_order = dict()
    pmap_order = make_assoc_property_map(map_order)
    g = make_binary_tree(10)
    vis = MyVisitor(pmap_order)
    bfs_tree(0, g, vis)
    assert map_order == {
        0: 0,
        1: 1,
        2: 2,
        3: 3,
        4: 4,
        5: 5,
        6: 6,
        7: 7,
        8: 8,
        9: 9,
    }
Beispiel #26
0
def test_dfs_tree():
    map_order = dict()
    pmap_order = make_assoc_property_map(map_order)
    g = make_binary_tree(10)
    vis = MyVisitor(pmap_order)
    dfs_tree(0, g, vis)
    assert map_order == {
        0: 0,
        1: 4,
        2: 1,
        3: 7,
        4: 5,
        5: 3,
        6: 2,
        7: 9,
        8: 8,
        9: 6,
    }
Beispiel #27
0
def cut(s: int, g: Graph, in_cut) -> set:
    """
    Find a vertex cut given an edge cut.
    Args:
        g: A `Graph` instance corresponding to an acyclic graph.
        s: The `VertexDescriptor` corresponding to the source vertex.
        in_cut: `Callback(EdgeDescriptor, Graph) -> bool` indicating whether an
            edge belong to the considered cut.
    """
    class LeavesVisitor(DefaultDepthFirstSearchVisitor):
        def __init__(self, leaves: set):
            self.leaves = leaves

        def examine_edge(self, e: EdgeDescriptor, g: Graph):
            u = source(e, g)
            self.leaves.discard(u)

        def discover_vertex(self, u: int, g: Graph):
            self.leaves.add(u)

    class IfPush:
        def __init__(self, in_cut, cutting_edges: set):
            self.in_cut = in_cut
            self.cutting_edges = cutting_edges

        def __call__(self, e: EdgeDescriptor, g: Graph) -> bool:
            is_cutting_edge = self.in_cut(e, g)
            if is_cutting_edge:
                self.cutting_edges.add(e)
            return not is_cutting_edge

    leaves = set()
    cutting_edges = set()
    map_vcolor = defaultdict(int)
    depth_first_search(s,
                       g,
                       pmap_vcolor=make_assoc_property_map(map_vcolor),
                       vis=LeavesVisitor(leaves),
                       if_push=IfPush(in_cut, cutting_edges))
    return {target(e, g)
            for e in cutting_edges
            } | {u
                 for u in leaves} - {source(e, g)
                                     for e in cutting_edges}
Beispiel #28
0
def breadth_first_search_graph(
    g: Graph,
    sources: set = None,  # Or a generator e.g. vertices(g)
    pmap_vcolor: ReadWritePropertyMap = None,
    vis=None,
    # N.B: The following parameter does not exist in libboost:
    if_push=None  # if_push(e :EdgeDecriptor, g :Graph) -> bool returns True iff e is relevant
):
    if pmap_vcolor is None:
        map_vcolor = defaultdict(int)
        pmap_vcolor = make_assoc_property_map(map_vcolor)
    if vis is None:
        vis = DefaultBreadthFirstSearchVisitor()
    if not if_push:
        if_push = (lambda e, g: True)

    stack = deque()
    for s in sources:
        pmap_vcolor[s] = GRAY
        vis.discover_vertex(s, g)
        stack.append(s)

    while stack:
        u = stack.pop()
        vis.examine_vertex(u, g)
        for e in out_edges(u, g):
            if not if_push(e, g):
                continue
            v = target(e, g)
            vis.examine_edge(e, g)
            color_v = pmap_vcolor[v]
            if color_v == WHITE:
                vis.tree_edge(e, g)
                pmap_vcolor[v] = GRAY
                vis.discover_vertex(v, g)
                stack.appendleft(v)
            elif color_v == GRAY:
                vis.gray_target(e, g)
            else:
                vis.black_target(e, g)
        pmap_vcolor[u] = BLACK
        vis.finish_vertex(u, g)
Beispiel #29
0
def hopcroft_minimize(g: IncidenceAutomaton) -> IncidenceAutomaton:
    if is_empty(g):
        return g
    aggregated_states = list(hopcroft_agglomerate_states(g))

    # Find the aggregated state corresponding to the initial state
    q0 = None
    for idx, qs in enumerate(aggregated_states):
        if any(is_initial(q, g) for q in qs):
            q0 = idx
            break
    assert q0 is not None

    # Swap q0 and 0 so that the initial state is 0.
    if q0 != 0:
        tmp = aggregated_states[0]
        aggregated_states[0] = aggregated_states[q0]
        aggregated_states[q0] = tmp
    q0 = 0

    # Assign an index to each state in the new automaton
    map_set_idx = {qs: idx for idx, qs in enumerate(list(aggregated_states))}
    # Build the set of final states in the new automaton
    final_states_new = defaultdict(
        bool, {
            map_set_idx[qs]: True if any(is_final(q, g) for q in qs) else False
            for qs in aggregated_states
        })
    # Build the minimized automaton
    min_g = IncidenceAutomaton(len(aggregated_states), q0,
                               make_assoc_property_map(final_states_new))
    for qs in aggregated_states:
        for q in qs:
            for e in out_edges(q, g):
                r = target(e, g)
                a = label(e, g)
                rs = None
                for rs in aggregated_states:
                    if r in rs:
                        break
                add_edge(map_set_idx[qs], map_set_idx[rs], a, min_g)
    return min_g
Beispiel #30
0
def dijkstra_shortest_paths(
        g: DirectedGraph,
        s: int,
        pmap_eweight: ReadPropertyMap,
        pmap_vpreds: ReadWritePropertyMap,
        pmap_vdist: ReadWritePropertyMap,
        pmap_vcolor: ReadWritePropertyMap = None,
        compare: BinaryPredicate = None,  # Ignored, see Heap class.
        combine: BinaryFunction = ClosedPlus(),
        zero: int = 0,
        infty: int = INFINITY,
        vis: DijkstraVisitor = None):
    """
    Compute the shortest path in a graph from a given source node
    and according to the `(Distance, compare, combine)` semi-ring.
    Args:
        g: A `DirectedGraph` instance.
        s: The vertex descriptor of the source node.
        pmap_eweight: A `ReadPropertyMap{EdgeDescriptor : Distance}`
            which map each edge with its weight.
        pmap_vpreds: A `ReadWritePropertyMap{VertexDescriptor : EdgeDescriptor}`
            which will map each vertex with its incident arcs in the shortest
            path Directed Acyclic Graph.
            Each element must be initially mapped with `set()`.
        pmap_vdist: A `ReadWritePropertyMap{VertexDescriptor : Distance}`
            which will map each vertex with the weight of its shortest path(s)
            from `s`.
            Each element must be initialized to `zero`.
        zero: The null `Distance` (e.g. `0`).
        infty: The infinite `Distance` (e.g. `sys.maxsize`).
        vis: A `DijkstraVisitor` instance.

    Example:
        g = DirectedGraph(2)
        e, _ = add_edge(0, 1, g)
        map_eweight[e] = 10
        map_vpreds = defaultdict(set)
        map_vdist = dict()
        dijkstra_shortest_paths(
            g, u,
            make_assoc_property_map(map_eweight),
            make_assoc_property_map(map_vpreds),
            make_assoc_property_map(map_vdist)
        )
    """
    if vis is None:
        vis = DijkstraVisitor()

    if pmap_vcolor is None:
        color = defaultdict(int)
        pmap_vcolor = make_assoc_property_map(color)

    # Initialization
    dijkstra_shortest_paths_initialization(g, s, pmap_vcolor, pmap_vdist, zero,
                                           infty, vis)

    # Iteration
    if not compare:
        compare = Less()
        heap = Heap([s], to_comparable=lambda u: pmap_vdist[u])
    else:
        heap = Heap([s],
                    to_comparable=lambda u: Comparable(pmap_vdist[u], compare))

    while heap:
        dijkstra_shortest_paths_iteration(heap, g, pmap_eweight, pmap_vpreds,
                                          pmap_vdist, pmap_vcolor, compare,
                                          combine, vis)