Esempio n. 1
0
def _compute_rc(G):
    """Returns the rich-club coefficient for each degree in the graph
    `G`.

    `G` is an undirected graph without multiedges.

    Returns a dictionary mapping degree to rich-club coefficient for
    that degree.

    """
    deghist = nx.degree_histogram(G)
    total = sum(deghist)
    # Compute the number of nodes with degree greater than `k`, for each
    # degree `k` (omitting the last entry, which is zero).
    nks = (total - cs for cs in accumulate(deghist) if total - cs > 1)
    # Create a sorted list of pairs of edge endpoint degrees.
    #
    # The list is sorted in reverse order so that we can pop from the
    # right side of the list later, instead of popping from the left
    # side of the list, which would have a linear time cost.
    edge_degrees = sorted((sorted(map(G.degree, e)) for e in G.edges()),
                          reverse=True)
    ek = G.number_of_edges()
    k1, k2 = edge_degrees.pop()
    rc = {}
    for d, nk in enumerate(nks):
        while k1 <= d:
            if len(edge_degrees) == 0:
                ek = 0
                break
            k1, k2 = edge_degrees.pop()
            ek -= 1
        rc[d] = 2 * ek / (nk * (nk - 1))
    return rc
Esempio n. 2
0
def _compute_rc(G):
    """Returns the rich-club coefficient for each degree in the graph
    `G`.

    `G` is an undirected graph without multiedges.

    Returns a dictionary mapping degree to rich-club coefficient for
    that degree.

    """
    deghist = nx.degree_histogram(G)
    total = sum(deghist)
    # Compute the number of nodes with degree greater than `k`, for each
    # degree `k` (omitting the last entry, which is zero).
    nks = (total - cs for cs in accumulate(deghist) if total - cs > 1)
    # Create a sorted list of pairs of edge endpoint degrees.
    #
    # The list is sorted in reverse order so that we can pop from the
    # right side of the list later, instead of popping from the left
    # side of the list, which would have a linear time cost.
    edge_degrees = sorted((sorted(map(G.degree, e)) for e in G.edges()),
                          reverse=True)
    ek = G.number_of_edges()
    k1, k2 = edge_degrees.pop()
    rc = {}
    for d, nk in enumerate(nks):
        while k1 <= d:
            if len(edge_degrees) == 0:
                ek = 0
                break
            k1, k2 = edge_degrees.pop()
            ek -= 1
        rc[d] = 2 * ek / (nk * (nk - 1))
    return rc
Esempio n. 3
0
def _compute_rc(G):
    from networkx.utils import accumulate
    deghist = nx.degree_histogram(G)
    total = sum(deghist)
    # Compute the number of nodes with degree greater than `k`, for each
    # degree `k` (omitting the last entry, which is zero).
    nks = (total - cs for cs in accumulate(deghist) if total - cs > 1)
    # Create a sorted list of pairs of edge endpoint degrees.
    #
    # The list is sorted in reverse order so that we can pop from the
    # right side of the list later, instead of popping from the left
    # side of the list, which would have a linear time cost.
    edge_degrees = sorted((sorted(map(G.degree, e)) for e in G.edges()),
                          reverse=True)
    ek = G.number_of_edges()
    k1, k2 = edge_degrees.pop()
    rc = {}
    for d, nk in enumerate(nks):
        while k1 <= d:
            if len(edge_degrees) == 0:
                ek = 0
                break
            k1, k2 = edge_degrees.pop()
            ek -= 1
        rc[d] = 2 * ek / (nk * (nk - 1))
    return rc
Esempio n. 4
0
def _compute_rc_vic(G):
    deghist = nx.degree_histogram(G)
    total = sum(deghist)
    nks = (total - cs for cs in accumulate(deghist) if total - cs > 1)
    edge_degrees = sorted((sorted(map(G.degree, e)) for e in G.edges()),
                          reverse=True)
    ek = G.number_of_edges()
    k1, k2 = edge_degrees.pop()
    rc = {}
    for d, nk in enumerate(nks):
        while k1 <= d:
            if len(edge_degrees) == 0:
                ek = 0
                break
            k1, k2 = edge_degrees.pop()
            ek -= 1
        rc[d] = 2 * ek / (nk * (nk - 1))
    return rc
