class TestRace(unittest.TestCase):
    def setUp(self):
        romania = pickle.load(open('romania_graph.pickle', 'rb'))
        self.romania = ExplorableGraph(romania)
        self.romania.reset_search()
        # you can also load atlanta graph like in unit tests.

    def test_call_load_data(self):

        max_time = 600 * 1000  # time in milliseconds
        start_time_ms = get_time_milliseconds()

        def time_left():
            return max_time - (get_time_milliseconds() - start_time_ms)

        data = load_data(self.romania, time_left)

        if time_left() < 0:
            self.fail(msg="You went over the maximum time for load_data.")

    def test_run_race(self):
        max_time = 600 * 1000  # time in milliseconds
        start_time_ms = get_time_milliseconds()

        def time_left():
            return max_time - (get_time_milliseconds() - start_time_ms)

        data = load_data(self.romania, time_left)

        start = 'a'
        goal = 'u'
        path = custom_search(self.romania, start, goal, data=data)
Beispiel #2
0
class TestBidirectionalSearch(unittest.TestCase):
    """Test the bidirectional search algorithms: UCS, A*"""
    def setUp(self):
        """Load Atlanta map data"""
        with open('atlanta_osm.pickle', 'rb') as atl:
            atlanta = pickle.load(atl)
        self.atlanta = ExplorableGraph(atlanta)
        self.atlanta.reset_search()

    def test_bidirectional_ucs(self):
        """Test and generate GeoJSON for bidirectional UCS search"""
        path = bidirectional_ucs(self.atlanta, '69581003', '69581000')
        all_explored = self.atlanta.explored_nodes
        plot_search(self.atlanta, 'atlanta_search_bidir_ucs.json', path,
                    all_explored)
        print(path)
Beispiel #3
0
class TestBidirectionalSearch(unittest.TestCase):
    """Test the bidirectional search algorithms: UCS, A*"""
    def setUp(self):
        """Load Atlanta map data"""
        atlanta = pickle.load(open('atlanta_osm.pickle', 'rb'))
        self.atlanta = ExplorableGraph(atlanta)
        self.atlanta.reset_search()
        romania = pickle.load(open('romania_graph.pickle', 'rb'))
        self.romania = ExplorableGraph(romania)
        self.romania.reset_search()

    def test_bidirectional_ucs(self):
        """Test and generate GeoJSON for bidirectional UCS search"""
        #path = bidirectional_ucs(self.atlanta, '69581003', '69581000')
        #all_explored = self.atlanta.explored_nodes
        #plot_search(self.atlanta, 'atlanta_search_bidir_ucs.json', path,
        #           all_explored)
        start = 'a'
        goal = 'u'

        node_positions = {
            n: self.romania.node[n]['pos']
            for n in self.romania.node.keys()
        }

        self.romania.reset_search()
        path = bidirectional_ucs(self.romania, start, goal)

    def test_bidirectional_a_star(self):
        """Test and generate GeoJSON for bidirectional A* search"""
        path = bidirectional_a_star(self.atlanta, '69581003', '69581000')
        all_explored = self.atlanta.explored_nodes
        plot_search(self.atlanta, 'atlanta_search_bidir_a_star.json', path,
                    all_explored)
class TestBidirectionalSearchRomania(unittest.TestCase):
    """Test the bidirectional search algorithms: UCS, A*"""
    def setUp(self):
        """Load romania map data"""
        romania = pickle.load(open('romania_graph.pickle', 'rb'))
        self.romania = ExplorableGraph(romania)
        self.romania.reset_search()

    def test_bidirectional_ucs(self):
        """Test and generate GeoJSON for bidirectional UCS search"""
        start = 'v'
        goal = 'z'

        node_positions = {
            n: self.romania.node[n]['pos']
            for n in self.romania.node.keys()
        }
        self.romania.reset_search()

        path = bidirectional_ucs(self.romania, start, goal)
        all_explored = self.romania.explored_nodes
        self.draw_graph(self.romania,
                        node_positions=node_positions,
                        start=start,
                        goal=goal,
                        path=path)

    def test_bidirectional_a_star(self):
        """Test and generate GeoJSON for bidirectional A* search"""
        path = bidirectional_a_star(self.romania, '69581003', '69581000')
        all_explored = self.romania.explored_nodes

    @staticmethod
    def draw_graph(graph, node_positions={}, start=None, goal=None, path=[]):
        """Visualize results of graph search"""
        explored = list(graph.explored_nodes)

        labels = {}
        for node in graph:
            labels[node] = node

        if not node_positions:
            node_positions = networkx.spring_layout(graph)

        networkx.draw_networkx_nodes(graph, node_positions)
        networkx.draw_networkx_edges(graph, node_positions, style='dashed')
        networkx.draw_networkx_labels(graph, node_positions, labels)

        networkx.draw_networkx_nodes(graph,
                                     node_positions,
                                     nodelist=explored,
                                     node_color='g')

        if path:
            edges = [(path[i], path[i + 1]) for i in range(0, len(path) - 1)]
            networkx.draw_networkx_edges(graph,
                                         node_positions,
                                         edgelist=edges,
                                         edge_color='b')

        if start:
            networkx.draw_networkx_nodes(graph,
                                         node_positions,
                                         nodelist=[start],
                                         node_color='b')

        if goal:
            networkx.draw_networkx_nodes(graph,
                                         node_positions,
                                         nodelist=[goal],
                                         node_color='y')

        plt.plot()
        plt.show()
class TestBidirectionalSearch(unittest.TestCase):
    """Test the bidirectional search algorithms: UCS, A*"""
    def setUp(self):
        """Load Atlanta map data"""
        atlanta = pickle.load(open('atlanta_osm.pickle', 'rb'))
        self.atlanta = ExplorableGraph(atlanta)
        self.atlanta.reset_search()

        romania = pickle.load(open('romania_graph.pickle', 'rb'))
        self.romania = ExplorableGraph(romania)
        self.romania.reset_search()

    def test_bidirectional_ucs(self):
        """Test and generate GeoJSON for bidirectional UCS search"""
        # path = bidirectional_ucs(self.atlanta, '69581003', '69581000')
        # all_explored = self.atlanta.explored_nodes
        # plot_search(self.atlanta, 'atlanta_search_bidir_ucs.json', path,
        #             all_explored)

        # start = 'c'
        # goal = 'r'
        #
        # node_positions = {n: self.romania.node[n]['pos'] for n in
        #                   self.romania.node.keys()}
        #
        # self.romania.reset_search()
        # path = bidirectional_a_star(self.romania, start, goal)
        # print path

        goals = ['a', 'n', 'e']

        node_positions = {
            n: self.romania.node[n]['pos']
            for n in self.romania.node.keys()
        }

        self.romania.reset_search()
        path = tridirectional_search(self.romania, goals)
        print path
        self.draw_graph(self.romania,
                        node_positions=node_positions,
                        start=goals[0],
                        goal=goals[2],
                        path=path)

    # def test_bidirectional_a_star(self):
    #     """Test and generate GeoJSON for bidirectional A* search"""
    #     path = bidirectional_a_star(self.atlanta, '69581003', '69581000')
    #     all_explored = self.atlanta.explored_nodes
    #     plot_search(self.atlanta, 'atlanta_search_bidir_a_star.json', path,
    #                 all_explored)

    @staticmethod
    def draw_graph(graph,
                   node_positions=None,
                   start=None,
                   goal=None,
                   path=None):
        """Visualize results of graph search"""
        explored = list(graph.explored_nodes)

        labels = {}
        for node in graph:
            labels[node] = node

        if node_positions is None:
            node_positions = networkx.spring_layout(graph)

        networkx.draw_networkx_nodes(graph, node_positions)
        networkx.draw_networkx_edges(graph, node_positions, style='dashed')
        networkx.draw_networkx_labels(graph, node_positions, labels)

        networkx.draw_networkx_nodes(graph,
                                     node_positions,
                                     nodelist=explored,
                                     node_color='g')

        if path is not None:
            edges = [(path[i], path[i + 1]) for i in range(0, len(path) - 1)]
            networkx.draw_networkx_edges(graph,
                                         node_positions,
                                         edgelist=edges,
                                         edge_color='b')

        if start:
            networkx.draw_networkx_nodes(graph,
                                         node_positions,
                                         nodelist=[start],
                                         node_color='b')

        if goal:
            networkx.draw_networkx_nodes(graph,
                                         node_positions,
                                         nodelist=[goal],
                                         node_color='y')

        plt.plot()
        plt.show()
