Example #1
0
    def test_undirected_graph_vertex_already_exists(self):
        """ An undirected graph should not be able to add a vertex that already
            exists in the graph """
        g = UndirectedGraph()
        g.add_vertex(v_val='v0')

        with self.assertRaises(ValueError):
            g.add_vertex(v_val='v0')
Example #2
0
    def test_create_random_undirected_graph(self):
        """ Create an undirected graph with edges between random nodes """
        num_vertices = 10
        v_vals = ['v' + str(i) for i in xrange(num_vertices)]
        g_half = UndirectedGraph.random_graph(v_vals, 0.5)
        g_zero = UndirectedGraph.random_graph(v_vals, 0.0)
        g_one = UndirectedGraph.random_graph(v_vals, 1.0)

        max_edges = n_choose_2(num_vertices)
        self.assertEqual(g_half.num_vertices, num_vertices)
        self.assertEqual(g_zero.num_vertices, num_vertices)
        self.assertEqual(g_one.num_vertices, num_vertices)
        self.assertTrue(0 < g_half.num_edges < max_edges)
        self.assertEqual(g_zero.num_edges, 0)
        self.assertEqual(g_one.num_edges, max_edges)
Example #3
0
    def test_undirected_graph_is_connected(self):
        """ Get whether a path exists for every pair of vertices in an
            undirected graph """
        g_connected = UndirectedGraph.from_dict({'v0': [('v1',), ('v2',)],
                                                 'v1': [],
                                                 'v2': []})
        g_disconnected = UndirectedGraph.from_dict({'v0': [('v1',)],
                                                    'v1': [],
                                                    'v2': []})

        self.assertTrue(g_connected.is_connected)
        self.assertFalse(g_disconnected.is_connected)
        with self.assertRaises(AttributeError):
            g_connected.is_connected = False
        with self.assertRaises(AttributeError):
            g_disconnected.is_connected = True
Example #4
0
    def test_bad_undirected_graph_input(self):
        """ An undirected graph from_dict input must be of a certain form """
        graph_dict = {'v0': ['v1', {'weight': 3}],
                      'v1': [],
                      'v2': []}

        with self.assertRaises(ValueError):
            _ = UndirectedGraph.from_dict(graph_dict)
Example #5
0
    def test_create_complete_undirected_graph(self):
        """ Create an undirected graph with edges between all nodes """
        num_vertices = 10
        v_vals = ['v' + str(i) for i in xrange(num_vertices)]
        g = UndirectedGraph.complete_graph(v_vals)

        max_edges = n_choose_2(num_vertices)
        self.assertEqual(g.num_vertices, num_vertices)
        self.assertEqual(g.num_edges, max_edges)
Example #6
0
    def test_create_undirected_graph_from_lists(self):
        """ Create an undirected graph from lists of vertices and edges """
        vertices = [('v0', {'city': 'Paris'}),
                    (1, {'continent': 'Europe', 'city': 'London'}),
                    ((2, 2),),
                    ('v3',),
                    ('v4',)]
        edges = [(('v0', 1), {'weight': 3}),
                 (('v0', (2, 2)), {'weight': 4}),
                 ((1, 'v3'),)]
        g = UndirectedGraph.from_lists(vertices, edges)

        v0 = g.get_vertex('v0')
        v1 = g.get_vertex(1)
        v2 = g.get_vertex((2, 2))
        v3 = g.get_vertex('v3')
        v4 = g.get_vertex('v4')
        e01 = g.get_edge(('v0', 1))
        e02 = g.get_edge(('v0', (2, 2)))
        e13 = g.get_edge((1, 'v3'))
        self.assertEqual(g.num_vertices, 5)
        self.assertEqual(g.num_edges, 3)
        self.assertEqual(set(v0.neighbors), set([v1, v2]))
        self.assertEqual(set(v1.neighbors), set([v0, v3]))
        self.assertEqual(set(v2.neighbors), set([v0]))
        self.assertEqual(set(v3.neighbors), set([v1]))
        self.assertEqual(set(v4.neighbors), set())
        self.assertEqual(v0.get('city'), 'Paris')
        self.assertEqual(v1.get('continent'), 'Europe')
        self.assertEqual(v1.get('city'), 'London')
        self.assertIsNone(v2.get('city'))
        self.assertEqual(e01.get('weight'), 3)
        self.assertEqual(e02.get('weight'), 4)
        self.assertIsNone(e13.get('weight'))

        duplicate_vertices = [('v0_dupe',), ('v0_dupe',)]
        with self.assertRaises(ValueError):
            _ = UndirectedGraph.from_lists(duplicate_vertices, [])

        vertices_dupe_edge = [('v0_dupe_edge',), ('v1_dupe_edge',)]
        duplicate_edges = [(('v0_dupe_edge', 'v1_dupe_edge'),),
                           (('v1_dupe_edge', 'v0_dupe_edge'),)]
        with self.assertRaises(ValueError):
            _ = UndirectedGraph.from_lists(vertices_dupe_edge, duplicate_edges)
