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
示例#2
0
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
示例#4
0
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
示例#5
0
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
示例#9
0
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
示例#10
0
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
示例#11
0
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
示例#12
0
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