Ejemplo n.º 1
0
class TestGraphIteration(UnittestPythonCompatibility):
    """
    Test methods for iteration over nodes and edges in a graph
    """

    def setUp(self):
        """
        Build default Graph with node and edge attributes
        """

        self.graph = Graph()
        self.graph.add_nodes([('g', {'weight': 1.0, 'value': 'gr'}), ('r', {'weight': 1.5, 'value': 'ra'}),
                              ('a', {'weight': 2.0, 'value': 'ap'}), ('p', {'weight': 2.5, 'value': 'ph'}),
                              ('h', {'weight': 3.0})])
        self.graph.add_edges([(1, 2), (2, 3), (3, 4), (3, 5), (4, 5)], value=True, weight=43.2, key='edge')

    def test_iterators_isgenerator(self):
        """
        Node and edge iterators return a generator
        """

        self.assertTrue(isinstance(self.graph.iternodes(), types.GeneratorType))
        self.assertTrue(isinstance(self.graph.iteredges(), types.GeneratorType))

    def test_iterators_iternodes(self):
        """
        Iternodes returns single node graphs based on sorted node ID which in
        case of auto_nid returns the nodes in the order they where added.
        """

        for i, n in enumerate(self.graph.iternodes(), start=1):
            self.assertIsInstance(n, Graph)
            self.assertEqual(n.nid, i)

        # The Graph '__iter__' magic method points to iternodes
        for i, n in enumerate(self.graph, start=1):
            self.assertIsInstance(n, Graph)
            self.assertEqual(n.nid, i)

    def test_iterators_iternodes_reversed(self):
        """
        Iterate over nodes in reversed order based on node ID
        """

        self.assertListEqual([n.nid for n in self.graph.iternodes(reverse=True)], [5, 4, 3, 2, 1])

    def test_iterators_iternodes_subgraph(self):
        """
        Iternodes on a subgraph will only iterate over the nodes in the subgraph
        """

        sub = self.graph.getnodes([1, 3, 4])
        self.assertEqual(len(sub), 3)
        self.assertEqual([n.nid for n in sub.iternodes()], [1, 3, 4])
        self.assertEqual([n.nid for n in sub], [1, 3, 4])

    def test_iterators_iteredges(self):
        """
        Iteredges returns single edge graphs based on sorted edge ID.
        """

        edges = []
        for e in self.graph.iteredges():
            self.assertIsInstance(e, Graph)
            edges.append(e.nid)

        self.assertListEqual(edges, [(1, 2), (2, 1), (2, 3), (3, 2), (3, 4), (3, 5), (4, 3), (4, 5), (5, 3), (5, 4)])

    def test_iterators_iteredges_reversed(self):
        """
        Iterate over edges in reversed order based on edge ID
        """

        self.assertListEqual([e.nid for e in self.graph.iteredges(reverse=True)],
                             [(5, 4), (5, 3), (4, 5), (4, 3), (3, 5), (3, 4), (3, 2), (2, 3), (2, 1), (1, 2)])
