Exemple #1
0
class When_we_want_to_find_the_shortest_path_with_the_same_origin_and_destination:
    def given_a_graph(self):
        """
        (A)--1-->(B)--1-->(C)
         \                /
          <-------1-------
        """

        self.graph = Graph()
        self.vertexA = Vertex(element="Vertex A")
        self.vertexB = Vertex(element="Vertex B")
        self.vertexC = Vertex(element="Vertex C")

        self.edgeAB = Edge(self.vertexA, self.vertexB, element=1)
        self.edgeBC = Edge(self.vertexB, self.vertexC, element=1)
        self.edgeCA = Edge(self.vertexC, self.vertexA, element=1)

        self.graph.add_edge(self.edgeAB)
        self.graph.add_edge(self.edgeBC)
        self.graph.add_edge(self.edgeCA)

    def because_we_calculate_the_most_cost_effective_path(self):
        self.path, self.cost = shortest_path(self.graph, self.vertexA, self.vertexA)

    def it_should_return_the_shortest_path(self):
        expected_path = [self.vertexA, self.vertexB, self.vertexC, self.vertexA]
        expect(self.path).to(equal(expected_path))

    def it_should_return_the_correct_cost_of_the_shortest_path(self):
        expect(self.cost).to(equal(3))
Exemple #2
0
class When_we_want_to_find_the_path_with_the_smaller_cost:
    def given_a_graph(self):
        """
        (A)--3-->(B)--1-->(C)--1-->(D)
                  \                /
                   -------1------->
        """

        self.graph = Graph()
        self.vertexA = Vertex(element="Vertex A")
        self.vertexB = Vertex(element="Vertex B")
        self.vertexC = Vertex(element="Vertex C")
        self.vertexD = Vertex(element="Vertex D")

        self.edgeAB = Edge(self.vertexA, self.vertexB, element=3)
        self.edgeBC = Edge(self.vertexB, self.vertexC, element=1)
        self.edgeCD = Edge(self.vertexC, self.vertexD, element=1)
        self.edgeBD = Edge(self.vertexB, self.vertexD, element=1)

        self.graph.add_edge(self.edgeAB)
        self.graph.add_edge(self.edgeBC)
        self.graph.add_edge(self.edgeCD)
        self.graph.add_edge(self.edgeBD)

    def because_we_calculate_the_most_cost_effective_path(self):
        self.path, self.cost = shortest_path(self.graph, self.vertexA, self.vertexD)

    def it_should_return_the_shortest_path(self):
        expected_path = [self.vertexA, self.vertexB, self.vertexD]
        expect(self.path).to(equal(expected_path))

    def it_should_return_the_correct_cost_of_the_shortest_path(self):
        expect(self.cost).to(equal(4))
Exemple #3
0
class When_we_want_to_work_with_a_simple_graph:

    def given_an_empty_graph(self):
        self.graph = Graph()

    def because_we_configure_the_graph_with_vertices_and_edges(self):
        self.vertex1 = Vertex(element="Vertex 1")
        self.vertex2 = Vertex(element="Vertex 2")
        self.vertex3 = Vertex(element="Vertex 3")

        self.edge12 = Edge(self.vertex1, self.vertex2, element="6")
        self.edge23 = Edge(self.vertex2, self.vertex3, element="4")

        self.graph.add_edge(self.edge12)
        self.graph.add_edge(self.edge23)

    def it_should_have_the_correct_number_of_vertices(self):
        expect(self.graph.vertices).to(have_len(3))

    def it_should_have_the_correct_number_of_edges(self):
        expect(self.graph.edges).to(have_len(2))

    def it_should_have_the_correct_configuration(self):
        expect(self.graph).to(equal({
            self.vertex1: {self.vertex2: self.edge12},
            self.vertex2: {self.vertex3: self.edge23},
            self.vertex3: {}}))