Example #7
0
    def test_undirected_graph_add_edge(self):
        """ Add edges to an undirected graph """
        g = UndirectedGraph()
        g.add_vertex(v_val='v0')
        g.add_vertex(v_val='v1')
        g.add_edge(('v0', 'v0'), attrs={'weight': 5})
        g.add_edge(('v0', 'v1'), attrs={'weight': 7})

        e00 = g.get_edge(('v0', 'v0'))
        e01 = g.get_edge(('v0', 'v1'))
        self.assertTrue(g.has_edge(('v0', 'v0')))
        self.assertTrue(g.has_edge(('v0', 'v1')))
        self.assertFalse(g.has_edge(('v0', 'v2')))
        self.assertTrue(g.has_edge(('v1', 'v0')))
        self.assertEqual(e00.get('weight'), 5)
        self.assertEqual(e01.get('weight'), 7)
Example #8
0
    def test_undirected_graph_vertices_and_edges(self):
        """ Get undirected graphs' vertices and edges properties """
        g = UndirectedGraph()
        g.add_vertex(v_val='v0')
        g.add_vertex(v_val='v1')
        g.add_edge(('v0', 'v1'))

        v0 = g.get_vertex('v0')
        v1 = g.get_vertex('v1')
        e01 = g.get_edge(('v0', 'v1'))
        self.assertEqual(set(g.vertices), set([v0, v1]))
        self.assertEqual(set(g.edges), set([e01]))
        with self.assertRaises(AttributeError):
            g.vertices = set()
        with self.assertRaises(AttributeError):
            g.edges = set()
Example #9
0
    def test_undirected_graph_average_degree(self):
        """ Get the average degree of all vertices in an undirected graph """
        g = UndirectedGraph.from_dict({'v0': [('v1',)],
                                       'v1': [],
                                       'v2': []})
        empty_g = UndirectedGraph()

        self.assertEqual(g.average_degree, 2.0 / 3.0)
        with self.assertRaises(AttributeError):
            g.average_degree = 0
        self.assertEqual(empty_g.average_degree, 0)
Example #10
0
    def test_undirected_graph_num_vertices_and_num_edges(self):
        """ Get the number of an undirected graph's vertices and edges """
        g = UndirectedGraph.from_dict({'v0': [('v1',)],
                                       'v1': []})

        self.assertEqual(g.num_vertices, 2)
        self.assertEqual(g.num_edges, 1)
        with self.assertRaises(AttributeError):
            g.num_vertices = 0
        with self.assertRaises(AttributeError):
            g.num_edges = 0
Example #11
0
    def test_create_undirected_graph_from_directed_graph(self):
        """ Create an undirected graph from a directed graph """
        graph_dict = {'v0': [('v0',), ('v1',), ('v2',)],
                      'v1': [('v0',), ('v3',)],
                      'v2': [],
                      'v3': [('v1',)],
                      'v4': []}
        dg = DirectedGraph.from_dict(graph_dict)
        g = UndirectedGraph.from_directed_graph(dg)

        self.assertEqual(g.num_vertices, 5)
        self.assertEqual(g.num_edges, 4)
