From d677a4c78d32b4652b66fcdaf2430f99dd90c89c Mon Sep 17 00:00:00 2001 From: 0xFugue <119708655+0xFugue@users.noreply.github.com> Date: Thu, 22 Dec 2022 23:55:48 +0530 Subject: [PATCH] Tweaks (#2) * added scalefree/newman_watts_strogatz models, fixed a bug * Readme * Readme * added PR2 suggestions --- Readme.md | 2 +- generate_network.py | 136 ++++++++++++++++++++++++++------------------ topology.json | 1 - topology.png | Bin 2396 -> 0 bytes 4 files changed, 83 insertions(+), 56 deletions(-) delete mode 100755 topology.json delete mode 100755 topology.png diff --git a/Readme.md b/Readme.md index 903056e..a1de36e 100644 --- a/Readme.md +++ b/Readme.md @@ -27,7 +27,7 @@ gen_jsons.sh can generate given number of Waku networs and outputs them to a dir > usage: ./gen_jsons.sh <#json files needed>
## generate_network.py -generate_network.py can generate networks with specified number of nodes and topics. the network types currently supported is "configuration_model" and more are on the way. Use with Python3. +generate_network.py can generate networks with specified number of nodes and topics. the network types currently supported is "configuration_model" and more are on the way. Use with Python3. Comment out the `#draw(fname, H)` line to visualise the generated graph. > usage: generate_network [-h] [-o ] [-n <#nodes>] [-t <#topics>] [-T ]
diff --git a/generate_network.py b/generate_network.py index 3e65ce6..67a0896 100755 --- a/generate_network.py +++ b/generate_network.py @@ -1,34 +1,40 @@ #! /usr/bin/env python3 -import matplotlib.pyplot as mp +import matplotlib.pyplot as plt import networkx as nx -import networkx.readwrite.json_graph import random, math import json -import argparse,sys +import argparse, os, sys +# Dump to a json file def write_json(filename, data_2_dump): json.dump(data_2_dump, open(filename,'w'), indent=2) + # has trouble with non-integer/non-hashable keys def read_json(filename): with open(filename) as f: jdata = json.load(f) return nx.node_link_graph(jdata) -def draw(H): - nx.draw(H, pos=nx.kamada_kawai_layout(H), with_labels=True) - mp.show() - mp.savefig("topology.png", format="PNG") -def init_arg_parser() : - # Initialize parser, add arguments and set the defaults +# Draw the network and output the image to a file +def draw(fname, H): + nx.draw(H, pos=nx.kamada_kawai_layout(H), with_labels=True) + plt.savefig(os.path.splitext(fname)[0] + ".png", format="png") + plt.show() + + +# Initialize parser, set the defaults, and extract the options +def get_options(): parser = argparse.ArgumentParser( prog = 'generate_network', description = '''Generates and outputs the Waku network conforming to input parameters''', - epilog = '''The defaults are: -o "Topology.json"; - -n 1; -t 1; -p 1; -T "configuration_model"''') + epilog = '''Defaults: -o "Topology.json"; + -n 1; -t 1; -p 1; -T "configuration_model" + Supported nw types "configuration_model", "scalefree", + "newman_watts_strogatz"''') parser.add_argument("-o", "--output", default='Topology.json', dest='fname', help='output json filename for the Waku network', @@ -53,34 +59,28 @@ def init_arg_parser() : # default=1, dest='num_edges', # help='The number of edges in the Waku network', # type=int, metavar='#edges>') - return parser + return parser.parse_args() -# https://networkx.org/documentation/stable/reference/generated/networkx.generators.degree_seq.configuration_model.html -def generate_config_model(n): - #degrees = nx.random_powerlaw_tree_sequence(n, tries=10000) - degrees = [random.randint(1, n) for i in range(n)] - if (sum(degrees)) % 2 != 0: # adjust the degree sum to be even - degrees[-1] += 1 - G = nx.configuration_model(degrees) # generate the graph - return G +# Generate a random string (UC chars) of len n def generate_topic_string(n): rs = "" for _ in range(n): - r = random.randint(65, 65 + 26 - 1) # only letters + r = random.randint(65, 65 + 26 - 1) # generate a random UC char rs += (chr(r)) # append the char generated return rs + +# Generate the topics - UC chars prefixed by "topic" def generate_topics(num_topics): - # generate the topics - uppercase chars prefixed by "topic" topics = [] base = 26 topic_len = int(math.log(num_topics)/math.log(base)) + 1 - topics = {} - for i in range(num_topics): - topics[i] = "topic_" + generate_topic_string(topic_len) + topics = {i: f"topic_{generate_topic_string(topic_len)}" for i in range(num_topics)} return topics + +# Get a random sub-list of topics def get_random_sublist(topics): n = len(topics) lo = random.randint(0, n - 1) @@ -90,28 +90,53 @@ def get_random_sublist(topics): sublist.append(topics[i]) return sublist -def generate_network(num_nodes, prefix): + +# Network Types +# https://networkx.org/documentation/stable/reference/generated/networkx.generators.degree_seq.configuration_model.html +def generate_config_model(n): + #degrees = nx.random_powerlaw_tree_sequence(n, tries=10000) + degrees = [random.randint(1, n) for i in range(n)] + if (sum(degrees)) % 2 != 0: # adjust the degree to even + degrees[-1] += 1 + return nx.configuration_model(degrees) # generate the graph + + +def generate_scalefree_graph(n): + return nx.scale_free_graph(n) + + +# n must be larger than k +def generate_newman_watts_strogatz_graph(n): + return nx.newman_watts_strogatz_graph(n, 12, 0.5) + + +# Generate the network from nw type +def generate_network(num_nodes, nw_type, prefix): G = nx.empty_graph() if nw_type == "configuration_model": G = generate_config_model(num_nodes) + elif nw_type == "scalefree": + G = generate_scalefree_graph(num_nodes) + elif nw_type == "newman_watts_strogatz": + G = generate_newman_watts_strogatz_graph(num_nodes) else: print(nw_type +": Unsupported network type") sys.exit(1) H = postprocess_network(G, prefix) return H -# used by generate_dump_data - *ought* to be global for handling partitions -ports_shifted = 0 +# used by generate_dump_data, *ought* to be global to handle partitions +ports_shifted = 0 def postprocess_network(G, prefix): G = nx.Graph(G) # prune out parallel/multi edges G.remove_edges_from(nx.selfloop_edges(G)) # Removing self-loops # Labeling nodes to match waku containers - mapping = {} - for i in range(num_nodes): - mapping[i] = prefix + str(i) + mapping = {i: f"{prefix}{i}" for i in range(len(G))} return nx.relabel_nodes(G, mapping) + +# Generate dump data from the network and topics def generate_dump_data(H, topics): data_to_dump = {} global ports_shifted @@ -125,31 +150,34 @@ def generate_dump_data(H, topics): data_to_dump[node]["static-nodes"].append(edge[1]) return data_to_dump -#extract the CLI arguments -args = init_arg_parser().parse_args() -#parameters to generate the network -fname = args.fname -num_nodes = args.num_nodes -num_topics = args.num_topics -nw_type = args.nw_type -prefix = "waku_" -num_partitions = args.num_partitions -#num_edges = args.num_edges ## do we need to control #edges? +def main(): + #extract the CLI arguments and assign params + options = get_options() + fname = options.fname + num_nodes = options.num_nodes + num_topics = options.num_topics + nw_type = options.nw_type + prefix = "waku_" + num_partitions = options.num_partitions + #num_edges = options.num_edges ## need to control num_edges? -if num_partitions > 1 : - print("-p",num_partitions, ": Sorry, we do not yet support partitions") - sys.exit(1) + if num_partitions > 1: + print("-p",num_partitions, + "Sorry, we do not yet support partitions") + sys.exit(1) -# Generate the network and postprocess it -H = generate_network(num_nodes, prefix) + # Generate the network and postprocess it + H = generate_network(num_nodes, nw_type, prefix) + # Generate the topics + topics = generate_topics(num_topics) + # Generate the dump data + dump_data = generate_dump_data(H, topics) + # Dump the network in a json file + write_json(fname, dump_data) + # Display the graph + draw(fname, H) -#generate the topics -topics = generate_topics(num_topics) -# Generate the dump data -dump_data = generate_dump_data(H, topics) - -# dump the network to the json file -write_json(fname, dump_data) -#draw(H) +if __name__ == "__main__": + main() diff --git a/topology.json b/topology.json deleted file mode 100755 index 94fbf7f..0000000 --- a/topology.json +++ /dev/null @@ -1 +0,0 @@ -{"waku_0": {"ports-shift": 0, "topics": "test", "static-nodes": ["waku_46", "waku_14"]}, "waku_1": {"ports-shift": 1, "topics": "test", "static-nodes": ["waku_39", "waku_14", "waku_42", "waku_5"]}, "waku_2": {"ports-shift": 2, "topics": "test", "static-nodes": ["waku_44", "waku_32", "waku_8", "waku_20", "waku_11", "waku_24", "waku_13", "waku_21"]}, "waku_3": {"ports-shift": 3, "topics": "test", "static-nodes": ["waku_23", "waku_37", "waku_45", "waku_32"]}, "waku_4": {"ports-shift": 4, "topics": "test", "static-nodes": ["waku_30", "waku_20", "waku_42", "waku_22", "waku_28"]}, "waku_5": {"ports-shift": 5, "topics": "test", "static-nodes": ["waku_1", "waku_13", "waku_28", "waku_46", "waku_24", "waku_32"]}, "waku_6": {"ports-shift": 6, "topics": "test", "static-nodes": ["waku_14"]}, "waku_7": {"ports-shift": 7, "topics": "test", "static-nodes": ["waku_19", "waku_10"]}, "waku_8": {"ports-shift": 8, "topics": "test", "static-nodes": ["waku_2", "waku_45", "waku_23", "waku_16", "waku_11"]}, "waku_9": {"ports-shift": 9, "topics": "test", "static-nodes": ["waku_24", "waku_20"]}, "waku_10": {"ports-shift": 10, "topics": "test", "static-nodes": ["waku_7", "waku_36"]}, "waku_11": {"ports-shift": 11, "topics": "test", "static-nodes": ["waku_2", "waku_8", "waku_36"]}, "waku_12": {"ports-shift": 12, "topics": "test", "static-nodes": ["waku_22", "waku_13", "waku_30", "waku_43"]}, "waku_13": {"ports-shift": 13, "topics": "test", "static-nodes": ["waku_2", "waku_5", "waku_12", "waku_42", "waku_35", "waku_21"]}, "waku_14": {"ports-shift": 14, "topics": "test", "static-nodes": ["waku_0", "waku_1", "waku_6", "waku_43", "waku_24", "waku_45", "waku_18"]}, "waku_15": {"ports-shift": 15, "topics": "test", "static-nodes": ["waku_38", "waku_41", "waku_47"]}, "waku_16": {"ports-shift": 16, "topics": "test", "static-nodes": ["waku_8", "waku_26"]}, "waku_17": {"ports-shift": 17, "topics": "test", "static-nodes": ["waku_34"]}, "waku_18": {"ports-shift": 18, "topics": "test", "static-nodes": ["waku_14", "waku_37", "waku_46", "waku_19", "waku_47", "waku_41", "waku_39"]}, "waku_19": {"ports-shift": 19, "topics": "test", "static-nodes": ["waku_7", "waku_18", "waku_25", "waku_34", "waku_36", "waku_28", "waku_32", "waku_48"]}, "waku_20": {"ports-shift": 20, "topics": "test", "static-nodes": ["waku_2", "waku_4", "waku_9", "waku_29", "waku_23", "waku_46", "waku_45", "waku_49", "waku_22"]}, "waku_21": {"ports-shift": 21, "topics": "test", "static-nodes": ["waku_2", "waku_13", "waku_46", "waku_31", "waku_41"]}, "waku_22": {"ports-shift": 22, "topics": "test", "static-nodes": ["waku_4", "waku_12", "waku_20", "waku_33"]}, "waku_23": {"ports-shift": 23, "topics": "test", "static-nodes": ["waku_3", "waku_8", "waku_20", "waku_37"]}, "waku_24": {"ports-shift": 24, "topics": "test", "static-nodes": ["waku_2", "waku_5", "waku_9", "waku_14", "waku_41"]}, "waku_25": {"ports-shift": 25, "topics": "test", "static-nodes": ["waku_19", "waku_32", "waku_27", "waku_38", "waku_37"]}, "waku_26": {"ports-shift": 26, "topics": "test", "static-nodes": ["waku_16", "waku_45"]}, "waku_27": {"ports-shift": 27, "topics": "test", "static-nodes": ["waku_25"]}, "waku_28": {"ports-shift": 28, "topics": "test", "static-nodes": ["waku_4", "waku_5", "waku_19"]}, "waku_29": {"ports-shift": 29, "topics": "test", "static-nodes": ["waku_20", "waku_41", "waku_36", "waku_43"]}, "waku_30": {"ports-shift": 30, "topics": "test", "static-nodes": ["waku_4", "waku_12"]}, "waku_31": {"ports-shift": 31, "topics": "test", "static-nodes": ["waku_21", "waku_43"]}, "waku_32": {"ports-shift": 32, "topics": "test", "static-nodes": ["waku_2", "waku_3", "waku_5", "waku_19", "waku_25", "waku_34", "waku_33"]}, "waku_33": {"ports-shift": 33, "topics": "test", "static-nodes": ["waku_22", "waku_32"]}, "waku_34": {"ports-shift": 34, "topics": "test", "static-nodes": ["waku_17", "waku_19", "waku_32", "waku_45", "waku_44", "waku_46"]}, "waku_35": {"ports-shift": 35, "topics": "test", "static-nodes": ["waku_13", "waku_36", "waku_44", "waku_41"]}, "waku_36": {"ports-shift": 36, "topics": "test", "static-nodes": ["waku_10", "waku_11", "waku_19", "waku_29", "waku_35", "waku_39"]}, "waku_37": {"ports-shift": 37, "topics": "test", "static-nodes": ["waku_3", "waku_18", "waku_23", "waku_25"]}, "waku_38": {"ports-shift": 38, "topics": "test", "static-nodes": ["waku_15", "waku_25", "waku_43", "waku_47", "waku_41"]}, "waku_39": {"ports-shift": 39, "topics": "test", "static-nodes": ["waku_1", "waku_18", "waku_36", "waku_47"]}, "waku_40": {"ports-shift": 40, "topics": "test", "static-nodes": ["waku_44"]}, "waku_41": {"ports-shift": 41, "topics": "test", "static-nodes": ["waku_15", "waku_18", "waku_21", "waku_24", "waku_29", "waku_35", "waku_38", "waku_45"]}, "waku_42": {"ports-shift": 42, "topics": "test", "static-nodes": ["waku_1", "waku_4", "waku_13", "waku_44"]}, "waku_43": {"ports-shift": 43, "topics": "test", "static-nodes": ["waku_12", "waku_14", "waku_29", "waku_31", "waku_38", "waku_46", "waku_44"]}, "waku_44": {"ports-shift": 44, "topics": "test", "static-nodes": ["waku_2", "waku_34", "waku_35", "waku_40", "waku_42", "waku_43", "waku_46"]}, "waku_45": {"ports-shift": 45, "topics": "test", "static-nodes": ["waku_3", "waku_8", "waku_14", "waku_20", "waku_26", "waku_34", "waku_41"]}, "waku_46": {"ports-shift": 46, "topics": "test", "static-nodes": ["waku_0", "waku_5", "waku_18", "waku_20", "waku_21", "waku_34", "waku_43", "waku_44", "waku_47"]}, "waku_47": {"ports-shift": 47, "topics": "test", "static-nodes": ["waku_15", "waku_18", "waku_38", "waku_39", "waku_46", "waku_49"]}, "waku_48": {"ports-shift": 48, "topics": "test", "static-nodes": ["waku_19"]}, "waku_49": {"ports-shift": 49, "topics": "test", "static-nodes": ["waku_20", "waku_47"]}} \ No newline at end of file diff --git a/topology.png b/topology.png deleted file mode 100755 index 48eca1f62247d90e47f6f8b66ad3a301b0382e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2396 zcmeAS@N?(olHy`uVBq!ia0y~yU}|7sV0^&A1{5*9c;^X_vMh0pC<)F_D=AMbN@eg( zEGfvzFUiSFQYcF;D$dN$GuAWHGt^PYC@Co@w$j(ng)7j@FG|FSZ?73LGAQsIFgURP`9r2YHLj|%^JjDz7>v%n2kN|M z)WE=C$R@y`aEyV8;fRC-LxTh}2ZKN|10zEcj{<{34