From 451524bf26c4f930589c943530118cadf0bb5a8a Mon Sep 17 00:00:00 2001 From: Martin Ruefenacht Date: Fri, 10 Jan 2020 20:04:11 +0000 Subject: [PATCH 1/9] Added initial StandardParser --- lemonspotter/parsers/standardparser.py | 33 ++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 lemonspotter/parsers/standardparser.py diff --git a/lemonspotter/parsers/standardparser.py b/lemonspotter/parsers/standardparser.py new file mode 100644 index 0000000..a6cacc8 --- /dev/null +++ b/lemonspotter/parsers/standardparser.py @@ -0,0 +1,33 @@ +""" +The StandardParser parses the apis.json emitted by the MPI Standard +pythonization effort. +""" + +import json + + +from pathlib import Path + +from lemonspotter.core.database import Database + + +class StandardParser: + """ + This class is a parser for the MPI Standard. + """ + + def __init__(self, database_path: Path) -> None: + if database_path.suffix != '.json': + raise RuntimeError(f'The given database path is not a json file: ' + f'{database_path}') + + with database_path.open() as encoded: + apis = json.load(encoded) + + for api in apis: + if 'lemonspotter' in api and api['lemonspotter']: + # read this api + + print(api) + + # populate database with it From d01185adb602cea41764e0419015d008df6f0438 Mon Sep 17 00:00:00 2001 From: Martin Ruefenacht Date: Fri, 10 Jan 2020 20:05:03 +0000 Subject: [PATCH 2/9] Added initial network visualization --- .gitignore | 1 + lemonspotter/tools/__init__.py | 0 lemonspotter/tools/database_plotter.py | 57 ++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 lemonspotter/tools/__init__.py create mode 100644 lemonspotter/tools/database_plotter.py diff --git a/.gitignore b/.gitignore index 5478b5e..3ee13f5 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ **/*.json **/*_binary **/*.c +**/*.html *.swp .hypothesis diff --git a/lemonspotter/tools/__init__.py b/lemonspotter/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lemonspotter/tools/database_plotter.py b/lemonspotter/tools/database_plotter.py new file mode 100644 index 0000000..ec28964 --- /dev/null +++ b/lemonspotter/tools/database_plotter.py @@ -0,0 +1,57 @@ +""" +""" + +import sys +from pathlib import Path + + +from pyvis.network import Network + + +from lemonspotter.parsers.mpiparser import MPIParser +from lemonspotter.core.database import Database + + +def main() -> None: + """ + """ + + parser = MPIParser() + parser.parse(Path(sys.argv[1])) + + net = Network(height='100%', width='100%', directed=True) + net.barnes_hut(overlap=1, central_gravity=1) + + idmap = {} + + # add all nodes + for id, function in enumerate(Database().get_functions()): + idmap[function.name] = id + + if not function.leads_all and not function.leads_any and not function.needs_all and not function.needs_any: + net.add_node(id, function.name, color='#F4F1BB') + + elif not function.needs_all and not function.needs_any: + net.add_node(id, function.name, color='#ED6A5A') + + elif not function.leads_all and not function.leads_any: + net.add_node(id, function.name, color='#E6EBE0') + + else: + net.add_node(id, function.name) + + # add need edges + for function in Database().get_functions(): + for need in function.needs_any: + net.add_edge(idmap[need.name], idmap[function.name], color='blue') + + # add lead edges + for function in Database().get_functions(): + for lead in function.leads_any: + net.add_edge(idmap[function.name], idmap[lead.name], color='green') + + net.show('plot.html') + + +if __name__ == '__main__': + main() From 835a727753d6ab640eb15d9271b7ebfe7c68ea20 Mon Sep 17 00:00:00 2001 From: Martin Ruefenacht Date: Fri, 10 Jan 2020 20:31:01 +0000 Subject: [PATCH 3/9] Parsing started --- lemonspotter/parsers/standardparser.py | 43 ++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/lemonspotter/parsers/standardparser.py b/lemonspotter/parsers/standardparser.py index a6cacc8..685d817 100644 --- a/lemonspotter/parsers/standardparser.py +++ b/lemonspotter/parsers/standardparser.py @@ -3,12 +3,18 @@ pythonization effort. """ + import json +import sys +import logging +from typing import Mapping, MutableMapping from pathlib import Path + from lemonspotter.core.database import Database +from lemonspotter.core.function import Function class StandardParser: @@ -16,7 +22,7 @@ class StandardParser: This class is a parser for the MPI Standard. """ - def __init__(self, database_path: Path) -> None: + def __call__(self, database_path: Path) -> None: if database_path.suffix != '.json': raise RuntimeError(f'The given database path is not a json file: ' f'{database_path}') @@ -24,10 +30,35 @@ def __init__(self, database_path: Path) -> None: with database_path.open() as encoded: apis = json.load(encoded) - for api in apis: - if 'lemonspotter' in api and api['lemonspotter']: - # read this api + for name, definition in apis.items(): + if 'lemonspotter' in definition and definition['lemonspotter']: + self._parse_API(definition) + + def _parse_API(self, definition: Mapping) -> None: + """ + Parse the API definition from the MPI Standard. + """ + + translation = {} + + translation['name'] = definition['name'] + translation['return'] = definition['return'] + translation['needs_any'] = definition['needs_any'] + translation['needs_all'] = definition['needs_all'] + translation['leads_any'] = definition['leads_any'] + translation['leads_all'] = definition['leads_all'] + + # TODO parameters + # TODO filter, valid combinations of parameters + + Database().add_function(Function(translation)) + + +if __name__ == '__main__': + parser = StandardParser() + parser(Path(sys.argv[1])) - print(api) + print(Database()._functions) - # populate database with it + for function in Database()._functions: + print(function._json) From 6a3cf89e1dccfb74c14833eedb8567333a20f5a0 Mon Sep 17 00:00:00 2001 From: Martin Ruefenacht Date: Fri, 10 Jan 2020 21:57:47 +0000 Subject: [PATCH 4/9] Started data graph plotting --- ...se_plotter.py => compute_graph_plotter.py} | 26 ++++++++--- lemonspotter/tools/data_graph_plotter.py | 45 +++++++++++++++++++ 2 files changed, 66 insertions(+), 5 deletions(-) rename lemonspotter/tools/{database_plotter.py => compute_graph_plotter.py} (64%) create mode 100644 lemonspotter/tools/data_graph_plotter.py diff --git a/lemonspotter/tools/database_plotter.py b/lemonspotter/tools/compute_graph_plotter.py similarity index 64% rename from lemonspotter/tools/database_plotter.py rename to lemonspotter/tools/compute_graph_plotter.py index ec28964..5881e23 100644 --- a/lemonspotter/tools/database_plotter.py +++ b/lemonspotter/tools/compute_graph_plotter.py @@ -9,6 +9,7 @@ from lemonspotter.parsers.mpiparser import MPIParser +from lemonspotter.parsers.standardparser import StandardParser from lemonspotter.core.database import Database @@ -16,11 +17,14 @@ def main() -> None: """ """ - parser = MPIParser() - parser.parse(Path(sys.argv[1])) + # parser = MPIParser() + # parser.parse(Path(sys.argv[1])) + + parser = StandardParser() + parser(Path(sys.argv[1])) net = Network(height='100%', width='100%', directed=True) - net.barnes_hut(overlap=1, central_gravity=1) + net.barnes_hut(overlap=1, central_gravity=2) idmap = {} @@ -43,12 +47,24 @@ def main() -> None: # add need edges for function in Database().get_functions(): for need in function.needs_any: - net.add_edge(idmap[need.name], idmap[function.name], color='blue') + if function in need.leads_all or function in need.leads_any: + continue + + net.add_edge(idmap[need.name], idmap[function.name], color='#95C623') # add lead edges for function in Database().get_functions(): for lead in function.leads_any: - net.add_edge(idmap[function.name], idmap[lead.name], color='green') + if function in lead.needs_all or function in lead.needs_any: + continue + + net.add_edge(idmap[function.name], idmap[lead.name], color='#0E4749') + + # add critical edges, start -> end + for function in Database().get_functions(): + for lead in function.leads_any: + if function in lead.needs_any: + net.add_edge(idmap[function.name], idmap[lead.name], color='#E55812') net.show('plot.html') diff --git a/lemonspotter/tools/data_graph_plotter.py b/lemonspotter/tools/data_graph_plotter.py new file mode 100644 index 0000000..0f1a2f8 --- /dev/null +++ b/lemonspotter/tools/data_graph_plotter.py @@ -0,0 +1,45 @@ +""" +""" + +import sys +from pathlib import Path + + +from pyvis.network import Network + + +from lemonspotter.parsers.mpiparser import MPIParser +from lemonspotter.parsers.standardparser import StandardParser +from lemonspotter.core.database import Database + + +def main() -> None: + """ + """ + + # parser = MPIParser() + # parser.parse(Path(sys.argv[1])) + + parser = StandardParser() + parser(Path(sys.argv[1])) + + net = Network(height='100%', width='100%', directed=True) + net.barnes_hut(overlap=1, central_gravity=2) + + idmap = {} + + # add all nodes + for id, function in enumerate(Database().get_functions()): + idmap[function.name] = id + + net.add_node(id, function.name) + + # draw edges between constructors to consumers + + # constants exist, how do we represent it? a node per constant or a single constant node? + + net.show('plot.html') + + +if __name__ == '__main__': + main() From 6492f295f7b1b47b3bcbc0cde363b66d94fad560 Mon Sep 17 00:00:00 2001 From: Martin Ruefenacht Date: Fri, 10 Jan 2020 22:42:58 +0000 Subject: [PATCH 5/9] Added parsing parameters from Standard --- lemonspotter/parsers/standardparser.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lemonspotter/parsers/standardparser.py b/lemonspotter/parsers/standardparser.py index 685d817..0266b65 100644 --- a/lemonspotter/parsers/standardparser.py +++ b/lemonspotter/parsers/standardparser.py @@ -47,9 +47,22 @@ def _parse_API(self, definition: Mapping) -> None: translation['needs_all'] = definition['needs_all'] translation['leads_any'] = definition['leads_any'] translation['leads_all'] = definition['leads_all'] + translation['parameters'] = [] - # TODO parameters - # TODO filter, valid combinations of parameters + for parameter in definition['params']: + param = {} + + param['name'] = parameter['name'] + param['abstract_type'] = parameter['kind'] + param['direction'] = param['param_direction'] + param['length'] = param['length'] + + # TODO pointer + # TODO const + + translation['parameters'].append(param) + + # TODO filter, valid combinations of parameters Database().add_function(Function(translation)) From 29bd29d5a5ff124c8c81d64a4cbd86e83944f3cf Mon Sep 17 00:00:00 2001 From: Martin Ruefenacht Date: Sat, 11 Jan 2020 00:59:24 +0000 Subject: [PATCH 6/9] Data graph partially done --- lemonspotter/core/function.py | 7 ++++ lemonspotter/core/parameter.py | 7 ++++ lemonspotter/parsers/standardparser.py | 7 ++-- lemonspotter/tools/compute_graph_plotter.py | 18 ++++------ lemonspotter/tools/data_graph_plotter.py | 38 ++++++++++++++++++--- 5 files changed, 60 insertions(+), 17 deletions(-) diff --git a/lemonspotter/core/function.py b/lemonspotter/core/function.py index 3a51a8e..7153a60 100644 --- a/lemonspotter/core/function.py +++ b/lemonspotter/core/function.py @@ -70,6 +70,13 @@ def return_type(self) -> Type: return Database().get_type(self._json['return']) + @property + def return_abstract_type(self) -> str: + """ + """ + + return self._json['return'] + @property # type: ignore @lru_cache() def needs_any(self) -> AbstractSet['Function']: diff --git a/lemonspotter/core/parameter.py b/lemonspotter/core/parameter.py index 6b967b7..392feb7 100644 --- a/lemonspotter/core/parameter.py +++ b/lemonspotter/core/parameter.py @@ -41,6 +41,13 @@ def type(self) -> Type: return Database().get_type(self._json['abstract_type']) + @property + def abstract_type(self) -> str: + """ + """ + + return self._json['abstract_type'] + @property def direction(self) -> Direction: """This property provides the direction of the Parameter.""" diff --git a/lemonspotter/parsers/standardparser.py b/lemonspotter/parsers/standardparser.py index 0266b65..139adaf 100644 --- a/lemonspotter/parsers/standardparser.py +++ b/lemonspotter/parsers/standardparser.py @@ -50,12 +50,15 @@ def _parse_API(self, definition: Mapping) -> None: translation['parameters'] = [] for parameter in definition['params']: + if parameter['name'] == 'ierror': + continue + param = {} param['name'] = parameter['name'] param['abstract_type'] = parameter['kind'] - param['direction'] = param['param_direction'] - param['length'] = param['length'] + param['direction'] = parameter['param_direction'] + param['length'] = parameter['length'] # TODO pointer # TODO const diff --git a/lemonspotter/tools/compute_graph_plotter.py b/lemonspotter/tools/compute_graph_plotter.py index 5881e23..99e3f46 100644 --- a/lemonspotter/tools/compute_graph_plotter.py +++ b/lemonspotter/tools/compute_graph_plotter.py @@ -26,23 +26,19 @@ def main() -> None: net = Network(height='100%', width='100%', directed=True) net.barnes_hut(overlap=1, central_gravity=2) - idmap = {} - # add all nodes for id, function in enumerate(Database().get_functions()): - idmap[function.name] = id - if not function.leads_all and not function.leads_any and not function.needs_all and not function.needs_any: - net.add_node(id, function.name, color='#F4F1BB') + net.add_node(function.name, color='#F4F1BB') elif not function.needs_all and not function.needs_any: - net.add_node(id, function.name, color='#ED6A5A') + net.add_node(function.name, color='#ED6A5A') elif not function.leads_all and not function.leads_any: - net.add_node(id, function.name, color='#E6EBE0') + net.add_node(function.name, color='#E6EBE0') else: - net.add_node(id, function.name) + net.add_node(function.name) # add need edges for function in Database().get_functions(): @@ -50,7 +46,7 @@ def main() -> None: if function in need.leads_all or function in need.leads_any: continue - net.add_edge(idmap[need.name], idmap[function.name], color='#95C623') + net.add_edge(need.name, function.name, color='#95C623') # add lead edges for function in Database().get_functions(): @@ -58,13 +54,13 @@ def main() -> None: if function in lead.needs_all or function in lead.needs_any: continue - net.add_edge(idmap[function.name], idmap[lead.name], color='#0E4749') + net.add_edge(function.name, lead.name, color='#0E4749') # add critical edges, start -> end for function in Database().get_functions(): for lead in function.leads_any: if function in lead.needs_any: - net.add_edge(idmap[function.name], idmap[lead.name], color='#E55812') + net.add_edge(function.name, lead.name, color='#E55812') net.show('plot.html') diff --git a/lemonspotter/tools/data_graph_plotter.py b/lemonspotter/tools/data_graph_plotter.py index 0f1a2f8..7868a71 100644 --- a/lemonspotter/tools/data_graph_plotter.py +++ b/lemonspotter/tools/data_graph_plotter.py @@ -11,6 +11,7 @@ from lemonspotter.parsers.mpiparser import MPIParser from lemonspotter.parsers.standardparser import StandardParser from lemonspotter.core.database import Database +from lemonspotter.core.parameter import Direction def main() -> None: @@ -26,16 +27,45 @@ def main() -> None: net = Network(height='100%', width='100%', directed=True) net.barnes_hut(overlap=1, central_gravity=2) - idmap = {} + # add all constants + # net.add_node('MPI_COMM_WORLD', color='#F4A261') + # net.add_node('MPI_COMM_SELF', color='#F4A261') + # net.add_node('MPI_COMM_NULL', color='#F4A261') # add all nodes for id, function in enumerate(Database().get_functions()): - idmap[function.name] = id - - net.add_node(id, function.name) + net.add_node(function.name) # draw edges between constructors to consumers + for producer in Database().get_functions(): + outs = [] + outs.append(producer.return_abstract_type) + outs.extend([param.abstract_type for param in producer.parameters if param.direction == Direction('out')]) + + for out_type in outs: + found = False + + for consumer in Database().get_functions(): + # TODO self loop allowed? + + for param in consumer.parameters: + if param.direction == Direction('in') and param.abstract_type == out_type: + # draw edge + net.add_edge(producer.name, consumer.name, title=out_type) + found = True + + if not found: + if not ('TYPE_' + out_type) in net.get_nodes(): + net.add_node('TYPE_' + out_type, color='#E76F51') + + net.add_edge(producer.name, 'TYPE_' + out_type, color='#E76F51') + + for in_type in [param.abstract_type for param in producer.parameters if param.direction == Direction('in')]: + if in_type not in outs: + net.add_node('TYPE_' + in_type, color='#2A9D8F') + net.add_edge('TYPE_' + in_type, producer.name, color='#2A9D8F') + # constants exist, how do we represent it? a node per constant or a single constant node? net.show('plot.html') From ceac9ed18ab827af12656924ce1860d5f5a4caaa Mon Sep 17 00:00:00 2001 From: Martin Ruefenacht Date: Sun, 12 Jan 2020 20:02:12 +0000 Subject: [PATCH 7/9] Updated StandardParser to latest apis.json format --- lemonspotter/parsers/standardparser.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lemonspotter/parsers/standardparser.py b/lemonspotter/parsers/standardparser.py index 0266b65..ed9a878 100644 --- a/lemonspotter/parsers/standardparser.py +++ b/lemonspotter/parsers/standardparser.py @@ -42,14 +42,14 @@ def _parse_API(self, definition: Mapping) -> None: translation = {} translation['name'] = definition['name'] - translation['return'] = definition['return'] - translation['needs_any'] = definition['needs_any'] - translation['needs_all'] = definition['needs_all'] - translation['leads_any'] = definition['leads_any'] - translation['leads_all'] = definition['leads_all'] + translation['return'] = definition['return_kind'] + translation['needs_any'] = definition['attributes']['needs_any'] + translation['needs_all'] = definition['attributes']['needs_all'] + translation['leads_any'] = definition['attributes']['leads_any'] + translation['leads_all'] = definition['attributes']['leads_all'] translation['parameters'] = [] - for parameter in definition['params']: + for parameter in definition['parameters']: param = {} param['name'] = parameter['name'] From fecd497e495e1594a63103a56127886152add6a6 Mon Sep 17 00:00:00 2001 From: Martin Ruefenacht Date: Sun, 12 Jan 2020 22:07:05 +0000 Subject: [PATCH 8/9] Initial work on control flow generation --- lemonspotter/tools/control_flow_graphs.py | 146 ++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 lemonspotter/tools/control_flow_graphs.py diff --git a/lemonspotter/tools/control_flow_graphs.py b/lemonspotter/tools/control_flow_graphs.py new file mode 100644 index 0000000..267dac6 --- /dev/null +++ b/lemonspotter/tools/control_flow_graphs.py @@ -0,0 +1,146 @@ +""" +""" + +import sys +from pathlib import Path +from random import choice, random +from itertools import chain + + +from pyvis.network import Network + + +from lemonspotter.parsers.mpiparser import MPIParser +from lemonspotter.parsers.standardparser import StandardParser +from lemonspotter.core.database import Database + + +def main() -> None: + """ + """ + + # parser = MPIParser() + # parser.parse(Path(sys.argv[1])) + + parser = StandardParser() + parser(Path(sys.argv[1])) + + net = Network(height='100%', width='100%', directed=True, layout=True) + # net.barnes_hut(overlap=1, central_gravity=2) + + nodes = Database().get_functions() + + # # filter down to non-independent + # # TODO ignore for now, include after, they can be used always + # nodes = [node for node in nodes if (node.needs_all or node.needs_any or + # node.leads_any or node.leads_all)] + + print(nodes) + + # starting points + no_need_nodes = [node for node in nodes if (not node.needs_any and not node.needs_all and + (node.leads_any or node.leads_all))] + print(no_need_nodes) + + # end points + no_lead_nodes = [node for node in nodes if (not node.leads_any and not node.leads_all and + (node.needs_any or node.needs_all))] + print(no_lead_nodes) + + internal_nodes = [node for node in nodes if ((node.leads_all or node.leads_any) and + (node.needs_all or node.needs_any))] + print(internal_nodes) + + independent_nodes = [node for node in nodes if (not node.leads_all and not node.leads_any and + not node.needs_all and not node.needs_any)] + print(independent_nodes) + + paths = [] + + def generate_path(): + path = [] + + # start + path.append(no_need_nodes[0]) + + while random() > 0.01: + node = choice(list(chain(independent_nodes, internal_nodes))) + + if node in path: + continue + + path.append(node) + + # end + path.append(no_lead_nodes[0]) + + return path + + for idx in range(100): + path = generate_path() + + if path not in paths: + paths.append(path) + + for idx, path in enumerate(paths): + # nodes + for node in path: + if node in no_lead_nodes: + # end + net.add_node(node.name+'_'+str(idx), label=node.name, color='#F6AE2D') + + elif node in no_need_nodes: + # start + net.add_node(node.name+'_'+str(idx), label=node.name, color='#F26419') + + elif node in independent_nodes: + net.add_node(node.name+'_'+str(idx), label=node.name, color='#33658A') + + else: + net.add_node(node.name+'_'+str(idx), label=node.name, color='#758E4F') + + # edges + for n0, n1 in zip(path, path[1:]): + net.add_edge(n0.name+'_'+str(idx), n1.name+'_'+str(idx), color='#86BBD8') + +# # add all nodes +# for id, function in enumerate(Database().get_functions()): +# if not function.leads_all and not function.leads_any and not function.needs_all and not function.needs_any: +# net.add_node(function.name, color='#F4F1BB') +# +# elif not function.needs_all and not function.needs_any: +# net.add_node(function.name, color='#ED6A5A') +# +# elif not function.leads_all and not function.leads_any: +# net.add_node(function.name, color='#E6EBE0') +# +# else: +# net.add_node(function.name) +# +# # add need edges +# for function in Database().get_functions(): +# for need in function.needs_any: +# if function in need.leads_all or function in need.leads_any: +# continue +# +# net.add_edge(need.name, function.name, color='#95C623') +# +# # add lead edges +# for function in Database().get_functions(): +# for lead in function.leads_any: +# if function in lead.needs_all or function in lead.needs_any: +# continue +# +# net.add_edge(function.name, lead.name, color='#0E4749') +# +# # add critical edges, start -> end +# for function in Database().get_functions(): +# for lead in function.leads_any: +# if function in lead.needs_any: +# net.add_edge(function.name, lead.name, color='#E55812') + + net.show('plot.html') + + +if __name__ == '__main__': + main() From eef9460877c56a8da97a28cd8db5da43b7dbd51a Mon Sep 17 00:00:00 2001 From: Martin Ruefenacht Date: Sun, 12 Jan 2020 23:35:10 +0000 Subject: [PATCH 9/9] Working control flow graph --- lemonspotter/tools/control_flow_graphs.py | 48 +++-------------------- 1 file changed, 6 insertions(+), 42 deletions(-) diff --git a/lemonspotter/tools/control_flow_graphs.py b/lemonspotter/tools/control_flow_graphs.py index 267dac6..8547714 100644 --- a/lemonspotter/tools/control_flow_graphs.py +++ b/lemonspotter/tools/control_flow_graphs.py @@ -76,7 +76,7 @@ def generate_path(): return path - for idx in range(100): + for idx in range(1000): path = generate_path() if path not in paths: @@ -87,57 +87,21 @@ def generate_path(): for node in path: if node in no_lead_nodes: # end - net.add_node(node.name+'_'+str(idx), label=node.name, color='#F6AE2D') + net.add_node(node.name+'_'+str(idx), label=node.name, color='#E76F51') elif node in no_need_nodes: # start - net.add_node(node.name+'_'+str(idx), label=node.name, color='#F26419') + net.add_node(node.name+'_'+str(idx), label=node.name, color='#F4A261') elif node in independent_nodes: - net.add_node(node.name+'_'+str(idx), label=node.name, color='#33658A') + net.add_node(node.name+'_'+str(idx), label=node.name, color='#E9C46A') else: - net.add_node(node.name+'_'+str(idx), label=node.name, color='#758E4F') + net.add_node(node.name+'_'+str(idx), label=node.name, color='#2A9D8F') # edges for n0, n1 in zip(path, path[1:]): - net.add_edge(n0.name+'_'+str(idx), n1.name+'_'+str(idx), color='#86BBD8') - -# # add all nodes -# for id, function in enumerate(Database().get_functions()): -# if not function.leads_all and not function.leads_any and not function.needs_all and not function.needs_any: -# net.add_node(function.name, color='#F4F1BB') -# -# elif not function.needs_all and not function.needs_any: -# net.add_node(function.name, color='#ED6A5A') -# -# elif not function.leads_all and not function.leads_any: -# net.add_node(function.name, color='#E6EBE0') -# -# else: -# net.add_node(function.name) -# -# # add need edges -# for function in Database().get_functions(): -# for need in function.needs_any: -# if function in need.leads_all or function in need.leads_any: -# continue -# -# net.add_edge(need.name, function.name, color='#95C623') -# -# # add lead edges -# for function in Database().get_functions(): -# for lead in function.leads_any: -# if function in lead.needs_all or function in lead.needs_any: -# continue -# -# net.add_edge(function.name, lead.name, color='#0E4749') -# -# # add critical edges, start -> end -# for function in Database().get_functions(): -# for lead in function.leads_any: -# if function in lead.needs_any: -# net.add_edge(function.name, lead.name, color='#E55812') + net.add_edge(n0.name+'_'+str(idx), n1.name+'_'+str(idx), color='#264653') net.show('plot.html')