Ejemplo n.º 2
0
class TestGraphUndirectional(UnittestPythonCompatibility):
    """
    Test graph with undirected edges
    """
    def setUp(self):
        """
        Build undirected Graph
        """

        self.graph = Graph()
        self.graph.add_edges([(1, 2), (2, 3), (2, 4), (4, 5), (4, 3), (3, 5),
                              (3, 6)],
                             node_from_edge=True,
                             arg1=1.22,
                             arg2=False)

    def test_graph_is_undirected(self):

        self.assertFalse(self.graph.directed)
        self.assertEqual(graph_directionality(self.graph), 'undirectional')
        self.assertTrue(
            all([not edge.is_directed for edge in self.graph.iteredges()]))
        self.assertTrue(len(self.graph.edges) == 14)  # 2 * 7

    def test_graph_contains(self):
        """
        Test if pair of directed edges is contained in undirected edge
        """

        for edge in self.graph.edges:
            self.assertTrue(edge in self.graph.edges)
            self.assertTrue(tuple(reversed(edge)) in self.graph.edges)

    def test_graph_adjacency(self):
        """
        Node adjacency in a undirected graph reflects the pairs of directed
        edges that exists between nodes. This is also seen in the adjacency
        'link count' and 'degree' metrics for nodes.
        """

        # Number of edges equals the link count of the full node adjacency
        self.assertEqual(len(self.graph.edges),
                         self.graph.adjacency.link_count())

        # Undirected degree is bidirectional. It equals the number of
        # connected edges to a node
        degree = self.graph.adjacency.degree()
        for node in self.graph:
            self.assertEqual(degree[node.nid], len(node.connected_edges()))

    def test_graph_degree(self):
        """
        Total degree equals sum of equal inwards and outwards degree
        """

        degree = self.graph.adjacency.degree()
        indegree = self.graph.adjacency.degree(method='indegree')
        outdegree = self.graph.adjacency.degree(method='outdegree')

        self.assertDictEqual(indegree, outdegree)
        self.assertEqual(sum(indegree.values()) * 2, sum(degree.values()))

    def test_graph_edge_removal_undirected(self):
        """
        Undirected edge removal removes pair of directed edges
        """

        self.graph.remove_edge(2, 3)

        self.assertFalse((2, 3) in self.graph.edges)
        self.assertFalse((3, 2) in self.graph.edges)
        self.assertEqual(len(self.graph.edges), 12)

    def test_graph_edge_removal_directed(self):
        """
        Directed removal in a undirected graph is supported
        """

        self.graph.remove_edge(2, 3, directed=True)

        self.assertFalse((2, 3) in self.graph.edges)
        self.assertTrue((3, 2) in self.graph.edges)
        self.assertEqual(len(self.graph.edges), 13)

        # globally still marked as undirected but of mixed type
        self.assertFalse(self.graph.directed)
        self.assertEqual(graph_directionality(self.graph), 'mixed')

    def test_graph_edge_removal_directed_data_reference(self):
        """
        Test resolving data references after directed edge removal in a
        undirected graph to prevent orphan pointers
        """

        # Before removal values are referenced
        self.assertDictEqual(self.graph.edges[(2, 3)],
                             self.graph.edges[(2, 3)])
        self.assertEqual(id(self.graph.edges[(2, 3)]),
                         id(self.graph.edges[(2, 3)]))

        # Remove parent edge copies data to referencing edge
        self.graph.remove_edge(2, 3, directed=True)

        self.assertTrue(
            self.graph.edges._data_pointer_key not in self.graph.edges[(3, 2)])
        self.assertDictEqual(self.graph.edges[(3, 2)], {
            'arg1': 1.22,
            'arg2': False
        })

        # Remove referencing edge does not change anything
        self.graph.remove_edge(4, 2, directed=True)

        self.assertTrue(
            self.graph.edges._data_pointer_key not in self.graph.edges[(2, 4)])
        self.assertDictEqual(self.graph.edges[(2, 4)], {
            'arg1': 1.22,
            'arg2': False
        })

    def test_graph_undirectional_to_directional(self):
        """
        Test conversion of a undirectional to directional graph
        Conversion essentially breaks all linked edge pairs by removing the
        data reference pointer.
        """

        directional = graph_undirectional_to_directional(self.graph)

        # directed attribute changed to True
        self.assertTrue(directional.directed)
        self.assertNotEqual(id(directional), id(self.graph))

        # directional graph still contains same nodes and edges
        self.assertEqual(directional, self.graph)

        # data reference pointers determine directionality
        self.assertEqual(graph_directionality(directional), 'directional')
        self.assertEqual(
            graph_directionality(directional, has_data_reference=False),
            'undirectional')

        # directional edge pair no longer point to same value
        directional_checked = []
        for edge in directional.edges:
            directional_checked.append(
                id(directional.edges[edge]) != id(directional.edges[(
                    edge[1], edge[0])]))
        self.assertTrue(all(directional_checked))

    def test_graph_undirected_linked_values(self):
        """
        Test setting and getting linked edge data
        """

        self.graph.edges[(2, 3)]['test'] = True

        # In storage backend only one edge of the pair has the data
        self.assertTrue('test' in self.graph.edges._storage[(2, 3)])
        self.assertFalse('test' in self.graph.edges._storage[(3, 2)])

        # transparent getting and setting of linked data
        self.assertTrue(self.graph.edges[(2, 3)]['test'])
        self.assertTrue(self.graph.edges[(3, 2)]['test'])

        self.graph.edges[(3, 2)]['test'] = False
        self.assertFalse(self.graph.edges[(2, 3)]['test'])
        self.assertFalse(self.graph.edges[(3, 2)]['test'])
