Exemple #1
0
 def test_returns_hyperpath_containing_source_if_source_equals_destination(
         self):
     s = '1'
     T = {s: None}
     H = DirectedHypergraph()
     H.add_node(s)
     path = directed_paths.get_hyperpath_from_predecessors(H, T, s, s)
     self.assertTrue(path.has_node(s))
 def test_returns_hyperpath_containing_source_if_source_equals_destination(
         self):
     s = '1'
     T = {s: None}
     H = DirectedHypergraph()
     H.add_node(s)
     path = directed_paths.get_hyperpath_from_predecessors(H, T, s, s)
     self.assertTrue(path.has_node(s))
 def test_returns_hyperpath_with_single_node_if_source_equals_destination(
         self):
     s = '1'
     T = {s: None}
     H = DirectedHypergraph()
     H.add_node(s)
     path = directed_paths.get_hyperpath_from_predecessors(H, T, s, s)
     self.assertEqual(len(path.get_node_set()), 1)
     self.assertEqual(len(path.get_hyperedge_id_set()), 0)
Exemple #4
0
 def test_returns_hyperpath_with_single_node_if_source_equals_destination(
         self):
     s = '1'
     T = {s: None}
     H = DirectedHypergraph()
     H.add_node(s)
     path = directed_paths.get_hyperpath_from_predecessors(H, T, s, s)
     self.assertEqual(len(path.get_node_set()), 1)
     self.assertEqual(len(path.get_hyperedge_id_set()), 0)
 def test_returns_hyperpath_for_simple_tree(self):
     s1, s2, s3, s4 = 1, 2, 3, 4
     H = DirectedHypergraph()
     H.add_nodes([s1, s2, s3, s4])
     e1 = H.add_hyperedge([s1], [s2])
     e2 = H.add_hyperedge([s1], [s3])
     e3 = H.add_hyperedge([s3], [s4])
     T = {s4: e3, s3: e2, s2: e1, s1: None}
     path = directed_paths.get_hyperpath_from_predecessors(H, T, s1, s4)
     # validate nodes
     self.assertEqual(path.get_node_set(), {s1, s3, s4})
     # validate hyperedges
     self.assertEqual(len(path.get_hyperedge_id_set()), 2)
     self.assertTrue(path.get_hyperedge_id([1], [3]))
     self.assertTrue(path.get_hyperedge_id([3], [4]))
Exemple #6
0
 def test_returns_hyperpath_for_simple_tree(self):
     s1, s2, s3, s4 = 1, 2, 3, 4
     H = DirectedHypergraph()
     H.add_nodes([s1, s2, s3, s4])
     e1 = H.add_hyperedge([s1], [s2])
     e2 = H.add_hyperedge([s1], [s3])
     e3 = H.add_hyperedge([s3], [s4])
     T = {s4: e3, s3: e2, s2: e1, s1: None}
     path = directed_paths.get_hyperpath_from_predecessors(H, T, s1, s4)
     # validate nodes
     self.assertEqual(path.get_node_set(), {s1, s3, s4})
     # validate hyperedges
     self.assertEqual(len(path.get_hyperedge_id_set()), 2)
     self.assertTrue(path.get_hyperedge_id([1], [3]))
     self.assertTrue(path.get_hyperedge_id([3], [4]))
    def test_returns_hyperpath_when_node_is_in_tail_of_two_edges(self):
        s1, s2, s3 = 1, 2, 3
        s4 = 4
        H = DirectedHypergraph()
        e1 = H.add_hyperedge([s1], [s2])
        e2 = H.add_hyperedge([s2], [s3])
        e3 = H.add_hyperedge([s2, s3], [s4])

        T = {s4: e3, s3: e2, s2: e1, s1: None}
        path = directed_paths.get_hyperpath_from_predecessors(H, T, s1, s4)
        # validate nodes
        self.assertEqual(path.get_node_set(), {s1, s2, s3, s4})
        # validate hyperedges
        self.assertEqual(len(path.get_hyperedge_id_set()), 3)
        self.assertTrue(path.get_hyperedge_id([2, 3], [4]))
        self.assertTrue(path.get_hyperedge_id([2], [3]))
        self.assertTrue(path.get_hyperedge_id([1], [2]))