Exemple #4
0
class When_we_want_to_find_the_path_when_it_is_unreachable:
    def given_a_graph(self):
        """
        (A)--3-->(B)--1-->(C)<--1--(D)
                  \                /
                   <-------1-------
        """

        self.graph = Graph()
        self.vertexA = Vertex(element="Vertex A")
        self.vertexB = Vertex(element="Vertex B")
        self.vertexC = Vertex(element="Vertex C")
        self.vertexD = Vertex(element="Vertex D")

        self.edgeAB = Edge(self.vertexA, self.vertexB, element=3)
        self.edgeBC = Edge(self.vertexB, self.vertexC, element=1)
        self.edgeDC = Edge(self.vertexD, self.vertexC, element=1)
        self.edgeDB = Edge(self.vertexD, self.vertexB, element=1)

        self.graph.add_edge(self.edgeAB)
        self.graph.add_edge(self.edgeBC)
        self.graph.add_edge(self.edgeDC)
        self.graph.add_edge(self.edgeDB)

    def because_we_calculate_the_shortest_path_to_an_unreachable_vertex(self):
        self.path, self.cost = shortest_path(self.graph, self.vertexA, self.vertexD)

    def it_should_return_the_shortest_path(self):
        expect(self.path).to(equal([]))

    def it_should_return_the_correct_cost_of_the_shortest_path(self):
        expect(self.cost).to(equal(float("inf")))
Exemple #5
0
    def given_a_graph(self):
        """         1
                  / \
                  \ /
        (A)--3-->(B)--1-->(C)--2-->(D)
                  \                /
                   -------10------>
        """

        self.graph = Graph()
        self.vertexA = Vertex(element="Vertex A")
        self.vertexB = Vertex(element="Vertex B")
        self.vertexC = Vertex(element="Vertex C")
        self.vertexD = Vertex(element="Vertex D")

        self.edgeAB = Edge(self.vertexA, self.vertexB, element=3)
        self.edgeBC = Edge(self.vertexB, self.vertexC, element=1)
        self.edgeCD = Edge(self.vertexC, self.vertexD, element=2)
        self.edgeBD = Edge(self.vertexB, self.vertexD, element=10)

        # Add special case of edge that is looping from vertexB to itself
        self.edgeBB = Edge(self.vertexB, self.vertexB, element=1)

        self.graph.add_edge(self.edgeAB)
        self.graph.add_edge(self.edgeBC)
        self.graph.add_edge(self.edgeCD)
        self.graph.add_edge(self.edgeBD)
        self.graph.add_edge(self.edgeBB)
    def given_a_graph(self):
        """
            -----------5---------->
           /        <--2---       \
          /        /       \       \
        (A)--3-->(B)--1-->(C)--1-->(D)
         \        \       /        /
          \        <-----/--3------
           -----2------>/
        """

        self.graph = Graph()
        self.vertexA = Vertex(element="Vertex A")
        self.vertexB = Vertex(element="Vertex B")
        self.vertexC = Vertex(element="Vertex C")
        self.vertexD = Vertex(element="Vertex D")

        self.edgeAB = Edge(self.vertexA, self.vertexB, element=3)
        self.edgeAD = Edge(self.vertexA, self.vertexD, element=5)
        self.edgeAC = Edge(self.vertexA, self.vertexC, element=2)
        self.edgeBC = Edge(self.vertexB, self.vertexC, element=1)
        self.edgeCD = Edge(self.vertexC, self.vertexD, element=1)
        self.edgeDB = Edge(self.vertexD, self.vertexB, element=3)

        self.graph.add_edge(self.edgeAB)
        self.graph.add_edge(self.edgeAD)
        self.graph.add_edge(self.edgeAC)
        self.graph.add_edge(self.edgeBC)
        self.graph.add_edge(self.edgeCD)
        self.graph.add_edge(self.edgeDB)
Exemple #7
0
    def given_a_graph(self):
        """
        (A)--1-->(B)--1-->(C)
         \                /
          <-------1-------
        """

        self.graph = Graph()
        self.vertexA = Vertex(element="Vertex A")
        self.vertexB = Vertex(element="Vertex B")
        self.vertexC = Vertex(element="Vertex C")

        self.edgeAB = Edge(self.vertexA, self.vertexB, element=1)
        self.edgeBC = Edge(self.vertexB, self.vertexC, element=1)
        self.edgeCA = Edge(self.vertexC, self.vertexA, element=1)

        self.graph.add_edge(self.edgeAB)
        self.graph.add_edge(self.edgeBC)
        self.graph.add_edge(self.edgeCA)
