forked from networkx/networkx
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding tree broadcasting algorithm in a new module. (networkx#6928)
New functions to compute tree broadcast time for undirected graphs. Co-authored-by: Transurgeon <peter.zijie@gmail.com> Co-authored-by: Dan Schult <dschult@colgate.edu> Co-authored-by: Ross Barnowski <rossbar@berkeley.edu>
- Loading branch information
1 parent
8b30ff4
commit 98bb36c
Showing
5 changed files
with
246 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
************ | ||
Broadcasting | ||
************ | ||
|
||
.. automodule:: networkx.algorithms.broadcasting | ||
.. autosummary:: | ||
:toctree: generated/ | ||
|
||
tree_broadcast_center | ||
tree_broadcast_time |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ Algorithms | |
bipartite | ||
boundary | ||
bridges | ||
broadcasting | ||
centrality | ||
chains | ||
chordal | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
"""Routines to calculate the broadcast time of certain graphs. | ||
Broadcasting is an information dissemination problem in which a node in a graph, | ||
called the originator, must distribute a message to all other nodes by placing | ||
a series of calls along the edges of the graph. Once informed, other nodes aid | ||
the originator in distributing the message. | ||
The broadcasting must be completed as quickly as possible subject to the | ||
following constraints: | ||
- Each call requires one unit of time. | ||
- A node can only participate in one call per unit of time. | ||
- Each call only involves two adjacent nodes: a sender and a receiver. | ||
""" | ||
|
||
import networkx as nx | ||
from networkx import NetworkXError | ||
from networkx.utils import not_implemented_for | ||
|
||
__all__ = [ | ||
"tree_broadcast_center", | ||
"tree_broadcast_time", | ||
] | ||
|
||
|
||
def _get_max_broadcast_value(G, U, v, values): | ||
adj = sorted(set(G.neighbors(v)) & U, key=values.get, reverse=True) | ||
return max(values[u] + i for i, u in enumerate(adj, start=1)) | ||
|
||
|
||
def _get_broadcast_centers(G, v, values, target): | ||
adj = sorted(G.neighbors(v), key=values.get, reverse=True) | ||
j = next(i for i, u in enumerate(adj, start=1) if values[u] + i == target) | ||
return set([v] + adj[:j]) | ||
|
||
|
||
@not_implemented_for("directed") | ||
@not_implemented_for("multigraph") | ||
def tree_broadcast_center(G): | ||
"""Return the Broadcast Center of the tree `G`. | ||
The broadcast center of a graph G denotes the set of nodes having | ||
minimum broadcast time [1]_. This is a linear algorithm for determining | ||
the broadcast center of a tree with ``N`` nodes, as a by-product it also | ||
determines the broadcast time from the broadcast center. | ||
Parameters | ||
---------- | ||
G : undirected graph | ||
The graph should be an undirected tree | ||
Returns | ||
------- | ||
BC : (int, set) tuple | ||
minimum broadcast number of the tree, set of broadcast centers | ||
Raises | ||
------ | ||
NetworkXNotImplemented | ||
If the graph is directed or is a multigraph. | ||
References | ||
---------- | ||
.. [1] Slater, P.J., Cockayne, E.J., Hedetniemi, S.T, | ||
Information dissemination in trees. SIAM J.Comput. 10(4), 692–701 (1981) | ||
""" | ||
# Assert that the graph G is a tree | ||
if not nx.is_tree(G): | ||
NetworkXError("Input graph is not a tree") | ||
# step 0 | ||
if G.number_of_nodes() == 2: | ||
return 1, set(G.nodes()) | ||
if G.number_of_nodes() == 1: | ||
return 0, set(G.nodes()) | ||
|
||
# step 1 | ||
U = {node for node, deg in G.degree if deg == 1} | ||
values = {n: 0 for n in U} | ||
T = G.copy() | ||
T.remove_nodes_from(U) | ||
|
||
# step 2 | ||
W = {node for node, deg in T.degree if deg == 1} | ||
values.update((w, G.degree[w] - 1) for w in W) | ||
|
||
# step 3 | ||
while T.number_of_nodes() >= 2: | ||
# step 4 | ||
w = min(W, key=lambda n: values[n]) | ||
v = next(T.neighbors(w)) | ||
|
||
# step 5 | ||
U.add(w) | ||
W.remove(w) | ||
T.remove_node(w) | ||
|
||
# step 6 | ||
if T.degree(v) == 1: | ||
# update t(v) | ||
values.update({v: _get_max_broadcast_value(G, U, v, values)}) | ||
W.add(v) | ||
|
||
# step 7 | ||
v = nx.utils.arbitrary_element(T) | ||
b_T = _get_max_broadcast_value(G, U, v, values) | ||
return b_T, _get_broadcast_centers(G, v, values, b_T) | ||
|
||
|
||
@not_implemented_for("directed") | ||
@not_implemented_for("multigraph") | ||
def tree_broadcast_time(G, node=None): | ||
"""Return the Broadcast Time of the tree `G`. | ||
The minimum broadcast time of a node is defined as the minimum amount | ||
of time required to complete broadcasting starting from the | ||
originator. The broadcast time of a graph is the maximum over | ||
all nodes of the minimum broadcast time from that node [1]_. | ||
This function returns the minimum broadcast time of `node`. | ||
If `node` is None the broadcast time for the graph is returned. | ||
Parameters | ||
---------- | ||
G : undirected graph | ||
The graph should be an undirected tree | ||
node: int, optional | ||
index of starting node. If `None`, the algorithm returns the broadcast | ||
time of the tree. | ||
Returns | ||
------- | ||
BT : int | ||
Broadcast Time of a node in a tree | ||
Raises | ||
------ | ||
NetworkXNotImplemented | ||
If the graph is directed or is a multigraph. | ||
References | ||
---------- | ||
.. [1] Harutyunyan, H. A. and Li, Z. | ||
"A Simple Construction of Broadcast Graphs." | ||
In Computing and Combinatorics. COCOON 2019 | ||
(Ed. D. Z. Du and C. Tian.) Springer, pp. 240-253, 2019. | ||
""" | ||
b_T, b_C = tree_broadcast_center(G) | ||
if node is not None: | ||
return b_T + min(nx.shortest_path_length(G, node, u) for u in b_C) | ||
dist_from_center = dict.fromkeys(G, len(G)) | ||
for u in b_C: | ||
for v, dist in nx.shortest_path_length(G, u).items(): | ||
if dist < dist_from_center[v]: | ||
dist_from_center[v] = dist | ||
return b_T + max(dist_from_center.values()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
"""Unit tests for the broadcasting module.""" | ||
import math | ||
|
||
import networkx as nx | ||
|
||
|
||
def test_example_tree_broadcast(): | ||
""" | ||
Test the BROADCAST algorithm on the example in the paper titled: "Information Dissemination in Trees" | ||
""" | ||
edge_list = [ | ||
(0, 1), | ||
(1, 2), | ||
(2, 7), | ||
(3, 4), | ||
(5, 4), | ||
(4, 7), | ||
(6, 7), | ||
(7, 9), | ||
(8, 9), | ||
(9, 13), | ||
(13, 14), | ||
(14, 15), | ||
(14, 16), | ||
(14, 17), | ||
(13, 11), | ||
(11, 10), | ||
(11, 12), | ||
(13, 18), | ||
(18, 19), | ||
(18, 20), | ||
] | ||
G = nx.Graph(edge_list) | ||
b_T, b_C = nx.tree_broadcast_center(G) | ||
assert b_T == 6 | ||
assert b_C == {13, 9} | ||
# test broadcast time from specific vertex | ||
assert nx.tree_broadcast_time(G, 17) == 8 | ||
assert nx.tree_broadcast_time(G, 3) == 9 | ||
# test broadcast time of entire tree | ||
assert nx.tree_broadcast_time(G) == 10 | ||
|
||
|
||
def test_path_broadcast(): | ||
for i in range(2, 12): | ||
G = nx.path_graph(i) | ||
b_T, b_C = nx.tree_broadcast_center(G) | ||
assert b_T == math.ceil(i / 2) | ||
assert b_C == { | ||
math.ceil(i / 2), | ||
math.floor(i / 2), | ||
math.ceil(i / 2 - 1), | ||
math.floor(i / 2 - 1), | ||
} | ||
assert nx.tree_broadcast_time(G) == i - 1 | ||
|
||
|
||
def test_empty_graph_broadcast(): | ||
H = nx.empty_graph(1) | ||
b_T, b_C = nx.tree_broadcast_center(H) | ||
assert b_T == 0 | ||
assert b_C == {0} | ||
assert nx.tree_broadcast_time(H) == 0 | ||
|
||
|
||
def test_star_broadcast(): | ||
for i in range(4, 12): | ||
G = nx.star_graph(i) | ||
b_T, b_C = nx.tree_broadcast_center(G) | ||
assert b_T == i | ||
assert b_C == set(G.nodes()) | ||
assert nx.tree_broadcast_time(G) == b_T | ||
|
||
|
||
def test_binomial_tree_broadcast(): | ||
for i in range(2, 8): | ||
G = nx.binomial_tree(i) | ||
b_T, b_C = nx.tree_broadcast_center(G) | ||
assert b_T == i | ||
assert b_C == {0, 2 ** (i - 1)} | ||
assert nx.tree_broadcast_time(G) == 2 * i - 1 |