def calibrate_motzoi(self, MC=None, verbose=True, update=True): motzois = gen_sweep_pts(center=0, span=1, num=31) # large range a = self.measure_motzoi(MC=MC, motzois=motzois, analyze=True) opt_motzoi = a.optimal_motzoi if opt_motzoi > max(motzois) or opt_motzoi < min(motzois): if verbose: print('optimal motzoi {:.3f} '.format(opt_motzoi) + 'outside of measured span, aborting') return False # fine range around optimum motzois = gen_sweep_pts(center=a.optimal_motzoi, span=.4, num=31) a = self.measure_motzoi(motzois) opt_motzoi = a.optimal_motzoi if opt_motzoi > max(motzois) or opt_motzoi < min(motzois): if verbose: print('optimal motzoi {:.3f} '.format(opt_motzoi) + 'outside of measured span, aborting') if update: if verbose: print('Setting motzoi to {:.3f}'.format(opt_motzoi)) self.motzoi(opt_motzoi) return opt_motzoi
def setUpClass(self): self.test_file_dir = join(pq.__path__[0], 'tests', 'qasm_files') self.config_fn = join(self.test_file_dir, 'config.json') self.simple_config_fn = join(self.test_file_dir, 'config_simple.json') self.qubit_name = 'q0' self.jump_to_start = ("beq r14, r14, Exp_Start " + "\t# Jump to start ad nauseam") self.times = gen.gen_sweep_pts(start=100e-9, stop=5e-6, step=200e-9) self.clocks = np.round(self.times / 5e-9).astype(int)
def test_gen_sweep_pts(self): lin = gen.gen_sweep_pts(start=3.8, stop=4.2, num=21) np.testing.assert_array_equal(lin, np.linspace(3.8, 4.2, 21)) linspan = gen.gen_sweep_pts(center=3.8, span=.2, num=21) linspan2 = gen.span_num(3.8, .2, 21) np.testing.assert_array_equal(linspan, linspan2) ran = gen.gen_sweep_pts(start=3.8, stop=4.2, step=.05) np.testing.assert_array_equal(ran, np.arange(3.8, 4.2001, .05)) ran = gen.gen_sweep_pts(center=3.8, span=.2, step=.05) np.testing.assert_array_equal(ran, gen.span_step(3.8, .200, .05)) # missing arguments or invalid combinations of arguments should # raise errors with self.assertRaises(ValueError): gen.gen_sweep_pts(center=3.8, stop=4, step=5) with self.assertRaises(ValueError): gen.gen_sweep_pts(start=3.8, stop=.3) with self.assertRaises(ValueError): gen.gen_sweep_pts(center=3.8, span=.3)
def setUpClass(self): self.test_file_dir = join(pq.__path__[0], 'tests', 'qasm_files') self.config_fn = join(self.test_file_dir, 'config.json') self.times = gen.gen_sweep_pts(start=100e-9, stop=5e-6, step=200e-9) self.clocks = np.round(self.times / 5e-9).astype(int) self.simple_config_fn = join(self.test_file_dir, 'config_simple.json') self.jump_to_start = ("beq r14, r14, Exp_Start " + "\t# Jump to start ad nauseam") self.QWG_flux_lutman = qlm.QWG_FluxLookuptableManager( 'QWG_flux_lutman') with open(self.simple_config_fn) as data_file: self.config_simple = json.load(data_file)
def calibrate_grover_1Q_phase_fine(self, correction_qubit=None, spectator_qubit=None, msmt_suffix: str = None, span: float = 0.04, num: int = 31, min_fit_pts: int = 15, MC=None) -> bool: ''' Fine-tune the single qubit phase correction for the second CZ pulse in Grover's algorithm based on the last known value. A range around the last known value is measured and a parabolic fit is used to find the minimum. Args: correction_qubit (obj): Qubit object representing the qubit to which the phase correction is applied. spectator_qubit (obj): Qubit object representing the other qubit involved in the CZ. span (float): Full span of the range around the last known value for Z_amp_grover. num (int): Number of points measured in the specified range. min_fit_pts (int): Minimum number of points that should be used for the fit. The measurement is repeated with an adapted range if there are less points than left after discarding points that are too far away from the minimum. ''' if MC is None: MC = qc.station.components['MC'] if correction_qubit is None: correction_qubit = self.qubits()[0] if spectator_qubit is None: spectator_qubit = self.qubits()[1] old_z_amp = correction_qubit.flux_LutMan.get_instr().Z_amp_grover() repeat_calibration = True while repeat_calibration: amp_pts = gen_sweep_pts(center=old_z_amp, span=span, num=num) self.measure_grover_1Q_phase(amp_pts, correction_qubit, spectator_qubit, msmt_suffix=msmt_suffix, MC=MC) try: a = ma.CZ_1Q_phase_analysis(use_diff=False, meas_vals_idx=1) except RuntimeError as e: # Analysis returns a RuntimeError when the fit fails due to # bad range and it can't fix itself. print(e) return False except Exception as e: raise e new_z_amp = a.opt_z_amp if len(a.fit_data) < min_fit_pts: print('Bad measurement range: too large or too far from ' 'minimum for parabolic model.\nRetrying...') old_z_amp = new_z_amp if a.del_indices[0] == 0 and a.del_indices[-1] == num - 1: # Values larger than one found on both sides # -> reduce range span *= 0.5 continue if new_z_amp < amp_pts[0]: print('Fitted minimum below scan range. Repeating scan ' 'around lowest point {}.'.format(amp_pts[0])) old_z_amp = amp_pts[0] elif new_z_amp > amp_pts[-1]: print('Fitted minimum above scan range. Repeating scan ' 'around hightest point {}.'.format(amp_pts[-1])) old_z_amp = amp_pts[-1] else: repeat_calibration = False # This has to be set in the qubit object. # the "prepare_for_fluxing" in turn should ensure the right vals # get updated. correction_qubit.flux_LutMan.get_instr().Z_amp_grover(new_z_amp) return True
def calibrate_CZ_1Q_phase_fine(self, correction_qubit=None, spectator_qubit=None, span: float = 0.04, num: int = 31, min_fit_pts: int = 15, MC=None, msmt_suffix: str = None) -> bool: ''' Measures a the Z-amp cost function in a small range around the value from the last calibration, fits a parabola, extracts a new minimum, and sets the new Z-amp in the flux lookup table manager of the correction qubit. Args: correction_qubit (Instr): Qubit object representing the qubit for which the single qubit phase correction should be calibrated. spectator_qubit (Instr): Qubit object representing the other qubit involved in the CZ. span (float): Full span of the range around the last known value for Z-amp in which the cost function is measured. num (int): Number of points measured in the specified range. min_fit_pts (int): Minimum number of points that should be used for the fit. The measurement is repeated with an adapted range if there are less points than left after discarding points that are too far away from the minimum. Returns: success (bool): True if calibration succeeded, False otherwise. ''' if MC is None: MC = qc.station.components['MC'] if correction_qubit is None: correction_qubit = self.qubits()[0] if spectator_qubit is None: spectator_qubit = self.qubits()[1] if msmt_suffix is None: msmt_suffix = '_' + correction_qubit.name old_z_amp = correction_qubit.flux_LutMan.get_instr().Z_amp() repeat_calibration = True while repeat_calibration: amp_pts = gen_sweep_pts(center=old_z_amp, span=span, num=num) CZ_cost_Z_amp(correction_qubit, spectator_qubit, MC, Z_amps_q0=amp_pts) try: a = ma.CZ_1Q_phase_analysis() except RuntimeError as e: # Analysis returns a RuntimeError when the fit fails due to # bad range and it can't fix itself. print(e) return False except Exception as e: raise e new_z_amp = a.opt_z_amp if len(a.fit_data) < min_fit_pts: print('Bad measurement range: too large or too far from ' 'minimum for parabolic model.\nRetrying...') if a.del_indices[0] == 0: old_z_amp = amp_pts[-1] elif a.del_indices[-1] == num - 1: old_z_amp = amp_pts[0] elif a.del_indices[0] == 0 and a.del_indices[-1] == num - 1: # Values larger than one found on both sides # -> reduce range span *= 0.5 continue if new_z_amp < amp_pts[0]: print('Fitted minimum below scan range. Repeating scan ' 'around lowest point {}.'.format(amp_pts[0])) old_z_amp = amp_pts[0] elif new_z_amp > amp_pts[-1]: print('Fitted minimum above scan range. Repeating scan ' 'around hightest point {}.'.format(amp_pts[-1])) old_z_amp = amp_pts[-1] else: repeat_calibration = False # This has to be set in the qubit object. # the "prepare_for_fluxing" in turn should ensure the right vals # get updated. correction_qubit.flux_LutMan.get_instr().Z_amp(new_z_amp) return True