Ejemplo n.º 3
0
class TestGraphMixed(UnittestPythonCompatibility):
    """
    Test graph with mixed directed and undirected edges

        1 - 2 - 3 - 6
            | / |
            4 - 5
    """
    def setUp(self):
        """
        Build mixed directed and undirected Graph
        """

        self.graph = Graph(directed=True)
        self.graph.add_edges([(1, 2), (2, 3), (3, 2), (3, 6), (3, 5), (5, 4),
                              (4, 5), (4, 2)],
                             node_from_edge=True,
                             arg1=1.22,
                             arg2=False)
        self.graph.add_edge(3,
                            4,
                            directed=False,
                            node_from_edge=True,
                            arg1=1.22,
                            arg2=False)

        for i, edge in enumerate(self.graph.iteredges()):
            edge['nd'] = i

    def test_graph_is_mixed(self):

        self.assertTrue(self.graph.directed)
        self.assertEqual(graph_directionality(self.graph), 'mixed')
        self.assertEqual(
            sum([1 for edge in self.graph.iteredges() if edge.is_directed]), 4)
        self.assertEqual(
            sum([1 for edge in self.graph.iteredges()
                 if not edge.is_directed]), 6)
        self.assertTrue(len(self.graph.edges) == 10)

    def test_graph_contains(self):
        """
        Test a mix of directed and undirected (pairs) edges
        """

        directed = [edge.is_directed for edge in self.graph.iteredges()]
        self.assertEqual(
            directed,
            [True, False, False, False, True, True, True, False, False, False])

    def test_graph_directional_to_undirectional(self):
        """
        Test conversion of a directional to undirectional graph
        """

        undirectional = graph_directional_to_undirectional(self.graph)

        # directed attribute changed to True
        self.assertFalse(undirectional.directed)
        self.assertNotEqual(undirectional, self.graph)

        # data reference pointers determine directionality
        self.assertEqual(graph_directionality(undirectional), 'undirectional')
        self.assertEqual(
            graph_directionality(undirectional, has_data_reference=False),
            'undirectional')

        # all edges exist in pairs resulting duplicated values
        values = undirectional.edges(data='nd').values()
        self.assertEqual(len(values), len(set(values)) * 2)
Ejemplo n.º 4
0
class TestGraphDirectional(UnittestPythonCompatibility):
    """
    Test graph with directed edges

        1 - 2 - 3 - 6
            | / |
            4 - 5
    """
    def setUp(self):
        """
        Build directed Graph
        """

        self.graph = Graph(directed=True)
        self.graph.add_edges([(1, 2), (2, 3), (3, 6), (3, 5), (5, 4), (4, 3),
                              (4, 2)],
                             node_from_edge=True,
                             arg1=1.22,
                             arg2=False)
        self.graph.edges[(3, 6)]['arg1'] = 2.44
        self.graph.edges[(5, 4)]['arg3'] = 'test'

    def test_graph_is_directed(self):

        self.assertTrue(self.graph.directed)
        self.assertEqual(graph_directionality(self.graph), 'directional')
        self.assertTrue(
            all([edge.is_directed for edge in self.graph.iteredges()]))
        self.assertTrue(len(self.graph.edges) == 7)

    def test_graph_contains(self):
        """
        Only forward edge present
        """

        for edge in self.graph.edges:
            self.assertTrue(edge in self.graph.edges)
            self.assertFalse(tuple(reversed(edge)) in self.graph.edges)

    def test_graph_adjacency(self):
        """
        Node adjacency in a directed graph reflects the presence of only a
        forward edge connecting nodes. This is also seen in the adjacency
        'link count' and 'degree' metrics for nodes.
        """

        # Number of edges equals the link count of the full node adjacency
        self.assertEqual(len(self.graph.edges),
                         self.graph.adjacency.link_count())

        # Directed degree is unidirectional. It equals the number of
        # connected edges to a node
        degree = self.graph.adjacency.degree()
        for node in self.graph:
            self.assertEqual(degree[node.nid], len(node.connected_edges()))

    def test_graph_degree(self):
        """
        The total degree equals the sum of inwards and outwards degrees but the
        latter two are not equals
        """

        degree = self.graph.adjacency.degree()
        indegree = self.graph.adjacency.degree(method='indegree')
        outdegree = self.graph.adjacency.degree(method='outdegree')

        self.assertEqual(sum(degree.values()),
                         sum(indegree.values()) + sum(outdegree.values()))
        self.assertNotEqual(indegree, outdegree)

    def test_graph_directional_to_undirectional(self):
        """
        Test conversion of a directional to undirectional graph
        """

        undirectional = graph_directional_to_undirectional(self.graph)

        # directed attribute changed to True
        self.assertFalse(undirectional.directed)
        self.assertNotEqual(undirectional, self.graph)

        # data reference pointers determine directionality
        self.assertEqual(graph_directionality(undirectional), 'undirectional')
        self.assertEqual(
            graph_directionality(undirectional, has_data_reference=False),
            'undirectional')

        # directional edge pair point to same value
        undirectional_checked = []
        for edge in undirectional.edges:
            undirectional_checked.append(
                id(undirectional.edges[edge]) == id(undirectional.edges[(
                    edge[1], edge[0])]))
        self.assertTrue(all(undirectional_checked))

        # edge argument equality
        self.assertDictEqual(undirectional.edges[(3, 6)], {
            'arg1': 2.44,
            'arg2': False
        })
        self.assertDictEqual(undirectional.edges[(6, 3)], {
            'arg1': 2.44,
            'arg2': False
        })
        self.assertDictEqual(undirectional.edges[(5, 4)], {
            'arg1': 1.22,
            'arg2': False,
            'arg3': 'test'
        })
        self.assertDictEqual(undirectional.edges[(4, 5)], {
            'arg1': 1.22,
            'arg2': False,
            'arg3': 'test'
        })