Example #12
0
    def test_undirected_graph_edge_already_exists_exception(self):
        """ An undirected graph should not be able to add an edge that already
            exists in the graph """
        g = UndirectedGraph()
        g.add_vertex(v_val='v0')
        g.add_vertex(v_val='v1')
        g.add_edge(('v0', 'v1'))

        with self.assertRaises(ValueError):
            g.add_edge(('v1', 'v0'))
Example #13
0
    def test_create_undirected_graph_from_dict(self):
        """ Create an undirected graph from an adjacency dictionary """
        graph_dict = {'v0': [(1,), (1,), ((2, 2), {'weight': 5})],
                      1: [('v0',), ('v3',)],
                      (2, 2): [],
                      'v3': [],
                      'v4': []}
        vertex_attrs = {'v0': {'city': 'Paris'},
                        1: {'continent': 'Europe', 'city': 'London'},
                        'v5': {'city': 'Jamestown'}}
        g = UndirectedGraph.from_dict(graph_dict, vertex_attrs=vertex_attrs)

        v0 = g.get_vertex('v0')
        v1 = g.get_vertex(1)
        v2 = g.get_vertex((2, 2))
        v3 = g.get_vertex('v3')
        v4 = g.get_vertex('v4')
        v5 = g.get_vertex('v5')
        e01 = g.get_edge(('v0', 1))
        e02 = g.get_edge(('v0', (2, 2)))
        e13 = g.get_edge((1, 'v3'))
        self.assertEqual(g.num_vertices, 6)
        self.assertEqual(g.num_edges, 3)
        self.assertEqual(set(v0.neighbors), set([v1, v2]))
        self.assertEqual(set(v1.neighbors), set([v0, v3]))
        self.assertEqual(set(v2.neighbors), set([v0]))
        self.assertEqual(set(v3.neighbors), set([v1]))
        self.assertEqual(set(v4.neighbors), set())
        self.assertEqual(set(v5.neighbors), set())
        self.assertEqual(v0.get('city'), 'Paris')
        self.assertEqual(v1.get('continent'), 'Europe')
        self.assertEqual(v1.get('city'), 'London')
        self.assertEqual(v5.get('city'), 'Jamestown')
        self.assertIsNone(v2.get('city'))
        self.assertIsNone(e01.get('weight'))
        self.assertEqual(e02.get('weight'), 5)
        self.assertIsNone(e13.get('weight'))
        with self.assertRaises(ValueError):
            _ = UndirectedGraph.from_dict({'v0': [({'weight': 5},)],
                                           'v1': [({'weight': 3},)]})
Example #14
0
    def test_undirected_graph_length(self):
        """ Get the length of an undirected graph """
        g = UndirectedGraph()

        self.assertEqual(len(g), 0)

        g.add_vertex(v_val='v0')

        self.assertEqual(len(g), 1)

        g.add_vertex(v_val='v1')
        g.add_edge(('v0', 'v1'))

        self.assertEqual(len(g), 2)

        g.remove_vertex('v0')

        self.assertEqual(len(g), 1)
Example #15
0
    def test_undirected_graph_add_vertex(self):
        """ Add vertices to an undirected graph """
        g = UndirectedGraph()
        v0_val = g.add_vertex(v_val='v0', attrs={'city': 'Modena'})
        v1_val = g.add_vertex(v_val='v1')

        self.assertEqual(v0_val, 'v0')
        self.assertEqual(v1_val, 'v1')
        self.assertTrue(g.has_vertex('v0'))
        self.assertTrue(g.has_vertex('v1'))
        self.assertFalse(g.has_vertex('v2'))
        self.assertEqual(g.get_vertex(v0_val).get('city'), 'Modena')
        self.assertIsNone(g.get_vertex(v1_val).get('city'))
