def setUp(self):
        g = DirectedGraph()

        g.add_edge(1, 2, 2)
        g.add_edge(1, 3, 6)
        g.add_edge(2, 3, 3)
        g.add_edge(2, 4, 1)
        g.add_edge(3, 4, 1)
        g.add_edge(3, 5, 4)
        g.add_edge(4, 5, 6)

        self.graph = g
Example #2
0
    def test_question_2(self):

        directed = DirectedGraph()
        directed.add_edge(1, 2, 2)
        directed.add_edge(1, 3, 6)
        directed.add_edge(2, 3, 3)
        directed.add_edge(2, 4, 1)
        directed.add_edge(3, 4, 1)
        directed.add_edge(3, 5, 4)
        directed.add_edge(4, 5, 6)

        assert points_are_connected(directed, 1, 5)

        assert not points_are_connected(directed, 5, 1)
Example #3
0
    def setUp(self):
        g = DirectedGraph()

        g.add_edge(1, 2, 2)
        g.add_edge(1, 3, 6)
        g.add_edge(2, 3, 3)
        g.add_edge(2, 4, 1)
        g.add_edge(3, 4, 1)
        g.add_edge(3, 5, 4)
        g.add_edge(4, 5, 6)

        self.graph = g
Example #4
0
def find_path_with_capacity_dfs(graph: DirectedGraph, current_node, end_node,
                                visited, flows: Dict):
    """
    Finds a path with available capacity from current node to end node
    Returns none if no such paths exist
    """
    visited.add(current_node)

    for edge in graph.get_edges(current_node):

        origin, destination = (edge.a,
                               edge.b) if edge.a == current_node else (edge.b,
                                                                       edge.a)

        if (edge.weight > flows[edge]
                and edge.a == current_node) or (0 < flows[edge]
                                                and edge.b == current_node):

            if destination in visited:
                continue

            if destination == end_node:
                return [edge]

            result = find_path_with_capacity_dfs(graph, destination, end_node,
                                                 visited, flows)

            if result:
                return [edge] + result

    visited.remove(current_node)
Example #5
0
def find_path_with_capacity_dfs(graph: DirectedGraph, current_node, end_node, visited, flows: Dict):
    """
    Finds a path with available capacity from current node to end node
    Returns none if no such paths exist
    """
    visited.add(current_node)

    for edge in graph.get_edges(current_node):

        origin, destination = (edge.a, edge.b) if edge.a == current_node else (edge.b, edge.a)

        if (edge.weight > flows[edge] and edge.a == current_node) or (0 < flows[edge] and edge.b == current_node):

            if destination in visited:
                continue

            if destination == end_node:
                return [edge]

            result = find_path_with_capacity_dfs(graph, destination, end_node, visited, flows)

            if result:
                return [edge] + result

    visited.remove(current_node)
Example #6
0
def topological_sort(graph: DirectedGraph) -> List:
    """
    Called Kahns algorithm
    Sorts the vertices of a graph in a topological order
    or raises an exception when the graph is cyclical
    :param graph: The graph to be sorted toplogically
    """

    graph = copy.deepcopy(graph)

    sorted_nodes = []
    nodes = Queue()

    # Add the nodes without incoming edges to the starting nodes
    for vertex in graph.get_vertices():
        if not graph.has_incoming_edge(vertex):
            nodes.enqueue(vertex)

    # Keep removing nodes and edges while nodes with no incoming edges exist
    while not nodes.is_empty():
        node = nodes.dequeue()
        sorted_nodes.append(node)

        for edge in graph.get_edges(node)[:]:
            graph.delete_edge(edge.a, edge.b)
            if not graph.has_incoming_edge(edge.b):
                nodes.enqueue(edge.b)

    if len(list(graph.get_all_edges())):
        raise RuntimeError('Graph is cyclical')

    return sorted_nodes
