def UDecompositionFullConnectivity(party_map, q, num_qubit): ''' Naive methods for converting a party map with full connectivity ''' debug_flag = 0 operation_CNOT = [] for colunm in range(num_qubit): '''set diagonal entry to 1''' if party_map[colunm][colunm] == 0: for raw in list(range(colunm + 1, num_qubit)): if party_map[raw][colunm] == 1: if debug_flag == 1: print('control', raw, 'target', colunm) PerformRawAddinPartyMap(party_map, raw, colunm) if debug_flag == 1: print(party_map) add_CNOT = OperationCNOT(q[raw], q[colunm]) operation_CNOT.append(add_CNOT) break for raw in list(range(colunm)) + list(range(colunm + 1, num_qubit)): if party_map[raw][colunm] == 1: if debug_flag == 1: print('control', colunm, 'target', raw) PerformRawAddinPartyMap(party_map, colunm, raw) if debug_flag == 1: print(party_map) add_CNOT = OperationCNOT(q[colunm], q[raw]) operation_CNOT.append(add_CNOT) return operation_CNOT
def RemoteCNOTinArchitectureGraph(path, party_map, q): ''' implement remote CNOT in party map via path of nodes in architecture graph, i.e., [v_c, ..., v_t] ''' operation_CNOT = [] dis = len(path) - 1 v_c = path[0] v_t = path[-1] if dis == 2: add_CNOT = OperationCNOT(q[v_c], q[path[1]]) operation_CNOT.append(add_CNOT) PerformRawAddinPartyMap(party_map, v_c, path[1]) add_CNOT = OperationCNOT(q[path[1]], q[v_t]) operation_CNOT.append(add_CNOT) PerformRawAddinPartyMap(party_map, path[1], v_t) add_CNOT = OperationCNOT(q[v_c], q[path[1]]) operation_CNOT.append(add_CNOT) PerformRawAddinPartyMap(party_map, v_c, path[1]) add_CNOT = OperationCNOT(q[path[1]], q[v_t]) operation_CNOT.append(add_CNOT) PerformRawAddinPartyMap(party_map, path[1], v_t) else: if dis == 3: add_CNOT = OperationCNOT(q[v_c], q[path[1]]) operation_CNOT.append(add_CNOT) PerformRawAddinPartyMap(party_map, v_c, path[1]) add_CNOT = OperationCNOT(q[path[2]], q[v_t]) operation_CNOT.append(add_CNOT) PerformRawAddinPartyMap(party_map, path[2], v_t) add_CNOT = OperationCNOT(q[path[1]], q[path[2]]) operation_CNOT.append(add_CNOT) PerformRawAddinPartyMap(party_map, path[1], path[2]) add_CNOT = OperationCNOT(q[v_c], q[path[1]]) operation_CNOT.append(add_CNOT) PerformRawAddinPartyMap(party_map, v_c, path[1]) add_CNOT = OperationCNOT(q[path[1]], q[path[2]]) operation_CNOT.append(add_CNOT) PerformRawAddinPartyMap(party_map, path[1], path[2]) else: '''See Section 2B , arXiv:1904.01972''' '''first part''' for i in range(dis): R = [] add_CNOT = OperationCNOT(q[path[-1 - i - i]], q[path[-1 - i]]) R.append(add_CNOT) R_prime = copy.deepcopy(R_operation) R_prime.pop() R_prime.reverse() operation_CNOT.extend(R + R_prime) R_star = copy.deepcopy(R + R_prime) R_star.pop() R_star.pop(0) operation_CNOT.extend(R_star) return operation_CNOT
def FillSteinerTreeRootToLeaf(q, steiner_tree, party_map, terminal_nodes, shortest_path_steiner_tree): ''' Use CNOT operation to set all nodes in steiner tree 1 from root to leaf Refresh party map Return: list of CNOT operations ''' operation_CNOT = [] num_leaf = len(terminal_nodes) - 1 root_node = terminal_nodes[0] for i in range(num_leaf): leaf_node = terminal_nodes[i + 1] path = shortest_path_steiner_tree[leaf_node][root_node] l = len(path) for current_pos in range(l - 2, -1, -1): current_node = path[current_pos] son_node = path[current_pos + 1] if steiner_tree.node[current_node]['party_map_value'] == 0: add_CNOT = OperationCNOT(q[son_node], q[current_node]) operation_CNOT.append(add_CNOT) party_map[current_node][:] = np.logical_xor( party_map[current_node][:], party_map[son_node][:]) steiner_tree.node[current_node]['party_map_value'] = 1 return operation_CNOT
def QiskitGateToOperation(Gate): ''' convert a Qiskit Gate object to OperationU only support CNOT ''' if Gate.name == 'cx': qargs = Gate.qargs return OperationCNOT(qargs[0], qargs[1]) return None
def EmptySteinerTree(q, steiner_tree, party_map, terminal_nodes): operation_CNOT = [] DFT_edges = list(nx.dfs_edges(steiner_tree, source=terminal_nodes[0])) DFT_edges.reverse() for edge in DFT_edges: current_node = edge[0] son_node = edge[1] add_CNOT = OperationCNOT(q[current_node], q[son_node]) operation_CNOT.append(add_CNOT) party_map[son_node][:] = np.logical_xor(party_map[current_node][:], party_map[son_node][:]) steiner_tree.node[son_node]['party_map_value'] = 1 return operation_CNOT
def UDecompositionFullConnectivityPATEL(party_map, q, num_qubit, m=None): ''' Optimal methods for converting a party map with full connectivity Using partition See "OPTIMAL SYNTHESIS OF LINEAR REVERSIBLE CIRCUITS" ''' operation_CNOT = [] '''set value of m''' if m == None: cuurent_m = int(np.log2(num_qubit)) while int(num_qubit / cuurent_m) != (num_qubit / cuurent_m): cuurent_m -= 1 m = cuurent_m '''transform to upper triangle''' '''traverse all sections''' for start_col in range(0, num_qubit, m): list_all_col = list(range(start_col, start_col + m)) '''delete duplicate sub-rows''' for raw in list_all_col: module = party_map[raw][list_all_col] if np.sum(module) > 1: for raw2 in range(list_all_col[-1] + 1, num_qubit): module2 = party_map[raw2][list_all_col] if np.array_equal(module, module2) == True: PerformRawAddinPartyMap(party_map, raw, raw2) add_CNOT = OperationCNOT(q[raw], q[raw2]) operation_CNOT.append(add_CNOT) '''set values of all entries in each column of current subsection''' for current_col_sec in list_all_col: '''set diagonal entry to 1''' if party_map[current_col_sec][current_col_sec] != 1: for i in range(current_col_sec + 1, num_qubit): if party_map[i][current_col_sec] == 1: PerformRawAddinPartyMap(party_map, i, current_col_sec) add_CNOT = OperationCNOT(q[i], q[current_col_sec]) operation_CNOT.append(add_CNOT) break '''set other entries in this column''' for current_raw in range(current_col_sec + 1, num_qubit): if party_map[current_raw][current_col_sec] == 1: PerformRawAddinPartyMap(party_map, current_col_sec, current_raw) add_CNOT = OperationCNOT(q[current_col_sec], q[current_raw]) operation_CNOT.append(add_CNOT) '''transform to upper identity''' '''traverse all sections''' for start_col in range(num_qubit - 1, -1, -1 * m): list_all_col = list(range(start_col, start_col - m, -1)) '''delete duplicate sub-rows''' for raw in list_all_col: module = party_map[raw][list_all_col] if np.sum(module) > 1: for raw2 in range(list_all_col[-1] - 1, -1, -1): module2 = party_map[raw2][list_all_col] if np.array_equal(module, module2) == True: PerformRawAddinPartyMap(party_map, raw, raw2) add_CNOT = OperationCNOT(q[raw], q[raw2]) operation_CNOT.append(add_CNOT) '''set values of all entries in each column of current subsection''' for current_col_sec in list_all_col: '''set diagonal entry to 1''' if party_map[current_col_sec][current_col_sec] != 1: for i in range(current_col_sec - 1, -1, -1): if party_map[i][current_col_sec] == 1: PerformRawAddinPartyMap(party_map, i, current_col_sec) add_CNOT = OperationCNOT(q[i], q[current_col_sec]) operation_CNOT.append(add_CNOT) break '''set other entries in this column''' for current_raw in range(current_col_sec - 1, -1, -1): if party_map[current_raw][current_col_sec] == 1: PerformRawAddinPartyMap(party_map, current_col_sec, current_raw) add_CNOT = OperationCNOT(q[current_col_sec], q[current_raw]) operation_CNOT.append(add_CNOT) return operation_CNOT
def EliminateOneEntryInColumn(party_map, steiner_tree_total, sub_steiner_trees, sub_trees_root_node, terminal_nodes, q): ''' See chapter 4.1, arXiv:1904.01972 ''' flag_debug = 0 operation_CNOT = [] for i in range(len(sub_steiner_trees)): '''if root node of a sub Steiner tree is not the biggest''' current_tree = sub_steiner_trees[i] current_root = sub_trees_root_node[i] leaf_nodes = FindAllLeafNodesInTree(current_tree) if current_root < max(leaf_nodes): #print('testing') add_operations = EliminateOneEntryInColumn(party_map, steiner_tree_total, [steiner_tree_total], [max(terminal_nodes)], terminal_nodes, q) operation_CNOT.extend(add_operations) return operation_CNOT '''else''' for i in range(len(sub_steiner_trees)): tree = sub_steiner_trees[i] root_node = sub_trees_root_node[i] R_operation = [] shortest_length_tree = dict( nx.shortest_path_length(tree, source=None, target=None, weight=None, method='dijkstra')) BFS_edges = list(nx.bfs_edges(tree, source=root_node)) BFS_edges.reverse() if flag_debug == 1: print('BFS edges are', BFS_edges) for edge in BFS_edges: if shortest_length_tree[edge[0]][root_node] < shortest_length_tree[ edge[1]][root_node]: control_q = q[edge[0]] target_q = q[edge[1]] else: control_q = q[edge[1]] target_q = q[edge[0]] R_operation.append(OperationCNOT(control_q, target_q)) '''calculate R_prime''' R_prime = copy.deepcopy(R_operation) '''delete redundancy of R_prime''' for operation in copy.copy(R_prime): if operation.control_qubit[1] == root_node: R_prime.remove(operation) #R_prime.pop() R_prime.reverse() '''calculate R_star''' add_R_star = [] leaf_nodes = FindAllLeafNodesInTree(tree) R_star = copy.deepcopy(R_operation) + copy.deepcopy(R_prime) for operation in copy.copy(R_star): if (operation.target_qubit[1] in terminal_nodes) and (operation.target_qubit[1] in leaf_nodes): R_star.remove(operation) '''这个部分不正确,但是可以用来预估增加的CNOT数目''' if (operation.target_qubit[1] in terminal_nodes) and ( not operation.target_qubit[1] in leaf_nodes): add_R_star.append( OperationCNOT(operation.target_qubit, operation.control_qubit)) add_R_star_copy = copy.deepcopy(add_R_star) add_R_star_copy.reverse() if add_R_star != []: R_star = add_R_star + R_star + add_R_star_copy '''total operation''' R_total = R_operation + R_prime + R_star operation_CNOT.extend(R_total) if flag_debug == 1: print('R_operation') PerformOperationCNOTinPartyMap(party_map, R_operation) if flag_debug == 1: print('R_prime') PerformOperationCNOTinPartyMap(party_map, R_prime) if flag_debug == 1: print('R_star') PerformOperationCNOTinPartyMap(party_map, R_star) #PerformOperationCNOTinPartyMap(party_map, R_total) return operation_CNOT