Beispiel #6
0
class TestBasicSearch(unittest.TestCase):
    """Test the simple search algorithms: BFS, UCS, A*"""
    def setUp(self):
        """Romania map data from Russell and Norvig, Chapter 3."""
        romania = pickle.load(open('romania_graph.pickle', 'rb'))
        self.romania = ExplorableGraph(romania)
        self.romania.reset_search()

    def test_bfs(self):
        """Test and visualize breadth-first search"""
        start = 'a'
        goal = 'u'

        node_positions = {
            n: self.romania.node[n]['pos']
            for n in self.romania.node.keys()
        }

        self.romania.reset_search()
        path = breadth_first_search(self.romania, start, goal)

        self.draw_graph(self.romania,
                        node_positions=node_positions,
                        start=start,
                        goal=goal,
                        path=path)

    def test_ucs(self):
        """Test and visualize uniform-cost search"""
        start = 'a'
        goal = 'u'

        node_positions = {
            n: self.romania.node[n]['pos']
            for n in self.romania.node.keys()
        }

        self.romania.reset_search()
        path = uniform_cost_search(self.romania, start, goal)

        self.draw_graph(self.romania,
                        node_positions=node_positions,
                        start=start,
                        goal=goal,
                        path=path)

    def test_a_star(self):
        """Test and visualize A* search"""
        start = 'a'
        goal = 'u'

        node_positions = {
            n: self.romania.node[n]['pos']
            for n in self.romania.node.keys()
        }

        self.romania.reset_search()
        path = a_star(self.romania, start, goal)

        self.draw_graph(self.romania,
                        node_positions=node_positions,
                        start=start,
                        goal=goal,
                        path=path)

    def test_bidirectional_ucs(self):
        """Test and visualize bidirectional UCS search"""
        start = 'a'
        goal = 'u'

        node_positions = {
            n: self.romania.node[n]['pos']
            for n in self.romania.node.keys()
        }

        self.romania.reset_search()
        path = bidirectional_ucs(self.romania, start, goal)

        self.draw_graph(self.romania,
                        node_positions=node_positions,
                        start=start,
                        goal=goal,
                        path=path)

    def test_bidirectional_a_star(self):
        """Test and visualize bidirectional A* search"""
        start = 'a'
        goal = 'u'

        node_positions = {
            n: self.romania.node[n]['pos']
            for n in self.romania.node.keys()
        }

        self.romania.reset_search()
        path = bidirectional_a_star(self.romania, start, goal)

        self.draw_graph(self.romania,
                        node_positions=node_positions,
                        start=start,
                        goal=goal,
                        path=path)

    @staticmethod
    def draw_graph(graph,
                   node_positions=None,
                   start=None,
                   goal=None,
                   path=None):
        """Visualize results of graph search"""
        explored = list(graph.explored_nodes)

        labels = {}
        for node in graph:
            labels[node] = node

        if node_positions is None:
            node_positions = networkx.spring_layout(graph)

        networkx.draw_networkx_nodes(graph, node_positions)
        networkx.draw_networkx_edges(graph, node_positions, style='dashed')
        networkx.draw_networkx_labels(graph, node_positions, labels)

        networkx.draw_networkx_nodes(graph,
                                     node_positions,
                                     nodelist=explored,
                                     node_color='g')

        if path is not None:
            edges = [(path[i], path[i + 1]) for i in range(0, len(path) - 1)]
            networkx.draw_networkx_edges(graph,
                                         node_positions,
                                         edgelist=edges,
                                         edge_color='b')

        if start:
            networkx.draw_networkx_nodes(graph,
                                         node_positions,
                                         nodelist=[start],
                                         node_color='b')

        if goal:
            networkx.draw_networkx_nodes(graph,
                                         node_positions,
                                         nodelist=[goal],
                                         node_color='y')

        plt.plot()
        plt.show()
class TestBasicSearch(unittest.TestCase):
    """Test the simple search algorithms: BFS, UCS, A*"""
    def setUp(self):
        """Romania map data from Russell and Norvig, Chapter 3."""
        with open('romania_graph.pickle', 'rb') as rom:
            romania = pickle.load(rom)
        self.romania = ExplorableGraph(romania)
        self.romania.reset_search()

    def test_bfs(self):
        """Test and visualize breadth-first search"""
        start = 'a'
        goal = 'u'

        node_positions = {
            n: self.romania.node[n]['pos']
            for n in self.romania.node.keys()
        }

        self.romania.reset_search()
        path = breadth_first_search(self.romania, start, goal)
        print(path)
        print(self.romania.explored_nodes)

        self.draw_graph(self.romania,
                        node_positions=node_positions,
                        start=start,
                        goal=goal,
                        path=path)

    def test_bfs_empty_path(self):
        start = "a"
        goal = "a"
        path = breadth_first_search(self.romania, start, goal)
        self.assertEqual([], path)

    @staticmethod
    def draw_graph(graph,
                   node_positions=None,
                   start=None,
                   goal=None,
                   path=None):
        """Visualize results of graph search"""
        explored = [
            key for key in graph.explored_nodes
            if graph.explored_nodes[key] > 0
        ]

        labels = {}
        for node in graph:
            labels[node] = node

        if node_positions is None:
            node_positions = networkx.spring_layout(graph)

        networkx.draw_networkx_nodes(graph, node_positions)
        networkx.draw_networkx_edges(graph, node_positions, style='dashed')
        networkx.draw_networkx_labels(graph, node_positions, labels)

        networkx.draw_networkx_nodes(graph,
                                     node_positions,
                                     nodelist=explored,
                                     node_color='g')
        edge_labels = networkx.get_edge_attributes(graph, 'weight')
        networkx.draw_networkx_edge_labels(graph,
                                           node_positions,
                                           edge_labels=edge_labels)

        if path is not None:
            edges = [(path[i], path[i + 1]) for i in range(0, len(path) - 1)]
            networkx.draw_networkx_edges(graph,
                                         node_positions,
                                         edgelist=edges,
                                         edge_color='b')

        if start:
            networkx.draw_networkx_nodes(graph,
                                         node_positions,
                                         nodelist=[start],
                                         node_color='b')

        if goal:
            networkx.draw_networkx_nodes(graph,
                                         node_positions,
                                         nodelist=[goal],
                                         node_color='y')

        plt.plot()
        plt.show()
