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 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 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