Exemple #8
0
    def test_returns_hyperpath_when_node_is_in_tail_of_two_edges(self):
        s1, s2, s3 = 1, 2, 3
        s4 = 4
        H = DirectedHypergraph()
        e1 = H.add_hyperedge([s1], [s2])
        e2 = H.add_hyperedge([s2], [s3])
        e3 = H.add_hyperedge([s2, s3], [s4])

        T = {s4: e3, s3: e2, s2: e1, s1: None}
        path = directed_paths.get_hyperpath_from_predecessors(H, T, s1, s4)
        # validate nodes
        self.assertEqual(path.get_node_set(), {s1, s2, s3, s4})
        # validate hyperedges
        self.assertEqual(len(path.get_hyperedge_id_set()), 3)
        self.assertTrue(path.get_hyperedge_id([2, 3], [4]))
        self.assertTrue(path.get_hyperedge_id([2], [3]))
        self.assertTrue(path.get_hyperedge_id([1], [2]))
    def test_returns_hyperpath_for_tree_with_multiple_nodes_in_tail(self):
        s1, s2, s3 = 1, 2, 3
        s4, s5, s6 = 4, 5, 6
        H = DirectedHypergraph()
        H.add_nodes([s1, s2, s3, s4, s5, s6])
        e1 = H.add_hyperedge([s1], [s2])
        e2 = H.add_hyperedge([s1], [s3])
        e3 = H.add_hyperedge([s1], [s4])
        e4 = H.add_hyperedge([s2, s3], [s5])
        e5 = H.add_hyperedge([s5], [s6])

        T = {s6: e5, s5: e4, s4: e3, s3: e2, s2: e1, s1: None}
        path = directed_paths.get_hyperpath_from_predecessors(H, T, s1, s6)
        # validate nodes
        self.assertEqual(path.get_node_set(), {s1, s2, s3, s5, s6})
        # validate hyperedges
        self.assertEqual(len(path.get_hyperedge_id_set()), 4)
        self.assertTrue(path.get_hyperedge_id([5], [6]))
        self.assertTrue(path.get_hyperedge_id([2, 3], [5]))
        self.assertTrue(path.get_hyperedge_id([1], [3]))
        self.assertTrue(path.get_hyperedge_id([1], [2]))
Exemple #10
0
    def test_returns_hyperpath_for_tree_with_multiple_nodes_in_tail(self):
        s1, s2, s3 = 1, 2, 3
        s4, s5, s6 = 4, 5, 6
        H = DirectedHypergraph()
        H.add_nodes([s1, s2, s3, s4, s5, s6])
        e1 = H.add_hyperedge([s1], [s2])
        e2 = H.add_hyperedge([s1], [s3])
        e3 = H.add_hyperedge([s1], [s4])
        e4 = H.add_hyperedge([s2, s3], [s5])
        e5 = H.add_hyperedge([s5], [s6])

        T = {s6: e5, s5: e4, s4: e3, s3: e2, s2: e1, s1: None}
        path = directed_paths.get_hyperpath_from_predecessors(H, T, s1, s6)
        # validate nodes
        self.assertEqual(path.get_node_set(), {s1, s2, s3, s5, s6})
        # validate hyperedges
        self.assertEqual(len(path.get_hyperedge_id_set()), 4)
        self.assertTrue(path.get_hyperedge_id([5], [6]))
        self.assertTrue(path.get_hyperedge_id([2, 3], [5]))
        self.assertTrue(path.get_hyperedge_id([1], [3]))
        self.assertTrue(path.get_hyperedge_id([1], [2]))
