def ExecuteAllPossibileNodesInDG(executable_vertex, executed_vertex, G, DG, mapping, draw, DiG, edges_DiG, cir_phy=None, q_phy=None): '''check whether this window already has appliable vertexes, if has, then execute them''' temp = True while temp == True: temp = False removed_nodes = [] for vertex in executable_vertex: if ct.IsVertexInDGOperatiable(vertex, DG, G, mapping) == True: '''check whether this CNOT needs 4 H gates to convert direction''' if DiG != None: flag_4H = ct.CheckCNOTNeedConvertDirection2( vertex, DG, mapping, edges_DiG) if flag_4H == False: '''if no need 4 extra H, then execute it''' if draw == True: ct.ConductCNOTOperationInVertex( DG, vertex, mapping, cir_phy, q_phy, reverse_drection=flag_4H, remove_node=False) cir_phy.barrier() removed_nodes.append(vertex) temp = True else: '''if architecture graph is undirected, execute it''' if draw == True: ct.ConductCNOTOperationInVertex(DG, vertex, mapping, cir_phy, q_phy, reverse_drection=False, remove_node=False) cir_phy.barrier() removed_nodes.append(vertex) temp = True if temp == True: executable_vertex = FindExecutableNode(DG, executed_vertex, executable_vertex, removed_nodes) return executed_vertex, executable_vertex
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