Exemple #8
0
    def given_a_graph(self):
        """
        (A)--3-->(B)--1-->(C)--1-->(D)
                  \                /
                   -------1------->
        """

        self.graph = Graph()
        self.vertexA = Vertex(element="Vertex A")
        self.vertexB = Vertex(element="Vertex B")
        self.vertexC = Vertex(element="Vertex C")
        self.vertexD = Vertex(element="Vertex D")

        self.edgeAB = Edge(self.vertexA, self.vertexB, element=3)
        self.edgeBC = Edge(self.vertexB, self.vertexC, element=1)
        self.edgeCD = Edge(self.vertexC, self.vertexD, element=1)
        self.edgeBD = Edge(self.vertexB, self.vertexD, element=1)

        self.graph.add_edge(self.edgeAB)
        self.graph.add_edge(self.edgeBC)
        self.graph.add_edge(self.edgeCD)
        self.graph.add_edge(self.edgeBD)
class When_we_want_to_find_the_number_of_paths_between_two_vertices_in_a_cyclic_graph:
    def given_a_graph(self):
        """
            -----------5---------->
           /        <--2---       \
          /        /       \       \
        (A)--3-->(B)--1-->(C)--1-->(D)
         \        \       /        /
          \        <-----/--3------
           -----2------>/
        """

        self.graph = Graph()
        self.vertexA = Vertex(element="Vertex A")
        self.vertexB = Vertex(element="Vertex B")
        self.vertexC = Vertex(element="Vertex C")
        self.vertexD = Vertex(element="Vertex D")

        self.edgeAB = Edge(self.vertexA, self.vertexB, element=3)
        self.edgeAD = Edge(self.vertexA, self.vertexD, element=5)
        self.edgeAC = Edge(self.vertexA, self.vertexC, element=2)
        self.edgeBC = Edge(self.vertexB, self.vertexC, element=1)
        self.edgeCD = Edge(self.vertexC, self.vertexD, element=1)
        self.edgeDB = Edge(self.vertexD, self.vertexB, element=3)

        self.graph.add_edge(self.edgeAB)
        self.graph.add_edge(self.edgeAD)
        self.graph.add_edge(self.edgeAC)
        self.graph.add_edge(self.edgeBC)
        self.graph.add_edge(self.edgeCD)
        self.graph.add_edge(self.edgeDB)

    def because_we_want_all_available_paths_from_A_to_B(self):
        self.paths = list(find_paths(self.graph, self.vertexA, self.vertexD, 5))

    def it_should_return_the_correct_list_of_available_paths(self):
        expected_paths = [
            [self.vertexA, self.vertexD],
            [self.vertexA, self.vertexC, self.vertexD],
            [self.vertexA, self.vertexB, self.vertexC, self.vertexD]
        ]
        expect(self.paths).to(have_len(3))
        for path in expected_paths:
            expect(self.paths).to(contain(path))
Exemple #10
0
class When_we_want_to_find_the_path_with_the_smaller_cost_on_a_more_compicated_graph:
    def given_a_graph(self):
        """         1
                  / \
                  \ /
        (A)--3-->(B)--1-->(C)--2-->(D)
                  \                /
                   -------10------>
        """

        self.graph = Graph()
        self.vertexA = Vertex(element="Vertex A")
        self.vertexB = Vertex(element="Vertex B")
        self.vertexC = Vertex(element="Vertex C")
        self.vertexD = Vertex(element="Vertex D")

        self.edgeAB = Edge(self.vertexA, self.vertexB, element=3)
        self.edgeBC = Edge(self.vertexB, self.vertexC, element=1)
        self.edgeCD = Edge(self.vertexC, self.vertexD, element=2)
        self.edgeBD = Edge(self.vertexB, self.vertexD, element=10)

        # Add special case of edge that is looping from vertexB to itself
        self.edgeBB = Edge(self.vertexB, self.vertexB, element=1)

        self.graph.add_edge(self.edgeAB)
        self.graph.add_edge(self.edgeBC)
        self.graph.add_edge(self.edgeCD)
        self.graph.add_edge(self.edgeBD)
        self.graph.add_edge(self.edgeBB)

    def because_we_calculate_the_most_cost_effective_path(self):
        self.path, self.cost = shortest_path(self.graph, self.vertexA, self.vertexD)

    def it_should_return_the_shortest_path(self):
        expected_path = [self.vertexA, self.vertexB, self.vertexC, self.vertexD]
        expect(self.path).to(equal(expected_path))

    def it_should_return_the_correct_cost_of_the_shortest_path(self):
        expect(self.cost).to(equal(6))