Example #7
0
    def setUp(self):
        self.undirected = UndirectedGraph()
        self.undirected.add_edge(1, 2, 2)
        self.undirected.add_edge(1, 3, 6)
        self.undirected.add_edge(2, 3, 3)
        self.undirected.add_edge(2, 4, 1)
        self.undirected.add_edge(3, 4, 1)
        self.undirected.add_edge(3, 5, 4)
        self.undirected.add_edge(4, 5, 6)

        self.directed = DirectedGraph()
        self.directed.add_edge(1, 2, 2)
        self.directed.add_edge(1, 3, 6)
        self.directed.add_edge(2, 3, 3)
        self.directed.add_edge(2, 4, 1)
        self.directed.add_edge(3, 4, 1)
        self.directed.add_edge(3, 5, 4)
        self.directed.add_edge(4, 5, 6)
Example #8
0
    def test_dijkstra_2(self):
        g = DirectedGraph()

        for i in range(100):
            g.add_vertex(i)

        for _ in range(250):
            a = random.randint(1, 100)
            b = random.randint(1, 100)
            if a != b:
                g.add_edge(a, b, random.randint(1, 100))

        distance, path = dijkstra(g, 1, 100)

        if path:
            cur_dist = 0
            start = 1
            for i in path:
                for edge in g.adjacency_list[start]:
                    if edge.b == i:
                        cur_dist += edge.weight
                        break
                start = i

            if cur_dist == 0:
                cur_dist = sys.maxsize

            assert cur_dist == distance
Example #9
0
def ford_fulkerson(graph: DirectedGraph, source,
                   sink) -> Tuple[Dict[Any, int], int]:
    """
    In optimization theory, maximum flow problems involve finding a feasible flow through a
    single-source, single-sink flow network that is maximum.
    :param graph: Directed graph with the capacity of each edge as the weight
    :param source: Source node (from which the flow originates)
    :param sink: Sink node (where the flow leaves the system
    """

    # Store the current flows in a dict
    flows = {edge: 0 for edge in graph.get_all_edges()}
    max_flow = 0

    while True:
        # Find a path with capacity from source to sink and stop is none is available
        next_path = find_path_with_capacity_dfs(graph, source, sink, set(),
                                                flows)

        if next_path is None:
            break

        # Calculate the max flow for the current path
        current_max_flow = sys.maxsize
        start = source
        for edge in next_path:
            if edge.a == start:
                current_max_flow = min(current_max_flow,
                                       edge.weight - flows[edge])
                start = edge.b
            else:
                current_max_flow = min(current_max_flow, flows[edge])
                start = edge.a

        # Add this flow to the found path
        start = source
        for edge in next_path:
            if edge.a == start:
                flows[edge] += current_max_flow
                start = edge.b
            else:
                flows[edge] -= current_max_flow
                start = edge.a

        max_flow += current_max_flow

    # Return the optimal flows per edge and the total max flow
    return flows, max_flow
Example #10
0
def ford_fulkerson(graph: DirectedGraph, source, sink) -> Tuple[Dict[Any, int], int]:
    """
    In optimization theory, maximum flow problems involve finding a feasible flow through a
    single-source, single-sink flow network that is maximum.
    :param graph: Directed graph with the capacity of each edge as the weight
    :param source: Source node (from which the flow originates)
    :param sink: Sink node (where the flow leaves the system
    """

    # Store the current flows in a dict
    flows = {edge: 0 for edge in graph.get_all_edges()}
    max_flow = 0

    while True:
        # Find a path with capacity from source to sink and stop is none is available
        next_path = find_path_with_capacity_dfs(graph, source, sink, set(), flows)

        if next_path is None:
            break

        # Calculate the max flow for the current path
        current_max_flow = sys.maxsize
        start = source
        for edge in next_path:
            if edge.a == start:
                current_max_flow = min(current_max_flow, edge.weight - flows[edge])
                start = edge.b
            else:
                current_max_flow = min(current_max_flow, flows[edge])
                start = edge.a

        # Add this flow to the found path
        start = source
        for edge in next_path:
            if edge.a == start:
                flows[edge] += current_max_flow
                start = edge.b
            else:
                flows[edge] -= current_max_flow
                start = edge.a

        max_flow += current_max_flow

    # Return the optimal flows per edge and the total max flow
    return flows, max_flow