Beispiel #8
0
class SearchUnitTests(unittest.TestCase):
    """
    Error Diagnostic code courtesy one of our former students -  Mac Chan

    The following unit tests will check for all pairs on romania and random
    points on atlanta.
    Comment out any tests that you haven't implemented yet.

    If you failed on bonnie because of non-optimal path, make sure you pass
    all the local tests.
    Change test_count=-1 if you failed the path test on bonnie, it will run
    tests on atlanta until it finds a set of points that fail.

    If you failed on bonnie because of your explored set is too large,
    there is no easy way to test without a reference implementation.
    But you can read the pdf slides for the optimized terminal condition.

    To run,
    nosetests --nocapture -v search_unit_tests.py:SearchUnitTests
    nosetests --nocapture -v
                        search_unit_tests.py:SearchUnitTests.test_bfs_romania
    """
    def setUp(self):
        """Setup both atlanta and romania graph data."""

        romania = pickle.load(open('romania_graph.pickle', 'rb'))
        self.romania = ExplorableGraph(romania)
        self.romania.reset_search()

        atlanta = pickle.load(open('atlanta_osm.pickle', 'rb'))
        self.atlanta = ExplorableGraph(atlanta)
        self.atlanta.reset_search()

        self.margin_of_error = 1.0e-6

    def reference_path(self, graph, src_node, dst_node, weight='weight'):
        """
        Path as generated by networkx shortest path.

        Args:
            graph (ExplorableGraph): Undirected graph to search.
            src_node (node): Key for the start node.
            dst_node (node): Key for the end node.
            weight (:obj:`str`):
                If None, every edge has weight/distance/cost 1.
                If a string, use this edge attribute as the edge weight.
                Any edge attribute not present defaults to 1.

        Returns:
            Tuple with (cost of path, path as list).
        """

        graph.reset_search()
        path = networkx.shortest_path(graph, src_node, dst_node, weight=weight)
        cost = self.sum_weight(graph, path)

        return cost, path

    def reference_bfs_path(self, graph, src_node, dst_node):
        """
        Breadth First Search as generated by networkx shortest path.

        Args:
            graph (ExplorableGraph): Undirected graph to search.
            src_node (node): Key for the start node.
            dst_node (node): Key for the end node.

        Returns:

        """
        return self.reference_path(graph, src_node, dst_node, weight=None)

    @staticmethod
    def sum_weight(graph, path):
        """
        Calculate the total cost of a path by summing edge weights.

        Args:
            graph (ExplorableGraph): Graph that contains path.
            path (list(nodes)): List of nodes from src to dst.

        Returns:
            Sum of edge weights in path.
        """
        pairs = zip(path, path[1:])

        return sum([graph.get_edge_data(a, b)['weight'] for a, b in pairs])

    def run_romania_data(self, ref_method, method, **kwargs):
        """
        Run the test search against the Romania data.

        Args:
            ref_method (func): Reference search function to compare test search
            method (func): Test search function.
            kwargs: Keyword arguments.

        Asserts:
            True if the path from the test search is equivalent to the
            reference search.
        """

        keys = self.romania.node.keys()
        pairs = zip(keys, keys[1:])
        for src, dst in pairs:
            self.romania.reset_search()
            path = method(self.romania, src, dst, **kwargs)
            print path
            ref_len, ref_path = ref_method(self.romania, src, dst)

            if path != ref_path:
                print src, dst

            self.assertEqual(path, ref_path)

    def run_romania_tri(self, method, **kwargs):
        """
        Run the tridirectional test search against the Romania data.

        Args:
            method (func): Test search function.
            kwargs: Keyword arguments.

        Asserts:
            True if the path from the test search is equivalent to the
            reference search.
        """

        keys = self.romania.node.keys()
        triplets = zip(keys, keys[1:], keys[2:])
        for goals in triplets:
            for all_combo in itertools.permutations(goals):
                #all_combo=('d', 'f', 'g')
                self.romania.reset_search()
                path = method(self.romania, all_combo, **kwargs)
                # print all_combo,"des"
                # print path,"path"
                path_len = self.sum_weight(self.romania, path)
                s1len, _ = self.reference_path(self.romania, all_combo[0],
                                               all_combo[1])
                s2len, _ = self.reference_path(self.romania, all_combo[2],
                                               all_combo[1])
                s3len, _ = self.reference_path(self.romania, all_combo[0],
                                               all_combo[2])
                min_len = min(s1len + s2len, s1len + s3len, s3len + s2len)

                if path_len != min_len:
                    print all_combo

        self.assertEqual(path_len, min_len)

    def run_atlanta_data(self, method, test_count=10, **kwargs):
        """
        Run the bidirectional test search against the Atlanta data.

        Args:
            method (func): Test search function.
            test_count (int): Number of tests to run. Default is 10.
            kwargs: Keyword arguments.

        Asserts:
            True if the path from the test search is equivalent to the
            reference search.
        """

        keys = list(networkx.connected_components(self.atlanta).next())
        random.shuffle(keys)
        for src, dst in zip(keys, keys[1:])[::2]:
            self.atlanta.reset_search()
            path = method(self.atlanta, src, dst, **kwargs)
            path_len = self.sum_weight(self.atlanta, path)
            ref_len, ref_path = self.reference_path(self.atlanta, src, dst)

            if abs(path_len - ref_len) > self.margin_of_error:
                print src, dst

            self.assertAlmostEqual(path_len,
                                   ref_len,
                                   delta=self.margin_of_error)
            test_count -= 1

            if test_count == 0:
                break

    def run_atlanta_tri(self, method, test_count=10, **kwargs):
        """
        Run the tridirectional test search against the Atlanta data.

        Args:
            method (func): Test search function.
            test_count (int): Number of tests to run. Default is 10.
            kwargs: Keyword arguments.

        Asserts:
            True if the path from the test search is equivalent to the
            reference search.
        """

        keys = list(next(networkx.connected_components(self.atlanta)))
        random.shuffle(keys)
        for goals in zip(keys, keys[1:], keys[2:])[::3]:
            self.atlanta.reset_search()
            path = method(self.atlanta, goals, **kwargs)
            path_len = self.sum_weight(self.atlanta, path)
            s1len, _ = self.reference_path(self.atlanta, goals[0], goals[1])
            s2len, _ = self.reference_path(self.atlanta, goals[2], goals[1])
            s3len, _ = self.reference_path(self.atlanta, goals[0], goals[2])
            min_len = min(s1len + s2len, s1len + s3len, s3len + s2len)

            if abs(path_len - min_len) > self.margin_of_error:
                print goals
            self.assertAlmostEqual(path_len,
                                   min_len,
                                   delta=self.margin_of_error)
            test_count -= 1
            if test_count == 0:
                break

    def same_node_bi(self, graph, method, test_count=10, **kwargs):
        """
        Run the a bidirectional test search using same start and end node.

        Args:
            graph (ExplorableGraph): Graph that contains path.
            method (func): Test search function.
            test_count (int): Number of tests to run. Default is 10.
            kwargs: Keyword arguments.

        Asserts:
            True if the path between the same start and end node is empty.
        """

        keys = list(networkx.connected_components(graph).next())
        random.shuffle(keys)

        for i in range(test_count):
            path = method(graph, keys[i], keys[i], **kwargs)

            self.assertFalse(path)

    # def test_same_node_bi(self):
    #     """
    #     Test bidirectional search using the same start and end nodes.
    #
    #     Searches Tested:
    #         breadth_first_search
    #         uniform_cost_search
    #         a_star, null_heuristic
    #         a_star, euclidean_dist_heuristic
    #         bidirectional_ucs
    #         bidirectional_a_star, null_heuristic
    #         bidirectional_a_star, euclidean_dist_heuristic
    #     """

    # self.same_node_bi(self.romania, breadth_first_search)
    # self.same_node_bi(self.romania, uniform_cost_search)
    # self.same_node_bi(self.romania, a_star, heuristic=null_heuristic)
    # self.same_node_bi(self.romania, a_star,
    #                   heuristic=euclidean_dist_heuristic)
    # self.same_node_bi(self.romania, bidirectional_ucs)
    # self.same_node_bi(self.romania, bidirectional_a_star,
    #                   heuristic=null_heuristic)
    # self.same_node_bi(self.romania, bidirectional_a_star,
    #                   heuristic=euclidean_dist_heuristic)

    # def same_node_tri_test(self, graph, method, test_count=10, **kwargs):
    #     """
    #     Run the tridirectional test search using same start and end nodes
    #
    #     Args:
    #         graph (ExplorableGraph): Graph that contains path.
    #         method (func): Test search function.
    #         test_count (int): Number of tests to run. Default is 10.
    #         kwargs: Keyword arguments.
    #
    #     Asserts:
    #         True if the path between the same start and end node is empty.
    #     """
    #
    #     keys = list(next(networkx.connected_components(graph)))
    #     random.shuffle(keys)
    #     for i in range(test_count):
    #         path = method(graph, [keys[i], keys[i], keys[i]], **kwargs)
    #         self.assertFalse(path)
    #
    # def test_same_node_tri(self):
    #     """
    #     Test bidirectional search using the same start and end nodes.
    #
    #     Searches Tested:
    #         tridirectional_search
    #         tridirectional_upgraded, null_heuristic
    #         tridirectional_upgraded, euclidean_dist_heuristic
    #     """
    #
    #     self.same_node_tri_test(self.romania, tridirectional_search)
    #     self.same_node_tri_test(self.romania, tridirectional_upgraded,
    #                             heuristic=null_heuristic)
    #     self.same_node_tri_test(self.romania, tridirectional_upgraded,
    #                             heuristic=euclidean_dist_heuristic)

    # def test_bfs_romania(self):
    #     """Test breadth first search with Romania data."""
    #
    #     self.run_romania_data(self.reference_bfs_path, breadth_first_search)
    #
    # def test_ucs_romania(self):
    #     """Test uniform cost search with Romania data."""
    #
    #     self.run_romania_data(self.reference_path, uniform_cost_search)
    #
    # def test_a_star_null_romania(self):
    #     """Test A* search with Romania data and the Null heuristic."""
    #
    #     self.run_romania_data(self.reference_path, a_star,
    #                           heuristic=null_heuristic)
    #
    # def test_a_star_euclidean_romania(self):
    #     """Test A* search with Romania data and the Euclidean heuristic."""
    #
    #     self.run_romania_data(self.reference_path, a_star,
    #                           heuristic=euclidean_dist_heuristic)

    # def test_bi_ucs_romania(self):
    #     """Test Bi-uniform cost search with Romania data."""
    #
    #     self.run_romania_data(self.reference_path, bidirectional_ucs)

    # def test_bi_ucs_atlanta(self):
    #     """
    #     Test Bi-uniform cost search with Atlanta data.
    #
    #     To loop test forever, set test_count to -1
    #     """
    #
    #     self.run_atlanta_data(bidirectional_ucs, test_count=1)

    # def test_bi_a_star_null_romania(self):
    #     """Test Bi-A* search with Romania data and the Null heuristic."""
    #
    #     self.run_romania_data(self.reference_path, bidirectional_a_star,
    #                           heuristic=null_heuristic)
    #
    # def test_bi_a_star_null_atlanta(self):
    #     """
    #     Test Bi-A* search with Atlanta data and the Null heuristic.
    #
    #     To loop test forever, set test_count to -1
    #     """
    #
    #     self.run_atlanta_data(bidirectional_a_star, heuristic=null_heuristic,
    #                           test_count=10)
    #
    # def test_bi_a_star_euclidean_romania(self):
    #     """Test Bi-A* search with Romania data and the Euclidean heuristic."""
    #
    #     self.run_romania_data(self.reference_path, bidirectional_a_star,
    #                           heuristic=euclidean_dist_heuristic)
    #
    # def test_bi_a_star_euclidean_atlanta(self):
    #     """
    #     Test Bi-A* search with Atlanta data and the Euclidean heuristic.
    #
    #     To loop test forever, set test_count to -1
    #     """
    #
    #     self.run_atlanta_data(bidirectional_a_star,
    #                           heuristic=euclidean_dist_heuristic,
    #                           test_count=10)
    #
    # def test_tri_ucs_romania(self):
    #     """Test Tri-UC search with Romania data."""
    #
    #     self.run_romania_tri(tridirectional_search)
    #
    # def test_tri_ucs_atlanta(self):
    #     """
    #     Test Tri-UC search with Atlanta data.
    #
    #     To loop test forever, set test_count to -1
    #     """
    #
    #     self.run_atlanta_tri(tridirectional_search, test_count=10)
    #
    # def test_tri_upgraded_null_romania(self):
    #     """
    #     Test upgraded tri search with Romania data and the Null heuristic.
    #     """
    #
    #     self.run_romania_tri(tridirectional_upgraded, heuristic=null_heuristic)
    #
    # def test_tri_upgraded_null_atlanta(self):
    #     """
    #     Test upgraded tri search with Atlanta data and the Null heuristic.
    #
    #     To loop test forever, set test_count to -1
    #     """
    #
    #     self.run_atlanta_tri(tridirectional_upgraded, test_count=10,
    #                          heuristic=null_heuristic)
    #
    def test_tri_upgraded_euclidean_romania(self):
        """
        Test upgraded tri search with Romania data and the Euclidean heuristic.
        """

        self.run_romania_tri(tridirectional_upgraded,
                             heuristic=euclidean_dist_heuristic)