Exemple #11
0
class When_we_configure_a_graph_by_passing_only_the_elements:

    def given_an_empty_graph(self):
        self.graph = Graph()

    def because_we_configure_the_graph_by_passing_only_the_elements(self):
        self.vertex1 = Vertex(element="Vertex 1")
        self.vertex2 = Vertex(element="Vertex 2")
        self.vertex3 = Vertex(element="Vertex 3")
        self.vertex4 = Vertex(element="Vertex 4")

        self.edge12 = Edge(self.vertex1, self.vertex2, element=1)
        self.edge23 = Edge(self.vertex2, self.vertex3, element=2)
        self.edge34 = Edge(self.vertex3, self.vertex4, element=3)
        self.edge43 = Edge(self.vertex4, self.vertex3, element=4)
        self.edge42 = Edge(self.vertex4, self.vertex2, element=5)

        self.graph.create_edge("Vertex 1", "Vertex 2", 1)
        self.graph.create_edge("Vertex 2", "Vertex 3", 2)
        self.graph.create_edge("Vertex 3", "Vertex 4", 3)
        self.graph.create_edge("Vertex 4", "Vertex 3", 4)
        self.graph.create_edge("Vertex 4", "Vertex 2", 5)

    def it_should_have_the_correct_number_of_vertices(self):
        expect(self.graph.vertices).to(have_len(4))

    def it_should_have_the_correct_number_of_edges(self):
        expect(self.graph.edges).to(have_len(5))

    def it_should_have_the_correct_configuration(self):
        expect(self.graph).to(equal({
            self.vertex1: {self.vertex2: self.edge12},
            self.vertex2: {self.vertex3: self.edge23},
            self.vertex3: {self.vertex4: self.edge34},
            self.vertex4: {self.vertex3: self.edge43,
                           self.vertex2: self.edge42},
        }))
Exemple #12
0
class When_we_want_to_work_with_a_graph_with_cycles:

    def given_an_empty_graph(self):
        self.graph = Graph()

    def because_we_configure_the_graph_with_vertices_and_edges(self):
        self.vertex1 = Vertex(element="Vertex 1")
        self.vertex2 = Vertex(element="Vertex 2")
        self.vertex3 = Vertex(element="Vertex 3")
        self.vertex4 = Vertex(element="Vertex 4")

        self.edge12 = Edge(self.vertex1, self.vertex2, element=1)
        self.edge23 = Edge(self.vertex2, self.vertex3, element=2)
        self.edge34 = Edge(self.vertex3, self.vertex4, element=3)
        self.edge43 = Edge(self.vertex4, self.vertex3, element=4)
        self.edge42 = Edge(self.vertex4, self.vertex2, element=5)

        self.graph.add_edge(self.edge12)
        self.graph.add_edge(self.edge23)
        self.graph.add_edge(self.edge34)
        self.graph.add_edge(self.edge43)
        self.graph.add_edge(self.edge42)

    def it_should_have_the_correct_number_of_vertices(self):
        expect(self.graph.vertices).to(have_len(4))

    def it_should_have_the_correct_number_of_edges(self):
        expect(self.graph.edges).to(have_len(5))

    def it_should_have_the_correct_configuration(self):
        expect(self.graph).to(equal({
            self.vertex1: {self.vertex2: self.edge12},
            self.vertex2: {self.vertex3: self.edge23},
            self.vertex3: {self.vertex4: self.edge34},
            self.vertex4: {self.vertex3: self.edge43,
                           self.vertex2: self.edge42},
        }))
