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 dovier_piazza_policriti_partition( partition: RankedPartition, ) -> Tuple[RankedPartition, List[List[_Vertex]]]: """Apply *Dovier-Piazza-Policriti*'s algorithm to the given ranked partition. :param partition: A ranked partition (:math:`P` in the paper). :returns: A tuple such that the first item is the partition at the end of the algorithm (which at this point is made of blocks of size 1 containing only the vertexes which survived the collapse), and the second is a list which maps a survivor nodes to the list of nodes collapsed to that survivor node. """ # maps each survivor node to a list of nodes collapsed into it collapse_map = [None for _ in range(partition.nvertexes)] # loop over the ranks for partition_idx in range(len(partition)): if len(partition[partition_idx]) == 1: if len(partition[partition_idx][0].vertexes): block = partition[partition_idx][0] survivor_vertex, collapsed_vertexes = collapse(block) if survivor_vertex is not None: # update the collapsed nodes map collapse_map[survivor_vertex.label] = collapsed_vertexes # update the partition split_upper_ranks(partition, block) # OPTIMIZATION: if at the current rank we only have blocks of single # vertexes, skip this step. elif any(map(lambda block: block.size > 1, partition[partition_idx])): current_label = 0 for block in partition[partition_idx]: for vertex in block.vertexes: # scale vertex vertex.scale_label(current_label) current_label += 1 # exclude nodes having the wrong rank from the image and # counterimage of the vertex. from now they're gone # forever. vertex.restrict_to_subgraph( validation=lambda vx: vx.rank == vertex.rank) # apply PTA to the subgraph at the current examined rank # CAREFUL: if you debug here, you'll see that there are some # "duplicate" nodes (nodes with the same label in different blocks # of the partition). this happens becaus of the SCALING (which is # used to pass a normal graph to PTA) rscp = paige_tarjan_qblocks(partition[partition_idx]) # clear the partition at the current rank partition.clear_index(partition_idx) # insert the new blocks in the partition at the current rank, and # collapse each block. for block in rscp: block_vertexes = [] for scaled_vertex in block.vertexes: scaled_vertex.back_to_original_label() scaled_vertex.back_to_original_graph() block_vertexes.append(scaled_vertex) # we can set XBlock to None because PTA won't be called again # on these blocks internal_block = _Block(block_vertexes, None) survivor_vertex, collapsed_vertexes = collapse(internal_block) if survivor_vertex is not None: # update the collapsed nodes map collapse_map[survivor_vertex.label] = collapsed_vertexes # add the new block to the partition partition.append_at_index(internal_block, partition_idx) # update the upper ranks with respect to this block split_upper_ranks(partition, internal_block) else: for block in partition[partition_idx]: # update the upper ranks with respect to this block split_upper_ranks(partition, block) return (partition, collapse_map)