Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updated functions in core.py #7027

Merged
merged 9 commits into from
Nov 17, 2023
138 changes: 94 additions & 44 deletions networkx/algorithms/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

"""
import networkx as nx
from networkx.exception import NetworkXError
from networkx.exception import NetworkXNotImplemented
from networkx.utils import not_implemented_for

__all__ = [
Expand All @@ -46,7 +46,7 @@
@not_implemented_for("multigraph")
@nx._dispatch
def core_number(G):
"""Returns the core number for each vertex.
"""Returns the core number for each node.

A k-core is a maximal subgraph that contains nodes of degree k or more.

Expand All @@ -65,17 +65,27 @@ def core_number(G):

Raises
------
NetworkXError
The k-core is not implemented for graphs with self loops
or parallel edges.
NetworkXNotImplemented
The k-core is not implemented for graphs with self loops.
NetworkXNotImplemented
If `G` is a Multigraph.

Notes
-----
Not implemented for graphs with parallel edges or self loops.

For directed graphs the node degree is defined to be the
in-degree + out-degree.

Examples
--------
>>> degrees = [0, 1, 2, 2, 2, 2, 3]
>>> H = nx.havel_hakimi_graph(degrees)
>>> nx.core_number(H)
{0: 1, 1: 2, 2: 2, 3: 2, 4: 1, 5: 2, 6: 0}
>>> G = nx.DiGraph()
>>> G.add_edges_from([(1, 2), (2, 1), (2, 3), (2, 4), (3, 4), (4, 3)])
>>> nx.core_number(G)
{1: 2, 2: 2, 3: 2, 4: 2}

References
----------
.. [1] An O(m) Algorithm for Cores Decomposition of Networks
Expand All @@ -87,7 +97,7 @@ def core_number(G):
"Input graph has self loops which is not permitted; "
"Consider using G.remove_edges_from(nx.selfloop_edges(G))."
)
raise NetworkXError(msg)
raise NetworkXNotImplemented(msg)
degrees = dict(G.degree())
# Sort nodes by degree.
nodes = sorted(degrees, key=degrees.get)
Expand Down Expand Up @@ -153,7 +163,7 @@ def k_core(G, k=None, core_number=None):
G : NetworkX graph
A graph or directed graph
k : int, optional
The order of the core. If not specified return the main core.
The order of the core. If not specified return the main core.
core_number : dictionary, optional
Precomputed core numbers for the graph G.

Expand All @@ -164,20 +174,28 @@ def k_core(G, k=None, core_number=None):

Raises
------
NetworkXError
The k-core is not defined for graphs with self loops or parallel edges.
NetworkXNotImplemented
The k-core is not defined for graphs with self loops
or parallel edges.

Notes
-----
The main core is the core with the largest degree.

Not implemented for graphs with parallel edges or self loops.
The main core is the core with `k` as the largest core_number.

For directed graphs the node degree is defined to be the
in-degree + out-degree.

Graph, node, and edge attributes are copied to the subgraph.

Examples
--------
>>> degrees = [0, 1, 2, 2, 2, 2, 3]
>>> H = nx.havel_hakimi_graph(degrees)
>>> H.degree
DegreeView({0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 3, 6: 0})
>>> nx.k_core(H).nodes()
NodeView((1, 2, 3, 5))

See Also
--------
core_number
Expand Down Expand Up @@ -219,7 +237,7 @@ def k_shell(G, k=None, core_number=None):

Raises
------
NetworkXError
NetworkXNotImplemented
The k-shell is not implemented for graphs with self loops
or parallel edges.

Expand All @@ -228,13 +246,20 @@ def k_shell(G, k=None, core_number=None):
This is similar to k_corona but in that case only neighbors in the
k-core are considered.

Not implemented for graphs with parallel edges or self loops.

For directed graphs the node degree is defined to be the
in-degree + out-degree.

Graph, node, and edge attributes are copied to the subgraph.

Examples
--------
>>> degrees = [0, 1, 2, 2, 2, 2, 3]
>>> H = nx.havel_hakimi_graph(degrees)
>>> H.degree
DegreeView({0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 3, 6: 0})
>>> nx.k_shell(H, k=1).nodes()
NodeView((0, 4))

See Also
--------
core_number
Expand Down Expand Up @@ -267,7 +292,7 @@ def k_crust(G, k=None, core_number=None):
G : NetworkX graph
A graph or directed graph.
k : int, optional
The order of the shell. If not specified return the main crust.
The order of the shell. If not specified return the main crust.
core_number : dictionary, optional
Precomputed core numbers for the graph G.

Expand All @@ -278,7 +303,7 @@ def k_crust(G, k=None, core_number=None):

Raises
------
NetworkXError
NetworkXNotImplemented
The k-crust is not implemented for graphs with self loops
or parallel edges.

Expand All @@ -287,13 +312,20 @@ def k_crust(G, k=None, core_number=None):
This definition of k-crust is different than the definition in [1]_.
The k-crust in [1]_ is equivalent to the k+1 crust of this algorithm.

Not implemented for graphs with parallel edges or self loops.

For directed graphs the node degree is defined to be the
in-degree + out-degree.

Graph, node, and edge attributes are copied to the subgraph.

Examples
--------
>>> degrees = [0, 1, 2, 2, 2, 2, 3]
>>> H = nx.havel_hakimi_graph(degrees)
>>> H.degree
DegreeView({0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 3, 6: 0})
>>> nx.k_crust(H, k=1).nodes()
NodeView((0, 4, 6))

See Also
--------
core_number
Expand Down Expand Up @@ -338,19 +370,26 @@ def k_corona(G, k, core_number=None):

Raises
------
NetworkXError
The k-corona is not defined for graphs with self loops or
parallel edges.
NetworkXNotImplemented
The k-corona is not defined for graphs with self loops
or parallel edges.

Notes
-----
Not implemented for graphs with parallel edges or self loops.

For directed graphs the node degree is defined to be the
in-degree + out-degree.

Graph, node, and edge attributes are copied to the subgraph.

Examples
--------
>>> degrees = [0, 1, 2, 2, 2, 2, 3]
>>> H = nx.havel_hakimi_graph(degrees)
>>> H.degree
DegreeView({0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 3, 6: 0})
>>> nx.k_corona(H, k=2).nodes()
NodeView((1, 2, 3, 5))

See Also
--------
core_number
Expand Down Expand Up @@ -393,17 +432,15 @@ def k_truss(G, k):

Raises
------
NetworkXError

The k-truss is not defined for graphs with self loops, directed graphs
and multigraphs.
NetworkXNotImplemented
The k-truss is not defined for graphs with self loops.
NetworkXNotImplemented
If `G` is a Multigraph or Directed graph.

Notes
-----
A k-clique is a (k-2)-truss and a k-truss is a (k+1)-core.

Not implemented for digraphs or graphs with parallel edges or self loops.

Graph, node, and edge attributes are copied to the subgraph.

K-trusses were originally defined in [2] which states that the k-truss
Expand All @@ -412,6 +449,15 @@ def k_truss(G, k):
definition requiring that each edge belong to at least `k` triangles.
This implementation uses the original definition of `k-2` triangles.

Examples
--------
>>> degrees = [0, 1, 2, 2, 2, 2, 3]
>>> H = nx.havel_hakimi_graph(degrees)
>>> H.degree
DegreeView({0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 3, 6: 0})
>>> nx.k_truss(H, k=2).nodes()
NodeView((0, 1, 2, 3, 4, 5))

References
----------
.. [1] Bounds and Algorithms for k-truss. Paul Burkhardt, Vance Faber,
Expand All @@ -424,7 +470,7 @@ def k_truss(G, k):
"Input graph has self loops which is not permitted; "
"Consider using G.remove_edges_from(nx.selfloop_edges(G))."
)
raise NetworkXError(msg)
raise NetworkXNotImplemented(msg)

H = G.copy()

Expand Down Expand Up @@ -460,25 +506,29 @@ def onion_layers(G):
Parameters
----------
G : NetworkX graph
A simple graph without self loops or parallel edges
An undirected graph without self loops.

Returns
-------
od_layers : dictionary
A dictionary keyed by vertex to the onion layer. The layers are
A dictionary keyed by node to the onion layer. The layers are
contiguous integers starting at 1.

Raises
------
NetworkXError
The onion decomposition is not implemented for graphs with self loops
or parallel edges or for directed graphs.

Notes
-----
Not implemented for graphs with parallel edges or self loops.
NetworkXNotImplemented
The onion decomposition is not implemented for graphs with self loops.
NetworkXNotImplemented
If `G` is a Multigraph or Directed graph.

Not implemented for directed graphs.
Examples
--------
>>> degrees = [0, 1, 2, 2, 2, 2, 3]
>>> H = nx.havel_hakimi_graph(degrees)
>>> H.degree
DegreeView({0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 3, 6: 0})
>>> nx.onion_layers(H)
{6: 1, 0: 2, 4: 3, 1: 4, 2: 4, 3: 4, 5: 4}

See Also
--------
Expand All @@ -501,7 +551,7 @@ def onion_layers(G):
"Input graph contains self loops which is not permitted; "
"Consider using G.remove_edges_from(nx.selfloop_edges(G))."
)
raise NetworkXError(msg)
raise NetworkXNotImplemented(msg)
# Dictionaries to register the k-core/onion decompositions.
od_layers = {}
# Adjacency list
Expand Down
16 changes: 14 additions & 2 deletions networkx/algorithms/tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ def test_core_number2(self):
def test_core_number_self_loop(self):
G = nx.cycle_graph(3)
G.add_edge(0, 0)
with pytest.raises(nx.NetworkXError, match="Input graph has self loops"):
with pytest.raises(
nx.NetworkXNotImplemented, match="Input graph has self loops"
):
nx.core_number(G)

def test_directed_core_number(self):
Expand Down Expand Up @@ -166,6 +168,14 @@ def test_k_truss(self):
k_truss_subgraph = nx.k_truss(self.G, 5)
assert sorted(k_truss_subgraph.nodes()) == []

def test_k_truss_self_loop(self):
G = nx.cycle_graph(3)
G.add_edge(0, 0)
with pytest.raises(
nx.NetworkXNotImplemented, match="Input graph has self loops"
):
nx.k_truss(G, k=1)

def test_onion_layers(self):
layers = nx.onion_layers(self.G)
nodes_by_layer = [
Expand All @@ -181,5 +191,7 @@ def test_onion_layers(self):
def test_onion_self_loop(self):
G = nx.cycle_graph(3)
G.add_edge(0, 0)
with pytest.raises(nx.NetworkXError, match="Input graph contains self loops"):
with pytest.raises(
nx.NetworkXNotImplemented, match="Input graph contains self loops"
):
nx.onion_layers(G)