def test_can_create_valid_schedule(self): """Test valid schedule creation without error.""" gp0 = library.gaussian(duration=20, amp=0.7, sigma=3) gp1 = library.gaussian(duration=20, amp=0.7, sigma=3) sched = Schedule() sched = sched.append(Play(gp0, self.config.drive(0))) sched = sched.insert(60, ShiftPhase(-1.57, self.config.drive(0))) sched = sched.insert(30, Play(gp1, self.config.drive(0))) sched = sched.insert(60, Play(gp0, self.config.control([0, 1])[0])) sched = sched.insert(80, Snapshot("label", "snap_type")) sched = sched.insert(90, ShiftPhase(1.57, self.config.drive(0))) sched = sched.insert( 90, Acquire(10, self.config.acquire(0), MemorySlot(0), RegisterSlot(0)) ) self.assertEqual(0, sched.start_time) self.assertEqual(100, sched.stop_time) self.assertEqual(100, sched.duration) new_sched = Schedule() new_sched = new_sched.append(sched) new_sched = new_sched.append(sched) self.assertEqual(0, new_sched.start_time) self.assertEqual(200, new_sched.stop_time) self.assertEqual(200, new_sched.duration) ids = set() for _, inst in sched.instructions: self.assertFalse(inst.id in ids) ids.add(inst.id)
def sample_schedule(self): """Generate a sample schedule that includes the most common elements of pulse schedules.""" gp0 = library.gaussian(duration=20, amp=1.0, sigma=1.0) gp1 = library.gaussian(duration=20, amp=-1.0, sigma=2.0) gs0 = library.gaussian_square(duration=20, amp=-1.0, sigma=2.0, risefall=3) sched = Schedule(name='test_schedule') sched = sched.append(gp0(DriveChannel(0))) sched = sched.insert(0, Play(library.Constant(duration=60, amp=0.2 + 0.4j), ControlChannel(0))) sched = sched.insert(60, ShiftPhase(-1.57, DriveChannel(0))) sched = sched.insert(60, SetFrequency(8.0, DriveChannel(0))) sched = sched.insert(60, SetPhase(3.14, DriveChannel(0))) sched = sched.insert(70, ShiftFrequency(4.0e6, DriveChannel(0))) sched = sched.insert(30, Play(gp1, DriveChannel(1))) sched = sched.insert(60, Play(gp0, ControlChannel(0))) sched = sched.insert(60, Play(gs0, MeasureChannel(0))) sched = sched.insert(90, ShiftPhase(1.57, DriveChannel(0))) sched = sched.insert(90, Acquire(10, AcquireChannel(1), MemorySlot(1), RegisterSlot(1))) sched = sched.append(Delay(100, DriveChannel(0))) sched = sched + sched sched |= Snapshot("snapshot_1", "snap_type") << 60 sched |= Snapshot("snapshot_2", "snap_type") << 120 return sched
def test_immutability(self): """Test that operations are immutable.""" gp0 = library.gaussian(duration=100, amp=0.7, sigma=3) gp1 = library.gaussian(duration=20, amp=0.5, sigma=3) sched = Play(gp1, self.config.drive(0)) << 100 # if schedule was mutable the next two sequences would overlap and an error # would be raised. sched.insert(0, Play(gp0, self.config.drive(0))) sched.insert(0, Play(gp0, self.config.drive(0)))
def test_inplace(self): """Test that in place operations on schedule are still immutable.""" gp0 = library.gaussian(duration=100, amp=0.7, sigma=3) gp1 = library.gaussian(duration=20, amp=0.5, sigma=3) sched = Schedule() sched = sched + Play(gp1, self.config.drive(0)) sched2 = sched sched += Play(gp0, self.config.drive(0)) self.assertNotEqual(sched, sched2)
def test_immutability(self): """Test that operations are immutable.""" gp0 = library.gaussian(duration=100, amp=0.7, sigma=3) gp1 = library.gaussian(duration=20, amp=0.5, sigma=3) sched = Play(gp1, self.config.drive(0)) << 100 # if schedule was mutable the next two sequences would overlap and an error # would be raised. with self.assertWarns(DeprecationWarning): sched.union(gp0(self.config.drive(0))) with self.assertWarns(DeprecationWarning): sched.union(gp0(self.config.drive(0)))
def test_can_create_valid_schedule_with_syntax_sugar(self): """Test that in place operations on schedule are still immutable and return equivalent schedules.""" gp0 = library.gaussian(duration=20, amp=0.7, sigma=3) gp1 = library.gaussian(duration=20, amp=0.5, sigma=3) sched = Schedule() sched += Play(gp0, self.config.drive(0)) sched |= ShiftPhase(-1.57, self.config.drive(0)) << 60 sched |= Play(gp1, self.config.drive(0)) << 30 sched |= Play(gp0, self.config.control(qubits=[0, 1])[0]) << 60 sched |= Snapshot("label", "snap_type") << 60 sched |= ShiftPhase(1.57, self.config.drive(0)) << 90 sched |= Acquire(10, self.config.acquire(0), MemorySlot(0)) << 90 sched += sched
def test_name_inherited(self): """Test that schedule keeps name if an instruction is added.""" gp0 = library.gaussian(duration=100, amp=0.7, sigma=3, name='pulse_name') snapshot = Snapshot('snapshot_label', 'state') sched1 = Schedule(name='test_name') sched2 = Schedule(name=None) sched3 = sched1 | sched2 self.assertEqual(sched3.name, 'test_name') sched_acq = Acquire( 10, self.config.acquire(1), MemorySlot(1), name='acq_name') | sched1 self.assertEqual(sched_acq.name, 'acq_name') sched_pulse = Play(gp0, self.config.drive(0)) | sched1 self.assertEqual(sched_pulse.name, 'pulse_name') sched_fc = ShiftPhase(0.1, self.config.drive(0), name='fc_name') | sched1 self.assertEqual(sched_fc.name, 'fc_name') sched_snapshot = snapshot | sched1 self.assertEqual(sched_snapshot.name, 'snapshot_label')
def create_excited_freq_sweep_program(self, freqs, amp): if len(freqs) > 75: raise ValueError("You can only run 75 schedules at a time.") base_12_pulse = pulse_lib.gaussian(duration=self.drive_samples, sigma=self.drive_sigma, amp=amp, name='base_12_pulse') schedules = [] for jj, freq in enumerate(freqs): freq_sweep_12_pulse = self.apply_sideband(base_12_pulse, freq) schedule = pulse.Schedule(name="Frequency = {}".format(freq)) schedule |= self.sched_x schedule |= pulse.Play(freq_sweep_12_pulse, DriveChannel( self.qubit)) << schedule.duration schedule |= self.sched_meas << schedule.duration # 駆動パルスの後に測定をシフト schedules.append(schedule) excited_freq_sweep_program = assemble( schedules, backend=self.backend, meas_level=1, meas_return='avg', shots=self.shots, schedule_los=[{ DriveChannel(self.qubit): self.default_qubit_freq }] * len(freqs)) return excited_freq_sweep_program
def calibrated_x01(self, pi_amp_01): pi_pulse_01 = pulse_lib.gaussian(duration=self.drive_samples, amp=pi_amp_01, sigma=self.drive_sigma, name='pi_pulse_01') return pi_pulse_01
def create_ground_freq_sweep_program(self, freqs, amp): if len(freqs) > 75: raise ValueError("You can only run 75 schedules at a time.") # Define the drive pulse ground_sweep_drive_pulse = pulse_lib.gaussian( duration=self.drive_samples, sigma=self.drive_sigma, amp=amp, name='ground_sweep_drive_pulse') # Create the base schedule schedule = pulse.Schedule( name='Frequency sweep starting from ground state.') schedule |= pulse.Play(ground_sweep_drive_pulse, DriveChannel(self.qubit)) schedule |= self.sched_meas << schedule.duration # define frequencies for the sweep schedule_freqs = [{DriveChannel(self.qubit): freq} for freq in freqs] # assemble the program ground_freq_sweep_program = assemble(schedule, backend=self.backend, meas_level=1, meas_return='avg', shots=self.shots, schedule_los=schedule_freqs) return ground_freq_sweep_program
def test_gaussian_pulse(self): """Test that Gaussian sample pulse matches the pulse library.""" gauss = Gaussian(duration=25, sigma=4, amp=0.5j) sample_pulse = gauss.get_waveform() self.assertIsInstance(sample_pulse, Waveform) pulse_lib_gauss = gaussian(duration=25, sigma=4, amp=0.5j, zero_ends=True).samples np.testing.assert_almost_equal(sample_pulse.samples, pulse_lib_gauss)
def rabi_schedules(amp_list, qubits, pulse_width, pulse_sigma=None, width_sigma_ratio=4, drives=None, inst_map=None, meas_map=None): """ Generates schedules for a rabi experiment using a Gaussian pulse Args: amp_list (list): A list of floats of amplitudes for the Gaussian pulse [-1,1] qubits (list): A list of integers for indices of the qubits to perform a rabi pulse_width (float): width of gaussian (in dt units) pulse_sigma (float): sigma of gaussian width_sigma_ratio (int): set sigma to a certain ratio of the width (use if pulse_sigma is None) drives (list): list of :class:`~qiskit.pulse.DriveChannel` objects inst_map (qiskit.pulse.InstructionScheduleMap): InstructionScheduleMap object to use meas_map (list): meas_map to use Returns: A list of QuantumSchedules xdata: a list of amps Raises: QiskitError: when necessary variables are not supplied. """ xdata = amp_list # copy the instruction to schedule mapping inst_map = copy.deepcopy(inst_map) # Following variables should not be optional. # To keep function interface constant, errors are inserted here. # TODO: redesign this function in next release if inst_map is None: QiskitError('Instruction schedule map is not provided. ', 'Run `backend.defaults().instruction_schedule_map` to get inst_map.') if meas_map is None: QiskitError('Measurement map is not provided. ', 'Run `backend.configuration().meas_map` to get meas_map.') if pulse_sigma is None: pulse_sigma = pulse_width / width_sigma_ratio # Construct the schedules rabi_scheds = [] for index, g_amp in enumerate(amp_list): rabi_pulse = pulse_lib.gaussian(duration=pulse_width, amp=g_amp, sigma=pulse_sigma, name='rabi_pulse_%d' % index) sched = pulse.Schedule(name='rabisched_%d_0' % index) for qubit in qubits: sched += pulse.Play(rabi_pulse, drives[qubit]) sched += measure(qubits, inst_map=inst_map, meas_map=meas_map).shift(pulse_width) rabi_scheds.append(sched) return rabi_scheds, xdata
def test_sampled_pulse(self): """Test that we can convert to a sampled pulse.""" gauss = Gaussian(duration=25, sigma=4, amp=0.5j) sample_pulse = gauss.get_waveform() self.assertIsInstance(sample_pulse, Waveform) pulse_lib_gaus = gaussian(duration=25, sigma=4, amp=0.5j, zero_ends=False).samples np.testing.assert_almost_equal(sample_pulse.samples, pulse_lib_gaus)
def calibrated_x12(self, rabi_freq, pi_amp_12): pi_pulse_12 = pulse_lib.gaussian(duration=self.drive_samples, amp=pi_amp_12, sigma=self.drive_sigma, name='pi_pulse_12') pi_pulse_12 = self.apply_sideband(pi_pulse_12, rabi_freq) return pi_pulse_12
def test_schedule_drawer_show_framechange(self): filename = self._get_resource_path('current_show_framechange_ref.png') gp0 = library.gaussian(duration=20, amp=1.0, sigma=1.0) sched = Schedule(name='test_schedule') sched = sched.append(Play(gp0, DriveChannel(0))) sched = sched.insert(60, ShiftPhase(-1.57, DriveChannel(0))) sched = sched.insert(30, ShiftPhase(-1.50, DriveChannel(1))) sched = sched.insert(70, ShiftPhase(1.50, DriveChannel(1))) pulse_drawer(sched, filename=filename, show_framechange_channels=False) self.assertImagesAreEqual(filename, self.schedule_show_framechange_ref) os.remove(filename)
def get_pi_pulse_12(c): pulse = pulse_lib.gaussian(duration=c["drive_samples"], amp=c["pi_amp_12"], sigma=c["drive_sigma"], name="pi_pulse_12") t_samples = np.linspace(0, c["dt"] * c["drive_samples"], c["drive_samples"]) sine_pulse = np.sin(2 * np.pi * (c["qubit_12_freq"] - c["cal_qubit_freq"]) * t_samples) return pulse_lib.SamplePulse(np.multiply(np.real(pulse.samples), sine_pulse), name='sideband_pulse')
def test_gaussian(self): """Test gaussian pulse.""" amp = 0.5 sigma = 2 duration = 10 center = duration/2 times = np.arange(0, duration) + 0.5 gaussian_ref = continuous.gaussian(times, amp, center, sigma, zeroed_width=2*(center+1), rescale_amp=True) gaussian_pulse = library.gaussian(duration, amp, sigma) self.assertIsInstance(gaussian_pulse, Waveform) np.testing.assert_array_almost_equal(gaussian_pulse.samples, gaussian_ref)
def create_ground_freq_sweep_program(freqs, drive_power): """Builds a program that does a freq sweep by exciting the ground state. Depending on drive power this can reveal the 0->1 frequency or the 0->2 frequency. Args: freqs (np.ndarray(dtype=float)): Numpy array of frequencies to sweep. drive_power (float) : Value of drive amplitude. Raises: ValueError: Raised if use more than 75 frequencies; currently, an error will be thrown on the backend if you try to do this. Returns: Qobj: Program for ground freq sweep experiment. """ if len(freqs) > 75: raise ValueError("You can only run 75 schedules at a time.") # print information on the sweep print( f"The frequency sweep will go from {freqs[0] / GHz} GHz to {freqs[-1]/ GHz} GHz \ using {len(freqs)} frequencies. The drive power is {drive_power}.") # Define the drive pulse ground_sweep_drive_pulse = pulse_lib.gaussian( duration=drive_samples, sigma=drive_sigma, amp=drive_power, name='ground_sweep_drive_pulse') # Create the base schedule schedule = pulse.Schedule( name='Frequency sweep starting from ground state.') schedule |= pulse.Play(ground_sweep_drive_pulse, drive_chan) schedule |= measure << schedule.duration # define frequencies for the sweep schedule_freqs = [{drive_chan: freq} for freq in freqs] # assemble the program # Note: we only require a single schedule since each does the same thing; # for each schedule, the LO frequency that mixes down the drive changes # this enables our frequency sweep ground_freq_sweep_program = assemble(schedule, backend=backend, meas_level=1, meas_return='avg', shots=NUM_SHOTS, schedule_los=schedule_freqs) return ground_freq_sweep_program
def test_pulse_name_conflicts_in_other_schedule(self): """Test two pulses with the same name in different schedule can be resolved.""" backend = FakeAlmaden() schedules = [] ch_d0 = pulse.DriveChannel(0) for amp in (0.1, 0.2): sched = Schedule() sched += Play(gaussian(duration=100, amp=amp, sigma=30, name='my_pulse'), ch_d0) sched += measure(qubits=[0], backend=backend) << 100 schedules.append(sched) qobj = assemble(schedules, backend) # two user pulses and one measurement pulse should be contained self.assertEqual(len(qobj.config.pulse_library), 3)
def amp(self, rabi_freq, amp_med): if amp_med == None: drive_amp_min = 0 drive_amp_max = 0.5 drive_amps = np.linspace(drive_amp_min, drive_amp_max, self.times) else: drive_amps = np.linspace(0, amp_med + 0.1, self.times) # スケジュールの作成 rabi_12_schedules = [] # すべての駆動振幅をループします for ii, drive_amp in enumerate(drive_amps): base_12_pulse = pulse_lib.gaussian(duration=self.drive_samples, sigma=self.drive_sigma, amp=drive_amp, name='base_12_pulse') # 1->2の周波数においてサイドバンドを適用 rabi_12_pulse = self.apply_sideband(base_12_pulse, rabi_freq) # スケジュールにコマンドを追加 sched = pulse.Schedule(name='Rabi Experiment at drive amp = %s' % drive_amp) sched |= self.sched_x # 0->1 sched |= pulse.Play(rabi_12_pulse, DriveChannel( self.qubit)) << sched.duration # 1->2のラビパルス sched |= self.sched_meas << sched.duration # 駆動パルスの後に測定をシフト rabi_12_schedules.append(sched) rabi_12_expt_program = assemble( rabi_12_schedules, backend=self.backend, meas_level=1, meas_return='avg', shots=self.shots, schedule_los=[{ DriveChannel(self.qubit): self.default_qubit_freq }] * len(drive_amps)) rabi_12_job = self.backend.run(rabi_12_expt_program) job_monitor(rabi_12_job) rabi_12_data = self.get_job_data(rabi_12_job, average=True) return rabi_12_data, drive_amps
def __init__(self, qubit, shots, backend, scale_factor, x01_freq, x01_amp): self.qubit = qubit self.shots = shots self.backend = backend self.scale_factor = scale_factor # Backend backend_config = self.backend.configuration() assert backend_config.open_pulse, "Backend doesn't support Pulse" self.dt = backend_config.dt backend_defaults = self.backend.defaults() # Default measurement pulse qc_meas = QuantumCircuit(1, 1) qc_meas.measure(0, 0) transpiled_qc_meas = transpile(qc_meas, self.backend, initial_layout=[self.qubit]) self.sched_meas = schedule(transpiled_qc_meas, backend) # Default pi pulse qc_x = QuantumCircuit(1) qc_x.x(0) transpiled_qc_x = transpile(qc_x, self.backend, initial_layout=[self.qubit]) sched_x = schedule(transpiled_qc_x, self.backend) pulse_info = sched_x.instructions[0][1].pulse self.drive_samples = pulse_info.duration self.drive_sigma = pulse_info.sigma if x01_amp == None: self.sched_x = sched_x self.default_qubit_freq = backend_defaults.qubit_freq_est[ self.qubit] else: pi_pulse_01 = pulse_lib.gaussian(duration=self.drive_samples, amp=x01_amp, sigma=self.drive_sigma) self.sched_x = pulse.Schedule() self.sched_x |= pulse.Play(pi_pulse_01, DriveChannel(self.qubit)) self.default_qubit_freq = x01_freq self.times = 50
def amp(self, rabi_freq, amp_med): if amp_med == None: drive_amp_min = 0 drive_amp_max = 0.5 drive_amps = np.linspace(drive_amp_min, drive_amp_max, self.times) else: drive_amps = np.linspace(0, amp_med + 0.1, self.times) # スケジュールの作成 rabi_01_schedules = [] # loop over all drive amplitudes for ii, drive_amp in enumerate(drive_amps): # drive pulse rabi_01_pulse = pulse_lib.gaussian(duration=self.drive_samples, amp=drive_amp, sigma=self.drive_sigma, name='rabi_01_pulse_%d' % ii) # add commands to schedule schedule = pulse.Schedule( name='Rabi Experiment at drive amp = %s' % drive_amp) schedule |= pulse.Play(rabi_01_pulse, DriveChannel(self.qubit)) schedule |= self.sched_meas << schedule.duration # shift measurement to after drive pulse rabi_01_schedules.append(schedule) rabi_01_expt_program = assemble( rabi_01_schedules, backend=self.backend, meas_level=1, meas_return='avg', shots=self.shots, schedule_los=[{ DriveChannel(self.qubit): rabi_freq }] * self.times) rabi_01_job = self.backend.run(rabi_01_expt_program) job_monitor(rabi_01_job) rabi_01_data = self.get_job_data(rabi_01_job, average=True) return rabi_01_data, drive_amps
) num_rabi_points = 50 # number of experiments (ie amplitudes to sweep out) # Drive amplitude values to iterate over: 50 amplitudes evenly spaced from 0 to 0.75 drive_amp_min = 0 drive_amp_max = 0.75 drive_amps = np.linspace(drive_amp_min, drive_amp_max, num_rabi_points) # Create schedule rabi_01_schedules = [] # loop over all drive amplitudes for ii, drive_amp in enumerate(drive_amps): # drive pulse rabi_01_pulse = pulse_lib.gaussian(duration=drive_samples, amp=drive_amp, sigma=drive_sigma, name='rabi_01_pulse_%d' % ii) # add commands to schedule schedule = pulse.Schedule(name='Rabi Experiment at drive amp = %s' % drive_amp) schedule |= pulse.Play(rabi_01_pulse, drive_chan) schedule |= measure << schedule.duration # shift measurement to after drive pulse rabi_01_schedules.append(schedule) # Assemble the schedules into a program # Note: We drive at the calibrated frequency. rabi_01_expt_program = assemble(rabi_01_schedules, backend=backend, meas_level=1, meas_return='avg',
def get_pi_pulse_01(c): return pulse_lib.gaussian(duration=c["drive_samples"], amp=c["pi_amp_01"], sigma=c["drive_sigma"], name="pi_pulse_01")
def sample_pulse(self): """Generate a sample pulse.""" return library.gaussian(20, 0.8, 1.0, name='test')
in steps of {frequency_step_Hz / MHz} MHz.") #%% # samples need to be multiples of 16 def get_closest_multiple_of_16(num): return int(num + 8) - (int(num + 8) % 16) #%% from qiskit import pulse # This is where we access all of our Pulse features! from qiskit.pulse import Play # This Pulse module helps us build sampled pulses for common pulse shapes from qiskit.pulse import library as pulse_lib # Drive pulse parameters (us = microseconds) drive_sigma_us = 0.075 # This determines the actual width of the gaussian drive_samples_us = drive_sigma_us * 8 # This is a truncating parameter, because gaussians don't have # a natural finite length drive_sigma = get_closest_multiple_of_16( drive_sigma_us * us / dt) # The width of the gaussian in units of dt drive_samples = get_closest_multiple_of_16( drive_samples_us * us / dt) # The truncating parameter in units of dt drive_amp = 0.05 # Drive pulse samples drive_pulse = pulse_lib.gaussian(duration=drive_samples, sigma=drive_sigma, amp=drive_amp, name='freq_sweep_excitation_pulse')