def test_fail_measure(self): """Test failing measure.""" with self.assertRaises(PulseError): macros.measure(qubits=[0], meas_map=self.backend.configuration().meas_map) with self.assertRaises(PulseError): macros.measure(qubits=[0], inst_map=self.inst_map)
def test_measure_sched_with_meas_map(self): """Test measure with custom meas_map as list and dict.""" sched_with_meas_map_list = macros.measure(qubits=[0], backend=self.backend, meas_map=[[0, 1]]) sched_with_meas_map_dict = macros.measure(qubits=[0], backend=self.backend, meas_map={0: [0, 1], 1: [0, 1]}) expected = Schedule( self.inst_map.get('measure', [0, 1]).filter(channels=[MeasureChannel(0)]), Acquire(10, AcquireChannel(0), MemorySlot(0)), Acquire(10, AcquireChannel(1), MemorySlot(1))) self.assertEqual(sched_with_meas_map_list.instructions, expected.instructions) self.assertEqual(sched_with_meas_map_dict.instructions, expected.instructions)
def test_call_gate_and_circuit(self): """Test calling circuit with gates.""" h_control = circuit.QuantumCircuit(2) h_control.h(0) with pulse.build(self.backend) as schedule: with pulse.align_sequential(): # this is circuit, a subroutine stored as Call instruction pulse.call(h_control) # this is instruction, not subroutine pulse.cx(0, 1) # this is macro, not subroutine pulse.measure([0, 1]) # subroutine h_reference = compiler.schedule(compiler.transpile(h_control, self.backend), self.backend) # gate cx_circ = circuit.QuantumCircuit(2) cx_circ.cx(0, 1) cx_reference = compiler.schedule(compiler.transpile(cx_circ, self.backend), self.backend) # measurement measure_reference = macros.measure( qubits=[0, 1], inst_map=self.inst_map, meas_map=self.configuration.meas_map ) reference = pulse.Schedule() reference += pulse.instructions.Call(h_reference) reference += cx_reference reference += measure_reference << reference.duration self.assertScheduleEqual(schedule, reference)
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_measure_with_custom_inst_map(self): """Test measure with custom inst_map, meas_map with measure_name.""" q0_sched = Play(GaussianSquare(1200, 1, 0.4, 1150), MeasureChannel(0)) q0_sched += Acquire(1200, AcquireChannel(0), MemorySlot(0)) inst_map = InstructionScheduleMap() inst_map.add('my_sched', 0, q0_sched) sched = macros.measure(qubits=[0], measure_name='my_sched', inst_map=inst_map, meas_map=[[0]]) self.assertEqual(sched.instructions, q0_sched.instructions) with self.assertRaises(PulseError): macros.measure(qubits=[0], measure_name="name", inst_map=inst_map, meas_map=[[0]])
def test_measure(self): """Test macro - measure.""" sched = macros.measure(qubits=[0], backend=self.backend) expected = Schedule( self.inst_map.get('measure', [0, 1]).filter(channels=[MeasureChannel(0)]), Acquire(10, AcquireChannel(0), MemorySlot(0)), Acquire(10, AcquireChannel(1), MemorySlot(1))) self.assertEqual(sched.instructions, expected.instructions)
def test_measure_sched_with_qubit_mem_slots(self): """Test measure with custom qubit_mem_slots.""" sched = macros.measure(qubits=[0], backend=self.backend, qubit_mem_slots={0: 1}) expected = Schedule( self.inst_map.get('measure', [0, 1]).filter(channels=[MeasureChannel(0)]), Acquire(10, AcquireChannel(0), MemorySlot(1)), Acquire(10, AcquireChannel(1), MemorySlot(0))) self.assertEqual(sched.instructions, expected.instructions)
def test_measure(self): """Test utility function - measure.""" with pulse.build(self.backend) as schedule: reg = pulse.measure(0) self.assertEqual(reg, pulse.MemorySlot(0)) reference = macros.measure(qubits=[0], inst_map=self.inst_map, meas_map=self.configuration.meas_map) self.assertEqual(schedule, reference)
def test_measure_multi_qubits(self): """Test utility function - measure with multi qubits.""" with pulse.build(self.backend) as schedule: regs = pulse.measure([0, 1]) self.assertListEqual(regs, [pulse.MemorySlot(0), pulse.MemorySlot(1)]) reference = macros.measure(qubits=[0, 1], inst_map=self.inst_map, meas_map=self.configuration.meas_map) self.assertEqual(schedule, reference)
def get_measure_schedule() -> CircuitPulseDef: """Create a schedule to measure the qubits queued for measuring.""" sched = Schedule() sched += measure(qubits=list(qubit_mem_slots.keys()), inst_map=inst_map, meas_map=schedule_config.meas_map, qubit_mem_slots=qubit_mem_slots) qubit_mem_slots.clear() return CircuitPulseDef(schedule=sched, qubits=[ chan.index for chan in sched.channels if isinstance(chan, AcquireChannel) ])
def get_measure_schedule( qubit_mem_slots: Dict[int, int]) -> CircuitPulseDef: """Create a schedule to measure the qubits queued for measuring.""" sched = Schedule() # Exclude acquisition on these qubits, since they are handled by the user calibrations acquire_excludes = {} if Measure().name in circuit.calibrations.keys(): qubits = tuple(sorted(qubit_mem_slots.keys())) params = () for qubit in qubits: try: meas_q = circuit.calibrations[Measure().name][((qubit, ), params)] meas_q = target_qobj_transform(meas_q) acquire_q = meas_q.filter(channels=[AcquireChannel(qubit)]) mem_slot_index = [ chan.index for chan in acquire_q.channels if isinstance(chan, MemorySlot) ][0] if mem_slot_index != qubit_mem_slots[qubit]: raise KeyError( "The measurement calibration is not defined on " "the requested classical bits") sched |= meas_q del qubit_mem_slots[qubit] acquire_excludes[qubit] = mem_slot_index except KeyError: pass if qubit_mem_slots: qubits = list(qubit_mem_slots.keys()) qubit_mem_slots.update(acquire_excludes) meas_sched = measure( qubits=qubits, inst_map=inst_map, meas_map=schedule_config.meas_map, qubit_mem_slots=qubit_mem_slots, ) meas_sched = target_qobj_transform(meas_sched) meas_sched = meas_sched.exclude( channels=[AcquireChannel(qubit) for qubit in acquire_excludes]) sched |= meas_sched qubit_mem_slots.clear() return CircuitPulseDef( schedule=sched, qubits=[ chan.index for chan in sched.channels if isinstance(chan, AcquireChannel) ], )
def test_clbits_of_calibrated_measurements(self): """Test that calibrated measurements are only used when the classical bits also match.""" q = QuantumRegister(2) c = ClassicalRegister(2) qc = QuantumCircuit(q, c) qc.measure(q[0], c[1]) meas_sched = Play(Gaussian(1200, 0.2, 4), MeasureChannel(0)) meas_sched |= Acquire(1200, AcquireChannel(0), MemorySlot(0)) qc.add_calibration("measure", [0], meas_sched) sched = schedule(qc, self.backend) # Doesn't use the calibrated schedule because the classical memory slots do not match expected = Schedule(macros.measure([0], self.backend, qubit_mem_slots={0: 1})) self.assertEqual(sched.instructions, expected.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 += 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 run_with_measure(qiskit_schedule, backend_name, meas_level=1): try: from qiskit import providers, assemble from qiskit.pulse import DriveChannel, SetFrequency from qiskit.pulse.macros import measure from qiskit.result.result import Result if qiskit_schedule.duration == 0: return Result(backend_name, None, None, None, None, None) if backend_name == 'Armonk': backend = get_qiskit_backend(backend_name) pulse_sim = providers.aer.PulseSimulator.from_backend(backend) pulse_qobj = assemble(qiskit_schedule, backend=pulse_sim) measure_qubits = [] for channel in qiskit_schedule.channels: if isinstance(channel, DriveChannel): measure_qubits.append(channel.index) frequency = None for start_time, instruction in qiskit_schedule.instructions: if isinstance(instruction, SetFrequency): frequency = {instruction.channel: instruction.frequency} break def strip_frequencies(instruction): if isinstance(instruction[1], SetFrequency): return False return True # Setting frequences isn't supported on simulators, so instead we use `schedule_los` to set a single frequency # and subsequently strip any SetFrequency instructions from the schedule. qiskit_schedule = qiskit_schedule.filter(strip_frequencies) qiskit_schedule += measure(measure_qubits, pulse_sim) << qiskit_schedule.duration pulse_qobj = assemble(qiskit_schedule, backend=pulse_sim, meas_level=meas_level, schedule_los=frequency) job = pulse_sim.run(pulse_qobj) return job.result() else: print( "Only FakeArmonk is supported for simulation currently because other backends are too slow" ) return Result(backend_name, None, None, None, None, None) except ImportError: pass
def test_subset_calibrated_measurements(self): """Test that measurement calibrations can be added and used for some qubits, even if the other qubits do not also have calibrated measurements.""" qc = QuantumCircuit(3, 3) qc.measure(0, 0) qc.measure(1, 1) qc.measure(2, 2) meas_scheds = [] for qubit in [0, 2]: meas = (Play(Gaussian(1200, 0.2, 4), MeasureChannel(qubit)) + Acquire(1200, AcquireChannel(qubit), MemorySlot(qubit))) meas_scheds.append(meas) qc.add_calibration('measure', [qubit], meas) meas = macros.measure([1], FakeOpenPulse3Q()) meas = meas.exclude(channels=[AcquireChannel(0), AcquireChannel(2)]) sched = schedule(qc, FakeOpenPulse3Q()) expected = Schedule(meas_scheds[0], meas_scheds[1], meas) self.assertEqual(sched.instructions, expected.instructions)
def test_complex_build(self): """Test a general program build with nested contexts, circuits and macros.""" d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) d2 = pulse.DriveChannel(2) delay_dur = 19 short_dur = 31 long_dur = 101 with pulse.build(self.backend) as schedule: with pulse.align_sequential(): pulse.delay(delay_dur, d0) pulse.u2(0, pi/2, 1) with pulse.align_right(): pulse.play(library.Constant(short_dur, 0.1), d1) pulse.play(library.Constant(long_dur, 0.1), d2) pulse.u2(0, pi/2, 1) with pulse.align_left(): pulse.u2(0, pi/2, 0) pulse.u2(0, pi/2, 1) pulse.u2(0, pi/2, 0) pulse.measure(0) # prepare and schedule circuits that will be used. single_u2_qc = circuit.QuantumCircuit(2) single_u2_qc.u2(0, pi/2, 1) single_u2_qc = compiler.transpile(single_u2_qc, self.backend) single_u2_sched = compiler.schedule(single_u2_qc, self.backend) # sequential context sequential_reference = pulse.Schedule() sequential_reference += instructions.Delay(delay_dur, d0) sequential_reference.insert(delay_dur, single_u2_sched, inplace=True) # align right align_right_reference = pulse.Schedule() align_right_reference += pulse.Play( library.Constant(long_dur, 0.1), d2) align_right_reference.insert(long_dur-single_u2_sched.duration, single_u2_sched, inplace=True) align_right_reference.insert( long_dur-single_u2_sched.duration-short_dur, pulse.Play(library.Constant(short_dur, 0.1), d1), inplace=True) # align left triple_u2_qc = circuit.QuantumCircuit(2) triple_u2_qc.u2(0, pi/2, 0) triple_u2_qc.u2(0, pi/2, 1) triple_u2_qc.u2(0, pi/2, 0) triple_u2_qc = compiler.transpile(triple_u2_qc, self.backend) align_left_reference = compiler.schedule( triple_u2_qc, self.backend, method='alap') # measurement measure_reference = macros.measure(qubits=[0], inst_map=self.inst_map, meas_map=self.configuration.meas_map) reference = pulse.Schedule() reference += sequential_reference # Insert so that the long pulse on d2 occurs as early as possible # without an overval on d1. insert_time = (reference.ch_stop_time(d1) - align_right_reference.ch_start_time(d1)) reference.insert(insert_time, align_right_reference, inplace=True) reference.insert(reference.ch_stop_time(d0, d1), align_left_reference, inplace=True) reference += measure_reference self.assertEqual(schedule, reference)
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(2*pulse_width) drag_scheds.append(sched) return drag_scheds, xdata