Example #11
0
    def setUp(self):
        self.undirected = UndirectedGraph()
        self.undirected.add_edge(1, 2, 2)
        self.undirected.add_edge(1, 3, 6)
        self.undirected.add_edge(2, 3, 3)
        self.undirected.add_edge(2, 4, 1)
        self.undirected.add_edge(3, 4, 1)
        self.undirected.add_edge(3, 5, 4)
        self.undirected.add_edge(4, 5, 6)

        self.directed = DirectedGraph()
        self.directed.add_edge(1, 2, 2)
        self.directed.add_edge(1, 3, 6)
        self.directed.add_edge(2, 3, 3)
        self.directed.add_edge(2, 4, 1)
        self.directed.add_edge(3, 4, 1)
        self.directed.add_edge(3, 5, 4)
        self.directed.add_edge(4, 5, 6)
Example #12
0
class TestGraph(unittest.TestCase):

    def setUp(self):
        self.undirected = UndirectedGraph()
        self.undirected.add_edge(1, 2, 2)
        self.undirected.add_edge(1, 3, 6)
        self.undirected.add_edge(2, 3, 3)
        self.undirected.add_edge(2, 4, 1)
        self.undirected.add_edge(3, 4, 1)
        self.undirected.add_edge(3, 5, 4)
        self.undirected.add_edge(4, 5, 6)

        self.directed = DirectedGraph()
        self.directed.add_edge(1, 2, 2)
        self.directed.add_edge(1, 3, 6)
        self.directed.add_edge(2, 3, 3)
        self.directed.add_edge(2, 4, 1)
        self.directed.add_edge(3, 4, 1)
        self.directed.add_edge(3, 5, 4)
        self.directed.add_edge(4, 5, 6)

    def test_get_edges(self):
        assert self.undirected.get_all_edges() == self.directed.get_all_edges()
        assert self.undirected.get_vertices() == self.directed.get_vertices()

    def test_directed_graph(self):

        assert len(self.directed.get_successive_vertices(4)) == 1

        assert len(self.undirected.get_successive_vertices(4)) == 3

        assert self.undirected.edge_exists(4, 3)
        assert not self.directed.edge_exists(4, 3)

        self.directed.delete_edge(4, 3)
        self.undirected.delete_edge(4, 3)

        assert len(self.directed.get_all_edges()) == len(self.undirected.get_all_edges()) + 1

    def test_undirected_graph(self):
        g = UndirectedGraph()
Example #13
0
class TestGraph(unittest.TestCase):
    def setUp(self):
        self.undirected = UndirectedGraph()
        self.undirected.add_edge(1, 2, 2)
        self.undirected.add_edge(1, 3, 6)
        self.undirected.add_edge(2, 3, 3)
        self.undirected.add_edge(2, 4, 1)
        self.undirected.add_edge(3, 4, 1)
        self.undirected.add_edge(3, 5, 4)
        self.undirected.add_edge(4, 5, 6)

        self.directed = DirectedGraph()
        self.directed.add_edge(1, 2, 2)
        self.directed.add_edge(1, 3, 6)
        self.directed.add_edge(2, 3, 3)
        self.directed.add_edge(2, 4, 1)
        self.directed.add_edge(3, 4, 1)
        self.directed.add_edge(3, 5, 4)
        self.directed.add_edge(4, 5, 6)

    def test_get_edges(self):
        assert self.undirected.get_all_edges() == self.directed.get_all_edges()
        assert self.undirected.get_vertices() == self.directed.get_vertices()

    def test_directed_graph(self):

        assert len(self.directed.get_successive_vertices(4)) == 1

        assert len(self.undirected.get_successive_vertices(4)) == 3

        assert self.undirected.edge_exists(4, 3)
        assert not self.directed.edge_exists(4, 3)

        self.directed.delete_edge(4, 3)
        self.undirected.delete_edge(4, 3)

        assert len(self.directed.get_all_edges()) == len(
            self.undirected.get_all_edges()) + 1

    def test_undirected_graph(self):
        g = UndirectedGraph()