Esempio n. 5
0
def complete_multipartite_graph(*block_sizes):
    """Returns the complete multipartite graph with the specified block sizes.

    Parameters
    ----------
    block_sizes : tuple of integers or tuple of node iterables
       The arguments can either all be integer number of nodes or they
       can all be iterables of nodes. If integers, they represent the
       number of vertices in each block of the multipartite graph.
       If iterables, each is used to create the nodes for that block.
       The length of block_sizes is the number of blocks.

    Returns
    -------
    G : NetworkX Graph
       Returns the complete multipartite graph with the specified blocks.

       For each node, the node attribute 'block' is an integer
       indicating which block contains the node.

    Examples
    --------
    Creating a complete tripartite graph, with blocks of one, two, and three
    vertices, respectively.

        >>> import networkx as nx
        >>> G = nx.complete_multipartite_graph(1, 2, 3)
        >>> [G.node[u]['block'] for u in G]
        [0, 1, 1, 2, 2, 2]
        >>> list(G.edges(0))
        [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)]
        >>> list(G.edges(2))
        [(2, 0), (2, 3), (2, 4), (2, 5)]
        >>> list(G.edges(4))
        [(4, 0), (4, 1), (4, 2)]

        >>> G = nx.complete_multipartite_graph('a', 'bc', 'def')
        >>> [G.node[u]['block'] for u in sorted(G)]
        [0, 1, 1, 2, 2, 2]

    Notes
    -----
    This function generalizes several other graph generator functions.

    - If no block sizes are given, this returns the null graph.
    - If a single block size `n` is given, this returns the empty graph on
      `n` nodes.
    - If two block sizes `m` and `n` are given, this returns the complete
      bipartite graph on `m + n` nodes.
    - If block sizes `1` and `n` are given, this returns the star graph on
      `n + 1` nodes.

    See also
    --------
    complete_bipartite_graph
    """
    # The complete multipartite graph is an undirected simple graph.
    G = nx.Graph()
    G.name = 'complete_multiparite_graph{}'.format(block_sizes)

    if len(block_sizes) == 0:
        return G

    # set up blocks of nodes
    try:
        extents = pairwise(accumulate((0,) + block_sizes))
        blocks = [range(start, end) for start, end in extents]
    except TypeError:
        blocks = block_sizes

    # add nodes with block attribute
    # while checking that ints are not mixed with iterables
    try:
        for (i, block) in enumerate(blocks):
            G.add_nodes_from(block, block=i)
    except TypeError:
        raise nx.NetworkXError("Arguments must be all ints or all iterables")

    # Across blocks, all vertices should be adjacent.
    # We can use itertools.combinations() because undirected.
    for block1, block2 in itertools.combinations(blocks, 2):
        G.add_edges_from(itertools.product(block1, block2))
    return G
Esempio n. 6
0
def complete_multipartite_graph(*block_sizes):
    """Returns the complete multipartite graph with the specified block sizes.

    Parameters
    ----------

    block_sizes : tuple of integers

       The number of vertices in each block of the multipartite graph. The
       length of this tuple is the number of blocks.

    Returns
    -------

    G : NetworkX Graph

       Returns the complete multipartite graph with the specified block sizes.

       For each node, the node attribute ``'block'`` is an integer indicating
       which block contains the node.

    Examples
    --------

    Creating a complete tripartite graph, with blocks of one, two, and three
    vertices, respectively.

        >>> import networkx as nx
        >>> G = nx.complete_multipartite_graph(1, 2, 3)
        >>> [G.node[u]['block'] for u in G]
        [0, 1, 1, 2, 2, 2]
        >>> G.edges(0)
        [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)]
        >>> G.edges(2)
        [(2, 0), (2, 3), (2, 4), (2, 5)]
        >>> G.edges(4)
        [(4, 0), (4, 1), (4, 2)]

    Notes
    -----

    This function generalizes several other graph generator functions.

    - If no block sizes are given, this returns the null graph.
    - If a single block size ``n`` is given, this returns the empty graph on
      ``n`` nodes.
    - If two block sizes ``m`` and ``n`` are given, this returns the complete
      bipartite graph on ``m + n`` nodes.
    - If block sizes ``1`` and ``n`` are given, this returns the star graph on
      ``n + 1`` nodes.

    See also
    --------

    complete_bipartite_graph

    """
    G = nx.empty_graph(sum(block_sizes))
    # If block_sizes is (n1, n2, n3, ...), create pairs of the form (0, n1),
    # (n1, n1 + n2), (n1 + n2, n1 + n2 + n3), etc.
    extents = zip([0] + list(accumulate(block_sizes)), accumulate(block_sizes))
    blocks = [range(start, end) for start, end in extents]
    for (i, block) in enumerate(blocks):
        G.add_nodes_from(block, block=i)
    # Across blocks, all vertices should be adjacent. We can use
    # itertools.combinations() because the complete multipartite graph is an
    # undirected graph.
    for block1, block2 in itertools.combinations(blocks, 2):
        G.add_edges_from(itertools.product(block1, block2))
    G.name = 'complete_multiparite_graph{0}'.format(block_sizes)
    return G
