new_scc_new_edge.append(((4, 0))) new_scc_correct_value.append(True) new_scc_finishing_time.append(None) # exists causal splitter exists_causal_splitter_qblocks = [] exists_causal_splitter_result_map = [] # 0 g0 = nx.DiGraph() g0.add_nodes_from(range(6)) g0.add_edges_from([(5, 0), (5, 5), (6, 5), (0, 3), (1, 3), (2, 4), (3, 3), (4, 3)]) ip0 = [(0, 1, 2), (3, 4), (5, ), (6, )] vertexes0, qblocks0 = decorate_nx_graph(g0, ip0) decorate_bispy_graph(vertexes0, ip0) exists_causal_splitter_qblocks.append(qblocks0) # integer tuples are the indexes of the blocks in qblocks0 result0 = [((2, 3), True), ((0, 1), True), ((1, 2), False)] exists_causal_splitter_result_map.append(result0) # both blocks go to block both_blocks_goto_result_map = [] # 0 both_blocks_goto_result_map.append([ ((0, 1, 0), True), ((0, 1, 1), True), ((0, 1, 2), True), ((0, 1, 3), True),
def test_mark_wf_nodes_correct(graph, wf_nodes, nwf_nodes): vertexes, _ = decorate_nx_graph(graph) for i in range(len(graph.nodes)): assert (i in wf_nodes and vertexes[i].wf) or (i in nwf_nodes and not vertexes[i].wf)
def test_clear_index(): vertexes, _ = decorate_nx_graph(nx.balanced_tree(2, 3)) partition = RankedPartition(vertexes) partition.clear_index(1) assert len(partition[1]) == 0
def test_get_item(): vertexes, _ = decorate_nx_graph(nx.balanced_tree(2, 3)) partition = RankedPartition(vertexes) assert partition[1] == partition._partition[1]
def test_len(): vertexes, _ = decorate_nx_graph(nx.balanced_tree(2, 3)) partition = RankedPartition(vertexes) assert len(partition) == 5
def test_scc_leaf_length(): vertexes, _ = decorate_nx_graph(nx.balanced_tree(2, 3)) partition = RankedPartition(vertexes) assert partition[0][0].size == 0
def test_append_at_index(): vertexes, _ = decorate_nx_graph(nx.balanced_tree(2, 3)) partition = RankedPartition(vertexes) block = _QBlock([], None) partition.append_at_index(block, 1) assert partition[1][-1] == block
def test_nvertexes(graph): vertexes, _ = decorate_nx_graph(graph) partition = RankedPartition(vertexes) assert partition.nvertexes == len(graph.nodes)
def test_compute_rank(graph, node_rank_dict: dict): vertexes, _ = decorate_nx_graph(graph) for idx in range(len(vertexes)): assert vertexes[idx].rank == node_rank_dict[idx]
def test_merge_condition_with_initial_partition(graph, initial_partition): vertexes, qblocks = decorate_nx_graph(graph, initial_partition) for tp in product(qblocks, qblocks): assert not merge_condition(tp[0], tp[1])
def dovier_piazza_policriti( graph: nx.Graph, initial_partition: List[Tuple[int]] = None, is_integer_graph: bool = False, ) -> List[Tuple]: """Compute the RSCP/maximum bisimulation of the given graph using *Dovier-Piazza-Policriti*'s algorithm. Example: >>> graph = networkx.balanced_tree(2,3) >>> dovier_piazza_policriti(graph) [(7, 8, 9, 10, 11, 12, 13, 14), (3, 4, 5, 6), (1, 2), (0,)] This function works with integer graph (nodes are integers starting from 0 and form an interval without holes). If the given graph is non-integer it is converted to an isomorphic integer graph automatically (unless `is_integer_graph` is `True`) and then re-converted to its original form after the end of the computation. For this reason nodes of `graph` **must** be hashable objects. .. warning:: Using a non integer graph and setting `is_integer_graph` to `True` will probably make the function fail with an exception, or, even worse, return a wrong output. :param graph: The input graph. :param initial_partition: The initial partition (or labeling set). Defaults to `None`, in which case the trivial labeling set (one block which contains all the nodes) is used. :param is_integer_graph: If `True`, we do not check if the given graph is integer (saves time). If `is_integer_graph` is `True` but the graph is not integer the output may be wrong. Defaults to False. :returns: The RSCP/maximum bisimulation of the given labeling set as a list of tuples, each of which contains bisimilar nodes. """ if not isinstance(graph, nx.DiGraph): raise Exception("graph should be a directed graph (nx.DiGraph)") # if True, the input graph is already an integer graph original_graph_is_integer = is_integer_graph or check_normal_integer_graph( graph) if not original_graph_is_integer: # convert the graph to an "integer" graph integer_graph, node_to_idx = convert_to_integer_graph(graph) else: integer_graph = graph vertexes, _ = decorate_nx_graph(integer_graph, initial_partition) partition = RankedPartition(vertexes) tp = dovier_piazza_policriti_partition(partition) collapsed_partition, collapse_map = tp # from the collapsed partition obtained from FBA, build the RSCP (external # representation, List[Tuple[int]]) rscp = [] for rank in collapsed_partition: for block in rank: if block.vertexes.size > 0: block_survivor_node = block.vertexes.first.value block_vertexes = [block_survivor_node.label] if collapse_map[block_survivor_node.label] is not None: block_vertexes.extend( map( lambda vertex: vertex.label, collapse_map[block_survivor_node.label], )) rscp.append(tuple(block_vertexes)) if original_graph_is_integer: return rscp else: return back_to_original(rscp, node_to_idx)