def CreateCNOTList(DG): CNOT_list = [] DG_copy = copy.deepcopy(DG) leaf_nodes = ct.FindExecutableNode(DG_copy) while len(leaf_nodes) > 0: for node in leaf_nodes: op = DG_copy.node[node]['operation'] add_CNOT = [op.involve_qubits[0][1], op.involve_qubits[1][1]] CNOT_list.append(add_CNOT) DG_copy.remove_nodes_from(leaf_nodes) leaf_nodes = ct.FindExecutableNode(DG_copy) return CNOT_list
def HeuristicCostZulehnerLookAhead(current_map, DG, executable_vertex, shortest_length_G, shortest_path_G=None, DiG=None): ''' Calculate heuristic cost for remaining gates see "An Efficient Methodology for Mapping Quantum Circuits to the IBM QX Architectures" ''' sum_num_swap = 0 current_H_num = 0 mapping = current_map finished = False if DiG != None: edges = list(DiG.edges) '''calculate cost for current level''' for v_DG in executable_vertex: current_operation = DG.node[v_DG]['operation'] q0 = current_operation.involve_qubits[0] q1 = current_operation.involve_qubits[1] v0 = mapping.DomToCod(q0) v1 = mapping.DomToCod(q1) current_num_swap = shortest_length_G[v0][v1] - 1 '''if architecture graph is directed, confirm whether use 4 H gates to change direction''' if DiG != None: flag_4H = ct.CheckCNOTNeedConvertDirection(v0, v1, shortest_path_G[v0][v1], edges) current_H_num += flag_4H * 4 / 7 #we only count the number of SWAP gates '''renew number of all swaps''' sum_num_swap = sum_num_swap + current_num_swap current_level_num_swap = sum_num_swap if current_level_num_swap == 0: finished = True current_level_num_swap += current_H_num sum_num_swap += current_H_num '''calculate cost for next level''' DG_copy = DG.copy() DG_copy.remove_nodes_from(executable_vertex) lookahead_vertex = ct.FindExecutableNode(DG_copy) for v_DG in lookahead_vertex: current_operation = DG.node[v_DG]['operation'] q0 = current_operation.involve_qubits[0] q1 = current_operation.involve_qubits[1] v0 = mapping.DomToCod(q0) v1 = mapping.DomToCod(q1) current_num_swap = shortest_length_G[v0][v1] - 1 '''if architecture graph is directed, confirm whether use 4 H gates to change direction''' if DiG != None: flag_4H = ct.CheckCNOTNeedConvertDirection(v0, v1, shortest_path_G[v0][v1], edges) current_num_swap += flag_4H * 4 / 7 '''renew number of all swaps''' sum_num_swap = sum_num_swap + current_num_swap return sum_num_swap, current_level_num_swap, finished
def CheckQiskitCircuitSatisfyAG(DG, cir, G, initial_map): ''' check whether circuit satisfies architecture graph only support: 1. undirected AG, 2. only swap added we will delete any gates except swap and CNOT ''' current_map = initial_map.Copy() current_vertex = ct.FindExecutableNode(DG) executed_vertex = [] data = cir.data '''search for all gates in physical circuit''' for Gate in data: if Gate.name == 'cx': flag_matched = False q_phys = Gate.qargs q_phy_pos = (q_phys[0][1], q_phys[1][1]) '''find match in DG''' for vertex in current_vertex: op = DG.nodes[vertex]['operation'] q_logs = op.involve_qubits q_log_pos = (current_map.LogToPhy(q_logs[0]), current_map.LogToPhy(q_logs[1])) if q_phy_pos == q_log_pos: flag_matched = True current_vertex = ct.FindExecutableNode( DG, executed_vertex, current_vertex, [vertex]) break '''judge whether a match has been found''' if flag_matched == False: #raise Exception('incompatible CNOT gate found') return False if Gate.name == 'swap': flag_matched = True q_phys = Gate.qargs v0 = q_phys[0][1] v1 = q_phys[1][1] current_map.RenewMapViaExchangeCod(v0, v1) if len(executed_vertex) == len(DG.nodes()) and current_vertex == []: return True else: return False
def NaiveSearch(q_phy, cir_phy, G, DG, initial_map, shortest_path_G, draw=False): executable_vertex = ct.FindExecutableNode(DG) #executable_operation = ct.FindExecutableOperation(DG, executable_vertex) current_map = initial_map.Copy() '''naive method''' swap_count = 0 while executable_vertex != []: for current_vertex in executable_vertex: current_operation = DG.node[current_vertex]['operation'] q_c = current_operation.control_qubit q_t = current_operation.target_qubit v_c = current_map.DomToCod(q_c) v_t = current_map.DomToCod(q_t) current_path = shortest_path_G[v_c][v_t].copy() flag_naive = True while len(current_path) > 2: if flag_naive == True: ct.SWAPInArchitectureGraph(current_path[0], current_path[1], current_map, q_phy, cir_phy) flag_naive = not flag_naive current_path.pop(0) swap_count = swap_count + 1 else: ct.SWAPInArchitectureGraph(current_path[-1], current_path[-2], current_map, q_phy, cir_phy) flag_naive = not flag_naive current_path.pop(-1) swap_count = swap_count + 1 ct.ConductOperationInVertex(DG, current_vertex, current_map, cir_phy, q_phy) executable_vertex = ct.FindExecutableNode(DG) if draw == True: print(cir_phy.draw()) return swap_count
def InitialMapSimulatedAnnealing(start_map, DG, G, DiG, q_log, shortest_length_G, shortest_path_G, num_consider_gates=0, convergence=False): ''' this function is modified from "https://blog.csdn.net/qq_34798326/article/details/79013338" ''' if convergence == True: temp = [] solution = [] solution_best = [] if len(start_map) != len(G.nodes()): for v in G.nodes(): if not v in start_map: start_map.append(v) if num_consider_gates <= 1: num_consider_gates = len(DG.nodes()) * num_consider_gates if num_consider_gates < 50: num_consider_gates = 50 if num_consider_gates > len(DG.nodes()): num_consider_gates = len(DG.nodes()) DG_copy = DG.copy() '''generate counted CNOTs''' counted_CNOT_nodes = [] while len(counted_CNOT_nodes) < num_consider_gates: added_nodes = ct.FindExecutableNode(DG_copy) counted_CNOT_nodes.extend(added_nodes) DG_copy.remove_nodes_from(added_nodes) print('number of counted gates is', len(counted_CNOT_nodes)) '''Simulated Annealing''' solutionnew = start_map num = len(start_map) #valuenew = np.max(num) solutioncurrent = solutionnew.copy() valuecurrent = 99000 #np.max这样的源代码可能同样是因为版本问题被当做函数不能正确使用,应取一个较大值作为初始值 #print(valuecurrent) solutionbest = solutionnew.copy() valuebest = 99000 #np.max alpha, t2, markovlen = initpara() t = t2[1] #temperature result = [] #记录迭代过程中的最优解 while t > t2[0]: for i in np.arange(markovlen): #下面的两交换和三角换是两种扰动方式,用于产生新解 if np.random.rand() > 0.5: # 交换路径中的这2个节点的顺序 # np.random.rand()产生[0, 1)区间的均匀随机数 while True: #产生两个不同的随机数 loc1 = np.int(np.around(np.random.rand() * (num - 1))) loc2 = np.int(np.around(np.random.rand() * (num - 1))) ## print(loc1,loc2) if loc1 != loc2: break solutionnew[loc1], solutionnew[loc2] = solutionnew[ loc2], solutionnew[loc1] else: #三交换 while True: loc1 = np.int(np.around(np.random.rand() * (num - 1))) loc2 = np.int(np.around(np.random.rand() * (num - 1))) loc3 = np.int(np.around(np.random.rand() * (num - 1))) if ((loc1 != loc2) & (loc2 != loc3) & (loc1 != loc3)): break # 下面的三个判断语句使得loc1<loc2<loc3 if loc1 > loc2: loc1, loc2 = loc2, loc1 if loc2 > loc3: loc2, loc3 = loc3, loc2 if loc1 > loc2: loc1, loc2 = loc2, loc1 #下面的三行代码将[loc1,loc2)区间的数据插入到loc3之后 tmplist = solutionnew[loc1:loc2].copy() solutionnew[loc1:loc3 - loc2 + 1 + loc1] = solutionnew[loc2:loc3 + 1].copy() solutionnew[loc3 - loc2 + 1 + loc1:loc3 + 1] = tmplist.copy() valuenew = CalCost(solutionnew, DG, counted_CNOT_nodes, shortest_length_G, shortest_path_G, q_log, G, DiG) # print (valuenew) if valuenew < valuecurrent: #接受该解 #更新solutioncurrent 和solutionbest valuecurrent = valuenew solutioncurrent = solutionnew.copy() #renew best solution if valuenew < valuebest: valuebest = valuenew solutionbest = solutionnew.copy() else: #按一定的概率接受该解 if np.random.rand() < np.exp(-(valuenew - valuecurrent) / t): valuecurrent = valuenew solutioncurrent = solutionnew.copy() else: solutionnew = solutioncurrent.copy() if convergence == True: temp.append(t) solution.append(valuecurrent) solution_best.append(valuebest) t = alpha * t #print(valuebest) result.append(valuebest) print('initial_map is', solutionbest) '''draw convergence graph''' if convergence == True: figure_fig = plt.figure() plt.grid() plt.xlabel('Times of Iteration') plt.ylabel('Cost of States') plt.plot(solution) plt.plot(solution_best) figure_fig.savefig('simulated annealing convergence.eps', format='eps', dpi=1000) return Map(q_log, G, solutionbest), solutionbest
def RemoteCNOTandWindowLookAheadLI(q_phy, cir_phy, G, DG, initial_map, shortest_length_Gs, shortest_path_G, depth_lookahead, use_prune, draw=False, DiG=None, level_lookahead=None): if level_lookahead == None: level_lookahead = level_lookahead_default '''initialize other parameters''' #use_prune = False SWAP_cost = 3 flag_4H = 0 if DiG != None: edges_DiG = list(DiG.edges) SWAP_cost = 7 else: edges_DiG = None shortest_length_G = shortest_length_Gs[0] shortest_length_G_with4H = shortest_length_Gs[1] max_shortest_length_G = max(shortest_length_G) total_fallback_num = max_shortest_length_G / 2 #maximum fall back count finished_nodes = [] if debug_mode == True: draw = True '''initialize possible swap''' possible_swap_combination = [] edges = list(G.edges()).copy() for current_edge in edges: possible_swap_combination.append([current_edge]) '''check whether DG already has appliable vertexes, if has, then execute them''' cost_g_initial = 0 #this is the count for number of added gates num_all_vertex = len(DG.nodes()) executed_vertex = [] executable_vertex = ct.FindExecutableNode(DG) if display_complete_state == True: print('RemoteCNOTandWindowLookAhead start') print('level_lookahead is', level_lookahead) print('fall back count is', total_fallback_num) res = ct.ExecuteAllPossibileNodesInDG(executable_vertex, executed_vertex, G, DG, initial_map, draw, DiG, edges_DiG, cir_phy, q_phy) executed_vertex = res[0] executable_vertex = res[1] '''initialize search tree''' search_tree = nx.DiGraph() next_node_list = [1] cost_h_initial = CalculateHeuristicCost(initial_map, DG, executable_vertex, executed_vertex, shortest_length_G, shortest_path_G, SWAP_cost, max_shortest_length_G, level_lookahead, DiG) cost_total_initial = CalculateTotalCost(cost_h_initial, 0) AddNewNodeToSearchTree(0, search_tree, initial_map, cost_g_initial, cost_h_initial, cost_total_initial, executed_vertex, executable_vertex) '''old version for adding nodes''' # ============================================================================= # search_tree.nodes[0]['mapping'] = initial_map # search_tree.nodes[0]['cost_g'] = cost_g_initial#this is the count for number of added gates # search_tree.nodes[0]['cost_h'] = cost_total_initial # search_tree.nodes[0]['num_executed_vertex'] = num_executed_vertex # ============================================================================= if draw == True: search_tree.nodes[0]['phy_circuit'] = cir_phy if len(executed_vertex) == num_all_vertex: finished_nodes.append(0) leaf_nodes = [0] num_pruned_nodes_list = [0] if display_complete_state == True: print(num_all_vertex - len(search_tree.nodes[0]['executed_vertex']), 'gates remaining') '''expand search tree for the first time''' for i in range(depth_lookahead + 1): if finished_nodes != []: break res = ExpandTreeForNextStep(G, DG, search_tree, leaf_nodes, possible_swap_combination, SWAP_cost, shortest_length_G, shortest_path_G, next_node_list, max_shortest_length_G, min_remoteCNOT_hop, level_lookahead, q_phy, draw, DiG) leaf_nodes = res[2] finished_nodes.extend(res[1]) if finished_nodes == []: best_leaf_node = res[0] '''initialize fall back module''' if use_fallback == True: fallback_count = total_fallback_num fallback_vertex = 0 pre_num_executed_vertex = len(executed_vertex) flag_no_leaf_fallback = False round_num = 0 while finished_nodes == []: round_num += 1 ST_file = open('ST_file.txt', 'a') ST_file.write('round number is ' + str(round_num) + '\n' + '\n') ST_file.close() next_node = FindNextNodeAndRenewTree(search_tree, best_leaf_node, depth_lookahead) leaf_nodes = ct.FindAllLeafNodesInDG(search_tree) if use_prune == True: SearchTreeLeafNodesPruning(search_tree, next_node, leaf_nodes, num_pruned_nodes_list) '''check whether fallback is needed''' if len(leaf_nodes) == 0: flag_no_leaf_fallback = True else: res = ExpandTreeForNextStep( G, DG, search_tree, leaf_nodes, possible_swap_combination, SWAP_cost, shortest_length_G, shortest_path_G, next_node_list, max_shortest_length_G, min_remoteCNOT_hop, level_lookahead, q_phy, draw, DiG) else: res = ExpandTreeForNextStep(G, DG, search_tree, leaf_nodes, possible_swap_combination, SWAP_cost, shortest_length_G, shortest_path_G, next_node_list, max_shortest_length_G, min_remoteCNOT_hop, level_lookahead, q_phy, draw, DiG) best_leaf_node = res[0] '''renew fallback count''' if use_fallback == True: #print(fallback_count) current_num_executed_vertex = len( search_tree.nodes[next_node]['executed_vertex']) #print(current_num_executed_vertex) if pre_num_executed_vertex == current_num_executed_vertex: fallback_count -= 1 else: if pre_num_executed_vertex < current_num_executed_vertex: pre_num_executed_vertex = current_num_executed_vertex fallback_vertex = next_node fallback_count = total_fallback_num '''check whether fallback is needed''' if fallback_count < 0 or flag_no_leaf_fallback == True: if display_complete_state == True: if fallback_count < 0: print('fall back') if flag_no_leaf_fallback == True: print('no leaf fall back') fallback_count = total_fallback_num flag_no_leaf_fallback = False res = FallBack(fallback_vertex, G, DG, search_tree, next_node_list, shortest_path_G, shortest_length_G, shortest_length_G_with4H, max_shortest_length_G, level_lookahead, possible_swap_combination, depth_lookahead, SWAP_cost, draw, q_phy, edges_DiG, DiG) best_leaf_node = res[0] next_node = res[3] if debug_mode == True: print(search_tree.nodes[best_leaf_node]['phy_circuit'].draw()) if display_complete_state == True: print( num_all_vertex - len(search_tree.nodes[best_leaf_node]['executed_vertex']), 'gates remaining') finished_nodes = res[1] '''find the best finished node''' best_CNOT_count = None for node in finished_nodes: if best_CNOT_count == None: best_finish_node = node best_CNOT_count = search_tree.nodes[node]['cost_g'] else: current_CNOT_count = search_tree.nodes[node]['cost_g'] if current_CNOT_count < best_CNOT_count: best_finish_node = node best_CNOT_count = current_CNOT_count swap_count = search_tree.nodes[best_finish_node]['cost_g'] / SWAP_cost additional_gate_count = search_tree.nodes[best_finish_node]['cost_g'] '''draw physical circuit''' if draw == True: best_cir_phy = search_tree.nodes[best_finish_node]['phy_circuit'] #print(best_cir_phy.draw()) if debug_mode == True: print('start saving output physical circuit') fig = (best_cir_phy.draw(scale=0.7, filename=None, style=None, output='mpl', interactive=False, line_length=None, plot_barriers=True, reverse_bits=False)) fig.savefig('Circuit_RemoteCNOTandWindowLookAhead.pdf', format='pdf', papertype='a4') if debug_mode == True: print('circuit saved') else: best_cir_phy = None '''number of traversed states''' num_total_state = next_node_list[0] - 1 num_pruned_nodes = num_pruned_nodes_list[0] #nx.draw(search_tree, with_labels=True) nx.draw(search_tree, with_labels=True) return swap_count, num_total_state, num_total_state - num_pruned_nodes, additional_gate_count, best_cir_phy, search_tree.nodes[ best_finish_node]['mapping']
def FallBack(father_node, G, DG, search_tree, next_node_list, shortest_path_G, shortest_length_G, shortest_length_G_with4H, max_shortest_length_G, level_lookahead, possible_swap_combination, depth_lookahead, SWAP_cost, draw, q_phy, edges_DiG, DiG): '''fallback''' leaf_nodes = [] '''get attributes from current leaf node''' current_map = search_tree.nodes[father_node]['mapping'] cost_g_current = search_tree.nodes[father_node]['cost_g'] executed_vertex_current = search_tree.nodes[father_node]['executed_vertex'] executable_vertex_current = search_tree.nodes[father_node][ 'executable_vertex'] #print('remaining gates before', len(DG_current.nodes())) if draw == True: cir_phy_current = search_tree.nodes[father_node]['phy_circuit'] '''fallback method: find the vertex in DG to be executed along shoetest path''' select_vertex = None for current_vertex in executable_vertex_current: current_operation = DG.nodes[current_vertex]['operation'] if select_vertex == None: select_vertex = current_vertex select_gate_cost = current_operation.CalSWAPCost( current_map, shortest_length_G_with4H) * SWAP_cost else: current_swap_cost = current_operation.CalSWAPCost( current_map, shortest_length_G_with4H) * SWAP_cost if fallback_mode == 1 and current_swap_cost > select_gate_cost: select_vertex = current_vertex select_gate_cost = current_swap_cost if fallback_mode == 0 and current_swap_cost < select_gate_cost: select_vertex = current_vertex select_gate_cost = current_swap_cost '''initialize next node''' next_map = current_map.Copy() executable_vertex_next = executable_vertex_current.copy() executed_vertex_next = executed_vertex_current.copy() cost_g_next = cost_g_current if draw == True: cir_phy_next = copy.deepcopy(cir_phy_current) else: cir_phy_next = None '''execute selected operation''' select_operation = DG.nodes[select_vertex]['operation'] v_c = current_map.LogToPhy(select_operation.control_qubit) v_t = current_map.LogToPhy(select_operation.target_qubit) select_path = shortest_path_G[v_c][v_t] if (use_remoteCNOT_fallback == True) and (shortest_length_G[v_c][v_t] <= min_remoteCNOT_hop ) and (shortest_length_G[v_c][v_t] >= 2): '''remote CNOT''' #print('current_hop is ', current_hop) # number of additional CNOTs in this remote CNOT operation cost_CNOT_remoteCNOT = ct.CalRemoteCNOTCostinArchitectureGraph( select_path, DiG) - 1 #这里减1是因为要去除本身的CNOT print('number of added gates for fallback is', cost_CNOT_remoteCNOT) #if cost_CNOT_remoteCNOT <= ct.OperationCost(current_operation, next_map, G, shortest_length_G, edges_DiG, shortest_path_G) cost_g_next = cost_g_current + cost_CNOT_remoteCNOT if draw == True: cir_phy_next = copy.deepcopy(cir_phy_current) ct.RemoteCNOTinArchitectureGraph(select_path, cir_phy_next, q_phy, DiG) cir_phy_next.barrier() executable_vertex_next = ct.FindExecutableNode(DG, executed_vertex_next, executable_vertex_next, [select_vertex]) # ============================================================================= # else: # '''swap along the shortest path''' # add_gates_count = ct.ConductCNOTInDGAlongPath(DG_next, select_vertex, select_path, next_map, draw, q_phy, cir_phy_next, edges_DiG) # num_executed_vertex_next += 1 # executable_vertex_next = ct.FindExecutableNode(DG_next) # cost_g_next += add_gates_count # ============================================================================= else: '''swap along the shortest path''' add_gates_count = ct.ConductCNOTInDGAlongPath(DG, select_vertex, select_path, next_map, draw, False, q_phy, cir_phy_next, edges_DiG) print('number of added gates for fallback is', add_gates_count) executable_vertex_next = ct.FindExecutableNode(DG, executed_vertex_next, executable_vertex_next, [select_vertex]) cost_g_next += add_gates_count '''check whether this window already has appliable vertexes, if has, then execute them''' res = ct.ExecuteAllPossibileNodesInDG(executable_vertex_next, executed_vertex_next, G, DG, next_map, draw, DiG, edges_DiG, cir_phy_next, q_phy) executed_vertex_next = res[0] executable_vertex_next = res[1] '''calculate h cost''' cost_h_next = CalculateHeuristicCost(next_map, DG, executable_vertex_next, executed_vertex_next, shortest_length_G, shortest_path_G, SWAP_cost, max_shortest_length_G, level_lookahead, DiG) cost_total_next = CalculateTotalCost(cost_h_next, cost_g_next) '''generate next node''' next_node = next_node_list[0] new_father_node = next_node next_node_list[0] = next_node_list[0] + 1 leaf_nodes.append(next_node) AddNewNodeToSearchTree(next_node, search_tree, next_map, cost_g_next, cost_h_next, cost_total_next, executed_vertex_next, executable_vertex_next) search_tree.add_edge(father_node, next_node) ST_file = open('ST_file.txt', 'a') ST_file.write('added edge is ' + str((leaf_node, next_node)) + '\n' + '\n') ST_file.close() if executable_vertex_next == []: return next_node, [next_node], leaf_nodes, new_father_node #print('remaining gates after', len(DG_next.nodes())) if draw == True: search_tree.nodes[next_node]['phy_circuit'] = cir_phy_next '''delete residula nodes in search tree''' delete_nodes = list(search_tree.nodes()) delete_nodes.remove(new_father_node) search_tree.remove_nodes_from(delete_nodes) '''expand search tree for the first time''' finished_nodes = [] for i in range(depth_lookahead + 1): res = ExpandTreeForNextStep(G, DG, search_tree, leaf_nodes, possible_swap_combination, SWAP_cost, shortest_length_G, shortest_path_G, next_node_list, max_shortest_length_G, min_remoteCNOT_hop, level_lookahead, q_phy, draw, DiG) leaf_nodes = res[2] finished_nodes.extend(res[1]) best_node = res[0] return best_node, finished_nodes, leaf_nodes, new_father_node
def ExpandTreeForNextStep(G, DG, search_tree, leaf_nodes, possible_swap_combination, SWAP_cost, shortest_length_G, shortest_path_G, next_node_list, max_shortest_length_G, min_remoteCNOT_hop, level_lookahead, q_phy, draw, DiG): best_cost_total = None flag_4H = 0 finished_nodes = [] added_nodes = [] cir_phy_next = None num_all_vertex = len(DG.nodes()) if DiG != None: edges_DiG = list(DiG.edges) else: edges_DiG = None '''find all possible operation for next step and expand the search tree accordingly''' #print('number of leaf nodes is', len(leaf_nodes)) for leaf_node in leaf_nodes: #print('current leaf node is', leaf_node) '''get attributes from current leaf node''' current_map = search_tree.nodes[leaf_node]['mapping'] cost_g_current = search_tree.nodes[leaf_node]['cost_g'] executed_vertex_current = search_tree.nodes[leaf_node][ 'executed_vertex'] executable_vertex_current = search_tree.nodes[leaf_node][ 'executable_vertex'] if draw == True: cir_phy_current = search_tree.nodes[leaf_node]['phy_circuit'] '''add successor nodes to current node''' '''SWAP''' for swaps in possible_swap_combination: '''judge whether the swap in trivial to avoid unnecessary state''' flag_nontrivial = ct.CheckSWAPInvolved(swaps, executable_vertex_current, DG, current_map) print('FL is ', executable_vertex_current) print('SWAP ', swaps) print(flag_nontrivial) if flag_nontrivial == False: #print('trivival swap') continue #print(swaps) #start = time() #elapsed = (time() - start) #print("deep copy Time used:", elapsed, 's') if draw == True: cir_phy_next = copy.deepcopy(cir_phy_current) executable_vertex_next = executable_vertex_current.copy() executed_vertex_next = executed_vertex_current.copy() cost_g_next = cost_g_current + len(swaps) * SWAP_cost next_map = current_map.Copy() for current_swap in swaps: '''conduct each swap''' v0 = current_swap[0] v1 = current_swap[1] next_map.RenewMapViaExchangeCod(v0, v1) if draw == True: cir_phy_next.swap(q_phy[v0], q_phy[v1]) '''check whether this window already has appliable vertexes, if has, then execute them''' res = ct.ExecuteAllPossibileNodesInDG(executable_vertex_next, executed_vertex_next, G, DG, next_map, draw, DiG, edges_DiG, cir_phy_next, q_phy) executed_vertex_next = res[0] executable_vertex_next = res[1] '''calculate cost for the new node''' #print('executable_vertex_next is', executable_vertex_next) cost_h_next = CalculateHeuristicCost( next_map, DG, executable_vertex_next, executed_vertex_next, shortest_length_G, shortest_path_G, SWAP_cost, max_shortest_length_G, level_lookahead, DiG) cost_total_next = CalculateTotalCost(cost_h_next, cost_g_next) '''generate next node''' next_node = next_node_list[0] next_node_list[0] = next_node_list[0] + 1 added_nodes.append(next_node) AddNewNodeToSearchTree(next_node, search_tree, next_map, cost_g_next, cost_h_next, cost_total_next, executed_vertex_next, executable_vertex_next, current_swap) search_tree.add_edge(leaf_node, next_node) ST_file = open('ST_file.txt', 'a') ST_file.write('added edge is ' + str((leaf_node, next_node)) + '\n' + '\n') ST_file.close() if draw == True: search_tree.nodes[next_node]['phy_circuit'] = cir_phy_next fig = (cir_phy_next.draw(scale=0.7, filename=None, style=None, output='mpl', interactive=False, line_length=None, plot_barriers=True, reverse_bits=False)) fig.savefig(str(next_node) + '.pdf', format='pdf', papertype='a4') '''renew best expanded node in search tree''' num_remaining_vertex_next = num_all_vertex - len( executed_vertex_next) if num_remaining_vertex_next == 0: finished_nodes.append(next_node) if best_cost_total == None: best_cost_total = cost_total_next best_node = next_node else: if cost_total_next < best_cost_total: best_cost_total = cost_total_next best_node = next_node '''execute possible CNOT needing 4 extra 4 H''' if DiG != None: for vertex in executable_vertex_current: if ct.IsVertexInDGOperatiable(vertex, DG, G, current_map) == True: '''check whether this CNOT needs 4 H gates to convert direction''' flag_4H = ct.CheckCNOTNeedConvertDirection2( vertex, DG, current_map, edges_DiG) if flag_4H == False: raise Exception( 'unexpected operatible CNOT without 4 H gates') if flag_4H == True: '''if need 4 extra H, then execute it and add to the new node''' next_map = current_map.Copy() cost_g_next = cost_g_current + flag_4H * 4 executed_vertex_next = executed_vertex_current.copy() if draw == True: cir_phy_next = copy.deepcopy(cir_phy_current) ct.ConductCNOTOperationInVertex( DG, vertex, current_map, cir_phy_next, q_phy, reverse_drection=flag_4H, remove_node=False) cir_phy_next.barrier() executable_vertex_next = executable_vertex_current.copy( ) executable_vertex_next = ct.FindExecutableNode( DG, executed_vertex_next, executable_vertex_next, [vertex]) '''check whether this window already has appliable vertexes, if has, then execute them''' res = ct.ExecuteAllPossibileNodesInDG( executable_vertex_next, executed_vertex_next, G, DG, next_map, draw, DiG, edges_DiG, cir_phy_next, q_phy) executed_vertex_next = res[0] executable_vertex_next = res[1] '''calculate cost for the new node''' #print('executable_vertex_next is', executable_vertex_next) cost_h_next = CalculateHeuristicCost( next_map, DG, executable_vertex_next, executed_vertex_next, shortest_length_G, shortest_path_G, SWAP_cost, max_shortest_length_G, level_lookahead, DiG) cost_total_next = CalculateTotalCost( cost_h_next, cost_g_next) '''generate next node''' next_node = next_node_list[0] next_node_list[0] = next_node_list[0] + 1 added_nodes.append(next_node) qbits = DG.node[vertex]['operation'].involve_qubits AddNewNodeToSearchTree(next_node, search_tree, next_map, cost_g_next, cost_h_next, cost_total_next, executed_vertex_next, executable_vertex_next, '4H' + str(qbits)) search_tree.add_edge(leaf_node, next_node) print('add 4H ', next_node) ST_file = open('ST_file.txt', 'a') ST_file.write('added edge is ' + str((leaf_node, next_node)) + '\n' + '\n') ST_file.close() if draw == True: search_tree.nodes[next_node][ 'phy_circuit'] = cir_phy_next fig = (cir_phy_next.draw(scale=0.7, filename=None, style=None, output='mpl', interactive=False, line_length=None, plot_barriers=True, reverse_bits=False)) fig.savefig(str(next_node) + '.pdf', format='pdf', papertype='a4') '''renew best expanded node in search tree''' num_remaining_vertex_next = num_all_vertex - len( executed_vertex_next) if num_remaining_vertex_next == 0: finished_nodes.append(next_node) if best_cost_total == None: best_cost_total = cost_total_next best_node = next_node else: if cost_total_next < best_cost_total: best_cost_total = cost_total_next best_node = next_node '''remote CNOT''' #f use_remoteCNOT == True and DiG == None: if use_remoteCNOT == True: '''judge whether remote CNOT is applicable''' for current_vertex in executable_vertex_current: '''calculate distance between two input qubits''' current_operation = DG.node[current_vertex]['operation'] q0 = current_operation.involve_qubits[0] q1 = current_operation.involve_qubits[1] v0 = current_map.DomToCod(q0) v1 = current_map.DomToCod(q1) current_hop = shortest_length_G[v0][v1] '''if a remote CNOT can be done, then execute it''' if (current_hop <= min_remoteCNOT_hop) and (current_hop >= 2): next_map = current_map.Copy() executable_vertex_next = executable_vertex_current.copy() executed_vertex_next = executed_vertex_current.copy() #print('current_hop is ', current_hop) current_path = shortest_path_G[v0][v1] # number of additional CNOTs in this remote CNOT operation cost_CNOT_remoteCNOT = ct.CalRemoteCNOTCostinArchitectureGraph( current_path, DiG) - 1 #这里减1是因为要去除本身的CNOT cost_g_next = cost_g_current + cost_CNOT_remoteCNOT if draw == True: cir_phy_next = copy.deepcopy(cir_phy_current) ct.RemoteCNOTinArchitectureGraph( current_path, cir_phy_next, q_phy, DiG) cir_phy_next.barrier() executable_vertex_next = ct.FindExecutableNode( DG, executed_vertex_next, executable_vertex_next, [current_vertex]) '''check whether this window already has appliable vertexes, if has, then execute them''' '''old version without considering the direction of CNOT gate''' # ============================================================================= # temp = True # while temp == True: # temp = False # for vertex in executable_vertex_next: # if ct.IsVertexInDGOperatiable(vertex, DG_next, G, next_map) == True: # if draw == True: # ct.ConductOperationInVertex(DG_next, vertex, next_map, cir_phy_next, q_phy) # cir_phy_next.barrier() # else: # DG_next.remove_node(vertex) # num_executed_vertex_next += 1 # temp = True # if temp == True: executable_vertex_next = ct.FindExecutableNode(DG_next) # ============================================================================= '''check whether this window already has appliable vertexes, if has, then execute them''' '''new version considering the direction of CNOT gate''' res = ct.ExecuteAllPossibileNodesInDG( executable_vertex_next, executed_vertex_next, G, DG, next_map, draw, DiG, edges_DiG, cir_phy_next, q_phy) executed_vertex_next = res[0] executable_vertex_next = res[1] '''calculate cost for the new node''' cost_h_next = CalculateHeuristicCost( next_map, DG, executable_vertex_next, executed_vertex_next, shortest_length_G, shortest_path_G, SWAP_cost, max_shortest_length_G, level_lookahead, DiG) # ============================================================================= # cost_h_next = search_tree.nodes[leaf_node]['cost_h'].copy() # cost_h_next[0] = cost_h_next[0] - ct.OperationCost(current_operation, next_map, G, shortest_length_G, edges_DiG, shortest_path_G) # ============================================================================= cost_total_next = CalculateTotalCost( cost_h_next, cost_g_next) '''generate next node''' next_node = next_node_list[0] next_node_list[0] = next_node_list[0] + 1 added_nodes.append(next_node) AddNewNodeToSearchTree(next_node, search_tree, next_map, cost_g_next, cost_h_next, cost_total_next, executed_vertex_next, executable_vertex_next) search_tree.add_edge(leaf_node, next_node) ST_file = open('ST_file.txt', 'a') ST_file.write('added edge is ' + str((leaf_node, next_node)) + '\n' + '\n') ST_file.close() if draw == True: search_tree.nodes[next_node][ 'phy_circuit'] = cir_phy_next '''renew best expanded node in search tree''' num_remaining_vertex_next = num_all_vertex - len( executed_vertex_next) if num_remaining_vertex_next == 0: finished_nodes.append(next_node) if best_cost_total == None: best_cost_total = cost_total_next best_node = next_node else: if cost_total_next < best_cost_total: best_cost_total = cost_total_next best_node = next_node ST_file = open('ST_file.txt', 'a') ST_file.write('chosen node is ' + str(best_node) + '\n') ST_file.close() return best_node, finished_nodes, added_nodes
def AStarSearchLookAhead(q_phy, cir_phy, G, DG, initial_map, shortest_length_G, shortest_path_G=None, possible_swap_combination=None, draw=False, DiG=None): # only set True when debugging debug_model = False display_complete_state = 1 flag_4H = 0 if DiG != None: edges_DiG = list(DiG.edges) #print('egdes are', edges_DiG) SWAP_cost = 7 else: SWAP_cost = 3 '''initial level and map''' executable_vertex = ct.FindExecutableNode(DG) finished_map = initial_map #executable_operation = ct.FindExecutableOperation(DG, executable_vertex) '''find all possible SWAP combinations for search in level''' if possible_swap_combination == None: possible_swap_combination = ct.FindAllPossibleSWAPParallel(G) '''search in all levels''' next_node_list = [1] swap_count = 0 while executable_vertex != []: if debug_model == True: jjj = 5 if display_complete_state == True: print(len(list(DG.node)), 'gates remaining') '''initial search tree for current level''' search_tree = nx.DiGraph() search_tree.add_node(0) next_node_list = [1] search_tree.nodes[0]['mapping'] = finished_map.Copy() search_tree.nodes[0]['cost_g'] = 0 search_tree.nodes[0]['exist_swaps'] = [] search_tree.nodes[0]['identity'] = search_tree.nodes[0]['mapping'].MapToTuple() '''initial nodes set for current level''' leaf_nodes_identity = search_tree.nodes[0]['identity'] leaf_nodes = {str(leaf_nodes_identity): 0} none_leaf_nodes = {} '''calculate heuristic cost for initial node''' cost_h_total = ct.HeuristicCostZulehnerLookAhead(finished_map, DG, executable_vertex, shortest_length_G, shortest_path_G, DiG) cost_h = cost_h_total[0] cost_h_current_level = cost_h_total[1] flag_finished = cost_h_total[2] search_tree.nodes[0]['cost_h'] = cost_h search_tree.nodes[0]['cost_h_current_level'] = cost_h_current_level search_tree.nodes[0]['flag_finished'] = flag_finished search_tree.nodes[0]['cost_total'] = search_tree.nodes[0]['cost_g'] + search_tree.nodes[0]['cost_h'] if flag_finished == True: finished_node = 0 finished_map = search_tree.nodes[finished_node]['mapping'] else: finished_node = None '''search til find the finished node''' flag_finished = False '''expand tree for the first time, set father node 0''' finished_node = ExpandSearchTree(DG, search_tree, next_node_list, 0, none_leaf_nodes, leaf_nodes, finished_node, executable_vertex, shortest_length_G, possible_swap_combination, shortest_path_G, DiG) while flag_finished == False: if debug_model == True: jjj -= 1 if jjj == 0: break '''set best leaf node as current node to be expanded''' father_node = None for node in leaf_nodes.values(): if father_node == None: father_node = node father_cost = search_tree.nodes[father_node]['cost_total'] else: if search_tree.nodes[node]['cost_total'] < father_cost: father_node = node father_cost = search_tree.nodes[father_node]['cost_total'] '''judge whether the search has finished''' if finished_node != None: finishe_node_cost = search_tree.nodes[finished_node]['cost_total'] if father_cost > finishe_node_cost: flag_finished = True break '''expand search tree based on current father node''' finished_node = ExpandSearchTree(DG, search_tree, next_node_list, father_node, none_leaf_nodes, leaf_nodes, finished_node, executable_vertex, shortest_length_G, possible_swap_combination, shortest_path_G, DiG) '''conduct SWAP operations before each level''' if draw == True: swaps = search_tree.nodes[finished_node]['exist_swaps'] for current_swap in swaps: cir_phy.swap(q_phy[current_swap[0]], q_phy[current_swap[1]]) '''conduct CNOT operations in current level''' #print('finished node is', finished_node) #print(search_tree.nodes[finished_node]['exist_swaps']) swap_count += len(search_tree.nodes[finished_node]['exist_swaps']) finished_map = search_tree.nodes[finished_node]['mapping'] for vertex in executable_vertex: '''check whether this CNOT needs 4 H gates to convert direction''' if DiG != None: flag_4H = ct.CheckCNOTNeedConvertDirection2(vertex, DG, finished_map, edges_DiG) swap_count += flag_4H*4/7 ct.ConductCNOTOperationInVertex(DG, vertex, finished_map, cir_phy, q_phy, flag_4H) cir_phy.barrier() if debug_model == True: print(cir_phy.draw()) '''refresh executable operations and go to the next level''' executable_vertex = ct.FindExecutableNode(DG) if draw == True: print(cir_phy.draw()) fig = (cir_phy.draw(scale=0.7, filename=None, style=None, output='mpl', interactive=False, line_length=None, plot_barriers=True, reverse_bits=False)) fig.savefig('circuit_Astarlookahead.eps', format='eps', dpi=1000) '''number of traversed states''' num_total_state = next_node_list[0] - 1 additional_gates = swap_count * SWAP_cost #nx.draw(search_tree, with_labels=True) return swap_count, num_total_state, additional_gates
def HeuristicGreedySearch(q_phy, cir_phy, G, DG, initial_map, shortest_length_G, possible_swap_combination=None, draw=False): # only set True when debugging debug_model = False # adjust parameter to Heuristic Cost calculation, [worst, sum, best] adjust_parameter = (1, 0, 0, 0.0001) '''initial level and map''' executable_vertex = ct.FindExecutableNode(DG) #executable_operation = ct.FindExecutableOperation(DG, executable_vertex) current_map = initial_map.Copy() '''find all possible SWAP combinations for search in level''' if possible_swap_combination == None: possible_swap_combination = ct.FindAllPossibleSWAPParallel(G) '''search in all levels''' swap_count = 0 while executable_vertex != []: if debug_model == True: jjj = 5 #print(len(list(DG.node)), 'gates remaining') cost_g = 0 cost_h_total = ct.HeuristicCostZulehner(current_map, DG, executable_vertex, shortest_length_G) cost_h = cost_h_total[0] * adjust_parameter[0] + cost_h_total[ 1] * adjust_parameter[1] + cost_h_total[2] * adjust_parameter[ 2] + cost_h_total[3] * adjust_parameter[3] #print('executable vertex is', executable_vertex) cost_h_current = cost_h cost_total_best = cost_g + cost_h cost_h_best = cost_h best_vertex = cost_h_total[4] #cost_total_best = None while int(cost_h_current) != 0: if debug_model == True: jjj -= 1 if jjj == 0: break swaps_best = None '''remove swaps that have no effect on any operations in current level''' '''ATTENTION: this code block may be not correct''' ''' v_op = [] for op in executable_vertex: q = DG.node[op]['operation'].involve_qubits for i in q: v_op.append(current_map.DomToCod(i)) possible_swap_combination_remove = possible_swap_combination.copy() for swaps in possible_swap_combination_remove: remove_flag = False for swap in swaps: if (not (swap[0] in v_op)) and (not (swap[1] in v_op)): remove_flag = True break if remove_flag == True: possible_swap_combination_remove.remove(swaps) ''' possible_swap_combination_remove = possible_swap_combination '''search until find the goal state''' for swaps in possible_swap_combination_remove: '''evaluate all possible swap combinations and choose the best as next state''' cost_g_current = cost_g + len(swaps) current_map_copy = current_map.Copy() for current_swap in swaps: '''try to conduct each swap''' v0 = current_swap[0] v1 = current_swap[1] current_map_copy.RenewMapViaExchangeCod(v0, v1) cost_h_total = ct.HeuristicCostZulehner( current_map_copy, DG, executable_vertex, shortest_length_G) cost_h_current = cost_h_total[0] * adjust_parameter[ 0] + cost_h_total[1] * adjust_parameter[1] + cost_h_total[ 2] * adjust_parameter[2] + cost_h_total[ 3] * adjust_parameter[3] cost_total_current = cost_g_current + cost_h_current #print(cost_total_current,swaps) '''judge whether current state is better''' if (cost_total_current <= cost_total_best) and (cost_h_current < cost_h_best): swaps_best = swaps cost_h_best = cost_h_current cost_total_best = cost_total_current best_vertex = cost_h_total[4] if swaps_best != None: '''conduct chosen best swap combination and renew swap counting and current map for next state''' #print(swaps_best) swap_count = swap_count + len(swaps_best) cost_h_current = cost_h_best cost_total_best = cost_h_best for swap in swaps_best: v0 = swap[0] v1 = swap[1] ct.SWAPInArchitectureGraph(v0, v1, current_map, q_phy, cir_phy) if debug_model == True: print(cir_phy.draw()) else: '''no better swaps found, fallback, i.e., use the worst CNOT as the only gate in current operation''' executable_vertex = [best_vertex] cost_h_total = ct.HeuristicCostZulehner( current_map, DG, executable_vertex, shortest_length_G) cost_h = cost_h_total[0] * adjust_parameter[0] + cost_h_total[ 1] * adjust_parameter[1] + cost_h_total[ 2] * adjust_parameter[2] + cost_h_total[ 3] * adjust_parameter[3] cost_h_current = cost_h cost_total_best = cost_g + cost_h cost_h_best = cost_h best_vertex = cost_h_total[4] '''conduct operations in current level''' for vertex in executable_vertex: ct.ConductOperationInVertex(DG, vertex, current_map, cir_phy, q_phy) cir_phy.barrier() if debug_model == True: print(cir_phy.draw()) '''refresh executable operations and go to the next level''' executable_vertex = ct.FindExecutableNode(DG) if draw == True: print(cir_phy.draw()) return swap_count
def HeuristicCostZhouML(ANN, current_map, DG, executed_vertex, executable_vertex, shortest_length_G, shortest_path_G, level_lookahead, DiG=None): ''' Calculate heuristic cost for remaining gates and return best path this cost is based on the minimial distance in architecture graph between two input qubits of each operations ATTENTION: this function is currently only for bidirectional AG Q20!!! for direction AG it need further modification input: ANN -> neural network via keras API ''' mapping = current_map if DiG != None: edges = list(DiG.edges) #DG_copy = copy.deepcopy(DG) executable_vertex_copy = executable_vertex.copy() executed_vertex_copy = executed_vertex.copy() num_counted_gates = 0 weights = [] data_set = np.zeros([len(level_lookahead), 20, 20]) num_q_log = 20 for current_lookahead_level in range(len(level_lookahead)): '''set the weight parameter for current level''' if current_lookahead_level == 0: '''current level''' current_executable_vertex = executable_vertex_copy weight = 1 else: '''lookahead level''' #DG_copy.remove_nodes_from(executable_vertex) current_executable_vertex = ct.FindExecutableNode( DG, executed_vertex_copy, current_executable_vertex, current_executable_vertex.copy()) weight = level_lookahead[current_lookahead_level - 1] weights.append(weight) num_counted_gates += len(current_executable_vertex) CNOT_list = [] for v_DG in current_executable_vertex: current_operation = DG.node[v_DG]['operation'] q0 = current_operation.involve_qubits[0] q1 = current_operation.involve_qubits[1] v0 = mapping.DomToCod(q0) v1 = mapping.DomToCod(q1) CNOT_list.append((v0, v1)) '''form data set for ANN input''' map_current = ct.machinelearning.CreateCircuitMap(CNOT_list, num_q_log) data_set[current_lookahead_level] = map_current '''calculate swap cost via ANN''' res = ct.machinelearning.CalSwapCostViaANN(ANN, data_set) #res = np.random.randint(19, size=len(level_lookahead))#test only!!! '''multiply weights to each level''' sum_num_swap = 0 for current_lookahead_level in range(len(level_lookahead)): sum_num_swap += res[current_lookahead_level] * weights[ current_lookahead_level] return None, sum_num_swap
def HeuristicCostZhou1(current_map, DG, executed_vertex, executable_vertex, shortest_length_G, shortest_path_G, level_lookahead, DiG=None): ''' Calculate heuristic cost for remaining gates and return best path this cost is based on the minimial distance in architecture graph between two input qubits of each operations ''' worst_num_swap = None count_same_worst = 0 sum_num_swap = 0 best_num_swap = None mapping = current_map best_executable_vertex = None best_path = None if DiG != None: edges = list(DiG.edges) #DG_copy = copy.deepcopy(DG) executable_vertex_copy = executable_vertex.copy() executed_vertex_copy = executed_vertex.copy() num_counted_gates = 0 for current_lookahead_level in range(len(level_lookahead)): if current_lookahead_level == 0: '''current level''' current_executable_vertex = executable_vertex_copy weight = 1 else: '''lookahead level''' #DG_copy.remove_nodes_from(executable_vertex) current_executable_vertex = ct.FindExecutableNode( DG, executed_vertex_copy, current_executable_vertex, current_executable_vertex.copy()) weight = level_lookahead[current_lookahead_level - 1] num_counted_gates += len(current_executable_vertex) for v_DG in current_executable_vertex: flag_4H = 0 current_operation = DG.node[v_DG]['operation'] q0 = current_operation.involve_qubits[0] q1 = current_operation.involve_qubits[1] v0 = mapping.DomToCod(q0) v1 = mapping.DomToCod(q1) current_num_swap = shortest_length_G[v0][v1] - 1 '''if architecture graph is directed, confirm whether use 4 H gates to change direction''' if DiG != None: flag_4H = ct.CheckCNOTNeedConvertDirection( v0, v1, shortest_path_G[v0][v1], edges) current_num_swap += flag_4H * 4 / 7 '''renew number of all swaps''' current_num_swap = current_num_swap * weight #multiply the weight for cost of gates in different levels sum_num_swap = sum_num_swap + current_num_swap '''renew swap number of worst operation''' if worst_num_swap == None: worst_num_swap = current_num_swap count_same_worst = 0 else: if current_num_swap > worst_num_swap: worst_num_swap = current_num_swap count_same_worst = 0 else: if current_num_swap == worst_num_swap: count_same_worst += 1 '''renew swap number of best operation''' if best_num_swap == None: best_num_swap = current_num_swap best_path = shortest_path_G[v0][v1] best_executable_vertex = v_DG else: if current_num_swap < best_num_swap: best_num_swap = current_num_swap best_path = shortest_path_G[v0][v1] best_executable_vertex = v_DG return worst_num_swap, sum_num_swap, best_num_swap, best_executable_vertex, best_path, count_same_worst, num_counted_gates
def RemoteCNOTandWindow(q_phy, cir_phy, G, DG, initial_map, shortest_length_G, shortest_path_G, possible_swap_combination=None, draw=False): # only set True when debugging debug_model = False flag_fallback = False SWAP_cost = 3 min_remoteCNOT_hop = 3 ues_which_h = 1 #decide to use which heuristic cost(max, min or total?) '''initial level and map''' executable_vertex = ct.FindExecutableNode(DG) #executable_operation = ct.FindExecutableOperation(DG, executable_vertex) current_map = initial_map.Copy() '''find all possible SWAP combinations for search in level''' if possible_swap_combination == None: possible_swap_combination = ct.FindAllPossibleSWAPParallel(G) '''search in all levels''' swap_count = 0 while executable_vertex != []: '''this section is only for debugging''' if debug_model == True: jjj = 5 #print(len(list(DG.node)), 'gates remaining') '''check whether this window already has appliable vertex''' temp = False for vertex in executable_vertex : if ct.IsVertexInDGOperatiable(vertex, DG, G, current_map) == True: ct.ConductOperationInVertex(DG, vertex, current_map, cir_phy, q_phy) temp = True flag_fallback = False if temp == True: executable_vertex = ct.FindExecutableNode(DG) continue '''calculate the heuristic cost for all vertexes in current window''' cost_h_total = ct.HeuristicCostZhou1(current_map, DG, executable_vertex, shortest_length_G, shortest_path_G) cost_h = cost_h_total[ues_which_h] * SWAP_cost + cost_h_total[5]*0.00001 '''judge whether remote CNOT is applicable''' flag_remoteCNOT = False if cost_h_total[2] <= min_remoteCNOT_hop - 1: flag_remoteCNOT = True remoteCNOT_vertex = cost_h_total[3] remoteCNOT_path = cost_h_total[4] # number of additional CNOTs in this remote CNOT operation cost_CNOT_remoteCNOT = ct.CalRemoteCNOTCostinArchitectureGraph(remoteCNOT_path) - 1 #这里减1是因为要去除本身的CNOT #print('executable vertex is', executable_vertex) cost_h_current =cost_h #cost_total_best = None '''this section is only for debugging''' if debug_model == True: jjj -= 1 if jjj == 0: break possible_swap_combination_remove = possible_swap_combination cost_h_best = cost_h_current cost_total_best = cost_h_current + 0 swaps_best = None best_operation_type = None cost_h_backup = cost_h_total cost_h_backup2 = cost_h '''in each available window, search for best swap combination for next step''' for swaps in possible_swap_combination_remove: cost_g_current = len(swaps) * SWAP_cost current_map_copy = current_map.Copy() for current_swap in swaps: '''try to conduct each swap''' v0 = current_swap[0] v1 = current_swap[1] current_map_copy.RenewMapViaExchangeCod(v0, v1) cost_h_total = ct.HeuristicCostZhou1(current_map_copy, DG, executable_vertex, shortest_length_G, shortest_path_G) cost_h_current = cost_h_total[ues_which_h] * SWAP_cost + cost_h_total[5]*0.00001 cost_total_current = cost_g_current + cost_h_current #print(cost_total_current,swaps) '''judge whether current state is better''' if cost_total_current <= cost_total_best: swaps_best = swaps cost_h_best = cost_h_current best_operation_type = 'SWAP' cost_total_best = cost_total_current '''in each available window, search for best remote CNOT for next step if remote CNOT exists''' if flag_remoteCNOT == True: cost_total_remoteCNOT = cost_h_backup2 + cost_CNOT_remoteCNOT - (len(remoteCNOT_path) - 2)*SWAP_cost if cost_total_remoteCNOT <= cost_total_best: '''conduct remote CNOT''' CNOT_add = ct.RemoteCNOTinArchitectureGraph(remoteCNOT_path, cir_phy, q_phy) DG.remove_node(remoteCNOT_vertex) executable_vertex.remove(remoteCNOT_vertex) swap_count = swap_count + (CNOT_add - 1)/SWAP_cost '''refresh executable operations and go to the next level''' executable_vertex = ct.FindExecutableNode(DG) flag_fallback = False #print('best remoteCNOT') continue if (swaps_best != None) and (flag_fallback == False): '''conduct chosen best swap combination and renew swap counting and current map for next state''' #print(swaps_best) swap_count = swap_count + len(swaps_best) cost_h_current = cost_h_best for swap in swaps_best: v0 = swap[0] v1 = swap[1] ct.SWAPInArchitectureGraph(v0, v1, current_map, q_phy, cir_phy) if debug_model == True: print(cir_phy.draw()) else: if flag_remoteCNOT == False: '''conduct swap along shorstest path''' flag_fallback = True v0 = cost_h_backup[4][0] v1 = cost_h_backup[4][1] ct.SWAPInArchitectureGraph(v0, v1, current_map, q_phy, cir_phy) swap_count = swap_count + 1 #print('swap along shorstest path') else: '''conduct remote CNOT''' CNOT_add = ct.RemoteCNOTinArchitectureGraph(remoteCNOT_path, cir_phy, q_phy) DG.remove_node(remoteCNOT_vertex) executable_vertex.remove(remoteCNOT_vertex) executable_vertex = ct.FindExecutableNode(DG) swap_count = swap_count + (CNOT_add - 1)/SWAP_cost flag_fallback = False #print('remoteCNOT') '''conduct appliable operations in current level''' temp = False for vertex in executable_vertex : if ct.IsVertexInDGOperatiable(vertex, DG, G, current_map) == True: ct.ConductOperationInVertex(DG, vertex, current_map, cir_phy, q_phy) temp = True flag_fallback = False if temp == True: executable_vertex = ct.FindExecutableNode(DG) if debug_model == True: print(cir_phy.draw()) if draw == True: print(cir_phy.draw()) return swap_count