def test_can_create_valid_schedule(self): """Test valid schedule creation without error.""" gp0 = pulse_lib.gaussian(duration=20, amp=0.7, sigma=3) gp1 = pulse_lib.gaussian(duration=20, amp=0.7, sigma=3) sched = Schedule() sched = sched.append(Play(gp0, self.config.drive(0))) with self.assertWarns(DeprecationWarning): sched = sched.insert( 0, PersistentValue(value=0.2 + 0.4j)(self.config.control([0, 1])[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))) # TODO: this shouldn't raise a warning 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 = pulse_lib.gaussian(duration=20, amp=1.0, sigma=1.0) gp1 = pulse_lib.gaussian(duration=20, amp=-1.0, sigma=2.0) gs0 = pulse_lib.gaussian_square(duration=20, amp=-1.0, sigma=2.0, risefall=3) fc_pi_2 = FrameChange(phase=1.57) acquire = Acquire(10) sched = Schedule() sched = sched.append(gp0(self.device.q[0].drive)) sched = sched.insert( 0, PersistentValue(value=0.2 + 0.4j)(self.device.q[0].controls[0])) sched = sched.insert(60, FrameChange(phase=-1.57)(self.device.q[0].drive)) sched = sched.insert(30, gp1(self.device.q[1].drive)) sched = sched.insert(60, gp0(self.device.q[0].controls[0])) sched = sched.insert(60, gs0(self.device.q[0].measure)) sched = sched.insert(90, fc_pi_2(self.device.q[0].drive)) sched = sched.insert( 90, acquire(self.device.q[1], self.device.mem[1], self.device.c[1])) sched = sched + sched sched |= Snapshot("snapshot_1", "snap_type") << 60 sched |= Snapshot("snapshot_2", "snap_type") << 120 return sched
def test_can_create_valid_schedule(self): """Test valid schedule creation without error.""" gp0 = pulse_lib.gaussian(duration=20, amp=0.7, sigma=3) gp1 = pulse_lib.gaussian(duration=20, amp=0.7, sigma=3) fc_pi_2 = FrameChange(phase=1.57) acquire = Acquire(10) sched = Schedule() sched = sched.append(gp0(self.config.drive(0))) sched = sched.insert( 0, PersistentValue(value=0.2 + 0.4j)(self.config.control(0))) sched = sched.insert(60, FrameChange(phase=-1.57)(self.config.drive(0))) sched = sched.insert(30, gp1(self.config.drive(0))) sched = sched.insert(60, gp0(self.config.control(0))) sched = sched.insert(80, Snapshot("label", "snap_type")) sched = sched.insert(90, fc_pi_2(self.config.drive(0))) sched = sched.insert( 90, acquire(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)
def test_can_create_valid_schedule(self): """Test valid schedule creation without error.""" device = self.two_qubit_device gp0 = pulse_lib.gaussian(duration=20, amp=0.7, sigma=3) gp1 = pulse_lib.gaussian(duration=20, amp=0.7, sigma=3) fc_pi_2 = FrameChange(phase=1.57) acquire = Acquire(10) sched = Schedule() sched = sched.append(gp0(device.q[0].drive)) sched = sched.insert( 0, PersistentValue(value=0.2 + 0.4j)(device.q[0].controls[0])) sched = sched.insert(60, FrameChange(phase=-1.57)(device.q[0].drive)) sched = sched.insert(30, gp1(device.q[1].drive)) sched = sched.insert(60, gp0(device.q[0].controls[0])) sched = sched.insert(80, Snapshot("label", "snap_type")) sched = sched.insert(90, fc_pi_2(device.q[0].drive)) sched = sched.insert(90, acquire(device.q[1], device.mem[1], device.c[1])) 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)
def sample_schedule(self): """Generate a sample schedule that includes the most common elements of pulse schedules.""" gp0 = pulse_lib.gaussian(duration=20, amp=1.0, sigma=1.0) gp1 = pulse_lib.gaussian(duration=20, amp=-1.0, sigma=2.0) gs0 = pulse_lib.gaussian_square(duration=20, amp=-1.0, sigma=2.0, risefall=3) fc_pi_2 = FrameChange(phase=1.57) acquire = Acquire(10) delay = Delay(100) sched = Schedule() sched = sched.append(gp0(DriveChannel(0))) sched = sched.insert( 0, pulse_lib.ConstantPulse(duration=60, amp=0.2 + 0.4j)(ControlChannel(0))) sched = sched.insert(60, FrameChange(phase=-1.57)(DriveChannel(0))) sched = sched.insert(60, SetFrequency(8.0, DriveChannel(0))) sched = sched.insert(30, gp1(DriveChannel(1))) sched = sched.insert(60, gp0(ControlChannel(0))) sched = sched.insert(60, gs0(MeasureChannel(0))) sched = sched.insert(90, fc_pi_2(DriveChannel(0))) sched = sched.insert( 90, acquire(AcquireChannel(1), MemorySlot(1), RegisterSlot(1))) sched = sched.append(delay(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 = pulse_lib.gaussian(duration=100, amp=0.7, sigma=3) gp1 = pulse_lib.gaussian(duration=20, amp=0.5, sigma=3) sched = gp1(self.config.drive(0)) << 100 # if schedule was mutable the next two sequences would overlap and an error # would be raised. sched.union(gp0(self.config.drive(0))) sched.union(gp0(self.config.drive(0)))
def test_inplace(self): """Test that in place operations on schedule are still immutable.""" gp0 = pulse_lib.gaussian(duration=100, amp=0.7, sigma=3) gp1 = pulse_lib.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.""" device = self.two_qubit_device gp0 = pulse_lib.gaussian(duration=100, amp=0.7, sigma=3) gp1 = pulse_lib.gaussian(duration=20, amp=0.5, sigma=3) sched = gp1(device.q[0].drive) << 100 # if schedule was mutable the next two sequences would overlap and an error # would be raised. sched.union(gp0(device.q[0].drive)) sched.union(gp0(device.q[0].drive))
def test_inplace(self): """Test that in place operations on schedule are still immutable.""" device = self.two_qubit_device gp0 = pulse_lib.gaussian(duration=100, amp=0.7, sigma=3) gp1 = pulse_lib.gaussian(duration=20, amp=0.5, sigma=3) sched = Schedule() sched = sched + gp1(device.q[0].drive) sched2 = sched sched += gp0(device.q[0].drive) self.assertNotEqual(sched, sched2)
def _valid_2q_schedule(self): """ Helper method to make a valid 2 qubit schedule Returns: schedule (pulse schedule): schedule for 2q experiment """ rabi_pulse = pulse_lib.gaussian(duration=128, amp=0.5, sigma=16, name='rabi_pulse') meas_pulse = pulse_lib.gaussian_square(duration=1200, amp=0.025, sigma=4, risefall=25, name='meas_pulse') acq_cmd = pulse.Acquire(duration=10) # create measurement schedule measure_and_acquire = \ meas_pulse(self.system.qubits[0].measure) | acq_cmd(self.system.acquires, self.system.memoryslots) # add commands to schedule schedule = pulse.Schedule(name='rabi_exp') schedule += rabi_pulse(self.system.qubits[0].drive) schedule += measure_and_acquire << schedule.duration return schedule
def test_buffering(self): """Test channel buffering.""" buffer_chan = DriveChannel(0, buffer=5) measure_chan = MeasureChannel(0, buffer=10) acquire_chan = AcquireChannel(0, buffer=10) memory_slot = MemorySlot(0) gp0 = pulse_lib.gaussian(duration=10, amp=0.7, sigma=3) fc_pi_2 = FrameChange(phase=1.57) # no initial buffer sched = Schedule() sched += gp0(buffer_chan) self.assertEqual(sched.duration, 10) # this pulse should be buffered sched += gp0(buffer_chan) self.assertEqual(sched.duration, 25) # should not be buffered as framechange sched += fc_pi_2(buffer_chan) self.assertEqual(sched.duration, 25) # use buffer with insert sched = sched.insert(sched.duration, gp0(buffer_chan), buffer=True) self.assertEqual(sched.duration, 40) sched = Schedule() sched = gp0(measure_chan) + Acquire(duration=10)(acquire_chan, memory_slot) self.assertEqual(sched.duration, 10)
def test_name_inherited(self): """Test that schedule keeps name if an instruction is added.""" device = self.two_qubit_device acquire = Acquire(10) gp0 = pulse_lib.gaussian(duration=100, amp=0.7, sigma=3, name='pulse_name') pv0 = PersistentValue(0.1) fc0 = FrameChange(0.1) 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(device.q[1], device.mem[1], name='acq_name') | sched1 self.assertEqual(sched_acq.name, 'acq_name') sched_pulse = gp0(device.q[0].drive) | sched1 self.assertEqual(sched_pulse.name, 'pulse_name') sched_pv = pv0(device.q[0].drive, name='pv_name') | sched1 self.assertEqual(sched_pv.name, 'pv_name') sched_fc = fc0(device.q[0].drive, name='fc_name') | sched1 self.assertEqual(sched_fc.name, 'fc_name') sched_snapshot = snapshot | sched1 self.assertEqual(sched_snapshot.name, 'snapshot_label')
def _valid_2q_schedule(self): """Returns a valid 2 qubit schedule.""" valid_pulse = pulse_lib.gaussian(duration=128, amp=0.5, sigma=16, name='valid_pulse') valid_meas_pulse = pulse_lib.gaussian_square(duration=1200, amp=0.025, sigma=4, risefall=25, name='valid_meas_pulse') acq_cmd = pulse.Acquire(duration=10) acquires = [pulse.AcquireChannel(0), pulse.AcquireChannel(1)] memoryslots = [pulse.MemorySlot(0), pulse.MemorySlot(1)] # create measurement schedule measure_and_acquire = \ valid_meas_pulse(pulse.MeasureChannel(0)) | acq_cmd(acquires, memoryslots) # add commands to schedule schedule = pulse.Schedule(name='valid_exp') schedule += valid_pulse(pulse.DriveChannel(0)) schedule += measure_and_acquire << schedule.duration return schedule
def test_name_inherited(self): """Test that schedule keeps name if an instruction is added.""" gp0 = pulse_lib.gaussian(duration=100, amp=0.7, sigma=3, name='pulse_name') with self.assertWarns(DeprecationWarning): pv0 = PersistentValue(0.1) 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') with self.assertWarns(DeprecationWarning): sched_pv = pv0(self.config.drive(0), name='pv_name') | sched1 self.assertEqual(sched_pv.name, 'pv_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 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_sample_pulse() self.assertIsInstance(sample_pulse, SamplePulse) 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 test_can_create_valid_schedule_with_syntax_sugar(self): """Test that in place operations on schedule are still immutable and return equivalent schedules.""" gp0 = pulse_lib.gaussian(duration=20, amp=0.7, sigma=3) gp1 = pulse_lib.gaussian(duration=20, amp=0.5, sigma=3) acquire = Acquire(10) sched = Schedule() sched += gp0(self.config.drive(0)) sched |= PersistentValue(value=0.2 + 0.4j)(self.config.control(0)) sched |= ShiftPhase(-1.57, self.config.drive(0)) << 60 sched |= gp1(self.config.drive(0)) << 30 sched |= gp0(self.config.control(0)) << 60 sched |= Snapshot("label", "snap_type") << 60 sched |= ShiftPhase(1.57, self.config.drive(0)) << 90 sched |= acquire(self.config.acquire(0), MemorySlot(0), RegisterSlot(0)) << 90 sched += sched
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 of floats): List of amplitudes for the Gaussian pulse [-1,1] qubits (list of integers): indices of the qubits to perform a rabi pulse_width: width of gaussian (in dt units) pulse_sigma: sigma of gaussian width_sigma_ratio: set sigma to a certain ratio of the width (use if pulse_sigma is None) drives: list of DriveChannel objects inst_map: InstructionScheduleMap object to use meas_map: 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_can_create_valid_schedule_with_syntax_sugar(self): """Test that in place operations on schedule are still immutable and return equivalent schedules.""" gp0 = pulse_lib.gaussian(duration=20, amp=0.7, sigma=3) gp1 = pulse_lib.gaussian(duration=20, amp=0.5, sigma=3) sched = Schedule() sched += Play(gp0, self.config.drive(0)) with self.assertWarns(DeprecationWarning): sched |= PersistentValue(value=0.2 + 0.4j)(self.config.control( [0, 1])[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_can_create_valid_schedule_with_syntax_sugar(self): """Test that in place operations on schedule are still immutable and return equivalent schedules.""" device = self.two_qubit_device gp0 = pulse_lib.gaussian(duration=20, amp=0.7, sigma=3) gp1 = pulse_lib.gaussian(duration=20, amp=0.5, sigma=3) fc_pi_2 = FrameChange(phase=1.57) acquire = Acquire(10) sched = Schedule() sched += gp0(device.q[0].drive) sched |= PersistentValue(value=0.2 + 0.4j)(device.q[0].controls[0]) sched |= FrameChange(phase=-1.57)(device.q[0].drive) << 60 sched |= gp1(device.q[1].drive) << 30 sched |= gp0(device.q[0].controls[0]) << 60 sched |= Snapshot("label", "snap_type") << 60 sched |= fc_pi_2(device.q[0].drive) << 90 sched |= acquire(device.q[1], device.mem[1], device.c[1]) << 90 sched += sched
def test_schedule_drawer_show_framechange(self): filename = self._get_resource_path('current_show_framechange_ref.png') gp0 = pulse_lib.gaussian(duration=20, amp=1.0, sigma=1.0) sched = Schedule() sched = sched.append(gp0(DriveChannel(0))) sched = sched.insert(60, FrameChange(phase=-1.57)(DriveChannel(0))) sched = sched.insert(30, FrameChange(phase=-1.50)(DriveChannel(1))) sched = sched.insert(70, FrameChange(phase=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 test_gaussian(self): """Test gaussian pulse.""" amp = 0.5 sigma = 2 duration = 10 center = duration/2 times = np.arange(0, duration) gaussian_ref = continuous.gaussian(times, amp, center, sigma, zeroed_width=2*(center+1), rescale_amp=True) gaussian_pulse = pulse_lib.gaussian(duration, amp, sigma) self.assertIsInstance(gaussian_pulse, SamplePulse) np.testing.assert_array_almost_equal(gaussian_pulse.samples, gaussian_ref)
def make_drive_pulse(dt, amp=.3, sigma=75): # Drive pulse parameters (us = microsecond) # This determines the actual width of the gaussians drive_sigma_ns = sigma # This is a truncating parameter drive_samples_ns = drive_sigma_ns*8 drive_sigma = get_closest_multiple_of_16(drive_sigma_ns / dt) # The width of the gaussian in units of dt drive_samples = get_closest_multiple_of_16(drive_samples_ns / dt) # The truncating parameter in units of dt drive_amp = amp # Drive pulse samples drive_pulse = pulse_lib.gaussian(duration=drive_samples, sigma=drive_sigma, amp=drive_amp, name='freq_sweep_excitation_pulse') return drive_pulse
def test_flatten(self): """Test schedule flattening.""" device = self.two_qubit_device chan = device.q[0].drive gp0 = pulse_lib.gaussian(duration=100, amp=0.7, sigma=3, name='pulse_name') sched = Schedule() for _ in range(10): sched += gp0(chan) flat_sched = sched.flatten() self.assertEqual(len(flat_sched._children), 10) self.assertEqual(flat_sched.instructions, sched.instructions)
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 += 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 test_buffering(self): """Test channel buffering.""" buffer_chan = DriveChannel(0, buffer=5) gp0 = pulse_lib.gaussian(duration=10, amp=0.7, sigma=3) fc_pi_2 = FrameChange(phase=1.57) # no initial buffer sched = Schedule() sched += gp0(buffer_chan) self.assertEqual(sched.duration, 10) # this pulse should not be buffered sched += gp0(buffer_chan) self.assertEqual(sched.duration, 20) # should not be buffered as framechange sched += fc_pi_2(buffer_chan) self.assertEqual(sched.duration, 20) # use buffer with insert sched = sched.insert(sched.duration, gp0(buffer_chan), buffer=True) self.assertEqual(sched.duration, 30)
def sample_pulse(self): """Generate a sample pulse.""" return pulse_lib.gaussian(20, 0.8, 1.0, name='test')
def runexp(qkback, energy, width, delay): results = {} #drive params drive_sigma_us = width/(2 * 10) drive_samples_us = drive_sigma_us*2 drive_sigma = get_closest_multiple_of_16(drive_sigma_us * qkback.us / qkback.dt) drive_samples = get_closest_multiple_of_16(drive_samples_us * qkback.us / qkback.dt) drive_amp = energy/10 scale_factor = 1 #Rabi # Rabi experiment parameters num_rabi_points = 50 # Drive amplitude values to iterate over: 50 amplitudes evenly spaced from 0 to 1 drive_amp_min = 0 drive_amp_max = 1 #input from 0 to 1 drive_amps = np.linspace(drive_amp_min, drive_amp_max, num_rabi_points) rabi_schedules = [] for drive_amp in drive_amps: rabi_pulse = pulse_lib.gaussian(duration=drive_samples, amp=drive_amp, sigma=drive_sigma, name=f"Rabi drive amplitude = {drive_amp}") this_schedule = pulse.Schedule(name=f"Rabi drive amplitude = {drive_amp}") this_schedule += Play(rabi_pulse, qkback.drive_chan) # Reuse the measure instruction from the frequency sweep experiment this_schedule += qkback.measure << this_schedule.duration rabi_schedules.append(this_schedule) # Assemble the schedules into a Qobj num_shots_per_point = 1024 test = qkback.center_frequency_Hz rabi_experiment_program = assemble(rabi_schedules, backend=qkback.backend, meas_level=1, meas_return='avg', shots=num_shots_per_point, schedule_los=[{qkback.drive_chan: test}] * num_rabi_points) # print(job.job_id()) job = qkback.backend.run(rabi_experiment_program) #job_monitor(job) rabi_results = job.result(timeout=120) #graph of Probability of being in |1> state vs. Power^1/2 rabi_values = [] for i in range(num_rabi_points): # Get the results for `qubit` from the ith experiment rabi_values.append(rabi_results.get_memory(i)[qkback.qubit]*scale_factor) rabi_values = np.real(baseline_remove(rabi_values)) prob = ((rabi_values / np.min(rabi_values)) + 1) / 2 rabix = drive_amps / np.sqrt(drive_samples_us) results['rabi'] = (rabix, prob) #ramsey def fit_function(x_values, y_values, function, init_params): fitparams, conv = curve_fit(function, x_values, y_values, init_params) y_fit = function(x_values, *fitparams) return fitparams, y_fit fit_params, y_fit = fit_function(drive_amps, rabi_values, lambda x, A, B, drive_period, phi: (A*np.cos(2*np.pi*x/drive_period - phi) + B), [3, 0.1, 0.5, 0]), drive_period = fit_params[2] # get period of rabi oscillation #Finding the value of pi pulse and x90 pulse (half pi pulse) pi_amp = abs(drive_period / 2) halfpi_amp = pi_amp/2 pi_pulse = pulse_lib.gaussian(duration=drive_samples, amp=pi_amp, sigma=drive_sigma, name='pi_pulse') halfpi_pulse = pulse_lib.gaussian(duration=drive_samples, amp=halfpi_amp, sigma=drive_sigma, name='halfpi_pulse') # Ramsey experiment parameters time_max_us = delay*4/1000 #frontend 1800 fs time_step_us = 0.025 #frontend 2.5 fs times_us = np.arange(0.1, time_max_us, time_step_us) # Convert to units of dt delay_times_dt = times_us * qkback.us / qkback.dt # Drive parameters # The drive amplitude for pi/2 is simply half the amplitude of the pi pulse ram_drive_amp = pi_amp / 2 # x_90 is a concise way to say pi_over_2; i.e., an X rotation of 90 degrees x90_pulse = pulse_lib.gaussian(duration=drive_samples, amp=ram_drive_amp, sigma=drive_sigma, name='x90_pulse') # create schedules for Ramsey experiment ramsey_schedules = [] for dely in delay_times_dt: this_schedule = pulse.Schedule(name=f"Ramsey delay = {delay * dt / us} us") this_schedule |= Play(x90_pulse, qkback.drive_chan) this_schedule |= Play(x90_pulse, qkback.drive_chan) << int(this_schedule.duration + dely) this_schedule |= qkback.measure << int(this_schedule.duration) ramsey_schedules.append(this_schedule) # Execution settings num_shots = 256 detuning_MHz = 2 ramsey_frequency = round(qkback.center_frequency_Hz + detuning_MHz * MHz, 6) # need ramsey freq in Hz ramsey_program = assemble(ramsey_schedules, backend=qkback.backend, meas_level=1, meas_return='avg', shots=num_shots, schedule_los=[{qkback.drive_chan: ramsey_frequency}]*len(ramsey_schedules) ) job = qkback.backend.run(ramsey_program) ramsey_results = job.result(timeout=120) #Ramsey experiment: Probability vs. time delay ramsey_values = [] for i in range(len(times_us)): ramsey_values.append(ramsey_results.get_memory(i)[qkback.qubit]*scale_factor) probramsey = (np.real(ramsey_values) / np.min (np.real(ramsey_values)) + 1) / 2 x = times_us results['ramsey'] = (x,probramsey) return results
from qiskit.pulse import Play from qiskit.pulse import pulse_lib # This Pulse module helps us build sampled pulses for common pulse shapes # 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.3 # Drive pulse samples drive_pulse = pulse_lib.gaussian(duration=drive_samples, sigma=drive_sigma, amp=drive_amp, name='freq_sweep_excitation_pulse') # Find out which group of qubits need to be acquired with this qubit meas_map_idx = None for i, measure_group in enumerate(backend_config.meas_map): if qubit in measure_group: meas_map_idx = i break assert meas_map_idx is not None, f"Couldn't find qubit {qubit} in the meas_map!" inst_sched_map = backend_defaults.instruction_schedule_map measure = inst_sched_map.get('measure', qubits=backend_config.meas_map[meas_map_idx]) ### Collect the necessary channels
# samples need to be multiples of 16 def get_closest_multiple_of_16(num): return int(num + 8) - (int(num + 8) % 16) 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 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.3 # Drive pulse samples drive_pulse = pulse_lib.gaussian(duration=drive_samples, sigma=drive_sigma, amp=drive_amp, name='freq_sweep_excitation_pulse') # берем амплитуду из второй строки текстового файла pi_pulse = pulse_lib.gaussian(duration=drive_samples, amp=pi_amp, sigma=drive_sigma, name='pi_pulse') # Find out which group of qubits need to be acquired with this qubit meas_map_idx = None for i, measure_group in enumerate(backend_config.meas_map): if qubit in measure_group: meas_map_idx = i break assert meas_map_idx is not None, f"Couldn't find qubit {qubit} in the meas_map!"
def rabi_schedules(amp_list, qubits, pulse_width, pulse_sigma=None, width_sigma_ratio=4, drives=None, cmd_def=None, meas_map=None): """ Generates schedules for a rabi experiment using a Gaussian pulse Args: amp_list (list of floats): List of amplitudes for the Gaussian pulse [-1,1] qubits (list of integers): indices of the qubits to perform a rabi pulse_width: width of gaussian (in dt units) pulse_sigma: sigma of gaussian width_sigma_ratio: set sigma to a certain ratio of the width (use if pulse_sigma is None) drives: list of DriveChannel objects cmd_def: CmdDef object to use meas_map: meas_map to use Returns: A list of QuantumSchedules xdata: a list of amps """ xdata = amp_list # copy the command def cmd_def = copy.deepcopy(cmd_def) if pulse_sigma is None: pulse_sigma = pulse_width / width_sigma_ratio # Construct the circuits qr = qiskit.QuantumRegister(max(qubits) + 1) cr = qiskit.ClassicalRegister(len(qubits)) circuits = [] for circ_index, g_amp in enumerate(amp_list): circ = qiskit.QuantumCircuit(qr, cr) circ.name = 'rabicircuit_%d_0' % circ_index rabi_pulse = pulse_lib.gaussian(duration=pulse_width, amp=g_amp, sigma=pulse_sigma, name='rabi_pulse_%d' % circ_index) rabi_gate = Gate(name='rabi_%d' % circ_index, num_qubits=1, params=[]) for _, qubit in enumerate(qubits): # add commands to schedule schedule = pulse.Schedule(name='rabi_pulse_%f_%d' % (g_amp, qubit)) schedule += rabi_pulse(drives[qubit]) # append this schedule to the cmd_def cmd_def.add('rabi_%d' % circ_index, qubits=[qubit], schedule=schedule) circ.append(rabi_gate, [qr[qubit]]) for qind, qubit in enumerate(qubits): circ.measure(qr[qubit], cr[qind]) circuits.append(circ) # schedule schedule_config = ScheduleConfig(cmd_def, meas_map) rabi_sched = [ schedule_circuit(qcirc, schedule_config) for qcirc in circuits ] return rabi_sched, xdata