def snapshot(self, directed_graph: DirectedGraph): """ Take a snapshot of the current directed graph Args: directed_graph (DirectedGraph): The directed graph """ dg = nx.DiGraph() vertex: Vertex for vertex in directed_graph.get_vertices(): dg.add_node(vertex.get_label()) edge: Edge for edge in directed_graph.get_edges(): dg.add_edge(edge.get_tail().get_label(), edge.get_head().get_label()) edges = [(u, v) for (u, v, _) in dg.edges(data=True)] pos = nx.planar_layout(dg) activated_nodes = self.get_nodes_by_state(directed_graph, VizTracing.ACTIVATED) visisted_nodes =\ self.get_nodes_by_state(directed_graph, VizTracing.VISITED) -\ activated_nodes default_nodes = {vertex.get_label() for vertex in directed_graph.get_vertices()} -\ visisted_nodes - activated_nodes self.draw_nodes(dg, pos, list(activated_nodes), directed_graph, VizTracing.ACTIVATED) self.draw_nodes(dg, pos, list(visisted_nodes), directed_graph, VizTracing.VISITED) self.draw_nodes(dg, pos, list(default_nodes), directed_graph, VizTracing.DEFAULT) nx.draw_networkx_edges(G=dg, pos=pos, edgelist=edges, width=VizTracingNetworkx.EDGE_WIDTH, edge_color=VizTracingNetworkx.EDGE_COLOR, style=VizTracingNetworkx.EDGE_STYLE, arrowsize=VizTracingNetworkx.EDGE_ARROW_SIZE) nx.draw_networkx_labels( G=dg, pos=pos, font_size=VizTracingNetworkx.NODE_FONT_SIZE, font_family=VizTracingNetworkx.NODE_FONT_FAMILY) plt.axis('off') plt.show() a = 100
def get_nodes_by_state(self, directed_graph: DirectedGraph, state: str) -> Set[str]: return { vertex.get_label() for vertex in directed_graph.get_vertices() if vertex.has_enabled_attr(state) }
def deactivate_graph(self, directed_graph: DirectedGraph): """ Method that resets the whole graph Args: directed_graph (DirectedGraph): The directed graph """ for v in directed_graph.get_vertices(): self.reset_status(v, VizTracing.ACTIVATED)
def reset_attrs(self, directed_graph: DirectedGraph): """ Method that resets all attributes of a vertex Args: directed_graph (DirectedGraph): The directed graph vertex(Vertex): the vertex to be activated """ for v in directed_graph.get_vertices(): v.reset_attrs()
def activate_graph(self, directed_graph: DirectedGraph): """ Method that sets the attribute "active" of all vertices to true. Args: directed_graph (DirectedGraph): The directed graph """ for v in directed_graph.get_vertices(): self.set_status(v, VizTracing.ACTIVATED)
def snapshot(self, directed_graph: DirectedGraph): """ Take a snapshot of the current directed graph Args: directed_graph (DirectedGraph): The directed graph """ graph = Digraph(format=VizTracingGraphviz.IMAGE_TYPE) for vertex in directed_graph.get_vertices(): found = False default_state: Union[Mapping[str, str], None] = {} for state in self.vertex_states: attr_name, attr_values = next(iter(state.items())) if attr_name != VizTracing.DEFAULT and\ vertex.get_attr(attr_name): graph.node(name=str(vertex.get_label()), label=self.get_extended_label(vertex), _attributes=None, **attr_values) found = True break elif attr_name == VizTracing.DEFAULT: default_state = attr_values if not found: graph.node(name=str(vertex.get_label()), label=self.get_extended_label(vertex), _attributes=None, **default_state or {}) for edge in vertex.get_edges(): found = False default_state: Union[Mapping[str, str], None] = {} for state in self.edge_states: attr_name, attr_values = next(iter(state.items())) if attr_name != VizTracing.DEFAULT and \ edge.get_attr(attr_name): graph.edge(str(edge.get_tail().get_label()), str(edge.get_head().get_label()), label=None, _attributes=None, **attr_values) found = True break elif attr_name == VizTracing.DEFAULT: default_state = attr_values if not found: graph.edge(str(edge.get_tail().get_label()), str(edge.get_head().get_label())) graph.render( path.join( self.path, VizTracingGraphviz.IMAGE_NAME_PREFIX + ("{:04d}".format(self.snapshot_no)))) self.snapshot_no += 1
def change_activated_vertex(self, directed_graph: DirectedGraph, vertex: Vertex): """ Method that sets the attribute "active" of the vertex to true. It deactivates all other vertices Args: directed_graph (DirectedGraph): The directed graph vertex(Vertex): the vertex to be activated """ self.set_status(vertex, VizTracing.ACTIVATED) for v in directed_graph.get_vertices(): if str(v.get_label()) != str(vertex.get_label()): self.reset_status(v, VizTracing.ACTIVATED)
def create_node_buckets(self, directed_graph: DirectedGraph) ->\ Dict[str, List[Vertex]]: """ Create different buckets that fit nodes with the same characteristics Args: directed_graph: The directed graph Returns: A dictionary that contains lists of vertices per characteristic """ mapping: Dict[str, List[Vertex]] = dict() for vertex in directed_graph.get_vertices(): if VizTracing.ACTIVATED in vertex.get_attrs(): mapping[VizTracing.ACTIVATED].append(vertex) elif VizTracing.VISITED in vertex.get_attrs(): mapping[VizTracing.VISITED].append(vertex) else: mapping[VizTracing.DEFAULT].append(vertex) return mapping
class TestDirectedGraph(unittest.TestCase): def setUp(self): self.vertices = {0: [1], 1: [2, 3], 2: [3], 3: [4, 6], 4: [5, 6], 5: [5], 6: [6]} self.directed_graph = DirectedGraph(self.vertices) def test_init(self): self.assertEqual(len(self.vertices.keys()), self.directed_graph.get_vertices_count()) def test_str(self): print(self.directed_graph) def test_one_vertex_self_loop(self): self.vertices = {0: [0]} self.directed_graph = DirectedGraph(self.vertices) def test_add_vertex(self): label = 7 self.directed_graph.add_vertex(label) vertex = self.directed_graph.get_vertex(label) self.assertIsNotNone(vertex) self.assertEqual(vertex.get_outdegree(), 0) self.assertEqual(vertex.get_indegree(), 0) self.assertListEqual(vertex.get_edge_heads(), list()) def test_add_duplicate_vertex(self): label = 7 self.directed_graph.add_vertex(label) with self.assertRaises(RuntimeError): self.directed_graph.add_vertex(label) def test_add_heads(self): vertex_to_test = 7 self.directed_graph.add_vertex(vertex_to_test) vertex = self.directed_graph.get_vertex(vertex_to_test) no_heads = 3 for i in range(no_heads): vertex.add_edge(self.directed_graph.get_vertex(i)) self.assertEqual(len(vertex.get_edge_heads()), no_heads) self.assertEqual(vertex.get_outdegree(), len(vertex.get_edge_heads())) def test_outdegree(self): vertex = self.directed_graph.get_vertex(1) self.assertEqual(vertex.get_outdegree(), len(vertex.get_edge_heads())) def test_indegree(self): vertex_to_test = 6 self.vertices = {0: [1], 1: [2, 3], 2: [3], 3: [4, vertex_to_test], 4: [5, vertex_to_test], 5: [5], vertex_to_test: []} self.directed_graph = DirectedGraph(self.vertices) vertex = self.directed_graph.get_vertex(vertex_to_test) self.assertEqual(vertex.get_indegree(), 2) def test_get_reversed_graph(self): self.directed_graph = DirectedGraph(self.vertices) self.directed_graph.reversed(inplace=True) self.check_big_reversed_graph(self.directed_graph) def test_get_reversed_small_graph_inplace_false(self): self.vertices = {0: [1], 1: [2], 2: []} self.directed_graph = DirectedGraph(self.vertices) reversed_graph = self.directed_graph.reversed(inplace=False) self.assertTrue(reversed_graph != self.directed_graph.get_direct_graph_core()) self.check_small_reversed_graph(reversed_graph) def test_get_reversed_small_graph_inplace_true(self): self.vertices = {0: [1], 1: [2], 2: []} self.directed_graph = DirectedGraph(self.vertices) reversed_graph = self.directed_graph.reversed(inplace=True) self.assertTrue(reversed_graph == self.directed_graph.get_direct_graph_core()) self.check_small_reversed_graph(reversed_graph) def test_ordering(self): self.vertices = {5: [5], 1: [2, 3], 2: [3], 3: [4, 6], 4: [5, 6], 0: [1], 6: [6]} self.directed_graph = DirectedGraph(self.vertices, AlgorithmOrdering.ASC) self.assertTrue(next(iter( self.directed_graph.get_vertices())).get_label() == 0) self.directed_graph = DirectedGraph(self.vertices, AlgorithmOrdering.DESC) self.assertTrue(next(iter( self.directed_graph.get_vertices())).get_label() == 6) def tearDown(self): pass def check_small_reversed_graph(self, reversed_graph): self.assertTrue(self.amount_of_tails2(reversed_graph, 2) == 1) self.assertTrue(self.has_vertex_label_as_head2(reversed_graph, 2, 1)) self.assertTrue(self.amount_of_tails2(reversed_graph, 1) == 1) self.assertTrue(self.has_vertex_label_as_head2(reversed_graph, 1, 0)) self.assertTrue(self.amount_of_tails2(reversed_graph, 0) == 0) def check_big_reversed_graph(self, reversed_graph): self.assertTrue(self.amount_of_tails2(reversed_graph, 6) == 3) self.assertTrue(self.has_vertex_label_as_head2(reversed_graph, 6, 4)) self.assertTrue(self.has_vertex_label_as_head2(reversed_graph, 6, 6)) self.assertTrue(self.has_vertex_label_as_head2(reversed_graph, 6, 3)) self.assertTrue(self.amount_of_tails2(reversed_graph, 5) == 2) self.assertTrue(self.has_vertex_label_as_head2(reversed_graph, 5, 5)) self.assertTrue(self.has_vertex_label_as_head2(reversed_graph, 5, 4)) self.assertTrue(self.amount_of_tails2(reversed_graph, 4) == 1) self.assertTrue(self.has_vertex_label_as_head2(reversed_graph, 4, 3)) self.assertTrue(self.amount_of_tails2(reversed_graph, 3) == 2) self.assertTrue(self.has_vertex_label_as_head2(reversed_graph, 3, 1)) self.assertTrue(self.has_vertex_label_as_head2(reversed_graph, 3, 2)) self.assertTrue(self.amount_of_tails2(reversed_graph, 2) == 1) self.assertTrue(self.has_vertex_label_as_head2(reversed_graph, 2, 1)) self.assertTrue(self.amount_of_tails2(reversed_graph, 1) == 1) self.assertTrue(self.has_vertex_label_as_head2(reversed_graph, 1, 0)) self.assertTrue(self.amount_of_tails2(reversed_graph, 0) == 0) def has_vertex_label_as_head( self, graph: DirectedGraphCore, vertex_label: Union[str, int], head_label: Union[str, int]) -> bool: return True if head_label in \ {v.get_label() for v in graph.get_vertex(vertex_label).get_edge_heads()} \ else False def amount_of_heads( self, graph: DirectedGraphCore, vertex_label: Union[str, int]) -> int: return len(graph.get_vertex(vertex_label).get_edge_heads()) def has_vertex_label_as_head2( self, graph: DirectedGraph, vertex_label: Union[str, int], head_label: Union[str, int]) -> bool: return True if head_label in \ {v.get_label() for v in graph.get_vertex(vertex_label).get_edge_heads()} \ else False def amount_of_tails2( self, graph: DirectedGraph, vertex_label: Union[str, int]) -> int: return len(graph.get_vertex(vertex_label).get_edge_heads())
class TestVizTracingGraphviz(unittest.TestCase): DIGRAPH_VIZ = "digraph_viz" RESOURCES_PATH = "python-test-resources" RESOURCES_PATH_RECYCLE = RESOURCES_PATH + "/recycle" @classmethod def setUpClass(cls): pt.clean_dir_in_user_home( TestVizTracingGraphviz.RESOURCES_PATH_RECYCLE) def setUp(self): self.vertices = { 0: [1], 1: [2, 3], 2: [3], 3: [4, 6], 4: [5, 6], 5: [5], 6: [6] } self.directed_graph = DirectedGraph(self.vertices) @unittest.skip def test_VizTracingGraphviz_vertex_only(self): self.vertices = { 0: [1], 1: [2, 3], 2: [3], 3: [4, 6], 4: [5, 6], 5: [5], 6: [6] } self.directed_graph = DirectedGraph(self.vertices) vertex_1 = self.directed_graph.get_vertex(1) vertex_1.set_attr("activated", True) vertex_2 = self.directed_graph.get_vertex(2) vertex_2.set_attr("in_cycle", True) dir = TestVizTracingGraphviz.RESOURCES_PATH_RECYCLE + "/" + \ inspect.currentframe().f_code.co_name pt.create_dir_in_user_home(dir) viz_cyclic_tracing: VizCyclicTracing = VizCyclicTracing( path=pt.get_dir_in_user_home(dir), directed_graph=self.directed_graph, vertex_states=[{ VizTracing.ACTIVATED: { "fillcolor": "red", "style": "filled" } }, { VizCyclicTracing.IN_CYCLE: { "fillcolor": "blue", "style": "filled" } }]) viz_cyclic_tracing.snapshot(self.directed_graph) self.assertTrue(True) @unittest.skip def test_VizTracingGraphviz_activate_vertex(self): self.vertices = { 0: [1], 1: [2, 3], 2: [3], 3: [4, 6], 4: [5, 6], 5: [5], 6: [6] } self.directed_graph = DirectedGraph(self.vertices) vertex_1 = self.directed_graph.get_vertex(1) dir = TestVizTracingGraphviz.RESOURCES_PATH_RECYCLE + "/" + \ inspect.currentframe().f_code.co_name viz_cyclic_tracing: VizCyclicTracing = VizCyclicTracing( path=pt.get_dir_in_user_home(dir), directed_graph=self.directed_graph, vertex_states=[{ VizTracing.ACTIVATED: { "fillcolor": "red", "style": "filled" } }, { VizCyclicTracing.IN_CYCLE: { "fillcolor": "blue", "style": "filled" } }]) viz_cyclic_tracing.change_activated_vertex(self.directed_graph, vertex_1) for vertex in self.directed_graph.get_vertices(): if str(vertex_1.get_label()) == str(vertex.get_label()): self.assertTrue(vertex.get_attr(VizTracing.ACTIVATED)) else: self.assertFalse(vertex.get_attr(VizTracing.ACTIVATED)) @unittest.skip def test_VizTracingGraphviz_set_status(self): self.vertices = { 0: [1], 1: [2, 3], 2: [3], 3: [4, 6], 4: [5, 6], 5: [5], 6: [6] } self.directed_graph = DirectedGraph(self.vertices) vertex_5 = self.directed_graph.get_vertex(5) vertex_6 = self.directed_graph.get_vertex(6) dir = TestVizTracingGraphviz.RESOURCES_PATH_RECYCLE + "/" + \ inspect.currentframe().f_code.co_name viz_cyclic_tracing: VizCyclicTracing = VizCyclicTracing( path=pt.get_dir_in_user_home(dir), directed_graph=self.directed_graph, vertex_states=[{ VizTracing.ACTIVATED: { "fillcolor": "red", "style": "filled" } }, { VizCyclicTracing.IN_CYCLE: { "fillcolor": "blue", "style": "filled" } }]) viz_cyclic_tracing.set_status(vertex_5, VizCyclicTracing.IN_CYCLE) viz_cyclic_tracing.set_status(vertex_6, VizCyclicTracing.IN_CYCLE) for vertex in self.directed_graph.get_vertices(): if str(vertex_5.get_label()) == str(vertex.get_label()) or \ str(vertex_6.get_label()) == str(vertex.get_label()): self.assertTrue(vertex.get_attr(VizCyclicTracing.IN_CYCLE)) else: self.assertFalse(vertex.get_attr(VizCyclicTracing.IN_CYCLE)) @unittest.skip def test_VizTracingGraphviz_snapshot(self): dir = TestVizTracingGraphviz.RESOURCES_PATH_RECYCLE + "/" + \ inspect.currentframe().f_code.co_name viz_cyclic_tracing: VizCyclicTracing = VizCyclicTracing( path=pt.get_dir_in_user_home(dir), directed_graph=self.directed_graph) viz_cyclic_tracing.snapshot(self.directed_graph) self.assertTrue( os.path.exists( path.join( pt.get_dir_in_user_home(dir), VizCyclicTracing.IMAGE_NAME_PREFIX + ("{:04d}".format(viz_cyclic_tracing.snapshot_no - 1)) + "." + VizCyclicTracing.IMAGE_TYPE))) viz_cyclic_tracing.snapshot(self.directed_graph) self.assertTrue( os.path.exists( path.join( pt.get_dir_in_user_home(dir), VizCyclicTracing.IMAGE_NAME_PREFIX + ("{:04d}".format(viz_cyclic_tracing.snapshot_no - 1)) + "." + VizCyclicTracing.IMAGE_TYPE))) def tearDown(self): dir = TestVizTracingGraphviz.RESOURCES_PATH_RECYCLE pt.clean_dir_in_user_home(dir) self.assertFalse(os.path.exists(pt.get_dir_in_user_home(dir)))