|
""" |
|
Provides functions for finding and testing for locally `(k, l)`-connected |
|
graphs. |
|
|
|
""" |
|
import copy |
|
|
|
import networkx as nx |
|
|
|
__all__ = ["kl_connected_subgraph", "is_kl_connected"] |
|
|
|
|
|
@nx._dispatchable(returns_graph=True) |
|
def kl_connected_subgraph(G, k, l, low_memory=False, same_as_graph=False): |
|
"""Returns the maximum locally `(k, l)`-connected subgraph of `G`. |
|
|
|
A graph is locally `(k, l)`-connected if for each edge `(u, v)` in the |
|
graph there are at least `l` edge-disjoint paths of length at most `k` |
|
joining `u` to `v`. |
|
|
|
Parameters |
|
---------- |
|
G : NetworkX graph |
|
The graph in which to find a maximum locally `(k, l)`-connected |
|
subgraph. |
|
|
|
k : integer |
|
The maximum length of paths to consider. A higher number means a looser |
|
connectivity requirement. |
|
|
|
l : integer |
|
The number of edge-disjoint paths. A higher number means a stricter |
|
connectivity requirement. |
|
|
|
low_memory : bool |
|
If this is True, this function uses an algorithm that uses slightly |
|
more time but less memory. |
|
|
|
same_as_graph : bool |
|
If True then return a tuple of the form `(H, is_same)`, |
|
where `H` is the maximum locally `(k, l)`-connected subgraph and |
|
`is_same` is a Boolean representing whether `G` is locally `(k, |
|
l)`-connected (and hence, whether `H` is simply a copy of the input |
|
graph `G`). |
|
|
|
Returns |
|
------- |
|
NetworkX graph or two-tuple |
|
If `same_as_graph` is True, then this function returns a |
|
two-tuple as described above. Otherwise, it returns only the maximum |
|
locally `(k, l)`-connected subgraph. |
|
|
|
See also |
|
-------- |
|
is_kl_connected |
|
|
|
References |
|
---------- |
|
.. [1] Chung, Fan and Linyuan Lu. "The Small World Phenomenon in Hybrid |
|
Power Law Graphs." *Complex Networks*. Springer Berlin Heidelberg, |
|
2004. 89--104. |
|
|
|
""" |
|
H = copy.deepcopy(G) |
|
|
|
graphOK = True |
|
deleted_some = True |
|
while deleted_some: |
|
deleted_some = False |
|
|
|
|
|
|
|
|
|
for edge in list(H.edges()): |
|
(u, v) = edge |
|
|
|
if low_memory: |
|
verts = {u, v} |
|
for i in range(k): |
|
for w in verts.copy(): |
|
verts.update(G[w]) |
|
G2 = G.subgraph(verts).copy() |
|
else: |
|
G2 = copy.deepcopy(G) |
|
|
|
path = [u, v] |
|
cnt = 0 |
|
accept = 0 |
|
while path: |
|
cnt += 1 |
|
if cnt >= l: |
|
accept = 1 |
|
break |
|
|
|
prev = u |
|
for w in path: |
|
if prev != w: |
|
G2.remove_edge(prev, w) |
|
prev = w |
|
|
|
try: |
|
path = nx.shortest_path(G2, u, v) |
|
except nx.NetworkXNoPath: |
|
path = False |
|
|
|
if accept == 0: |
|
H.remove_edge(u, v) |
|
deleted_some = True |
|
if graphOK: |
|
graphOK = False |
|
|
|
|
|
if same_as_graph: |
|
return (H, graphOK) |
|
return H |
|
|
|
|
|
@nx._dispatchable |
|
def is_kl_connected(G, k, l, low_memory=False): |
|
"""Returns True if and only if `G` is locally `(k, l)`-connected. |
|
|
|
A graph is locally `(k, l)`-connected if for each edge `(u, v)` in the |
|
graph there are at least `l` edge-disjoint paths of length at most `k` |
|
joining `u` to `v`. |
|
|
|
Parameters |
|
---------- |
|
G : NetworkX graph |
|
The graph to test for local `(k, l)`-connectedness. |
|
|
|
k : integer |
|
The maximum length of paths to consider. A higher number means a looser |
|
connectivity requirement. |
|
|
|
l : integer |
|
The number of edge-disjoint paths. A higher number means a stricter |
|
connectivity requirement. |
|
|
|
low_memory : bool |
|
If this is True, this function uses an algorithm that uses slightly |
|
more time but less memory. |
|
|
|
Returns |
|
------- |
|
bool |
|
Whether the graph is locally `(k, l)`-connected subgraph. |
|
|
|
See also |
|
-------- |
|
kl_connected_subgraph |
|
|
|
References |
|
---------- |
|
.. [1] Chung, Fan and Linyuan Lu. "The Small World Phenomenon in Hybrid |
|
Power Law Graphs." *Complex Networks*. Springer Berlin Heidelberg, |
|
2004. 89--104. |
|
|
|
""" |
|
graphOK = True |
|
for edge in G.edges(): |
|
(u, v) = edge |
|
|
|
if low_memory: |
|
verts = {u, v} |
|
for i in range(k): |
|
[verts.update(G.neighbors(w)) for w in verts.copy()] |
|
G2 = G.subgraph(verts) |
|
else: |
|
G2 = copy.deepcopy(G) |
|
|
|
path = [u, v] |
|
cnt = 0 |
|
accept = 0 |
|
while path: |
|
cnt += 1 |
|
if cnt >= l: |
|
accept = 1 |
|
break |
|
|
|
prev = u |
|
for w in path: |
|
if w != prev: |
|
G2.remove_edge(prev, w) |
|
prev = w |
|
|
|
try: |
|
path = nx.shortest_path(G2, u, v) |
|
except nx.NetworkXNoPath: |
|
path = False |
|
|
|
if accept == 0: |
|
graphOK = False |
|
break |
|
|
|
return graphOK |
|
|