class SearchUnitTests(unittest.TestCase):
    """
    Error Diagnostic code courtesy one of our former students -  Mac Chan

    The following unit tests will check for all pairs on romania and random
    points on atlanta.
    Comment out any tests that you haven't implemented yet.

    If you failed on bonnie because of non-optimal path, make sure you pass
    all the local tests.
    Change test_count=-1 if you failed the path test on bonnie, it will run
    tests on atlanta until it finds a set of points that fail.

    If you failed on bonnie because of your explored set is too large,
    there is no easy way to test without a reference implementation.
    But you can read the pdf slides for the optimized terminal condition.

    To run,
    nosetests --nocapture -v search_unit_tests.py:SearchUnitTests
    nosetests --nocapture -v
                        search_unit_tests.py:SearchUnitTests.test_bfs_romania
    """
    def setUp(self):
        """Setup both atlanta and romania graph data."""

        with (open("romania_graph.pickle", "rb")) as romFile:
            romania = pickle.load(romFile)
        self.romania = ExplorableGraph(romania)
        self.romania.reset_search()

        with (open("atlanta_osm.pickle", "rb")) as atlFile:
            atlanta = pickle.load(atlFile)
        self.atlanta = ExplorableGraph(atlanta)
        self.atlanta.reset_search()

        self.margin_of_error = 1.0e-6

    def reference_path(self, graph, src_node, dst_node, weight='weight'):
        """
        Path as generated by networkx shortest path.

        Args:
            graph (ExplorableGraph): Undirected graph to search.
            src_node (node): Key for the start node.
            dst_node (node): Key for the end node.
            weight (:obj:`str`):
                If None, every edge has weight/distance/cost 1.
                If a string, use this edge attribute as the edge weight.
                Any edge attribute not present defaults to 1.

        Returns:
            Tuple with (cost of path, path as list).
        """

        graph.reset_search()
        path = networkx.shortest_path(graph, src_node, dst_node, weight=weight)
        cost = self.sum_weight(graph, path)

        return cost, path

    def reference_bfs_path(self, graph, src_node, dst_node):
        """
        Breadth First Search as generated by networkx shortest path.

        Args:
            graph (ExplorableGraph): Undirected graph to search.
            src_node (node): Key for the start node.
            dst_node (node): Key for the end node.

        Returns:

        """
        return self.reference_path(graph, src_node, dst_node, weight=None)

    @staticmethod
    def sum_weight(graph, path):
        """
        Calculate the total cost of a path by summing edge weights.

        Args:
            graph (ExplorableGraph): Graph that contains path.
            path (list(nodes)): List of nodes from src to dst.

        Returns:
            Sum of edge weights in path.
        """
        pairs = zip(path, path[1:])

        return sum([graph.get_edge_data(a, b)['weight'] for a, b in pairs])

    def run_romania_data(self, ref_method, method, **kwargs):
        """
        Run the test search against the Romania data.

        Args:
            ref_method (func): Reference search function to compare test search
            method (func): Test search function.
            kwargs: Keyword arguments.

        Asserts:
            True if the path from the test search is equivalent to the
            reference search.
        """

        keys = self.romania.nodes.keys()
        pairs = itertools.permutations(keys, 2)
        for src, dst in pairs:
            self.romania.reset_search()
            path = method(self.romania, src, dst, **kwargs)
            ref_len, ref_path = ref_method(self.romania, src, dst)

            if path != ref_path:
                print(src, dst)

            self.assertEqual(ref_path, path)

    def run_romania_tri(self, method, **kwargs):
        """
        Run the tridirectional test search against the Romania data.

        Args:
            method (func): Test search function.
            kwargs: Keyword arguments.

        Asserts:
            True if the path from the test search is equivalent to the
            reference search.
        """

        keys = self.romania.nodes.keys()
        triplets = itertools.permutations(keys, 3)
        for goals in triplets:
            self.romania.reset_search()
            path = method(self.romania, goals, **kwargs)
            path_len = self.sum_weight(self.romania, path)
            s1len, _ = self.reference_path(self.romania, goals[0], goals[1])
            s2len, _ = self.reference_path(self.romania, goals[2], goals[1])
            s3len, _ = self.reference_path(self.romania, goals[0], goals[2])
            min_len = min(s1len + s2len, s1len + s3len, s3len + s2len)

            if path_len != min_len:
                print(goals)

            self.assertEqual(min_len, path_len)

    def run_atlanta_data(self, method, test_count=10, **kwargs):
        """
        Run the bidirectional test search against the Atlanta data.

        In the interest of time and memory, this is not an exhaustive search of
        all possible pairs in the graph.

        Args:
            method (func): Test search function.
            test_count (int): Number of tests to run. Default is 10.
            kwargs: Keyword arguments.

        Asserts:
            True if the path from the test search is equivalent to the
            reference search.
        """

        keys = list(networkx.connected_components(self.atlanta).__next__())
        random.shuffle(keys)
        for src, dst in list(zip(keys, keys[1:]))[::2]:
            self.atlanta.reset_search()
            path = method(self.atlanta, src, dst, **kwargs)
            path_len = self.sum_weight(self.atlanta, path)
            ref_len, ref_path = self.reference_path(self.atlanta, src, dst)
            if abs(path_len - ref_len) > self.margin_of_error:
                print(src, dst)

            self.assertAlmostEqual(path_len,
                                   ref_len,
                                   delta=self.margin_of_error)
            test_count -= 1

            if test_count == 0:
                break

    def run_atlanta_tri(self, method, test_count=10, **kwargs):
        """
        Run the tridirectional test search against the Atlanta data.

        In the interest of time and memory, this is not an exhaustive search of
        all possible triplets in the graph.

        Args:
            method (func): Test search function.
            test_count (int): Number of tests to run. Default is 10.
            kwargs: Keyword arguments.

        Asserts:
            True if the path from the test search is equivalent to the
            reference search.
        """

        keys = list(next(networkx.connected_components(self.atlanta)))
        random.shuffle(keys)
        for goals in list(zip(keys, keys[1:], keys[2:]))[::3]:
            self.atlanta.reset_search()
            path = method(self.atlanta, goals, **kwargs)
            path_len = self.sum_weight(self.atlanta, path)
            s1len, _ = self.reference_path(self.atlanta, goals[0], goals[1])
            s2len, _ = self.reference_path(self.atlanta, goals[2], goals[1])
            s3len, _ = self.reference_path(self.atlanta, goals[0], goals[2])
            min_len = min(s1len + s2len, s1len + s3len, s3len + s2len)

            if abs(path_len - min_len) > self.margin_of_error:
                print(goals)
            self.assertAlmostEqual(path_len,
                                   min_len,
                                   delta=self.margin_of_error)
            test_count -= 1
            if test_count == 0:
                break

    def same_node_bi(self, graph, method, test_count=10, **kwargs):
        """
        Run the a bidirectional test search using same start and end node.

        Args:
            graph (ExplorableGraph): Graph that contains path.
            method (func): Test search function.
            test_count (int): Number of tests to run. Default is 10.
            kwargs: Keyword arguments.

        Asserts:
            True if the path between the same start and end node is empty.
        """

        keys = list(networkx.connected_components(graph).__next__())
        random.shuffle(keys)

        for i in range(test_count):
            path = method(graph, keys[i], keys[i], **kwargs)

            self.assertFalse(path)

    def test_same_node_bi(self):
        """
        Test bidirectional search using the same start and end nodes.

        Searches Tested:
            breadth_first_search
            uniform_cost_search
            a_star, null_heuristic
            a_star, euclidean_dist_heuristic
            bidirectional_ucs
            bidirectional_a_star, null_heuristic
            bidirectional_a_star, euclidean_dist_heuristic
        """

        self.same_node_bi(self.romania, breadth_first_search)
        self.same_node_bi(self.romania, uniform_cost_search)
        self.same_node_bi(self.romania, a_star, heuristic=null_heuristic)
        self.same_node_bi(self.romania,
                          a_star,
                          heuristic=euclidean_dist_heuristic)
        self.same_node_bi(self.romania, bidirectional_ucs)
        self.same_node_bi(self.romania,
                          bidirectional_a_star,
                          heuristic=null_heuristic)
        self.same_node_bi(self.romania,
                          bidirectional_a_star,
                          heuristic=euclidean_dist_heuristic)

    def same_node_tri_test(self, graph, method, test_count=10, **kwargs):
        """
        Run the tridirectional test search using same start and end nodes

        Args:
            graph (ExplorableGraph): Graph that contains path.
            method (func): Test search function.
            test_count (int): Number of tests to run. Default is 10.
            kwargs: Keyword arguments.

        Asserts:
            True if the path between the same start and end node is empty.
        """

        keys = list(next(networkx.connected_components(graph)))
        random.shuffle(keys)
        for i in range(test_count):
            path = method(graph, [keys[i], keys[i], keys[i]], **kwargs)
            self.assertFalse(path)

    '''
    def test_same_node_tri(self):
        """
        Test bidirectional search using the same start and end nodes.

        Searches Tested:
            tridirectional_search
            tridirectional_upgraded, null_heuristic
            tridirectional_upgraded, euclidean_dist_heuristic
        """

        self.same_node_tri_test(self.romania, tridirectional_search)
        self.same_node_tri_test(self.romania, tridirectional_upgraded,
                                heuristic=null_heuristic)
        self.same_node_tri_test(self.romania, tridirectional_upgraded,
                                heuristic=euclidean_dist_heuristic)

    
    def test_bfs_romania(self):
        """Test breadth first search with Romania data."""


        keys = self.romania.nodes.keys()
        pairs = itertools.permutations(keys, 2)
        for src in keys:
            for dst in keys:
                self.romania.reset_search()
                path = breadth_first_search(self.romania, src, dst)
                ref_len, ref_path = self.reference_bfs_path(self.romania, src, dst)
                self.assertTrue(is_valid(self.romania, path, src, dst),
                     msg="path %s for start '%s' and goal '%s' is not valid" % (path, src, dst))
                if src != dst: # we want path == [] if src == dst
                    self.assertTrue(len(path) == len(ref_path), msg="Path is too long. Real path: %s, your path: %s" % (ref_path, path))

    
    def test_ucs_romania(self):
        """Test uniform cost search with Romania data."""

        self.run_romania_data(self.reference_path, uniform_cost_search)

    '''

    def test_a_star_null_romania(self):
        #Test A* search with Romania data and the Null heuristic."""

        self.run_romania_data(self.reference_path,
                              a_star,
                              heuristic=null_heuristic)

    '''
    def test_a_star_euclidean_romania(self):
        """Test A* search with Romania data and the Euclidean heuristic."""

        self.run_romania_data(self.reference_path, a_star,
                              heuristic=euclidean_dist_heuristic)
    
    
    def test_bi_ucs_romania(self):
        """Test Bi-uniform cost search with Romania data."""

        self.run_romania_data(self.reference_path, bidirectional_ucs)
    
    
    
    
    def test_bi_ucs_atlanta(self):
        """
        Test Bi-uniform cost search with Atlanta data.

        To loop test forever, set test_count to -1
        """

        self.run_atlanta_data(bidirectional_ucs, test_count=10)

    
    def test_bi_a_star_null_romania(self):
        """Test Bi-A* search with Romania data and the Null heuristic."""

        self.run_romania_data(self.reference_path, bidirectional_a_star,
                              heuristic=null_heuristic)

    
    def test_bi_a_star_null_atlanta(self):
        """
        Test Bi-A* search with Atlanta data and the Null heuristic.

        To loop test forever, set test_count to -1
        """

        self.run_atlanta_data(bidirectional_a_star, heuristic=null_heuristic,
                              test_count=10)
    
    def test_bi_a_star_euclidean_romania(self):
        """Test Bi-A* search with Romania data and the Euclidean heuristic."""

        self.run_romania_data(self.reference_path, bidirectional_a_star,
                              heuristic=euclidean_dist_heuristic)
    
    def test_bi_a_star_euclidean_atlanta(self):
        """
        Test Bi-A* search with Atlanta data and the Euclidean heuristic.

        To loop test forever, set test_count to -1
        """

        self.run_atlanta_data(bidirectional_a_star,
                              heuristic=euclidean_dist_heuristic,
                              test_count=10)

    def test_bi_a_star_haversine_atlanta(self):
        """
        Test Bi-A* search with Atlanta data and the Haversine heuristic.

        To loop test forever, set test_count to -1
        """

        self.run_atlanta_data(bidirectional_a_star,
                              heuristic=haversine_dist_heuristic,
                              test_count=10)

    
    def test_tri_ucs_romania(self):
        """Test Tri-UC search with Romania data."""

        self.run_romania_tri(tridirectional_search)
    
    def test_tri_ucs_atlanta(self):
        """
        Test Tri-UC search with Atlanta data.

        To loop test forever, set test_count to -1
        """

        self.run_atlanta_tri(tridirectional_search, test_count=10)
    
    '''

    def test_tri_upgraded_null_romania(self):
        """
        Test upgraded tri search with Romania data and the Null heuristic.
        """

        self.run_romania_tri(tridirectional_upgraded, heuristic=null_heuristic)

    '''
Beispiel #10
0
class TestSearchExperimental(unittest.TestCase):
    """Test your search algorithms with a nxn grid based graph and visualize your results"""
    def setUp(self):
        """Load grid map data"""
        file_name = 'grid.gpickle'

        # Use this function to create any custom grid
        #create_grid(20, file_name=file_name)
        with open(file_name, "rb") as file:
            self.original_grid = pickle.load(file)

        self.grid = ExplorableGraph(self.original_grid)
        self.grid.reset_search()

    def test_grid_viz_bidirectional_search(self):
        """ Use this function to test out your code on a grid to visualize
        the paths and explored nodes for Bidirectional Search.
        This function will save the image files grid_expansion_bidirectional_search.png and
        grid_paths_bidirectional_search.png.
        """

        coordinates = [(0, 0), (6, 7)]
        path = bidirectional_ucs(self.grid, coordinates[0], coordinates[1])
        # path = bidirectional_a_star(self.grid, coordinates[0], coordinates[1], heuristic=custom_heuristic)
        explored = list(self.grid.explored_nodes.keys())
        """

        Color Map Code:
        * Nodes never explored : White
        * Nodes explored but not in path : Red
        * Nodes in path : Green

        """
        val_map = {
            0: {
                0: {
                    0: 'w',
                    1: 'w'
                },
                1: {
                    0: 'w',
                    1: 'w'
                },
            },
            1: {
                0: {
                    0: 'r',
                    1: 'r'
                },
                1: {
                    0: 'g',
                    1: 'b'
                }
            }
        }
        color_values = [
            val_map[node in explored][node in path][node in coordinates]
            for node in self.grid.nodes()
        ]
        save_graph(self.original_grid,
                   "grid_paths_bidirectional_search.png",
                   show_node_labels=True,
                   show_edge_labels=False,
                   color_values=color_values)

        expanded_nodes_dict = dict(self.grid.explored_nodes)
        # Color of nodes gets lighter as it gets explored more
        expansion_color_values = list(expanded_nodes_dict.values())
        save_graph(self.original_grid,
                   "grid_expansion_bidirectional_search.png",
                   show_node_labels=True,
                   show_edge_labels=False,
                   color_values=expansion_color_values)

    def test_grid_viz_tridirectional_search(self):
        """ Use this function to test out your code on a grid to
        visualize the paths and explored nodes for Tridirectional Search.
        This function will save the image files grid_paths_tridirectional_search.png and
        grid_expansion_tridirectional_search.png
        """

        coordinates = [(0, 0), (5, 1), (19, 10)]
        path = tridirectional_search(self.grid, coordinates)
        # path = tridirectional_upgraded(self.grid, coordinates, heuristic=custom_heuristic)
        # path = three_bidirectional_search(self.grid, coordinates, heuristic=custom_heuristic)
        explored = list(self.grid.explored_nodes.keys())
        """

        Color Map Code:
        * Source/destination coordinates : Blue
        * Nodes never explored : White
        * Nodes explored but not in path : Red
        * Nodes in path : Green

        """
        val_map = {
            0: {
                0: {
                    0: 'w',
                    1: 'w'
                },
                1: {
                    0: 'w',
                    1: 'w'
                },
            },
            1: {
                0: {
                    0: 'r',
                    1: 'r'
                },
                1: {
                    0: 'g',
                    1: 'b'
                }
            }
        }
        color_values = [
            val_map[node in explored][node in path][node in coordinates]
            for node in self.grid.nodes()
        ]
        save_graph(self.original_grid,
                   "grid_paths_tridirectional_search.png",
                   show_node_labels=True,
                   show_edge_labels=False,
                   color_values=color_values)

        expanded_nodes_dict = dict(self.grid.explored_nodes)
        # Color of nodes gets lighter as it gets explored more
        expansion_color_values = list(expanded_nodes_dict.values())
        save_graph(self.original_grid,
                   "grid_expansion_tridirectional_search.png",
                   show_node_labels=True,
                   show_edge_labels=False,
                   color_values=expansion_color_values)
class TestBasicSearch(unittest.TestCase):
    """Test the simple search algorithms: BFS, UCS, A*"""

    def setUp(self):
        """Romania map data from Russell and Norvig, Chapter 3."""
        with open('romania_graph.pickle', 'rb') as rom:
            romania = pickle.load(rom)
        print("***")
        print(type(romania))
        print("***")
        
        """
        create graph
        """
        """
        currency_map = [('STNR', 'ISBL', 0.99),
                        ('STNR', 'GBP', 0.0645),
                        ('STNR', 'EUR', 0.0465),
                        ('STNR', 'BTC', 0.0610),
                        ('BTC', 'AUD', 0.005),
                        ('EUR', 'AUD', 0.0650),
                        ('EUR', 'CNY', 0.0120),
                        ('GBP', 'AUD', 0.0493),
                        ('GBP', 'CNY', 0.0571),
                        ('AUD', 'TRY', 0.0621),
                        ('AUD', 'UGX', 0.0023),
                        ('AUD', 'INR', 0.0260),
                        ('CNY', 'TRY', 0.0170),
                        ('CNY', 'UGX', 0.0892),
                        ('CNY', 'INR', 0.0400),
                        ('INR', 'ISBL', 0.0847),
                        ('UGX', 'ISBL', 0.0100),
                        ('TRY', 'ISBL', 0.0124)
                        ]
        
        """
        
        land_map = [('St', 'J', 238),
                    ('St', 'E', 106),
                    ('E', 'Bo', 113),
                    ('Bo', 'N', 145),
                    ('Bo', 'L', 123),
                    ('N', 'Se', 115),
                    ('L', 'H', 123),
                    ('H', 'P', 134),
                    ('Se', 'T', 212), #211 on map
                    ('Se', 'P', 244),
                    ('I', 'P', 124),
                    ('I', 'T', 153),
                    ('J', 'Ba', 155), #140 on map
                    ('Ba', 'T', 168)]
        


        pos_ = {'I' : (220.2, 382.1), 
               'P' : (154.5, 350.4),
               'T' : (360.4, 323.2),
               'J' : (248.3 , 287.1),
               'N' : (148.7, 240.5),
               'H' : (87.5, 300.5),
               'L' : (63.2, 211.7),
               'Bo' : (111.3, 132.6),
               'E' : (182.9, 92.0),
               'Se' : (206.0, 178.6),
               'Ba': (365.3, 185.6),
               'St' : (246.4, 49.3)}
        G = networkx.Graph()
        
        """
        for i in range(len(currency_map)):
            G.add_weighted_edges_from([currency_map[i]]) 
        """
        for i in range(len(land_map)):
            G.add_weighted_edges_from([land_map[i]]) 
        
        networkx.set_node_attributes(G,  pos_, 'pos')
        
        #edge_labels = networkx.get_edge_attributes(G, 'weight')
        #weight = G.get_edge_data('Washington', 'Boise')['weight']
        
        #print("edge_labels = ", weight)
        
        #                start=start, goal=goal, path=path)
    
        
        self.romania = ExplorableGraph(G)
        #print("Graph values")
        
        #self.draw_graph(self.romania, node_positions=pos_)
        
        node_list = list(G.nodes(data = True))
        print("node_list = ", node_list[0][0])
        for i in range(len(node_list)):
            d = self.euclidean_dist(self.romania, node_list[i][0], 'St' )
            print("euclidean distnace [", node_list[i][0], "] = ", d)
        
        self.romania.reset_search()

    @staticmethod
    def euclidean_dist(graph, v, goal):
        x1,y1 = graph.nodes[v]['pos']
        x2,y2 = graph.nodes[goal]['pos']
    
        #print(x1, ", ", y1, ", ", x2, ", ", y2)
    
        distance = math.sqrt(math.pow((x2 - x1),2) + math.pow((y2 - y1),2))
   
        return int(distance)
    
    @staticmethod
    def get_path_cost(graph, path):
        cost = 0
        for i in range(0, len(path)):
            if(i+1 >= len(path)):
                break
            cost = cost + graph.get_edge_weight(path[i], path[i+1])
        return cost
        #Test for 2a and 2b
    """
    def test_ucs(self):
        #Test and visualize uniform-cost search
        start = 'ISBL'
        goal = 'STNR'

        #node_positions = {n: self.romania.nodes[n]['pos'] for n in
        #                  self.romania.nodes.keys()}
        
        
        self.romania.reset_search()
        path = uniform_cost_search(self.romania, start, goal)
        
        print("path = " , path)
        print("cost = ", get_path_cost(self.romania, path))
   

        #self.draw_graph(self.romania, node_positions=node_positions,
        #                start=start, goal=goal, path=path)
    
    """
    def test_astar_path(self):
        start = "I"
        goal = "St"
        
        path = uniform_cost_search(self.romania, start, goal)
        print("Path using ucs = ", path)
        
        print("*** starting a-star***")
        path = a_star(self.romania, start, goal)
        print("Path using a-star = ", path)
        print("Path cost =", self.get_path_cost(self.romania, path))
        
    
    """
    def test_best_path(self):
        start_list = ['Washington', 'Oregon', 'Stanford', 'UCLA']
        goal_list = ['Brown', 'MIT', 'Georgetown', 'Duke'] 
        
        for i in start_list:
            for j in goal_list:
                self.bi_ucs(i, j)
              
    def test_astar_path(self):
        start = "Gatech"
        goal = "OSU"
        
        path = uniform_cost_search(self.romania, start, goal)
        print("Path using ucs = ", path)
        
        path = a_star(self.romania, start, goal)
        print("Path using a-star = ", path)
        
    """           
    
    @staticmethod
    def draw_graph(graph, node_positions=None, start=None, goal=None,
                   path=None):
        """Visualize results of graph search"""
        explored = [key for key in graph.explored_nodes if graph.explored_nodes[key] > 0]

        labels = {}
        for node in graph:
            labels[node] = node

        if node_positions is None:
            node_positions = networkx.spring_layout(graph)

        networkx.draw_networkx_nodes(graph, node_positions)
        networkx.draw_networkx_edges(graph, node_positions, style='dashed')
        networkx.draw_networkx_labels(graph, node_positions, labels)

        networkx.draw_networkx_nodes(graph, node_positions, nodelist=explored,
                                     node_color='g')
        edge_labels = networkx.get_edge_attributes(graph, 'weight')
        networkx.draw_networkx_edge_labels(graph, node_positions, edge_labels=edge_labels)
        
        if path is not None:
            edges = [(path[i], path[i + 1]) for i in range(0, len(path) - 1)]
            networkx.draw_networkx_edges(graph, node_positions, edgelist=edges,
                                         edge_color='b')

        if start:
            networkx.draw_networkx_nodes(graph, node_positions,
                                         nodelist=[start], node_color='b')

        if goal:
            networkx.draw_networkx_nodes(graph, node_positions,
                                         nodelist=[goal], node_color='y')

        plt.plot()
        plt.show()
Beispiel #12
0
class SearchUnitTests(unittest.TestCase):
    def setUp(self):
        """Setup both atlanta and romania graph data."""

        with (open("romania_graph.pickle", "rb")) as romFile:
            romania = pickle.load(romFile)
        self.romania = ExplorableGraph(romania)
        self.romania.reset_search()

        with (open("atlanta_osm.pickle", "rb")) as atlFile:
            atlanta = pickle.load(atlFile)
        self.atlanta = ExplorableGraph(atlanta)
        self.atlanta.reset_search()

        self.margin_of_error = 1.0e-6

    def reference_path(self, graph, src_node, dst_node, weight='weight'):
        """
        Path as generated by networkx shortest path.

        Args:
            graph (ExplorableGraph): Undirected graph to search.
            src_node (node): Key for the start node.
            dst_node (node): Key for the end node.
            weight (:obj:`str`):
                If None, every edge has weight/distance/cost 1.
                If a string, use this edge attribute as the edge weight.
                Any edge attribute not present defaults to 1.

        Returns:
            Tuple with (cost of path, path as list).
        """

        graph.reset_search()
        path = networkx.shortest_path(graph, src_node, dst_node, weight=weight)
        cost = self.sum_weight(graph, path)

        return cost, path

    def reference_bfs_path(self, graph, src_node, dst_node):
        """
        Breadth First Search as generated by networkx shortest path.

        Args:
            graph (ExplorableGraph): Undirected graph to search.
            src_node (node): Key for the start node.
            dst_node (node): Key for the end node.

        Returns:

        """
        return self.reference_path(graph, src_node, dst_node, weight=None)

    @staticmethod
    def sum_weight(graph, path):
        """
        Calculate the total cost of a path by summing edge weights.

        Args:
            graph (ExplorableGraph): Graph that contains path.
            path (list(nodes)): List of nodes from src to dst.

        Returns:
            Sum of edge weights in path.
        """
        pairs = zip(path, path[1:])

        return sum([graph.get_edge_data(a, b)['weight'] for a, b in pairs])

    def run_romania_data(self, ref_method, method, **kwargs):
        """
        Run the test search against the Romania data.

        Args:
            ref_method (func): Reference search function to compare test search
            method (func): Test search function.
            kwargs: Keyword arguments.

        Asserts:
            True if the path from the test search is equivalent to the
            reference search.
        """

        keys = self.romania.node.keys()
        pairs = itertools.permutations(keys, 2)
        for src, dst in pairs:
            self.romania.reset_search()
            path = method(self.romania, src, dst, **kwargs)
            ref_len, ref_path = ref_method(self.romania, src, dst)

            if path != ref_path:
                print (src, dst)

            self.assertEqual(ref_path, path)

    def run_romania_tri(self, method, **kwargs):
        """
        Run the tridirectional test search against the Romania data.

        Args:
            method (func): Test search function.
            kwargs: Keyword arguments.

        Asserts:
            True if the path from the test search is equivalent to the
            reference search.
        """

        keys = self.romania.node.keys()
        triplets = itertools.permutations(keys, 3)
        for goals in triplets:
            self.romania.reset_search()
            path = method(self.romania, goals, **kwargs)
            path_len = self.sum_weight(self.romania, path)
            s1len, _ = self.reference_path(self.romania, goals[0], goals[1])
            s2len, _ = self.reference_path(self.romania, goals[2], goals[1])
            s3len, _ = self.reference_path(self.romania, goals[0], goals[2])
            min_len = min(s1len + s2len, s1len + s3len, s3len + s2len)

            if path_len != min_len:
                print (goals)

            self.assertEqual(min_len, path_len)
    
    def test_tri_ucs_romania(self):
        """Test Tri-UC search with Romania data."""

        self.run_romania_tri(tridirectional_search)