Exemple #11
0
def k_shortest_hyperpaths(H, source_node, destination_node, k, F=sum_function):
    """Computes the k shortest hyperpaths from a source node to every other
    node in the hypergraph.
    This algorithm is only applicable to directed B-hypergraphs.
    The algorithm is described in the paper:
    Lars Relund Nielsen, Kim Allan Andersen, Daniele Pretolani,
    Finding the K shortest hyperpaths, Computers & Operations Research,
    Volume 32, Issue 6, June 2005, Pages 1477-1497, ISSN 0305-0548,
    http://dx.doi.org/10.1016/j.cor.2003.11.014.
    (http://www.sciencedirect.com/science/article/pii/S0305054803003459)

    :param H: the hypergraph for which the function will compute the shortest
              hyperpaths.
    :param source_node: the source node in H for the path computation.
    :param destination_node: the destination node in H for the path
                        computation.
    :param k: a positive integer indicating how many paths to compute.
    :param F: [optional] function used for the shortest path computation.
              See algorithms.directed_paths module for expected format of
              function.
    :returns: a list containing at most k hyperpaths (DirectedHypergraph) from
              source to destination in ascending order of path length.
    :raises: TypeError -- Input hypergraph must be a B-hypergraph
    :raises: TypeError -- Algorithm only applicable to directed hypergraphs
    :raises: ValueError -- source_node must be a node in H
    :raises: ValueError -- destination_node must be a node in H
    :raises: TypeError -- k must be an integer
    :raises: ValueError -- k must be a positive integer

    """
    try:
        if not H.is_B_hypergraph():
            raise TypeError("Input graph must be a B-hypergraph")
    except AttributeError:
        raise TypeError("Algorithm only applicable to directed hypergraphs")

    if not H.has_node(source_node):
        raise ValueError("source_node must be a node in H. \
                         %s received" % source_node)

    if not H.has_node(destination_node):
        raise ValueError("destination_node must be a node in H. \
                         %s received" % destination_node)

    if type(k) != int:
        raise TypeError("k must be an integer. %s received" % k)

    if k <= 0:
        raise ValueError("k must be a positive integer. %s received" % k)

    # Container for the k-shortest hyperpaths
    paths = []

    # Container for the candidate paths. Every item is a 4-tuple:
    # 1) subgraph H'
    # 2) lower bound on shortest hyperpath weight
    # 3) predecessor function of shortest hypertree rootes at s on H'
    # 4) valid ordering of the nodes in H'
    candidates = []

    shortest_hypertree, W, ordering = \
        shortest_b_tree(H, source_node, F=F, valid_ordering=True)
    # Check if there is source-destination hyperpath
    # if there isn't the for loop below
    # will break immediately and the function returns an empty list
    if W[destination_node] != float('inf'):
        candidates.append((H, W, shortest_hypertree, ordering))

    i = 1
    while i <= k and candidates:
        ind = candidates.index(
            min(candidates, key=lambda x: x[1][destination_node]))
        kShortest = candidates[ind]
        if kShortest[2]:
            candidates.pop(ind)
            path = \
                get_hyperpath_from_predecessors(kShortest[0], kShortest[2],
                                                source_node, destination_node)
            pathPredecessor = \
                {node: edge for node, edge in kShortest[2].items()
                 if node in path.get_node_set()}
            pathOrdering = \
                [node for node in kShortest[3] if node in pathPredecessor]
            paths.append(path)

            # check if we are done
            if len(paths) == k:
                break

            branches = _branching_step(kShortest[0], pathPredecessor,
                                       pathOrdering)
            for j, branch in enumerate(branches):
                lb = _compute_lower_bound(branch, j, kShortest[2],
                                          pathOrdering, kShortest[1],
                                          destination_node, F)
                if lb < float('inf'):
                    candidates.append((branch,
                                      {destination_node: lb},
                                      None, None))
            i += 1
        else:
            # Compute shortest hypertree for kShortest[0] and exact bound
            # reinsert into candidates
            H_sub = kShortest[0]
            tree_sub, W_sub, ordering_sub = \
                shortest_b_tree(H_sub, source_node, valid_ordering=True)
            candidates[ind] = (H_sub, W_sub, tree_sub, ordering_sub)

    return paths