Exemple #13
0
class When_we_want_to_find_the_number_of_paths_between_two_vertices:
    def given_a_graph(self):
        """
           ------------5---------->
          /                        \
        (A)--3-->(B)--1-->(C)--1-->(D)
                  \                /
                   -------3------->
        """

        self.graph = Graph()
        self.vertexA = Vertex(element="Vertex A")
        self.vertexB = Vertex(element="Vertex B")
        self.vertexC = Vertex(element="Vertex C")
        self.vertexD = Vertex(element="Vertex D")

        self.edgeAB = Edge(self.vertexA, self.vertexB, element=3)
        self.edgeAD = Edge(self.vertexA, self.vertexD, element=5)
        self.edgeBC = Edge(self.vertexB, self.vertexC, element=1)
        self.edgeCD = Edge(self.vertexC, self.vertexD, element=1)
        self.edgeBD = Edge(self.vertexB, self.vertexD, element=3)

        self.graph.add_edge(self.edgeAB)
        self.graph.add_edge(self.edgeAD)
        self.graph.add_edge(self.edgeBC)
        self.graph.add_edge(self.edgeCD)
        self.graph.add_edge(self.edgeBD)

    def because_we_want_all_available_paths_from_A_to_B_and_those_smaller_than_2(self):
        self.paths = list(find_paths(self.graph, self.vertexA, self.vertexD, 5))
        self.paths_less_than_cutoff = list(find_paths(self.graph, self.vertexA, self.vertexD, 2))
        self.paths_equal_2_size = list(find_paths_equal_to_size(self.graph, self.vertexA, self.vertexD, 2))
        self.paths_equal_3_size = list(find_paths_equal_to_size(self.graph, self.vertexA, self.vertexD, 3))
        self.paths_equal_4_size = list(find_paths_equal_to_size(self.graph, self.vertexA, self.vertexD, 4))

    def it_should_return_the_correct_list_of_available_paths(self):
        expected_paths = [
            [self.vertexA, self.vertexD],
            [self.vertexA, self.vertexB, self.vertexD],
            [self.vertexA, self.vertexB, self.vertexC, self.vertexD]
        ]
        expect(self.paths).to(have_len(3))
        for path in expected_paths:
            expect(self.paths).to(contain(path))

    def it_should_return_the_correct_list_of_available_paths_smaller_than_2_size(self):
        expected_paths = [
            [self.vertexA, self.vertexD],
            [self.vertexA, self.vertexB, self.vertexD]
        ]
        expect(self.paths_less_than_cutoff).to(have_len(2))
        for path in expected_paths:
            expect(self.paths_less_than_cutoff).to(contain(path))

    def it_should_return_the_correct_list_of_available_paths_equal_to_2_size(self):
        expected_paths = [
            [self.vertexA, self.vertexD]
        ]
        expect(self.paths_equal_2_size).to(have_len(1))
        for path in expected_paths:
            expect(self.paths_equal_2_size).to(contain(path))

    def it_should_return_the_correct_list_of_available_paths_equal_to_3_size(self):
        expected_paths = [
            [self.vertexA, self.vertexB, self.vertexD]
        ]
        expect(self.paths_equal_3_size).to(have_len(1))
        for path in expected_paths:
            expect(self.paths_equal_3_size).to(contain(path))

    def it_should_return_the_correct_list_of_available_paths_equal_to_4_size(self):
        expected_paths = [
            [self.vertexA, self.vertexB, self.vertexC, self.vertexD]
        ]
        expect(self.paths_equal_4_size).to(have_len(1))
        for path in expected_paths:
            expect(self.paths_equal_4_size).to(contain(path))
Exemple #14
0
 def given_an_empty_graph(self):
     self.graph = Graph()
Exemple #15
0
#!/usr/bin/env python3

from hermes import Graph, Edge, Vertex
from hermes.algorithms import total_path_cost, shortest_path, find_paths, find_paths_equal_to_size, find_paths_lt_hours
from hermes.exceptions import PathNotFoundException


def total_path_cost_days(*args, **kwargs):
    try:
        return "{} days".format(total_path_cost(*args, **kwargs))
    except PathNotFoundException:
        return "not possible"


shipping_graph = Graph()

new_york = Vertex(element="New York")
liverpool = Vertex(element="Liverpool")
casablanca = Vertex(element="Casablanca")
buenos_aires = Vertex(element="Buenos Aires")
cape_town = Vertex(element="Cape Town")


shipping_graph.add_edge(Edge(buenos_aires, new_york, element=6))
shipping_graph.add_edge(Edge(buenos_aires, casablanca, element=5))
shipping_graph.add_edge(Edge(buenos_aires, cape_town, element=4))
shipping_graph.add_edge(Edge(new_york, liverpool, element=4))
shipping_graph.add_edge(Edge(liverpool, casablanca, element=3))
shipping_graph.add_edge(Edge(liverpool, cape_town, element=6))
shipping_graph.add_edge(Edge(casablanca, liverpool, element=3))
shipping_graph.add_edge(Edge(casablanca, cape_town, element=6))