Esempio n. 7
0
def join(rooted_trees, label_attribute=None):
    """Returns a new rooted tree with a root node joined with the roots
    of each of the given rooted trees.

    Parameters
    ----------
    rooted_trees : list
        A list of pairs in which each left element is a NetworkX graph
        object representing a tree and each right element is the root
        node of that tree. The nodes of these trees will be relabeled to
        integers.

    label_attribute : str
        If provided, the old node labels will be stored in the new tree
        under this node attribute. If not provided, the node attribute
        ``'_old'`` will store the original label of the node in the
        rooted trees given in the input.

    Returns
    -------
    NetworkX graph
        The rooted tree whose subtrees are the given rooted trees. The
        new root node is labeled 0. Each non-root node has an attribute,
        as described under the keyword argument ``label_attribute``,
        that indicates the label of the original node in the input tree.

    Notes
    -----
    Graph, edge, and node attributes are propagated from the given
    rooted trees to the created tree. If there are any overlapping graph
    attributes, those from later trees will overwrite those from earlier
    trees in the tuple of positional arguments.

    Examples
    --------
    Join two full balanced binary trees of height *h* to get a full
    balanced binary tree of depth *h* + 1::

        >>> h = 4
        >>> left = nx.balanced_tree(2, h)
        >>> right = nx.balanced_tree(2, h)
        >>> joined_tree = nx.join([(left, 0), (right, 0)])
        >>> nx.is_isomorphic(joined_tree, nx.balanced_tree(2, h + 1))
        True

    """
    if len(rooted_trees) == 0:
        return nx.empty_graph(1)

    # Unzip the zipped list of (tree, root) pairs.
    trees, roots = zip(*rooted_trees)

    # The join of the trees has the same type as the type of the first
    # tree.
    R = type(trees[0])()

    # Relabel the nodes so that their union is the integers starting at 1.
    if label_attribute is None:
        label_attribute = '_old'
    relabel = partial(nx.convert_node_labels_to_integers,
                      label_attribute=label_attribute)
    lengths = (len(tree) for tree in trees[:-1])
    first_labels = chain([0], accumulate(lengths))
    trees = [
        relabel(tree, first_label=first_label + 1)
        for tree, first_label in zip(trees, first_labels)
    ]

    # Get the relabeled roots.
    roots = [
        next(v for v, d in tree.nodes(data=True) if d.get('_old') == root)
        for tree, root in zip(trees, roots)
    ]

    # Remove the old node labels.
    for tree in trees:
        for v in tree:
            tree.nodes[v].pop('_old')

    # Add all sets of nodes and edges, with data.
    nodes = (tree.nodes(data=True) for tree in trees)
    edges = (tree.edges(data=True) for tree in trees)
    R.add_nodes_from(chain.from_iterable(nodes))
    R.add_edges_from(chain.from_iterable(edges))

    # Add graph attributes; later attributes take precedent over earlier
    # attributes.
    for tree in trees:
        R.graph.update(tree.graph)

    # Finally, join the subtrees at the root. We know 0 is unused by the
    # way we relabeled the subtrees.
    R.add_node(0)
    R.add_edges_from((0, root) for root in roots)

    return R
