def tiling_layer(layers, tilings, pattern_offset, verbose): if (len(layers) < 1): print("Too few layers for tiling_layer") sys.exit() new_qregs = layers[0].qregs new_cregs = layers[0].cregs if len(new_qregs) > 1: print("Multiple q registers.") if len(new_cregs) == 0: new_circuit = QuantumCircuit(new_qregs[0]) elif len(new_cregs) == 1: new_circuit = QuantumCircuit(new_qregs[0], new_cregs[0]) else: print("Multiple c registers.") new_circuit = QuantumCircuit(new_qregs[0]) num_layers = len(layers) #print("nl %d" % num_layers) idx = 1 pattern_idx = 0 pending_g = [] patterns = [] for g in layers[0].data: pending_g.append(g) while len(pending_g) > 0 or idx < num_layers: #print("idx %d" % idx) #print(coupling) active_q = [] # active qubits in this layer next_pd_g = [] # gates/instructions two_q_layer = False two_q_tiling_delay = [] # 2q gates delayed due to tiling for inst, qargs, cargs in pending_g: if len(qargs) == 2: # two-qubit gates q1 = qargs[0].index q2 = qargs[1].index #print("Looking: (%d,%d)" % (q1, q2)) #print("Active: ", active_q) conf = False if (q1 in active_q or q2 in active_q): conf = True next_pd_g.append((inst, qargs, cargs)) if (verbose == 0): print("Delay gate (%d, %d)" % (q1,q2)) #for (n1, n2) in coupling: # if (q1 == n1 and n2 in active_q) or (q2 == n1 and n2 in active_q) or (q1 == n2 and n1 in active_q) or (q2 == n2 and n1 in active_q): # conf = True # if verbose==0: # print("Delay gate (%d, %d)" % (q1,q2)) # break if not conf: if (not((q1,q2) in tilings[(pattern_offset+pattern_idx) % 8] or (q2,q1) in tilings[(pattern_offset+pattern_idx) % 8])): conf = True two_q_tiling_delay.append((inst, qargs, cargs)) if verbose==0: print("Delay gate (%d, %d) due to tiling" % (q1,q2)) if not conf: two_q_layer = True active_q.append(q1) active_q.append(q2) new_circuit.data.append((inst, qargs, cargs)) elif len(qargs) == 1: # single-qubit gates q1 = qargs[0].index conf = False if (q1 in active_q): conf = True if (verbose == 0): print("Delay gate %d" % q1) if not conf: active_q.append(q1) new_circuit.data.append((inst, qargs, cargs)) else: next_pd_g.append((inst, qargs, cargs)) else: # Multi-qubit gates; Barrier? numq = len(qargs) conf = False for qii in range(numq): qi = qargs[qii].index if (qi in active_q): conf = True if not conf: active_q.append(qi) new_circuit.data.append((inst, qargs, cargs)) else: next_pd_g.append((inst, qargs, cargs)) if two_q_layer == False and len(two_q_tiling_delay) > 0: two_q_possible = [] for inst, qargs, cargs in two_q_tiling_delay: q1 = qargs[0].index q2 = qargs[1].index if (q1 in active_q or q2 in active_q): next_pd_g.append((inst, qargs, cargs)) else: two_q_possible.append((inst, qargs, cargs)) if len(two_q_possible) > 0: two_q_layer = True inst, qargs, cargs = two_q_possible[0] q1 = qargs[0].index q2 = qargs[1].index if (q1,q2) in tilings[pattern_offset % 8] or (q2,q1) in tilings[pattern_offset % 8]: pattern_idx = 0 elif (q1,q2) in tilings[(pattern_offset+1) % 8] or (q2,q1) in tilings[(pattern_offset+1) % 8]: pattern_idx = 1 elif (q1,q2) in tilings[(pattern_offset+2) % 8] or (q2,q1) in tilings[(pattern_offset+2) % 8]: pattern_idx = 2 elif (q1,q2) in tilings[(pattern_offset+3) % 8] or (q2,q1) in tilings[(pattern_offset+3) % 8]: pattern_idx = 3 elif (q1,q2) in tilings[(pattern_offset+4) % 8] or (q2,q1) in tilings[(pattern_offset+4) % 8]: pattern_idx = 4 elif (q1,q2) in tilings[(pattern_offset+5) % 8] or (q2,q1) in tilings[(pattern_offset+5) % 8]: pattern_idx = 5 elif (q1,q2) in tilings[(pattern_offset+6) % 8] or (q2,q1) in tilings[(pattern_offset+6) % 8]: pattern_idx = 6 elif (q1,q2) in tilings[(pattern_offset+7) % 8] or (q2,q1) in tilings[(pattern_offset+7) % 8]: pattern_idx = 7 for inst, qargs, cargs in two_q_possible: q1 = qargs[0].index q2 = qargs[1].index if (q1,q2) in tilings[(pattern_offset+pattern_idx) % 8] or (q2,q1) in tilings[(pattern_offset+pattern_idx) % 8]: if (q1 in active_q or q2 in active_q): next_pd_g.append((inst, qargs, cargs)) else: new_circuit.data.append((inst, qargs, cargs)) active_q.append(q1) active_q.append(q2) else: next_pd_g.append((inst, qargs, cargs)) pending_g = next_pd_g if (len(pending_g) == 0 and idx < num_layers): for g in layers[idx].data: pending_g.append(g) idx += 1 elif (idx < num_layers and not layers[idx].data[0][0].name == 'barrier'): for g in layers[idx].data: pending_g.append(g) idx += 1 patterns.append((pattern_idx+pattern_offset) % 8) new_circuit.barrier(new_qregs[0]) patterns.append((pattern_idx+pattern_offset) % 8) if (two_q_layer): pattern_idx += 1 return get_layer_circuits(new_circuit), (pattern_offset+pattern_idx) % 8, patterns
def static_coloring(device, circuit, scheduler, d, decomp, verbose, uniform_freq): freqsdata = [] gatesdata = [] width = device.side_length height = device.side_length num_q = device.qubits omega_max = device.omega_max delta_int = device.delta_int delta_ext = device.delta_ext delta_park = device.delta_park ALPHA = device.alpha G_connect = device.g_connect #get_connectivity_graph(width, height) park_coloring = nx.coloring.greedy_color(G_connect) num_park = len(set(park_coloring.values())) G_crosstalk = device.g_xtalk #get_aug_line_graph(width, height, d) q_arr = get_qubits(circuit) if uniform_freq: int_coloring = {} for node in G_crosstalk.nodes: int_coloring[node] = 0 else: int_coloring = nx.coloring.greedy_color(G_crosstalk) num_int = len(set(int_coloring.values())) def _build_color_map(): # negative colors for parking, non-negative colors for interaction. step_park = delta_park / num_park colormap = dict() if decomp == 'cphase' or decomp == 'flexible': step_int = (delta_int + ALPHA) / num_int for c in range(num_int): colormap[str(c)] = omega_max + ALPHA - c * step_int else: step_int = delta_int / num_int for c in range(num_int): colormap[str(c)] = omega_max - c * step_int for c in range(num_park): colormap[str( -(c + 1))] = omega_max - delta_int - delta_ext - c * step_park return colormap color_to_freq = _build_color_map() def _park_freq(c): omg = color_to_freq[str(-(c + 1))] return omg #+ get_flux_noise(device, omg, sigma)#+np.random.normal(0,sigma) def _int_freq(c): omg = color_to_freq[str(c)] return omg #+ get_flux_noise(device, omg, sigma)#+np.random.normal(0,sigma) def _initial_frequency(): freqs = dict() for q in range(num_q): freqs[q] = _park_freq(park_coloring[q]) return freqs t_act = np.zeros(num_q) t_2q = np.zeros(num_q) active_list = [False for i in range(num_q)] success_rate = 1.0 single_qb_err = 0.0015 tot_success = 0.0 tot_cnt = 0 worst_success = 1.0 max_colors = num_int # max number of colors used # Mapping coupling = device.coupling circ_mapped = get_map_circuit(circuit, coupling) Cqq = device.cqq park_freqs = _initial_frequency() alphas = [ALPHA for f in park_freqs] for i in range(num_q): if i < len(q_arr): q_arr[i].idle_freq = [park_freqs[i], park_freqs[i] + alphas[i]] ir = IR(qubits=q_arr, width=len(q_arr), coupling=coupling, alpha=ALPHA) #circuit.draw(output='mpl') # Check scheduler if (scheduler == 'hybrid'): print("Hybrid scheduler to be implemented.") sys.exit(2) else: # scheduler == qiskit or greedy layers = get_layer_circuits(circ_mapped) num_layers = len(layers) idx = 0 # qubit_freqs = park_freqs total_time = 0.0 # in ns total_tcz = 0.0 # total time spent on CZ gates #while (idx < num_layers or len(leftover) > 0): for idx in range(num_layers): # all_gates = [] layer_circuit = layers[idx] if verbose == 0: print(layer_circuit) print(idx, "-----------------") #print('leftover len: ' + str(len(leftover))) #print('left_gates len: ' + str(len(left_gates))) #decomp_layer = decompose_layer(layer_circuit, decomp) if decomp == 'flexible': if verbose == 0: print("Decompose layer", idx) decomp_layer = decompose_layer_flexible( layer_circuit, G_crosstalk, verbose) else: decomp_layer = decompose_layer(layer_circuit, decomp) if (scheduler == 'greedy'): resched_layer = reschedule_layer(decomp_layer, coupling, verbose) else: resched_layer = decomp_layer #print("Layers: %d %d" % (len(decomp_layer), len(resched_layer))) for layer in resched_layer: print(layer.qasm()) insts = [] #edges = [] #edges_cphase = [] # if (q1,q2) is in it, then (q2,q1) is also in it #edges_iswaps = [] # if (q1,q2) is in it, then (q2,q1) is also in it #edges = [e for e in leftover] #curr_gates = [e for e in left_gates] #curr_gates = [] taus = {} # For storing couplings that needed sqrt iswaps gt = 0.0 layer_time = 0.0 # ns barrier = False # single_qb_err = 0.0015 # single_qb_err_acc = 1.0 for g, qargs, cargs in layer.data: #print(g, qargs) #print(g.qasm()) if g.name == "barrier": barrier = True if g.name == "measure": continue if len(qargs) == 1: #all_gates.append((g.qasm(),(qargs[0].index, -1))) active_list[qargs[0].index] = True gt = device.gate_times[g.name] if gt > layer_time: layer_time = gt insts.append(Inst(g, qargs, cargs, None, gt)) # single_qb_err_acc *= 1 - single_qb_err if len(qargs) == 2: q1, q2 = qargs[0].index, qargs[1].index active_list[q1] = True active_list[q2] = True #edges.append((q1, q2)) #print((q1,q2)) #curr_gates.append((g.qasm(),(q1, q2))) try: ic = int_coloring[(q1, q2)] except: ic = int_coloring[(q2, q1)] f = _int_freq(ic) #print('freq:',f) if (g.name == 'unitary' and g.label == 'iswap'): f1 = f f2 = f taus[( q1, q2)] = np.pi / (2 * 0.5 * np.sqrt(f * f) * Cqq) elif (g.name == 'unitary' and g.label == 'sqrtiswap'): f1 = f f2 = f #tau_special[(q1,q2)] = 0.5 taus[(q1, q2)] = 0.5 * np.pi / (2 * 0.5 * np.sqrt(f * f) * Cqq) elif (g.name == 'cz' or g.label == 'cz'): f1 = f f2 = f - alphas[q2] # b/c match f1 with f2+alpha taus[(q1, q2)] = np.pi / ( np.sqrt(2) * 0.5 * np.sqrt(f * f) * Cqq ) # f is interaction freq else: print( "Gate %s(%s) not recognized. Supports iswap, sqrtiswap, cz." % (g.name, g.label)) t_2q[q1] += taus[(q1, q2)] t_2q[q2] += taus[(q1, q2)] insts.append( Inst(g, qargs, cargs, [f1, f2], taus[(q1, q2)])) # success_rate *= single_qb_err_acc #if (scheduler == 'greedy'): # edges, leftover, ind = greedy_reschedule(coupling, edges) # for i in range(len(ind)): # if (ind[i]): # all_gates.append(curr_gates[i]) # else: # left_gates.append(curr_gates[i]) #else: # for i in range(len(curr_gates)): # all_gates.append(curr_gates[i]) #for i in range(len(curr_gates)): # all_gates.append(curr_gates[i]) #print("qubit_freqs:") #print(qubit_freqs) if not barrier: ir.append_layer_from_insts(insts) qb_freqs = [q_omega[0] for q_omega in ir.data[-1][1]] print(qb_freqs) gt = get_max_time(gt, taus) tot_cnt += 1 if gt > layer_time: layer_time = gt total_time += layer_time for qubit in range(num_q): if active_list[qubit]: t_act[qubit] += layer_time # Reset the frequencies #for (q1, q2) in edges: # qubit_freqs[q1] = _park_freq(park_coloring[q1]) # qubit_freqs[q2] = _park_freq(park_coloring[q2]) # tot_success += (1 - err)*single_qb_err_acc # worst_success = min(worst_success, 1 - err) idx += 1 ir.depth_before = idx ir.depth_after = tot_cnt ir.total_time = total_time ir.max_colors = max_colors ir.t_act = t_act ir.t_2q = t_2q return ir
def google_like(device, circuit, scheduler, d, decomp, verbose, res_coup=0.0): freqsdata = [] gatesdata = [] width = device.side_length height = device.side_length num_q = device.qubits q_arr = get_qubits(circuit) ALPHA = device.alpha tilings = gen_tiling_pattern(device) G_connect = device.g_connect #get_connectivity_graph(width, height) G_crosstalk = device.g_xtalk #get_aug_line_graph(width, height, d) syc_device = Sycamore_device(device, num_q, res_coup) int_freqs = syc_device.int_freqs park_freqs = syc_device.park_freqs num_int = len(set(int_freqs.values())) def _initial_frequency(): freqs = dict() for q in range(num_q): freqs[q] = park_freqs[q] return freqs t_act = np.zeros(num_q) t_2q = np.zeros(num_q) active_list = [False for i in range(num_q)] success_rate = 1.0 # single_qb_err = 0.0015 tot_success = 0.0 tot_cnt = 0 worst_success = 1.0 max_colors = num_int # max number of colors used # Mapping coupling = device.coupling circ_mapped = get_map_circuit(circuit, coupling) Cqq = device.cqq park_freqs = _initial_frequency() alphas = [ALPHA for f in park_freqs] for i in range(num_q): q_arr[i].idle_freq = [park_freqs[i], park_freqs[i]+alphas[i]] ir = IR(qubits = q_arr, width = num_q, coupling = coupling, alpha = ALPHA) #circuit.draw(output='mpl') # Check scheduler if (scheduler == 'hybrid'): print("Hybrid scheduler to be implemented.") sys.exit(2) else: # scheduler == qiskit or greedy layers = get_layer_circuits(circ_mapped) qubit_freqs = park_freqs num_layers = len(layers) idx = 0 pattern_offset = 0 total_time = 0.0 # in ns #while (idx < num_layers or len(leftover) > 0): tiling_idx = 0 for idx in range(num_layers): all_gates = [] layer_circuit = layers[idx] if verbose == 0: print(layer_circuit) print(idx, "-----------------") #print('leftover len: ' + str(len(leftover))) #print('left_gates len: ' + str(len(left_gates))) #decomp_layer = decompose_layer(layer_circuit, decomp) if decomp == 'flexible': if verbose == 0: print("Decompose layer", idx) decomp_layer= decompose_layer_flexible(layer_circuit, G_crosstalk, verbose) else: decomp_layer = decompose_layer(layer_circuit, decomp) if (scheduler == 'greedy'): resched_layer = reschedule_layer(decomp_layer, coupling, verbose) elif (scheduler == 'tiling'): resched_layer, pattern_offset, patterns = tiling_layer(decomp_layer, tilings, pattern_offset, verbose) print(patterns) else: resched_layer = decomp_layer #print("Layers: %d %d" % (len(decomp_layer), len(resched_layer))) for (iid,layer) in enumerate(resched_layer): if (scheduler == 'tiling'): tiling_idx = patterns[iid] if verbose == 0: print("tiling_idx", tiling_idx) print(layer.qasm()) insts = [] edges = [] #edges_cphase = [] # if (q1,q2) is in it, then (q2,q1) is also in it #edges_iswaps = [] # if (q1,q2) is in it, then (q2,q1) is also in it #edges = [e for e in leftover] #curr_gates = [e for e in left_gates] #curr_gates = [] taus = {} # For storing couplings that needed sqrt iswaps gt = 0.0 layer_time = 0.0 # ns barrier = False # single_qb_err = 0.0015 for g, qargs, cargs in layer.data: #print(g, qargs) #print(g.qasm()) if g.name == "barrier": barrier = True if g.name == "measure": continue if len(qargs) == 1: #all_gates.append((g.qasm(),(qargs[0].index, -1))) active_list[qargs[0].index] = True gt = device.gate_times[g.name] if gt > layer_time: layer_time = gt insts.append(Inst(g,qargs,cargs, None, gt)) # success_rate *= 1 - single_qb_err if len(qargs) == 2: q1, q2 = qargs[0].index, qargs[1].index active_list[q1] = True active_list[q2] = True #edges.append((q1, q2)) #print((q1,q2)) #curr_gates.append((g.qasm(),(q1, q2))) try: f = int_freqs[(q1,q2)] except: f = int_freqs[(q2,q1)] # f += get_flux_noise(device, f, sigma) #print('freq:',f) if (g.name == 'unitary' and g.label == 'iswap'): f1 = f f2 = f taus[(q1,q2)] = np.pi / (2 * 0.5 * np.sqrt(f*f) * Cqq) elif (g.name == 'unitary' and g.label == 'sqrtiswap'): f1 = f f2 = f #tau_special[(q1,q2)] = 0.5 taus[(q1,q2)] = 0.5 * np.pi / (2 * 0.5 * np.sqrt(f*f) * Cqq) elif (g.name == 'cz' or g.label == 'cz'): f1 = f f2 = f - alphas[q2] # b/c match f1 with f2+alpha taus[(q1,q2)] = np.pi / (np.sqrt(2) * 0.5 * np.sqrt(f*f) * Cqq) # f is interaction freq else: print("Gate %s(%s) not recognized. Supports iswap, sqrtiswap, cz." % (g.name, g.label)) t_2q[q1] += taus[(q1,q2)] t_2q[q2] += taus[(q1,q2)] insts.append(Inst(g, qargs, cargs, [f1, f2], taus[(q1,q2)])) #if (scheduler == 'greedy'): # edges, leftover, ind = greedy_reschedule(coupling, edges) # for i in range(len(ind)): # if (ind[i]): # all_gates.append(curr_gates[i]) # else: # left_gates.append(curr_gates[i]) #else: # for i in range(len(curr_gates)): # all_gates.append(curr_gates[i]) #for i in range(len(curr_gates)): # all_gates.append(curr_gates[i]) if not barrier: coupling_factors = None if (scheduler == 'tiling'): tiling_active = tilings[tiling_idx] coupling_factors = [] for (qa,qb) in coupling: if (qa,qb) in tiling_active or (qb,qa) in tiling_active: coupling_factors.append(1.0) else: # strength of residual coupling, 0~1 coupling_factors.append(syc_device.res_coupling) ir.append_layer_from_insts(insts, coupling_factors) qb_freqs = [q_omega[0] for q_omega in ir.data[-1][1]] print(qb_freqs) gt = get_max_time(gt, taus) tot_cnt += 1 if gt > layer_time: layer_time = gt total_time += layer_time for qubit in range(num_q): if active_list[qubit]: t_act[qubit] += layer_time idx += 1 ir.depth_before = idx ir.depth_after = tot_cnt ir.total_time = total_time ir.max_colors = max_colors ir.t_act = t_act ir.t_2q = t_2q return ir
def color_dynamic(device, circuit, scheduler, d, decomp, lim_colors, verbose): freqsdata = [] gatesdata = [] width = device.side_length height = device.side_length num_q = device.qubits omega_max = device.omega_max delta_int = device.delta_int delta_ext = device.delta_ext delta_park = device.delta_park ALPHA = device.alpha G_connect = device.g_connect #G_connect = get_connectivity_graph(width*height, 'grid') park_coloring = nx.coloring.greedy_color(G_connect) num_park = len(set(park_coloring.values())) G_crosstalk = device.g_xtalk #G_crosstalk = get_aug_line_graph(width, height, d) coupling = device.coupling Cqq = device.cqq q_arr = get_qubits(circuit) def _build_park_color_map(): # negative colors for parking, non-negative colors for interaction. step_park = delta_park / num_park #step_int = delta_int / num_int colormap = dict() #for c in range(num_int): # colormap[str(c)] = omega_max - c * step_int for c in range(num_park): colormap[str( -(c + 1))] = omega_max - delta_int - delta_ext - c * step_park return colormap def _add_int_color_map(colormap, n_int): if decomp == 'cphase' or decomp == 'flexible': step_int = (delta_int + ALPHA) / n_int for c in range(n_int): colormap[str(c)] = omega_max + ALPHA - c * step_int else: step_int = delta_int / n_int for c in range(n_int): colormap[str(c)] = omega_max - c * step_int color_to_freq = _build_park_color_map() def _park_freq(c): omg = color_to_freq[str(-(c + 1))] return omg #+ get_flux_noise(device, omg, sigma) def _initial_frequency(): freqs = dict() for q in range(num_q): freqs[q] = _park_freq(park_coloring[q]) return freqs circ_mapped = get_map_circuit(circuit, coupling) #circuit.draw(output='mpl') t_act = np.zeros(num_q) t_2q = np.zeros(num_q) active_list = [False for i in range(num_q)] success_rate = 1.0 tot_success = 0.0 tot_cnt = 0 max_colors = 0 # max number of colors used worst_success = 1.0 park_freqs = _initial_frequency() alphas = [ALPHA for f in park_freqs] for i in range(num_q): q_arr[i].idle_freq = [park_freqs[i], park_freqs[i] + alphas[i]] ir = IR(qubits=q_arr, width=num_q, coupling=coupling, alpha=ALPHA) # Check scheduler if (scheduler == 'hybrid'): print("Hybrid scheduler to be implemented.") sys.exit(2) else: layers = get_layer_circuits(circ_mapped) num_layers = len(layers) idx = 0 total_time = 0.0 # ns total_tcz = 0.0 if verbose == 0: print("Num of layers:", num_layers) #while (idx < num_layers or len(leftover) > 0): for idx in range(num_layers): # all_gates = [] layer_circuit = layers[idx] if verbose == 0: print(layer_circuit) print(idx, "-----------------") if decomp == 'flexible': if verbose == 0: print("Decompose layer", idx) decomp_layer = decompose_layer_flexible( layer_circuit, G_crosstalk, verbose) else: decomp_layer = decompose_layer(layer_circuit, decomp) if (scheduler == 'greedy'): resched_layer = reschedule_layer(decomp_layer, coupling, verbose) else: resched_layer = decomp_layer if lim_colors > 0: resched_layer = limit_colors(resched_layer, lim_colors, G_crosstalk, verbose) for layer in resched_layer: print(layer.qasm()) insts = [] # Pre-fill edges for constructing (undirected) xtalk graph #edges = [leftover[i//2] if i%2==0 else (leftover[i//2][1], leftover[i//2][0]) for i in range(2*len(leftover))] edges = [] #edges_cphase = [] # if (q1,q2) is in it, then (q2,q1) is also in it #edges_iswaps = [] # if (q1,q2) is in it, then (q2,q1) is also in it #curr_gates = [e for e in left_gates] #leftover = [] #left_gates = [] taus = {} # For storing coupling times gt = 0.0 layer_time = 0.0 barrier = False for _, qargs, _ in layer.data: if len(qargs) == 2: q1, q2 = qargs[0].index, qargs[1].index edge = (q1, q2) edges.append(edge) edges.append((q2, q1)) # because undirected graph #print("+Edges:") #print(edges) if (len(edges) > 0): #idx += 1 #continue subgraph = nx.subgraph(G_crosstalk, edges) #print(G_crosstalk.nodes()) #print(subgraph.nodes()) int_coloring = nx.coloring.greedy_color(subgraph) #print("+int_coloring:") #print(int_coloring) num_int = len(set(int_coloring.values())) while lim_colors > 0 and num_int > lim_colors: # need to recolor the layer, cannot use greedy_color because it is not seeded # int_coloring = nx.coloring.greedy_color(subgraph,strategy='random_sequential') int_coloring = {} nodes = list(subgraph) np.random.shuffle(nodes) for u in nodes: # Set to keep track of colors of neighbours neighbour_colors = { int_coloring[v] for v in subgraph[u] if v in int_coloring } # Find the first unused color. temp_color = 0 while temp_color in neighbour_colors: temp_color += 1 # Assign the new color to the current node. int_coloring[u] = temp_color num_int = len(set(int_coloring.values())) if verbose == 0: print("num_int: ", num_int) int_coloring = relabel_coloring(int_coloring) if num_int > max_colors: max_colors = num_int if num_int == 0: idx += 1 continue _add_int_color_map(color_to_freq, num_int) def _int_freq(c): omg = color_to_freq[str(c)] #+np.random.normal(0,sigma) return omg #+ get_flux_noise(device, omg, sigma) #print(layer) #print("-----------------") # Refill edges and curr_gates #edges = [e for e in leftover] # edges = [] #curr_gates = [e for e in left_gates] # curr_gates = [] # single_qb_err = 0.0015 # single_qb_err_acc = 1.0 for g, qargs, cargs in layer.data: if g.name == "barrier": barrier = True if g.name == "measure": continue #print(qargs) #print(qargs[0].index) if len(qargs) == 1: # single qubit gates # all_gates.append((g.qasm(),(qargs[0].index, -1))) active_list[qargs[0].index] = True gt = device.gate_times[g.name] if gt > layer_time: layer_time = gt insts.append(Inst(g, qargs, cargs, None, gt)) # single_qb_err_acc *= 1 - single_qb_err elif len(qargs) == 2: q1, q2 = qargs[0].index, qargs[1].index active_list[q1] = True active_list[q2] = True #edges.append((q1, q2)) #curr_gates.append((g.qasm(),(q1, q2))) try: f = _int_freq(int_coloring[(q1, q2)]) except: f = _int_freq(int_coloring[(q2, q1)]) if (g.name == 'unitary' and g.label == 'iswap'): f1 = f f2 = f taus[( q1, q2)] = np.pi / (2 * 0.5 * np.sqrt(f * f) * Cqq) elif (g.name == 'unitary' and g.label == 'sqrtiswap'): f1 = f f2 = f taus[(q1, q2)] = 0.5 * np.pi / (2 * 0.5 * np.sqrt(f * f) * Cqq) elif (g.name == 'cz' or g.label == 'cz'): f1 = f f2 = f - alphas[q2] # b/c match f1 with f2+alpha taus[(q1, q2)] = np.pi / ( np.sqrt(2) * 0.5 * np.sqrt(f * f) * Cqq ) # f is interaction freq else: print( "Gate %s(%s) not recognized. Supports iswap, sqrtiswap, cz." % (g.name, g.label)) t_2q[q1] += taus[(q1, q2)] t_2q[q2] += taus[(q1, q2)] insts.append( Inst(g, qargs, cargs, [f1, f2], taus[(q1, q2)])) # success_rate *= single_qb_err_acc #if (scheduler == 'greedy'): # edges, leftover, ind = greedy_reschedule(coupling, edges) # for i in range(len(ind)): # if (ind[i]): # all_gates.append(curr_gates[i]) # else: # left_gates.append(curr_gates[i]) #else: # for i in range(len(curr_gates)): # all_gates.append(curr_gates[i]) #for i in range(len(curr_gates)): # all_gates.append(curr_gates[i]) if not barrier: ir.append_layer_from_insts(insts) qb_freqs = [q_omega[0] for q_omega in ir.data[-1][1]] print(qb_freqs) gt = get_max_time(gt, taus) tot_cnt += 1 if gt > layer_time: layer_time = gt total_time += layer_time for qubit in range(num_q): if active_list[qubit]: t_act[qubit] += layer_time idx += 1 ir.t_act = t_act ir.t_2q = t_2q ir.depth_before = idx ir.depth_after = tot_cnt ir.total_time = total_time ir.max_colors = max_colors return ir
def decompose_layer(layer, decomp): new_qregs = layer.qregs new_cregs = layer.cregs if len(new_qregs) > 1: print("Multiple q registers.") if len(new_cregs) == 0: new_circuit = QuantumCircuit(new_qregs[0]) elif len(new_cregs) == 1: new_circuit = QuantumCircuit(new_qregs[0], new_cregs[0]) else: print("Multiple c registers.") new_circuit = QuantumCircuit(new_qregs[0]) for inst, qargs, cargs in layer.data: #print(inst.name) if (inst.name == 'measure' or inst.name == 'barrier'): new_circuit.data.append((inst, qargs, cargs)) elif (inst.name == 'cx' or inst.name == 'cnot' or inst.label == 'cnot'): if decomp == 'iswap': new_circuit.rz(-np.pi / 2, qargs[0]) new_circuit.rx(np.pi / 2, qargs[1]) new_circuit.rz(np.pi / 2, qargs[1]) new_circuit.unitary(iswap(), [qargs[0], qargs[1]], label='iswap') new_circuit.rx(np.pi / 2, qargs[0]) new_circuit.unitary(iswap(), [qargs[0], qargs[1]], label='iswap') new_circuit.rz(np.pi / 2, qargs[1]) elif decomp == 'cphase' or decomp == 'mixed': new_circuit.h(qargs[1]) new_circuit.cz(qargs[0], qargs[1]) new_circuit.h(qargs[1]) else: print( "Decomposition method %s not recognized. Try iswap or cphase." % decomp) elif (inst.name == 'swap' or inst.label == 'swap'): if decomp == 'iswap' or decomp == 'mixed': new_circuit.unitary(sqrtiswap(), [qargs[0], qargs[1]], label='sqrtiswap') new_circuit.rx(np.pi / 2, qargs[0]) new_circuit.rx(np.pi / 2, qargs[1]) new_circuit.unitary(sqrtiswap(), [qargs[0], qargs[1]], label='sqrtiswap') new_circuit.rx(-np.pi / 2, qargs[1]) new_circuit.rx(-np.pi / 2, qargs[0]) new_circuit.ry(np.pi / 2, qargs[1]) new_circuit.ry(np.pi / 2, qargs[0]) new_circuit.unitary(sqrtiswap(), [qargs[0], qargs[1]], label='sqrtiswap') new_circuit.ry(-np.pi / 2, qargs[1]) new_circuit.ry(-np.pi / 2, qargs[0]) elif decomp == 'cphase': new_circuit.h(qargs[1]) new_circuit.cz(qargs[0], qargs[1]) new_circuit.h(qargs[1]) new_circuit.h(qargs[0]) new_circuit.cz(qargs[1], qargs[0]) new_circuit.h(qargs[0]) new_circuit.h(qargs[1]) new_circuit.cz(qargs[0], qargs[1]) new_circuit.h(qargs[1]) else: print("Decomposition method %s not recognized." % decomp) elif (inst.name == 'iswap' or inst.label == 'iswap'): new_circuit.unitary(iswap(), [qargs[0], qargs[1]], label='iswap') else: new_circuit.data.append((inst, qargs, cargs)) return get_layer_circuits(new_circuit)
def limit_colors(layers, lim_colors, G_crosstalk, verbose): # print("Limit colors:") if len(layers) < 1 and verbose == 0: print("Too few layers for limit_colors") sys.exit() new_qregs = layers[0].qregs new_cregs = layers[0].cregs if len(new_qregs) > 1 and verbose == 0: print("Multiple q registers.") if len(new_cregs) == 0: new_circuit = QuantumCircuit(new_qregs[0]) elif len(new_cregs) == 1: new_circuit = QuantumCircuit(new_qregs[0], new_cregs[0]) else: if verbose == 0: print("Multiple c registers.") new_circuit = QuantumCircuit(new_qregs[0]) num_layers = len(layers) # print("number of layers:",num_layers) idx = 1 pending_g = [] for g in layers[0].data: pending_g.append(g) while len(pending_g) > 0 or idx < num_layers: # print("idx (of the next layer, start with 1):",idx) #print("idx %d" % idx) #print(coupling) next_pd_g = [] # gates/instructions edges = [] for inst, qargs, cargs in pending_g: if len(qargs) == 2: # two-qubit gates q1 = qargs[0].index q2 = qargs[1].index edge = (q1, q2) edges.append(edge) edges.append((q2, q1)) next_pd_g.append((inst, qargs, cargs)) else: # 1-qubit gate new_circuit.data.append((inst, qargs, cargs)) # put the gates in the next layer into pending_g pending_g = [] if (idx < num_layers): for g in layers[idx].data: pending_g.append(g) # if there's at least 1 2-q gate if (len(next_pd_g) > 0): #print(" There are 2-q gates") # color the layer subgraph = nx.subgraph(G_crosstalk, edges) #print(G_crosstalk.nodes()) #print(subgraph.nodes()) int_coloring = nx.coloring.greedy_color(subgraph) #print("int_coloring:") #print(int_coloring) int_coloring = relabel_coloring(int_coloring) num_int = len(set(int_coloring.values())) # the number of colors # if the coloring uses more colors than allowed if num_int > lim_colors: #print(" Layer to be split, num_int:",num_int) # split the layer split = int(num_int / lim_colors) # the number of new layers if num_int % lim_colors != 0: split += 1 #print("number of sublayers:",split) # for all but the last of the new layers for i in range(split - 1): # append the gates that belong to the ith sublayer for inst, qargs, cargs in next_pd_g: q1 = qargs[0].index q2 = qargs[1].index try: ic = int_coloring[(q1, q2)] except: ic = int_coloring[(q2, q1)] if ic >= lim_colors * i and ic < lim_colors * (i + 1): new_circuit.data.append((inst, qargs, cargs)) new_circuit.barrier(new_qregs[0]) #print("Added sublayer:", i) # obtain the gates in the last sublayer last_layer = [] for inst, qargs, cargs in next_pd_g: q1 = qargs[0].index q2 = qargs[1].index try: ic = int_coloring[(q1, q2)] except: ic = int_coloring[(q2, q1)] if ic >= (split - 1) * lim_colors: last_layer.append((inst, qargs, cargs)) #print("Last sublayer obtained, len:",len(last_layer)) # for the last sublayer, we check if it can be combined with the next layer if idx >= num_layers: #print("Already the last layer, just append") for g in last_layer: new_circuit.data.append(g) new_circuit.barrier(new_qregs[0]) else: conf = False #print("check if can be combined with the next layer") active_next = [] # qubits used in the next layer for inst, qargs, cargs in pending_g: q1 = qargs[0].index active_next.append(q1) if len(qargs) == 2: q2 = qargs[1].index active_next.append(q2) #print("active_next:",active_next) for inst, qargs, cargs in last_layer: q1 = qargs[0].index q2 = qargs[1].index if q1 in active_next or q2 in active_next: conf = True break if conf: # the last sublayer cannot be combined with the next layer #print("cannot be combined") for g in last_layer: new_circuit.data.append(g) new_circuit.barrier(new_qregs[0]) else: # the last sublayer can be combined with the next layer #print("can be combined") for g in last_layer: pending_g.append(g) else: # if the layer doesn't need to be split #print(" Layer doesn't need to be split") for inst, qargs, cargs in next_pd_g: new_circuit.data.append((inst, qargs, cargs)) new_circuit.barrier(new_qregs[0]) else: # this layer only has 1-q gates #print(" There aren't 2-q gates") new_circuit.barrier(new_qregs[0]) idx += 1 return get_layer_circuits(new_circuit)
def reschedule_layer(layers, coupling, verbose): if (len(layers) < 1): print("Too few layers for reschedule_layer") sys.exit() new_qregs = layers[0].qregs new_cregs = layers[0].cregs if len(new_qregs) > 1: print("Multiple q registers.") if len(new_cregs) == 0: new_circuit = QuantumCircuit(new_qregs[0]) elif len(new_cregs) == 1: new_circuit = QuantumCircuit(new_qregs[0], new_cregs[0]) else: print("Multiple c registers.") new_circuit = QuantumCircuit(new_qregs[0]) num_layers = len(layers) #print("nl %d" % num_layers) idx = 1 pending_g = [] for g in layers[0].data: pending_g.append(g) while len(pending_g) > 0 or idx < num_layers: #print("idx %d" % idx) #print(coupling) active_q = [] # active qubits in this layer next_pd_g = [] # gates/instructions for inst, qargs, cargs in pending_g: if len(qargs) == 2: # two-qubit gates q1 = qargs[0].index q2 = qargs[1].index #print("Looking: (%d,%d)" % (q1, q2)) #print("Active: ", active_q) conf = False if (q1 in active_q or q2 in active_q): conf = True if not conf: for (n1, n2) in coupling: if (q1 == n1 and n2 in active_q) or ( q2 == n1 and n2 in active_q) or ( q1 == n2 and n1 in active_q) or ( q2 == n2 and n1 in active_q): conf = True if verbose == 0: print("Delay gate (%d, %d) due to crosstalk" % (q1, q2)) break if not conf: active_q.append(q1) active_q.append(q2) new_circuit.data.append((inst, qargs, cargs)) else: next_pd_g.append((inst, qargs, cargs)) elif len(qargs) == 1: # single-qubit gates q1 = qargs[0].index conf = False if (q1 in active_q): conf = True if not conf: active_q.append(q1) new_circuit.data.append((inst, qargs, cargs)) else: next_pd_g.append((inst, qargs, cargs)) else: # Multi-qubit gates; Barrier? numq = len(qargs) conf = False for qii in range(numq): qi = qargs[qii].index if (qi in active_q): conf = True if not conf: active_q.append(qi) new_circuit.data.append((inst, qargs, cargs)) else: next_pd_g.append((inst, qargs, cargs)) pending_g = next_pd_g if (len(pending_g) == 0 and idx < num_layers): for g in layers[idx].data: pending_g.append(g) idx += 1 elif (idx < num_layers and not layers[idx].data[0][0].name == 'barrier'): for g in layers[idx].data: pending_g.append(g) idx += 1 new_circuit.barrier(new_qregs[0]) return get_layer_circuits(new_circuit)
def decompose_layer_flexible(layer, G_crosstalk, verbose): new_qregs = layer.qregs new_cregs = layer.cregs if len(new_qregs) > 1: print("Multiple q registers.") if len(new_cregs) == 0: new_circuit = QuantumCircuit(new_qregs[0]) elif len(new_cregs) == 1: new_circuit = QuantumCircuit(new_qregs[0], new_cregs[0]) else: print("Multiple c registers.") new_circuit = QuantumCircuit(new_qregs[0]) to_decompose = [ ] # all the two qubit gates (q1,q2) in this layer that are also in G_crosstalk.nodes() cnot_gates = [] swap_gates = [] for inst, qargs, cargs in layer.data: if (inst.name == 'measure' or inst.name == 'barrier'): continue if (inst.name == 'cx' or inst.name == 'cnot' or inst.label == 'cnot' or inst.name == 'swap' or inst.label == 'swap'): q1, q2 = qargs[0].index, qargs[1].index if (q1, q2) in G_crosstalk.nodes(): to_decompose.append((q1, q2)) if (inst.name == 'cx' or inst.name == 'cnot' or inst.label == 'cnot'): cnot_gates.append((q1, q2)) else: swap_gates.append((q1, q2)) elif (q2, q1) in G_crosstalk.nodes(): to_decompose.append((q2, q1)) if (inst.name == 'cx' or inst.name == 'cnot' or inst.label == 'cnot'): cnot_gates.append((q1, q2)) else: swap_gates.append((q1, q2)) else: print("Error: 2-qubit gate not a node in G_crosstalk") if verbose == 0: print("to_decompose:", to_decompose) print("CNOT:", cnot_gates) print("SWAP:", swap_gates) decomp_iswap = [] # the gates that will be decomposed with iswap decomp_cphase = [] # the gates that will be decomposed with cphase temp = [] while to_decompose: if to_decompose[-1] in cnot_gates: decomp_cphase.append(to_decompose[-1]) temp.append((to_decompose.pop(), 1)) # 0-iswap, 1-cphase else: decomp_iswap.append(to_decompose[-1]) temp.append((to_decompose.pop(), 0)) # 0-iswap, 1-cphase while temp: v, d = temp.pop() for n in G_crosstalk[ v]: # loop through v's neighbors in G_crosstalk # if we need to decompose v's neighbor if n in to_decompose: to_decompose.remove(n) # if v is decomposed with iswap, decompose n with cphase if d == 0: decomp_cphase.append(n) temp.append((n, 1)) # if v is decomposed with cphase, decompose n with iswap else: decomp_iswap.append(n) temp.append((n, 0)) if verbose == 0: print("decomp_iswap:", decomp_iswap) print("decomp_cphase:", decomp_cphase) for inst, qargs, cargs in layer.data: if (inst.name == 'measure' or inst.name == 'barrier'): new_circuit.data.append((inst, qargs, cargs)) elif (inst.name == 'cx' or inst.name == 'cnot' or inst.label == 'cnot'): q1, q2 = qargs[0].index, qargs[1].index if (q1, q2) in decomp_iswap or (q2, q1) in decomp_iswap: new_circuit.rz(-np.pi / 2, qargs[0]) new_circuit.rx(np.pi / 2, qargs[1]) new_circuit.rz(np.pi / 2, qargs[1]) new_circuit.unitary(iswap(), [qargs[0], qargs[1]], label='iswap') new_circuit.rx(np.pi / 2, qargs[0]) new_circuit.unitary(iswap(), [qargs[0], qargs[1]], label='iswap') new_circuit.rz(np.pi / 2, qargs[1]) elif (q1, q2) in decomp_cphase or (q2, q1) in decomp_cphase: new_circuit.h(qargs[1]) new_circuit.cz(qargs[0], qargs[1]) new_circuit.h(qargs[1]) elif (inst.name == 'swap' or inst.label == 'swap'): q1, q2 = qargs[0].index, qargs[1].index if (q1, q2) in decomp_iswap or (q2, q1) in decomp_iswap: new_circuit.unitary(sqrtiswap(), [qargs[0], qargs[1]], label='sqrtiswap') new_circuit.rx(np.pi / 2, qargs[0]) new_circuit.rx(np.pi / 2, qargs[1]) new_circuit.unitary(sqrtiswap(), [qargs[0], qargs[1]], label='sqrtiswap') new_circuit.rx(-np.pi / 2, qargs[1]) new_circuit.rx(-np.pi / 2, qargs[0]) new_circuit.ry(np.pi / 2, qargs[1]) new_circuit.ry(np.pi / 2, qargs[0]) new_circuit.unitary(sqrtiswap(), [qargs[0], qargs[1]], label='sqrtiswap') new_circuit.ry(-np.pi / 2, qargs[1]) new_circuit.ry(-np.pi / 2, qargs[0]) elif (q1, q2) in decomp_cphase or (q2, q1) in decomp_cphase: new_circuit.h(qargs[1]) new_circuit.cz(qargs[0], qargs[1]) new_circuit.h(qargs[1]) new_circuit.h(qargs[0]) new_circuit.cz(qargs[1], qargs[0]) new_circuit.h(qargs[0]) new_circuit.h(qargs[1]) new_circuit.cz(qargs[0], qargs[1]) new_circuit.h(qargs[1]) elif (inst.name == 'iswap' or inst.label == 'iswap'): new_circuit.unitary(iswap(), [qargs[0], qargs[1]], label='iswap') else: new_circuit.data.append((inst, qargs, cargs)) return get_layer_circuits(new_circuit)