|
| 1 | +#!/usr/bin/python3 |
| 2 | + |
| 3 | +import argparse |
| 4 | +import graphviz |
| 5 | + |
| 6 | +import graphGeneration as g |
| 7 | + |
| 8 | +#################################################################### |
| 9 | +# How to |
| 10 | +# |
| 11 | +# Run script with ./createGraph |
| 12 | +# Add arguments, such as |
| 13 | +# --patterns_path path to the patterns file (default: ../lattice/patterns.lg) |
| 14 | +# --lattice_path path to the lattice file (default: ../lattice/lattice.lg) |
| 15 | +# --node_parser (default|patternsdebug|patternsrelease) |
| 16 | +# how the node labels in the patterns file should be interpreted |
| 17 | +#################################################################### |
| 18 | + |
| 19 | +d = graphviz.Digraph(filename="../lattice/createGraph.gv", engine='fdp') |
| 20 | + |
| 21 | +# set border colour of the nodes |
| 22 | +def nodeBorderColour(codetype): |
| 23 | + if codetype == g.CODETYPE_CODE: |
| 24 | + g.CODE_TYPE_CODE_COLOR |
| 25 | + else: |
| 26 | + g.CODE_TYPE_OTHER_COLOR |
| 27 | + |
| 28 | + |
| 29 | +# the filled colour of the node |
| 30 | +def nodeColour(difftype): |
| 31 | + if difftype == g.DIFFTYPE_NON: |
| 32 | + return g.DIFFTYPE_NON_COLOR |
| 33 | + elif difftype == g.DIFFTYPE_ADD: |
| 34 | + return g.DIFFTYPE_ADD_COLOR |
| 35 | + elif difftype == g.DIFFTYPE_REM: |
| 36 | + return g.DIFFTYPE_REM_COLOR |
| 37 | + |
| 38 | + |
| 39 | +# the colour of the edge according to the specification, for "a", "b", and "ab" |
| 40 | +def edgeColour(edge): |
| 41 | + if edge == "a": |
| 42 | + return g.EDGE_A_COLOUR |
| 43 | + elif edge == "b": |
| 44 | + return g.EDGE_B_COLOUR |
| 45 | + else: # "ab" |
| 46 | + return g.EDGE_AB_COLOUR |
| 47 | + |
| 48 | + |
| 49 | +# draw a node within a sub graph |
| 50 | +def drawNode(cluster, tree, nodeId, nodeLabel): |
| 51 | + nodedata = NODE_PARSER(nodeId, nodeLabel) |
| 52 | + |
| 53 | + # create node |
| 54 | + cluster.node( |
| 55 | + tree + "_" + nodeId, # the identifier of the node |
| 56 | + label = nodedata.label, # the label of the node |
| 57 | + color = nodeBorderColour(nodedata.codetype), # border colour of the node |
| 58 | + fillcolor = nodeColour(nodedata.difftype), style = "filled") # colour of the filled node |
| 59 | + #cluster.node_attr.update(height=10) |
| 60 | + |
| 61 | + |
| 62 | +# draw an edge between node which are inside a sub graph |
| 63 | +def drawEdge(cluster, tree, childNodeId, parentNodeId, nodeLabel): |
| 64 | + # create edge |
| 65 | + cluster.edge( |
| 66 | + tree + "_" + childNodeId, # identifier of the destination node (where the edge arrow points to) |
| 67 | + tree + "_" + parentNodeId, # identifier of the source node (where the edge arrow points from) |
| 68 | + color=edgeColour(nodeLabel)) # colour of the edge |
| 69 | + |
| 70 | + |
| 71 | +# draw one tree, i.e. sub graph, of the patterns file |
| 72 | +def drawCluster(tree, nodes, edges): |
| 73 | + with d.subgraph(name = ("cluster_" + tree)) as c: # add cluster/sub graph |
| 74 | + c.attr(label = "tree " + tree, overlap='false', sep="+10") # title of clusters |
| 75 | + # draw all nodes |
| 76 | + for v in nodes: |
| 77 | + drawNode(c, tree, v[0], v[1]) |
| 78 | + # draw all edges |
| 79 | + for e in edges: |
| 80 | + drawEdge(c, tree, e[0], e[1], e[2]) |
| 81 | + |
| 82 | + |
| 83 | +# read in patterns file and read in vertices and edges |
| 84 | +def patterns(patterns_file_path): |
| 85 | + patternsFile = open(patterns_file_path, "r") |
| 86 | + patternLines = patternsFile.readlines() |
| 87 | + |
| 88 | + trees = {} # contains all trees |
| 89 | + nodes = [] # contains all nodes of a tree |
| 90 | + edges = [] # contains all edges of a tree |
| 91 | + |
| 92 | + for line in patternLines: |
| 93 | + line = line.replace("\n", "") |
| 94 | + line = line.replace("\r", "") |
| 95 | + |
| 96 | + if line.startswith("t"): |
| 97 | + # save previous read tree |
| 98 | + if len(nodes): |
| 99 | + trees.update({tree : (nodes.copy(), edges.copy())}) |
| 100 | + drawCluster(tree, nodes, edges) |
| 101 | + |
| 102 | + # read new tree (and clear all nodes and edges) |
| 103 | + nodes.clear() |
| 104 | + edges.clear() |
| 105 | + # t # TREE_ID |
| 106 | + lineParams = line.split(" ") |
| 107 | + tree = lineParams[2] |
| 108 | + |
| 109 | + # read in node |
| 110 | + elif line.startswith("v"): |
| 111 | + # v ID LABEL |
| 112 | + lineParams = line.split(" ") |
| 113 | + nodes.append((lineParams[1], ' '.join(lineParams[2:]))) |
| 114 | + |
| 115 | + # read in edge |
| 116 | + elif line.startswith("e"): |
| 117 | + # e NODE_CHILD_ID NODE_PARENT_ID LABEL |
| 118 | + lineParams = line.split(" ") |
| 119 | + edges.append((lineParams[1], lineParams[2], lineParams[3])) |
| 120 | + |
| 121 | + # repeat saving process for the last tree |
| 122 | + trees.update({tree : (nodes.copy(), edges.copy())}) |
| 123 | + drawCluster(tree, nodes, edges) |
| 124 | + |
| 125 | + |
| 126 | +# read in lattice file, i.e. the connections between all subgraphs |
| 127 | +def lattice(lattice_file_path): |
| 128 | + latticeFile = open(lattice_file_path, "r") |
| 129 | + latticeLines = latticeFile.readlines() |
| 130 | + |
| 131 | + latticeNodes = {} |
| 132 | + #latticeEdges = [] |
| 133 | + |
| 134 | + for line in latticeLines: |
| 135 | + line = line.replace("\n", "") |
| 136 | + line = line.replace("\r", "") |
| 137 | + |
| 138 | + if line.startswith("t"): |
| 139 | + # t # TREE_ID |
| 140 | + pass |
| 141 | + |
| 142 | + elif line.startswith("v"): |
| 143 | + # v ID LABEL |
| 144 | + lineParams = line.split(" ") |
| 145 | + latticeNodes.update({lineParams[1]: lineParams[2]}) |
| 146 | + |
| 147 | + |
| 148 | + elif line.startswith("e"): |
| 149 | + # e NODE_CHILD_ID NODE_PARENT_ID LABEL |
| 150 | + lineParams = line.split(" ") |
| 151 | + child = lineParams[1] |
| 152 | + parent = lineParams[2] |
| 153 | + # latticeEdges.append((child, parent)) |
| 154 | + d.edge("cluster_" + latticeNodes.get(child), "cluster_" + latticeNodes.get(parent)) |
| 155 | + #d.edge(latticeNodes.get(child) + "_0", latticeNodes.get(parent) + "_" + str(len(trees.get(latticeNodes.get(parent)))), ltail = "cluster_" + latticeNodes.get(child), lhead = "cluster_" + latticeNodes.get(parent)) |
| 156 | + |
| 157 | +NODE_PARSER = g.parseNodeReleaseAtomics |
| 158 | + |
| 159 | +def main(): |
| 160 | + # get parameters |
| 161 | + argparser = argparse.ArgumentParser() |
| 162 | + argparser.add_argument('--patterns_path', nargs='?', default="../lattice/patterns.lg", type=str) |
| 163 | + argparser.add_argument('--lattice_path', nargs='?', default="../lattice/lattice.lg", type=str) |
| 164 | + argparser.add_argument('--node_parser', nargs='?', default="patternsrelease", type=str) |
| 165 | + args = argparser.parse_args() |
| 166 | + |
| 167 | + patterns_path = args.patterns_path |
| 168 | + lattice_path = args.lattice_path |
| 169 | + |
| 170 | + # select the node parser |
| 171 | + global NODE_PARSER # accessing the gloabl variable NODE_PARSER |
| 172 | + if args.node_parser == "default": |
| 173 | + NODE_PARSER = g.parseNodeDefault |
| 174 | + elif args.node_parser == "patternsdebug": |
| 175 | + NODE_PARSER = g.parseNodeDebugAtomics |
| 176 | + elif args.node_parser == "patternsrelease": |
| 177 | + NODE_PARSER = g.parseNodeReleaseAtomics |
| 178 | + else: |
| 179 | + print("Node parser type does not exist.") |
| 180 | + |
| 181 | + #d.attr(rankdir='LR') |
| 182 | + d.attr(overlap='false') |
| 183 | + #d.attr(compound='true') |
| 184 | + |
| 185 | + d.attr(sep = "+10") |
| 186 | + |
| 187 | + patterns(patterns_path) |
| 188 | + lattice(lattice_path) |
| 189 | + |
| 190 | + d.view() |
| 191 | + |
| 192 | + |
| 193 | +if __name__ == "__main__": |
| 194 | + main() |
0 commit comments