Esempio n. 8
0
def join(rooted_trees, label_attribute=None):
    """Returns a new rooted tree with a root node joined with the roots
    of each of the given rooted trees.

    Parameters
    ----------
    rooted_trees : list
        A list of pairs in which each left element is a NetworkX graph
        object representing a tree and each right element is the root
        node of that tree. The nodes of these trees will be relabeled to
        integers.

    label_attribute : str
        If provided, the old node labels will be stored in the new tree
        under this node attribute. If not provided, the node attribute
        ``'_old'`` will store the original label of the node in the
        rooted trees given in the input.

    Returns
    -------
    NetworkX graph
        The rooted tree whose subtrees are the given rooted trees. The
        new root node is labeled 0. Each non-root node has an attribute,
        as described under the keyword argument ``label_attribute``,
        that indicates the label of the original node in the input tree.

    Notes
    -----
    Graph, edge, and node attributes are propagated from the given
    rooted trees to the created tree. If there are any overlapping graph
    attributes, those from later trees will overwrite those from earlier
    trees in the tuple of positional arguments.

    Examples
    --------
    Join two full balanced binary trees of height *h* to get a full
    balanced binary tree of depth *h* + 1::

        >>> h = 4
        >>> left = nx.balanced_tree(2, h)
        >>> right = nx.balanced_tree(2, h)
        >>> joined_tree = nx.join([(left, 0), (right, 0)])
        >>> nx.is_isomorphic(joined_tree, nx.balanced_tree(2, h + 1))
        True

    """
    if len(rooted_trees) == 0:
        return nx.empty_graph(1)

    # Unzip the zipped list of (tree, root) pairs.
    trees, roots = zip(*rooted_trees)

    # The join of the trees has the same type as the type of the first
    # tree.
    R = type(trees[0])()

    # Relabel the nodes so that their union is the integers starting at 1.
    if label_attribute is None:
        label_attribute = '_old'
    relabel = partial(nx.convert_node_labels_to_integers,
                      label_attribute=label_attribute)
    lengths = (len(tree) for tree in trees[:-1])
    first_labels = chain([0], accumulate(lengths))
    trees = [relabel(tree, first_label=first_label + 1)
             for tree, first_label in zip(trees, first_labels)]

    # Get the relabeled roots.
    roots = [next(v for v, d in tree.nodes(data=True) if d.get('_old') == root)
             for tree, root in zip(trees, roots)]

    # Remove the old node labels.
    for tree in trees:
        for v in tree:
            tree.node[v].pop('_old')

    # Add all sets of nodes and edges, with data.
    nodes = (tree.nodes(data=True) for tree in trees)
    edges = (tree.edges(data=True) for tree in trees)
    R.add_nodes_from(chain.from_iterable(nodes))
    R.add_edges_from(chain.from_iterable(edges))

    # Add graph attributes; later attributes take precedent over earlier
    # attributes.
    for tree in trees:
        R.graph.update(tree.graph)

    # Finally, join the subtrees at the root. We know 0 is unused by the
    # way we relabeled the subtrees.
    R.add_node(0)
    R.add_edges_from((0, root) for root in roots)

    return R
Esempio n. 9
0
def complete_multipartite_graph(*block_sizes):
    """Returns the complete multipartite graph with the specified block sizes.

    Parameters
    ----------

    block_sizes : tuple of integers

       The number of vertices in each block of the multipartite graph. The
       length of this tuple is the number of blocks.

    Returns
    -------

    G : NetworkX Graph

       Returns the complete multipartite graph with the specified block sizes.

       For each node, the node attribute ``'block'`` is an integer indicating
       which block contains the node.

    Examples
    --------

    Creating a complete tripartite graph, with blocks of one, two, and three
    vertices, respectively.

        >>> import networkx as nx
        >>> G = nx.complete_multipartite_graph(1, 2, 3)
        >>> [G.node[u]['block'] for u in G]
        [0, 1, 1, 2, 2, 2]
        >>> G.edges(0)
        [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)]
        >>> G.edges(2)
        [(2, 0), (2, 3), (2, 4), (2, 5)]
        >>> G.edges(4)
        [(4, 0), (4, 1), (4, 2)]

    Notes
    -----

    This function generalizes several other graph generator functions.

    - If no block sizes are given, this returns the null graph.
    - If a single block size ``n`` is given, this returns the empty graph on
      ``n`` nodes.
    - If two block sizes ``m`` and ``n`` are given, this returns the complete
      bipartite graph on ``m + n`` nodes.
    - If block sizes ``1`` and ``n`` are given, this returns the star graph on
      ``n + 1`` nodes.

    See also
    --------

    complete_bipartite_graph

    """
    G = nx.empty_graph(sum(block_sizes))
    # If block_sizes is (n1, n2, n3, ...), create pairs of the form (0, n1),
    # (n1, n1 + n2), (n1 + n2, n1 + n2 + n3), etc.
    extents = zip([0] + list(accumulate(block_sizes)), accumulate(block_sizes))
    blocks = [range(start, end) for start, end in extents]
    for (i, block) in enumerate(blocks):
        G.add_nodes_from(block, block=i)
    # Across blocks, all vertices should be adjacent. We can use
    # itertools.combinations() because the complete multipartite graph is an
    # undirected graph.
    for block1, block2 in itertools.combinations(blocks, 2):
        G.add_edges_from(itertools.product(block1, block2))
    G.name = 'complete_multiparite_graph{0}'.format(block_sizes)
    return G