def FastFeedbackControl(latency, qubit_idx: int, platf_cfg: str): """ Single qubit sequence to test fast feedback control (fast conditional execution). Writes output files to the directory specified in openql. Output directory is set as an attribute to the program for convenience. Input pars: latency: the waiting time between measurement and the feedback pulse, which should be longer than the feedback latency. feedback: if apply qubit_idx: int specifying the target qubit (starting at 0) platf_cfg: filename of the platform config file Returns: p: OpenQL Program object containing """ p = oqh.create_program("FastFeedbackControl", platf_cfg) k = oqh.create_kernel("FastFdbkCtrl_nofb", p) k.prepz(qubit_idx) k.gate('rx90', [qubit_idx]) # k.gate('rx180', [qubit_idx]) k.measure(qubit_idx) wait_nanoseconds = int(round(latency/1e-9)) k.gate("wait", [qubit_idx], wait_nanoseconds) k.gate("i", [qubit_idx]) k.measure(qubit_idx) p.add_kernel(k) k = oqh.create_kernel("FastFdbkCtrl_fb0", p) k.prepz(qubit_idx) k.gate('rx90', [qubit_idx]) # k.gate('rx180', [qubit_idx]) k.measure(qubit_idx) wait_nanoseconds = int(round(latency/1e-9)) k.gate("wait", [qubit_idx], wait_nanoseconds) k.gate('C0rx180', [qubit_idx]) # fast feedback control here k.measure(qubit_idx) p.add_kernel(k) k = oqh.create_kernel("FastFdbkCtrl_fb1", p) k.prepz(qubit_idx) k.gate('rx90', [qubit_idx]) # k.gate('rx180', [qubit_idx]) k.measure(qubit_idx) wait_nanoseconds = int(round(latency/1e-9)) k.gate("wait", [qubit_idx], wait_nanoseconds) k.gate('C1rx180', [qubit_idx]) # fast feedback control here k.measure(qubit_idx) p.add_kernel(k) # adding the calibration points oqh.add_single_qubit_cal_points(p, qubit_idx=qubit_idx) p = oqh.compile(p) return p
def echo(times, qubit_idx: int, platf_cfg: str): """ Single qubit Echo sequence. Writes output files to the directory specified in openql. Output directory is set as an attribute to the program for convenience. Input pars: times: the list of waiting times for each Echo element qubit_idx: int specifying the target qubit (starting at 0) platf_cfg: filename of the platform config file Returns: p: OpenQL Program object containing """ p = oqh.create_program("echo", platf_cfg) for i, time in enumerate(times[:-4]): k = oqh.create_kernel("echo_{}".format(i), p) k.prepz(qubit_idx) # nr_clocks = int(time/20e-9/2) wait_nanoseconds = int(round(time/1e-9/2)) k.gate('rx90', [qubit_idx]) k.gate("wait", [qubit_idx], wait_nanoseconds) k.gate('rx180', [qubit_idx]) k.gate("wait", [qubit_idx], wait_nanoseconds) k.gate('rx90', [qubit_idx]) k.measure(qubit_idx) p.add_kernel(k) # adding the calibration points oqh.add_single_qubit_cal_points(p, qubit_idx=qubit_idx) p = oqh.compile(p) return p
def FluxTimingCalibration(qubit_idx: int, times, platf_cfg: str, cal_points: bool=True): """ A Ramsey sequence with varying waiting times `times` around a flux pulse. """ p = oqh.create_program('FluxTimingCalibration', platf_cfg) # don't use last 4 points if calibration points are used if cal_points: times = times[:-4] for t in times: t_nanoseconds = int(round(t/1e-9)) k = oqh.create_kernel('pi-flux-pi', p) k.prepz(qubit_idx) k.gate('rx90', [qubit_idx]) k.gate('fl_cw_02', [2, 0]) if t_nanoseconds > 10: k.gate("wait", [qubit_idx], t_nanoseconds) k.gate('rx90', [qubit_idx]) k.measure(qubit_idx) p.add_kernel(k) if cal_points: oqh.add_single_qubit_cal_points(p, qubit_idx=qubit_idx) p = oqh.compile(p) return p
def FluxTimingCalibration(qubit_idx: int, times, platf_cfg: str, flux_cw: str='fl_cw_02', qubit_other_idx=0, cal_points: bool=True): """ A Ramsey sequence with varying waiting times `times` around a flux pulse. """ p = oqh.create_program('FluxTimingCalibration', platf_cfg) # don't use last 4 points if calibration points are used if cal_points: times = times[:-4] for i_t,t in enumerate(times): t_nanoseconds = int(round(t/1e-9)) k = oqh.create_kernel('pi_flux_pi_{}'.format(i_t), p) k.prepz(qubit_idx) k.gate('rx90', [qubit_idx]) # k.gate("wait", [0, 1, 2, 3, 4, 5, 6], 0) #alignment workaround k.gate("wait", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], 0) #alignment workaround # k.gate(flux_cw, [2, 0]) k.gate('sf_square', [qubit_idx]) if t_nanoseconds > 10: # k.gate("wait", [0, 1, 2, 3, 4, 5, 6], t_nanoseconds) k.gate("wait", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], t_nanoseconds) #alignment workaround # k.gate("wait", [qubit_idx], t_nanoseconds) k.gate('rx90', [qubit_idx]) k.measure(qubit_idx) p.add_kernel(k) if cal_points: oqh.add_single_qubit_cal_points(p, qubit_idx=qubit_idx) p = oqh.compile(p) return p
def complex_Ramsey(times, qubit_idx: int, platf_cfg: str): """ Single qubit Ramsey sequence. Writes output files to the directory specified in openql. Output directory is set as an attribute to the program for convenience. Input pars: times: the list of waiting times for each Ramsey element qubit_idx: int specifying the target qubit (starting at 0) platf_cfg: filename of the platform config file Returns: p: OpenQL Program object containing """ p = oqh.create_program("complex_Ramsey", platf_cfg) prerotations = ['rx90', 'rym90'] timeloop = times[:-4][::2] for i, time in enumerate(timeloop): for rot in prerotations: k = oqh.create_kernel("Ramsey_" + rot + "_{}".format(i), p) k.prepz(qubit_idx) wait_nanoseconds = int(round(time / 1e-9)) k.gate('rx90', [qubit_idx]) k.gate("wait", [qubit_idx], wait_nanoseconds) k.gate(rot, [qubit_idx]) k.measure(qubit_idx) p.add_kernel(k) # adding the calibration points oqh.add_single_qubit_cal_points(p, qubit_idx=qubit_idx) p = oqh.compile(p) return p
def T1(qubit_idx: int, platf_cfg: str, times: list, nr_cz_instead_of_idle_time: list = None, qb_cz_idx: int = None, nr_flux_dance: float = None, wait_time_after_flux_dance: float = 0): """ Single qubit T1 sequence. Writes output files to the directory specified in openql. Output directory is set as an attribute to the program for convenience. Input pars: times: the list of waiting times for each T1 element qubit_idx: int specifying the target qubit (starting at 0) platf_cfg: filename of the platform config file Returns: p: OpenQL Program object containing """ p = oqh.create_program('T1', platf_cfg) for i, time in enumerate(times[:-4]): k = oqh.create_kernel('T1_{}'.format(i), p) k.prepz(qubit_idx) if nr_flux_dance: for _ in range(int(nr_flux_dance)): for step in [1, 2, 3, 4]: # if refocusing: # k.gate(f'flux-dance-{step}-refocus', [0]) # else: k.gate(f'flux-dance-{step}', [0]) k.gate("wait", [], 0) # alignment k.gate("wait", [], wait_time_after_flux_dance) k.gate('rx180', [qubit_idx]) if nr_cz_instead_of_idle_time is not None: for n in range(nr_cz_instead_of_idle_time[i]): k.gate("cz", [qubit_idx, qb_cz_idx]) k.gate("wait", [], 0) # alignment k.gate("wait", [], wait_time_after_flux_dance) else: wait_nanoseconds = int(round(time / 1e-9)) k.gate("wait", [qubit_idx], wait_nanoseconds) k.measure(qubit_idx) p.add_kernel(k) # adding the calibration points oqh.add_single_qubit_cal_points(p, qubit_idx=qubit_idx) p = oqh.compile(p) return p
def spin_lock_echo(times, qubit_idx: int, platf_cfg: str): """ Single qubit Echo sequence. Writes output files to the directory specified in openql. Output directory is set as an attribute to the program for convenience. Input pars: times: the list of waiting times for each Echo element qubit_idx: int specifying the target qubit (starting at 0) platf_cfg: filename of the platform config file Returns: p: OpenQL Program object containing """ p = oqh.create_program("spin_lock_echo", platf_cfg) for i, time in enumerate(times[:-4]): k = oqh.create_kernel("spin_lock_echo{}".format(i), p) k.prepz(qubit_idx) # nr_clocks = int(time/20e-9/2) square_us_cycles = np.floor(time / 1e-6).astype(int) square_ns_cycles = np.round( (time % 1e-6) / mw_gate_duration).astype(int) wait_nanoseconds = 1 # print("square_us_cycles", square_us_cycles) # print("square_us_cycles", square_ns_cycles) k.gate('rYm90', [qubit_idx]) k.gate("wait", [qubit_idx], wait_nanoseconds) k.gate('rx180', [qubit_idx]) k.gate("wait", [qubit_idx], wait_nanoseconds) for suc in range(square_us_cycles): k.gate('cw_10', [qubit_idx]) # make sure that the square pulse lasts 1us for snc in range(square_ns_cycles): k.gate('cw_11', [ qubit_idx ]) # make sure that the square pulse lasts mw_gate_duration ns k.gate("wait", [qubit_idx], wait_nanoseconds) k.gate('rx180', [qubit_idx]) k.gate("wait", [qubit_idx], wait_nanoseconds) k.gate('rYm90', [qubit_idx]) k.measure(qubit_idx) p.add_kernel(k) # adding the calibration points oqh.add_single_qubit_cal_points(p, qubit_idx=qubit_idx) p = oqh.compile(p) return p
def CPMG_SO(orders, tauN: int, qubit_idx: int, platf_cfg: str): """ Single qubit CPMG sequence. Writes output files to the directory specified in openql. Output directory is set as an attribute to the program for convenience. Input pars: times: the list of waiting times for each Echo element qubit_idx: int specifying the target qubit (starting at 0) platf_cfg: filename of the platform config file Returns: p: OpenQL Program object containing """ p = oqh.create_program("CPMG_SO", platf_cfg) for i, order in enumerate(orders[:-4]): k = oqh.create_kernel("CPMG_SO_{}".format(i), p) k.prepz(qubit_idx) # nr_clocks = int(time/20e-9/2) wait_nanoseconds = int(round((tauN / 1e-9) / 2)) k.gate('rx90', [qubit_idx]) k.gate("wait", [qubit_idx], wait_nanoseconds) for j in range(order - 1): k.gate('ry180', [qubit_idx]) k.gate("wait", [qubit_idx], 2 * wait_nanoseconds) k.gate('ry180', [qubit_idx]) k.gate("wait", [qubit_idx], wait_nanoseconds) # angle = (i*40)%360 # cw_idx = angle//20 + 9 # if angle == 0: k.gate('rx90', [qubit_idx]) # else: # k.gate('cw_{:02}'.format(cw_idx), [qubit_idx]) k.measure(qubit_idx) p.add_kernel(k) # adding the calibration points oqh.add_single_qubit_cal_points(p, qubit_idx=qubit_idx) p = oqh.compile(p) return p
def T1_second_excited_state(times, qubit_idx: int, platf_cfg: str): """ Single qubit T1 sequence for the second excited states. Writes output files to the directory specified in openql. Output directory is set as an attribute to the program for convenience. Input pars: times: the list of waiting times for each T1 element qubit_idx: int specifying the target qubit (starting at 0) platf_cfg: filename of the platform config file Returns: p: OpenQL Program object containing """ p = oqh.create_program("T1_2nd_exc", platf_cfg) for i, time in enumerate(times): for j in range(2): k = oqh.create_kernel("T1_2nd_exc_{}_{}".format(i, j), p) k.prepz(qubit_idx) wait_nanoseconds = int(round(time / 1e-9)) k.gate('rx180', [qubit_idx]) k.gate('rx12', [qubit_idx]) k.gate("wait", [qubit_idx], wait_nanoseconds) if j == 1: k.gate('rx180', [qubit_idx]) k.measure(qubit_idx) p.add_kernel(k) # adding the calibration points oqh.add_single_qubit_cal_points(p, qubit_idx=qubit_idx, f_state_cal_pts=True) dt = times[1] - times[0] sweep_points = np.concatenate( [np.repeat(times, 2), times[-1] + dt * np.arange(6) + dt]) # attribute get's added to program to help finding the output files p.sweep_points = sweep_points p = oqh.compile(p) return p
def ef_rabi_seq(q0: int, amps: list, platf_cfg: str, recovery_pulse: bool = True, add_cal_points: bool = True): """ Sequence used to calibrate pulses for 2nd excited state (ef/12 transition) Timing of the sequence: q0: -- X180 -- X12 -- (X180) -- RO Args: q0 (str): name of the addressed qubit amps (list): amps for the two state pulse, note that these are only used to label the kernels. Load the pulse in the LutMan recovery_pulse (bool): if True adds a recovery pulse to enhance contrast in the measured signal. """ if len(amps) > 18: raise ValueError('Only 18 free codewords available for amp pulses') p = oqh.create_program("ef_rabi_seq", platf_cfg) # These angles correspond to special pi/2 pulses in the lutman for i, amp in enumerate(amps): # cw_idx corresponds to special hardcoded pulses in the lutman cw_idx = i + 9 k = oqh.create_kernel("ef_A{}".format(int(abs(1000 * amp))), p) k.prepz(q0) k.gate('rx180', [q0]) k.gate('cw_{:02}'.format(cw_idx), [q0]) if recovery_pulse: k.gate('rx180', [q0]) k.measure(q0) p.add_kernel(k) if add_cal_points: p = oqh.add_single_qubit_cal_points(p, qubit_idx=q0) p = oqh.compile(p) if add_cal_points: cal_pts_idx = [ amps[-1] + .1, amps[-1] + .15, amps[-1] + .2, amps[-1] + .25 ] else: cal_pts_idx = [] p.sweep_points = np.concatenate([amps, cal_pts_idx]) # FIXME: remove try-except, when we depend hardly on >=openql-0.6 try: p.set_sweep_points(p.sweep_points) except TypeError: # openql-0.5 compatibility p.set_sweep_points(p.sweep_points, len(p.sweep_points)) return p
k.gate( flux_codeword, [qubit_map[qubit] for qubit in qubit_or_qubits], ) k.gate("wait", [], 0) k.gate("wait", [], 0) # align RO for qubit_idx in qubit_map.values(): k.measure(qubit_idx) # measure parking qubit only k.gate("wait", [], 0) p.add_kernel(k) if cal_points: if number_of_qubits == 1: p = oqh.add_single_qubit_cal_points( p, qubit_idx=qubits[0], f_state_cal_pts=f_state_cal_pts ) elif number_of_qubits == 2: if f_state_cal_pts: combinations = ["00", "01", "10", "11", "02", "20", "22"] else: combinations = ["00", "01", "10", "11"] p = oqh.add_multi_q_cal_points( p, qubits=qubits, combinations=combinations ) elif number_of_qubits == 3: p = oqh.add_single_qubit_cal_points( p, qubit_idx=qubit_map["q2"], f_state_cal_pts=f_state_cal_pts, # we must measure all 3 qubits to avoid alignment issues
def randomized_benchmarking(qubits: list, platf_cfg: str, nr_cliffords, nr_seeds: int, net_cliffords: list = [0], max_clifford_idx: int = 11520, flux_codeword: str = 'cz', simultaneous_single_qubit_RB=False, initialize: bool = True, interleaving_cliffords=[None], program_name: str = 'randomized_benchmarking', cal_points: bool = True, f_state_cal_pts: bool = True, sim_cz_qubits: list = None, recompile: bool = True): ''' Input pars: qubits: list of ints specifying qubit indices. based on the length this function detects if it should generate a single or two qubit RB sequence. platf_cfg: filename of the platform config file nr_cliffords: list nr_cliffords for which to generate RB seqs nr_seeds: int nr_seeds for which to generate RB seqs net_cliffords: list of ints index of net clifford the sequence should perform. See examples below on how to use this. Important clifford indices 0 -> Idx 3 -> rx180 3*24+3 -> {rx180 q0 | rx180 q1} 4368 -> CZ max_clifford_idx: Set's the maximum clifford group index from which to sample random cliffords. Important clifford indices 24 -> Size of the single qubit Cl group 576 -> Size of the single qubit like class contained in the two qubit Cl group 11520 -> Size of the complete two qubit Cl group initialize: if True initializes qubits to 0, disable for restless tuning interleaving_cliffords: list of integers which specifies which cliffords to interleave the sequence with (for interleaved RB) program_name: some string that can be used as a label. cal_points: bool whether to replace the last two elements with calibration points, set to False if you want to measure a single element (for e.g. optimization) sim_cz_qubits: A list of qubit indices on which a simultaneous cz instruction must be applied. This is for characterizing CZ gates that are intended to be performed in parallel with other CZ gates. recompile: True -> compiles the program, 'as needed' -> compares program to timestamp of config and existence, if required recompile. False -> compares program to timestamp of config. if compilation is required raises a ValueError If the program is more recent than the config it returns an empty OpenQL program object with the intended filename that can be used to upload the previously compiled file. Returns: p: OpenQL Program object *************************************************************************** Examples: 1. Single qubit randomized benchmarking: p = cl_oql.randomized_benchmarking( qubits=[0], nr_cliffords=[2, 4, 8, 16, 32, 128, 512, 1024], nr_seeds=1, # for CCL memory reasons platf_cfg=qubit.cfg_openql_platform_fn(), program_name='RB_{}'.format(i)) 2. Two qubit simultaneous randomized benchmarking: p = cl_oql.randomized_benchmarking( qubits=[0, 1], # simultaneous RB on both qubits simultaneous_single_qubit_RB=True, nr_cliffords=[2, 4, 8, 16, 32, 128, 512, 1024], nr_seeds=1, # for CCL memory reasons platf_cfg=qubit.cfg_openql_platform_fn(), program_name='RB_{}'.format(i)) 3. Single qubit interleaved randomized benchmarking: p = cl_oql.randomized_benchmarking( qubits=[0], interleaving_cliffords=[None, 0, 16, 3], cal_points=False # relevant here because of data binning nr_cliffords=[2, 4, 8, 16, 32, 128, 512, 1024], nr_seeds=1, platf_cfg=qubit.cfg_openql_platform_fn(), program_name='Interleaved_RB_s{}_int{}_ncl{}_{}'.format(i)) ''' p = oqh.create_program(program_name, platf_cfg) # attribute get's added to program to help finding the output files p.filename = join(p.output_dir, p.name + '.qisa') # FIXME: platform dependency if not oqh.check_recompilation_needed( program_fn=p.filename, platf_cfg=platf_cfg, recompile=recompile): return p if len(qubits) == 1: qubit_map = {'q0': qubits[0]} number_of_qubits = 1 Cl = SingleQubitClifford elif len(qubits) == 2 and not simultaneous_single_qubit_RB: qubit_map = {'q0': qubits[0], 'q1': qubits[1]} number_of_qubits = 2 Cl = TwoQubitClifford elif len(qubits) == 2 and simultaneous_single_qubit_RB: qubit_map = {'q0': qubits[0], 'q1': qubits[1]} # arguments used to generate 2 single qubit sequences number_of_qubits = 2 Cl = SingleQubitClifford else: raise NotImplementedError() for seed in range(nr_seeds): for j, n_cl in enumerate(nr_cliffords): for interleaving_cl in interleaving_cliffords: if not simultaneous_single_qubit_RB: cl_seq = rb.randomized_benchmarking_sequence( n_cl, number_of_qubits=number_of_qubits, desired_net_cl=None, # net_clifford, max_clifford_idx=max_clifford_idx, interleaving_cl=interleaving_cl) net_cl_seq = rb.calculate_net_clifford(cl_seq, Cl) cl_seq_decomposed = [] for cl in cl_seq: # FIXME: hacking in exception for benchmarking only CZ # (not as a member of CNOT group) if cl == -4368: cl_seq_decomposed.append([('CZ', ['q0', 'q1'])]) else: cl_seq_decomposed.append(Cl(cl).gate_decomposition) for net_clifford in net_cliffords: recovery_to_idx_clifford = net_cl_seq.get_inverse() recovery_clifford = Cl( net_clifford) * recovery_to_idx_clifford cl_seq_decomposed_with_net = cl_seq_decomposed + \ [recovery_clifford.gate_decomposition] k = oqh.create_kernel( 'RB_{}Cl_s{}_net{}_inter{}'.format( int(n_cl), seed, net_clifford, interleaving_cl), p) if initialize: for qubit_idx in qubit_map.values(): k.prepz(qubit_idx) for gates in cl_seq_decomposed_with_net: for g, q in gates: if isinstance(q, str): k.gate(g, [qubit_map[q]]) elif isinstance(q, list): if sim_cz_qubits is None: k.gate("wait", list(qubit_map.values()), 0) k.gate( flux_codeword, list(qubit_map.values()), ) # fix for QCC k.gate("wait", list(qubit_map.values()), 0) else: # A simultaneous CZ is applied to characterize cz gates that # have been calibrated to be used in parallel. k.gate( "wait", list(qubit_map.values()) + sim_cz_qubits, 0) k.gate( flux_codeword, list(qubit_map.values()), ) # fix for QCC k.gate(flux_codeword, sim_cz_qubits) # fix for QCC k.gate( "wait", list(qubit_map.values()) + sim_cz_qubits, 0) # FIXME: This hack is required to align multiplexed RO in openQL.. k.gate("wait", list(qubit_map.values()), 0) for qubit_idx in qubit_map.values(): k.measure(qubit_idx) k.gate("wait", list(qubit_map.values()), 0) p.add_kernel(k) elif simultaneous_single_qubit_RB: for net_clifford in net_cliffords: k = oqh.create_kernel( 'RB_{}Cl_s{}_net{}_inter{}'.format( int(n_cl), seed, net_clifford, interleaving_cl), p) if initialize: for qubit_idx in qubit_map.values(): k.prepz(qubit_idx) # FIXME: Gate seqs is a hack for failing openql scheduling gate_seqs = [[], []] for gsi, q_idx in enumerate(qubits): cl_seq = rb.randomized_benchmarking_sequence( n_cl, number_of_qubits=1, desired_net_cl=net_clifford, interleaving_cl=interleaving_cl) for cl in cl_seq: gates = Cl(cl).gate_decomposition # for g, q in gates: # k.gate(g, q_idx) # FIXME: THIS is a hack because of OpenQL # scheduling issues #157 gate_seqs[gsi] += gates # OpenQL #157 HACK l = max([len(gate_seqs[0]), len(gate_seqs[1])]) for gi in range(l): for gj, q_idx in enumerate(qubits): # gj = 0 # q_idx = 0 try: # for possible different lengths in gate_seqs g = gate_seqs[gj][gi] k.gate(g[0], [q_idx]) except IndexError as e: pass # end of #157 HACK # FIXME: This hack is required to align multiplexed RO in openQL.. k.gate("wait", list(qubit_map.values()), 0) for qubit_idx in qubit_map.values(): k.measure(qubit_idx) k.gate("wait", list(qubit_map.values()), 0) p.add_kernel(k) if cal_points: if number_of_qubits == 1: p = oqh.add_single_qubit_cal_points( p, qubit_idx=qubits[0], f_state_cal_pts=f_state_cal_pts) elif number_of_qubits == 2: if f_state_cal_pts: combinations = ['00', '01', '10', '11', '02', '20', '22'] else: combinations = ['00', '01', '10', '11'] p = oqh.add_multi_q_cal_points(p, qubits=qubits, combinations=combinations) p = oqh.compile(p) return p
def rabi_frequency(times, qubit_idx: int, platf_cfg: str, mw_gate_duration: float = 40e-9, tomo: bool = False): """ Rabi Sequence consising out of sequence of square pulses Writes output files to the directory specified in openql. Output directory is set as an attribute to the program for convenience. Input pars: times: the list of waiting times for each Echo element qubit_idx: int specifying the target qubit (starting at 0) platf_cfg: filename of the platform config file Returns: p: OpenQL Program object containing """ p = oqh.create_program("rabi_frequency", platf_cfg) if tomo: tomo_gates = ['I', 'rX180', 'rX12'] else: tomo_gates = ['I'] if tomo: timeloop = times[:-6][::3] else: timeloop = times[:-4] for i, time in enumerate(timeloop): for tomo_gate in tomo_gates: k = oqh.create_kernel( "rabi_frequency" + "_tomo_" + tomo_gate + "{}".format(i), p) k.prepz(qubit_idx) # nr_clocks = int(time/20e-9/2) square_us_cycles = np.floor((time + 1e-10) / 1e-6).astype(int) leftover_us = (time - square_us_cycles * 1e-6) square_ns_cycles = np.floor( (leftover_us + 1e-10) / mw_gate_duration).astype(int) leftover_ns = (leftover_us - square_ns_cycles * mw_gate_duration) print(leftover_us) print(leftover_ns) mwlutman_index = np.round((leftover_ns + 1e-10) / 4e-9).astype(int) print(mwlutman_index) print("square_us_cycles", square_us_cycles) print("square_ns_cycles", square_ns_cycles) for suc in range(square_us_cycles): k.gate( 'cw_10', [qubit_idx]) # make sure that the square pulse lasts 1us for snc in range(square_ns_cycles): k.gate('cw_11', [ qubit_idx ]) # make sure that the square pulse lasts mw_gate_duration ns k.gate('cw_{}'.format(mwlutman_index + 11), [qubit_idx]) if tomo: k.gate(tomo_gate, [qubit_idx]) k.measure(qubit_idx) p.add_kernel(k) # adding the calibration points oqh.add_single_qubit_cal_points(p, qubit_idx=qubit_idx, f_state_cal_pts=tomo) p = oqh.compile(p) return p
def spin_lock_simple(times, qubit_idx: int, platf_cfg: str, mw_gate_duration: float = 40e-9, tomo: bool = False): """ Single qubit Echo sequence. Writes output files to the directory specified in openql. Output directory is set as an attribute to the program for convenience. Input pars: times: the list of waiting times for each Echo element qubit_idx: int specifying the target qubit (starting at 0) platf_cfg: filename of the platform config file Returns: p: OpenQL Program object containing """ p = oqh.create_program("spin_lock_simple", platf_cfg) # Poor mans tomography: if tomo: tomo_gates = ['I', 'rX180', 'rX12'] else: tomo_gates = ['I'] if tomo: timeloop = times[:-6][::3] else: timeloop = times[:-4] for i, time in enumerate(timeloop): for tomo_gate in tomo_gates: k = oqh.create_kernel( "spin_lock_simple" + "_tomo_" + tomo_gate + "_{}".format(i), p) k.prepz(qubit_idx) # nr_clocks = int(time/20e-9/2) square_us_cycles = np.floor(time / 1e-6).astype(int) square_ns_cycles = np.round( (time % 1e-6) / mw_gate_duration).astype(int) # print("square_us_cycles", square_us_cycles) # print("square_us_cycles", square_ns_cycles) k.gate('rYm90', [qubit_idx]) for suc in range(square_us_cycles): k.gate( 'cw_10', [qubit_idx]) # make sure that the square pulse lasts 1us for snc in range(square_ns_cycles): k.gate('cw_11', [ qubit_idx ]) # make sure that the square pulse lasts mw_gate_duration ns k.gate('rYm90', [qubit_idx]) if tomo: k.gate(tomo_gate, [qubit_idx]) k.measure(qubit_idx) p.add_kernel(k) # adding the calibration points oqh.add_single_qubit_cal_points(p, qubit_idx=qubit_idx, f_state_cal_pts=tomo) p = oqh.compile(p) return p