def test_drag(self): """Test discrete sampled drag pulse.""" amp = 0.5 sigma = 0.1 beta = 0 duration = 10 center = 10/2 times = np.arange(0, duration) + 0.5 # reference drag pulse drag_ref = continuous.drag(times, amp, center, sigma, beta=beta, zeroed_width=2*(center+1), rescale_amp=True) drag_pulse = library.drag(duration, amp, sigma, beta=beta) self.assertIsInstance(drag_pulse, Waveform) np.testing.assert_array_almost_equal(drag_pulse.samples, drag_ref)
def _fit_drag_func(duration, amp, sigma, beta, exp_samples): """ Helper function to compare a drag pulse to samples from the experiment Args: duration (int): pulse duration amp (complex): gauss amp sigma (float): gauss sigma beta (complex): drag amp exp_samples (ndarray): the experiment pulse, split into real and imag Returns: ndarray: difference between the drag and experimental samples """ fit_pulse = pulse_lib.drag( duration=duration, amp=amp, sigma=sigma, beta=beta).samples * np.exp( -1j * np.pi / 2) return np.concatenate((fit_pulse.real, fit_pulse.imag)) - exp_samples
def drag_schedules(beta_list, qubits, pulse_amp, pulse_width, pulse_sigma=None, width_sigma_ratio=4, drives=None, inst_map=None, meas_map=None): """ Generates schedules for a drag experiment doing a pulse then the - pulse Args: beta_list (list of floats): List of relative amplitudes for the derivative pulse qubits (list of integers): indices of the qubits to perform a rabi pulse_amp (list): amp of the gaussian (list of length qubits) 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 (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 = beta_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 drag_scheds = [] for index, b_amp in enumerate(beta_list): sched = pulse.Schedule(name='dragsched_%d_0' % index) for qind, qubit in enumerate(qubits): drag_pulse_p = pulse_lib.drag(duration=pulse_width, amp=pulse_amp[qind], beta=b_amp, sigma=pulse_sigma, name='drag_pulse_%d_%d' % (index, qubit)) drag_pulse_m = pulse_lib.drag(duration=pulse_width, amp=-pulse_amp[qind], beta=b_amp, sigma=pulse_sigma, name='drag_pulse_%d_%d' % (index, qubit)) sched += pulse.Play(drag_pulse_p, drives[qubit]) sched += pulse.Play(drag_pulse_m, drives[qubit]) sched += measure(qubits, inst_map=inst_map, meas_map=meas_map).shift(pulse_width) drag_scheds.append(sched) return drag_scheds, xdata
def update_u_gates(drag_params, pi2_pulse_schedules=None, qubits=None, inst_map=None, drives=None): """Update the cmd_def with new single qubit gate values Will update U2, U3 Args: drag_params (list): list of drag params pi2_pulse_schedules (list): list of new pi/2 gate as a pulse schedule will use the drag_params if this is None. qubits (list): list of qubits to update inst_map (InstructionScheduleMap): InstructionScheduleMap providing circuit instruction to schedule definitions. drives (list): List of drive chs """ # pylint: disable = invalid-name # U2 is -P1.Y90p.-P0 # U3 is -P2.X90p.-P0.X90m.-P1 for qubit in qubits: drive_ch = drives[qubit] if pi2_pulse_schedules is None: x90_pulse = pulse_lib.drag(**drag_params[qubit]) x90_sched = Schedule() x90_sched += Play(x90_pulse, drive_ch).shift(0) else: x90_sched = pi2_pulse_schedules[qubit] # find channel dependency for u2 for _u2_group in _find_channel_groups('u2', qubits=qubit, inst_map=inst_map): if drive_ch in _u2_group: break else: _u2_group = (drive_ch, ) # find channel dependency for u3 for _u3_group in _find_channel_groups('u3', qubits=qubit, inst_map=inst_map): if drive_ch in _u3_group: break else: _u3_group = (drive_ch, ) # add commands to schedule # u2 with pulse.build(name=f"u2_{qubit}", default_alignment="sequential") as u2_sched: P0 = Parameter("P0") P1 = Parameter("P1") for ch in _u2_group: pulse.shift_phase(-P1 + np.pi / 2, ch) pulse.call(x90_sched) for ch in _u2_group: pulse.shift_phase(-P0 - np.pi / 2, ch) # u3 with pulse.build(name=f"u3_{qubit}", default_alignment="sequential") as u3_sched: P0 = Parameter("P0") P1 = Parameter("P1") P2 = Parameter("P2") for ch in _u3_group: pulse.shift_phase(-P2, ch) pulse.call(x90_sched) for ch in _u3_group: pulse.shift_phase(-P0 - np.pi, ch) pulse.call(x90_sched) for ch in _u3_group: pulse.shift_phase(-P1 + np.pi, ch) inst_map.add('u2', qubits=qubit, schedule=u2_sched) inst_map.add('u3', qubits=qubit, schedule=u3_sched)
def update_u_gates(drag_params, pi2_pulse_schedules=None, qubits=None, inst_map=None, drives=None): """Update the cmd_def with new single qubit gate values Will update U2, U3 Args: drag_params (list): list of drag params pi2_pulse_schedules (list): list of new pi/2 gate as a pulse schedule will use the drag_params if this is None. qubits (list): list of qubits to update inst_map (InstructionScheduleMap): InstructionScheduleMap providing circuit instruction to schedule definitions. drives (list): List of drive chs """ # U2 is -P1.Y90p.-P0 # U3 is -P2.X90p.-P0.X90m.-P1 def parametrized_fc(kw_name, phi0, chan, t_offset): def _parametrized_fc(**kwargs): return ShiftPhase(phase=-kwargs[kw_name] + phi0, channel=chan).shift(t_offset) return _parametrized_fc for qubit in qubits: drive_ch = drives[qubit] if pi2_pulse_schedules is None: x90_pulse = pulse_lib.drag(**drag_params[qubit]) x90_sched = Schedule() x90_sched += Play(x90_pulse, drive_ch).shift(0) else: x90_sched = pi2_pulse_schedules[qubit] pulse_dur = x90_sched.duration # find channel dependency for u2 for _u2_group in _find_channel_groups('u2', qubits=qubit, inst_map=inst_map): if drive_ch in _u2_group: break else: _u2_group = (drive_ch, ) u2_fc1s = [parametrized_fc('P1', np.pi / 2, ch, 0) for ch in _u2_group] u2_fc2s = [ parametrized_fc('P0', -np.pi / 2, ch, pulse_dur) for ch in _u2_group ] # find channel dependency for u3 for _u3_group in _find_channel_groups('u3', qubits=qubit, inst_map=inst_map): if drive_ch in _u3_group: break else: _u3_group = (drive_ch, ) u3_fc1s = [parametrized_fc('P2', 0, ch, 0) for ch in _u3_group] u3_fc2s = [ parametrized_fc('P0', -np.pi, ch, pulse_dur) for ch in _u3_group ] u3_fc3s = [ parametrized_fc('P1', np.pi, ch, 2 * pulse_dur) for ch in _u3_group ] # add commands to schedule # u2 sched_components = [*u2_fc1s, x90_sched, *u2_fc2s] schedule1 = ParameterizedSchedule(*sched_components, parameters=['P0', 'P1'], name='u2_%d' % qubit) # u3 sched_components = [ *u3_fc1s, x90_sched, *u3_fc2s, x90_sched.shift(pulse_dur), *u3_fc3s ] schedule2 = ParameterizedSchedule(*sched_components, parameters=['P0', 'P1', 'P2'], name='u3_%d' % qubit) inst_map.add('u2', qubits=qubit, schedule=schedule1) inst_map.add('u3', qubits=qubit, schedule=schedule2)