Example #16
0
    def test_undirected_graph_clone(self):
        """ Clone an undirected graph """
        vertices = [('v0', {'city': 'Paris'}),
                    ('v1', {'continent': 'Europe', 'city': 'London'}),
                    ('v2',),
                    ('v3',),
                    ('v4',)]
        edges = [(('v0', 'v0'), {'weight': 1}),
                 (('v0', 'v1'), {'weight': 3}),
                 (('v0', 'v2'), {'weight': 4}),
                 (('v1', 'v3'),)]
        g = UndirectedGraph.from_lists(vertices, edges)

        g_prime = g.clone()

        v0 = g.get_vertex('v0')
        v0_prime = g_prime.get_vertex('v0')
        e01 = g.get_edge(('v0', 'v1'))
        e01_prime = g_prime.get_edge(('v0', 'v1'))
        self.assertEqual(g_prime.num_vertices, g.num_vertices)
        self.assertEqual(g_prime.num_edges, g.num_edges)
        self.assertNotEqual(v0, v0_prime)
        self.assertNotEqual(e01, e01_prime)
        self.assertEqual(v0.attrs, v0_prime.attrs)

        g.add_vertex('v5', {'city': 'Jamestown'})

        self.assertTrue(g.has_vertex('v5'))
        self.assertFalse(g_prime.has_vertex('v5'))

        g.remove_vertex('v0')

        self.assertFalse(g.has_vertex('v0'))
        self.assertTrue(g_prime.has_vertex('v0'))
        self.assertFalse(g.has_edge(('v0', 'v1')))
        self.assertTrue(g_prime.has_edge(('v0', 'v1')))

        e01.set('weight', 5)

        self.assertEqual(e01.get('weight'), 5)
        self.assertEqual(e01_prime.get('weight'), 3)
Example #17
0
    def test_undirected_graph_iteration(self):
        """ Iterate through an undirected graph """
        g = UndirectedGraph()

        counter = 0
        for v in g:
            counter += 1
        self.assertEqual(counter, 0)

        g.add_vertex(v_val='v0')
        g.add_vertex(v_val='v1')
        g.add_edge(('v0', 'v1'))

        for v in g:
            counter += 1
            self.assertTrue(g.has_vertex(v.val))
        self.assertEqual(counter, 2)
Example #18
0
    def test_undirected_graph_remove_edge(self):
        """ Remove edges from an undirected graph """
        g = UndirectedGraph()
        g.add_vertex(v_val='v0')
        g.add_vertex(v_val='v1')
        g.add_vertex(v_val='v2')
        g.add_edge(('v0', 'v1'))
        g.add_edge(('v0', 'v2'))

        g.remove_edge(('v0', 'v1'))

        self.assertFalse(g.has_edge(('v0', 'v1')))
        self.assertFalse(g.has_edge(('v1', 'v0')))
        self.assertTrue(g.has_edge(('v0', 'v2')))

        g.remove_edge(('v0', 'v2'))

        self.assertFalse(g.has_edge(('v0', 'v1')))
        self.assertFalse(g.has_edge(('v1', 'v0')))
        self.assertFalse(g.has_edge(('v0', 'v2')))
Example #19
0
    def test_undirected_graph_dijkstra(self):
        """ Perform Dijkstra's algorithm on an undirected graph """

        """ 1_   E              1_   E
           | /                 | /
           A- 1 -B- 5 -D       A- 3 -B- 5 -D
             \   |               \   |
              2  0                2  -2
               \ |                 \ |
                 C                   C
        """
        g = UndirectedGraph()
        g.add_vertex(v_val='A')
        g.add_vertex(v_val='B')
        g.add_vertex(v_val='C')
        g.add_vertex(v_val='D')
        g.add_vertex(v_val='E')
        g.add_edge(('A', 'A'), attrs={'weight': 1})
        g.add_edge(('A', 'B'), attrs={'weight': 1})
        g.add_edge(('A', 'C'), attrs={'weight': 2})
        g.add_edge(('B', 'C'), attrs={'weight': 0})
        g.add_edge(('B', 'D'), attrs={'weight': 5})
        negative_weight_g = g.clone()
        negative_weight_g.get_edge(('A', 'B')).set('weight', 3)
        negative_weight_g.get_edge(('B', 'C')).set('weight', -2)
        missing_weight_g = g.clone()
        missing_weight_g.get_edge(('A', 'B')).set('weight', None)

        self.assertEqual(g.dijkstra('A', goal_val='A'), ['A'])
        self.assertEqual(g.dijkstra('A', goal_val='B'), ['A', 'B'])
        self.assertEqual(g.dijkstra('A', goal_val='C'), ['A', 'B', 'C'])
        self.assertEqual(g.dijkstra('A', goal_val='D'), ['A', 'B', 'D'])
        self.assertIsNone(g.dijkstra('A', goal_val='E'))
        # when returning all paths (no goal specified), paths aren't evaluated
        # until requested, to avoid the O(|V|^2) cost of backtracking |V| paths
        A_paths = g.dijkstra('A')
        # request each key
        _ = [A_paths[v.val] for v in g]
        self.assertEqual(dict(A_paths), {'A': ['A'],
                                         'B': ['A', 'B'],
                                         'C': ['A', 'B', 'C'],
                                         'D': ['A', 'B', 'D'],
                                         'E': None})
        self.assertEqual(g.dijkstra('A', goal_val='A', return_distances=True),
                         0)
        self.assertEqual(g.dijkstra('A', goal_val='B', return_distances=True),
                         1)
        self.assertEqual(g.dijkstra('A', goal_val='C', return_distances=True),
                         1)
        self.assertEqual(g.dijkstra('A', goal_val='D', return_distances=True),
                         6)
        self.assertEqual(g.dijkstra('A', goal_val='E', return_distances=True),
                         float('inf'))
        self.assertEqual(g.dijkstra('A', return_distances=True),
                         {'A': 0, 'B': 1, 'C': 1, 'D': 6, 'E': float('inf')})

        with self.assertRaises(ValueError):
            negative_weight_g.dijkstra('A')
        with self.assertRaises(ValueError):
            missing_weight_g.dijkstra('A')
Example #20
0
    def test_undirected_graph_search(self):
        """ Search for paths from an undirected vertex to all vertices reachable
            from it """

        """ __
           | /
           v0 - v1 - v3
             \
              v2
        """
        g = UndirectedGraph()
        g.add_vertex(v_val='v0')
        g.add_vertex(v_val='v1')
        g.add_vertex(v_val='v2')
        g.add_vertex(v_val='v3')
        g.add_vertex(v_val='v4')
        g.add_edge(('v0', 'v0'))
        g.add_edge(('v0', 'v1'))
        g.add_edge(('v0', 'v2'))
        g.add_edge(('v1', 'v3'))

        self.assertEqual(g.search('v0', goal_val='v0'), ['v0'])
        self.assertEqual(g.search('v0', goal_val='v1'), ['v0', 'v1'])
        self.assertEqual(g.search('v0', goal_val='v2'), ['v0', 'v2'])
        self.assertEqual(g.search('v0', goal_val='v3'), ['v0', 'v1', 'v3'])
        self.assertIsNone(g.search('v0', goal_val='v4'))
        self.assertEqual(g.search('v0'), {'v0': ['v0'],
                                          'v1': ['v0', 'v1'],
                                          'v2': ['v0', 'v2'],
                                          'v3': ['v0', 'v1', 'v3']})
        self.assertEqual(g.search('v0', goal_val='v0', method='depth_first'),
                         ['v0'])
        self.assertEqual(g.search('v0', goal_val='v1', method='depth_first'),
                         ['v0', 'v1'])
        self.assertEqual(g.search('v0', goal_val='v2', method='depth_first'),
                         ['v0', 'v2'])
        self.assertEqual(g.search('v0', goal_val='v3', method='depth_first'),
                         ['v0', 'v1', 'v3'])
        self.assertIsNone(g.search('v0', goal_val='v4', method='depth_first'))
        self.assertEqual(g.search('v0', method='depth_first'),
                         {'v0': ['v0'],
                          'v1': ['v0', 'v1'],
                          'v2': ['v0', 'v2'],
                          'v3': ['v0', 'v1', 'v3']})