def test_barrier_with_align_left(self): """Test barrier directive with left alignment context.""" d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) d2 = pulse.DriveChannel(2) with pulse.build() as schedule: with pulse.align_left(): pulse.delay(3, d0) pulse.barrier(d0, d1, d2) pulse.delay(11, d2) with pulse.align_left(): pulse.delay(5, d1) pulse.delay(7, d0) schedule = transforms.remove_directives(schedule) reference = pulse.Schedule() # d0 reference.insert(0, instructions.Delay(3, d0), inplace=True) reference.insert(3, instructions.Delay(7, d0), inplace=True) # d1 reference.insert(3, instructions.Delay(5, d1), inplace=True) # d2 reference.insert(3, instructions.Delay(11, d2), inplace=True) self.assertEqual(schedule, reference)
def pad( schedule: Schedule, channels: Optional[Iterable[chans.Channel]] = None, until: Optional[int] = None, inplace: bool = False, ) -> Schedule: """Pad the input Schedule with ``Delay``s on all unoccupied timeslots until ``schedule.duration`` or ``until`` if not ``None``. Args: schedule: Schedule to pad. channels: Channels to pad. Defaults to all channels in ``schedule`` if not provided. If the supplied channel is not a member of ``schedule`` it will be added. until: Time to pad until. Defaults to ``schedule.duration`` if not provided. inplace: Pad this schedule by mutating rather than returning a new schedule. Returns: The padded schedule. """ until = until or schedule.duration channels = channels or schedule.channels for channel in channels: if isinstance(channel, ClassicalIOChannel): continue if channel not in schedule.channels: schedule |= instructions.Delay(until, channel) continue curr_time = 0 # Use the copy of timeslots. When a delay is inserted before the current interval, # current timeslot is pointed twice and the program crashes with the wrong pointer index. timeslots = schedule.timeslots[channel].copy() # TODO: Replace with method of getting instructions on a channel for interval in timeslots: if curr_time >= until: break if interval[0] != curr_time: end_time = min(interval[0], until) schedule = schedule.insert(curr_time, instructions.Delay( end_time - curr_time, channel), inplace=inplace) curr_time = interval[1] if curr_time < until: schedule = schedule.insert(curr_time, instructions.Delay( until - curr_time, channel), inplace=inplace) return schedule
def test_align_right_with_barrier(self): """Test right alignment with a barrier.""" d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) d2 = pulse.DriveChannel(2) schedule = pulse.Schedule() schedule.insert(1, instructions.Delay(3, d0), inplace=True) schedule.append(directives.RelativeBarrier(d0, d1, d2), inplace=True) schedule.insert(17, instructions.Delay(11, d2), inplace=True) sched_grouped = pulse.Schedule() sched_grouped.insert(2, instructions.Delay(5, d1), inplace=True) sched_grouped += instructions.Delay(7, d0) schedule.append(sched_grouped, inplace=True) schedule = transforms.remove_directives( transforms.align_right(schedule)) reference = pulse.Schedule() # d0 reference.insert(0, instructions.Delay(3, d0), inplace=True) reference.insert(7, instructions.Delay(7, d0), inplace=True) # d1 reference.insert(9, instructions.Delay(5, d1), inplace=True) # d2 reference.insert(3, instructions.Delay(11, d2), inplace=True) self.assertEqual(schedule, reference)
def test_delay_qubits(self): """Test delaying on multiple qubits to make sure we don't insert delays twice.""" with pulse.build(self.backend) as schedule: pulse.delay_qubits(10, 0, 1) d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) m0 = pulse.MeasureChannel(0) m1 = pulse.MeasureChannel(1) a0 = pulse.AcquireChannel(0) a1 = pulse.AcquireChannel(1) u0 = pulse.ControlChannel(0) u1 = pulse.ControlChannel(1) reference = pulse.Schedule() reference += instructions.Delay(10, d0) reference += instructions.Delay(10, d1) reference += instructions.Delay(10, m0) reference += instructions.Delay(10, m1) reference += instructions.Delay(10, a0) reference += instructions.Delay(10, a1) reference += instructions.Delay(10, u0) reference += instructions.Delay(10, u1) self.assertEqual(schedule, reference)
def test_align_left(self): """Test left alignment without a barrier.""" d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) d2 = pulse.DriveChannel(2) schedule = pulse.Schedule() schedule.insert(1, instructions.Delay(3, d0), inplace=True) schedule.insert(17, instructions.Delay(11, d2), inplace=True) sched_grouped = pulse.Schedule() sched_grouped += instructions.Delay(5, d1) sched_grouped += instructions.Delay(7, d0) schedule.append(sched_grouped, inplace=True) schedule = transforms.align_left(schedule) reference = pulse.Schedule() # d0 reference.insert(0, instructions.Delay(3, d0), inplace=True) reference.insert(3, instructions.Delay(7, d0), inplace=True) # d1 reference.insert(3, instructions.Delay(5, d1), inplace=True) # d2 reference.insert(0, instructions.Delay(11, d2), inplace=True) self.assertEqual(schedule, reference)
def test_remove_directives(self): """Test that all directives are removed.""" d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) schedule = pulse.Schedule() schedule += _TestDirective(d0, d1) schedule += instructions.Delay(3, d0) schedule += _TestDirective(d0, d1) schedule = transforms.remove_directives(schedule) reference = pulse.Schedule() # d0 reference += instructions.Delay(3, d0) self.assertEqual(schedule, reference)
def pad(schedule: Schedule, channels: Optional[Iterable[chans.Channel]] = None, until: Optional[int] = None, inplace: bool = False ) -> Schedule: r"""Pad the input Schedule with ``Delay``\s on all unoccupied timeslots until ``schedule.duration`` or ``until`` if not ``None``. Args: schedule: Schedule to pad. channels: Channels to pad. Defaults to all channels in ``schedule`` if not provided. If the supplied channel is not a member of ``schedule`` it will be added. until: Time to pad until. Defaults to ``schedule.duration`` if not provided. inplace: Pad this schedule by mutating rather than returning a new schedule. Returns: The padded schedule. """ until = until or schedule.duration channels = channels or schedule.channels for channel in channels: if channel not in schedule.channels: schedule |= instructions.Delay(until, channel) continue curr_time = 0 # TODO: Replace with method of getting instructions on a channel for interval in schedule.timeslots[channel]: if curr_time >= until: break if interval[0] != curr_time: end_time = min(interval[0], until) schedule = schedule.insert( curr_time, instructions.Delay(end_time - curr_time, channel), inplace=inplace) curr_time = interval[1] if curr_time < until: schedule = schedule.insert( curr_time, instructions.Delay(until - curr_time, channel), inplace=inplace) return schedule
def test_append_instruction(self): """Test appending an instruction to the active builder.""" d0 = pulse.DriveChannel(0) instruction = instructions.Delay(10, d0) with pulse.build() as schedule: builder.append_instruction(instruction) self.assertEqual(schedule, instruction)
def test_default(self): """Test default snapshot.""" snapshot = instructions.Snapshot(label='test_name', snapshot_type='state') self.assertIsInstance(snapshot.id, int) self.assertEqual(snapshot.name, 'test_name') self.assertEqual(snapshot.type, 'state') self.assertEqual(snapshot.duration, 0) self.assertNotEqual(snapshot, instructions.Delay(10, channels.DriveChannel(0))) self.assertEqual(repr(snapshot), "Snapshot(test_name, state, name='test_name')")
def test_append_schedule(self): """Test appending a schedule to the active builder.""" d0 = pulse.DriveChannel(0) reference = pulse.Schedule() reference += instructions.Delay(10, d0) with pulse.build() as schedule: builder.append_schedule(reference) self.assertEqual(schedule, reference)
def test_delay(self): """Test delay.""" delay = instructions.Delay(10, channels.DriveChannel(0), name='test_name') self.assertIsInstance(delay.id, int) self.assertEqual(delay.name, 'test_name') self.assertEqual(delay.duration, 10) self.assertIsInstance(delay.duration, int) self.assertEqual(delay.operands, (10, channels.DriveChannel(0))) self.assertEqual(delay, instructions.Delay(10, channels.DriveChannel(0))) self.assertNotEqual(delay, instructions.Delay(11, channels.DriveChannel(1))) self.assertEqual(repr(delay), "Delay(10, DriveChannel(0), name='test_name')") # Test numpy int for duration delay = instructions.Delay(np.int32(10), channels.DriveChannel(0), name='test_name2') self.assertEqual(delay.duration, 10) self.assertIsInstance(delay.duration, np.integer)
def test_align_sequential(self): """Test the sequential alignment context.""" d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) with pulse.build() as schedule: with pulse.align_sequential(): pulse.delay(3, d0) pulse.delay(5, d1) pulse.delay(7, d0) reference = pulse.Schedule() # d0 reference.insert(0, instructions.Delay(3, d0), inplace=True) reference.insert(8, instructions.Delay(7, d0), inplace=True) # d1 reference.insert(3, instructions.Delay(5, d1), inplace=True) self.assertEqual(schedule, reference)
def test_delay_qubit(self): """Test delaying on a qubit macro.""" with pulse.build(self.backend) as schedule: pulse.delay_qubits(10, 0) d0 = pulse.DriveChannel(0) m0 = pulse.MeasureChannel(0) a0 = pulse.AcquireChannel(0) u0 = pulse.ControlChannel(0) u1 = pulse.ControlChannel(1) reference = pulse.Schedule() reference += instructions.Delay(10, d0) reference += instructions.Delay(10, m0) reference += instructions.Delay(10, a0) reference += instructions.Delay(10, u0) reference += instructions.Delay(10, u1) self.assertEqual(schedule, reference)
def test_delay(self): """Test delay instruction.""" d0 = pulse.DriveChannel(0) with pulse.build() as schedule: pulse.delay(10, d0) reference = pulse.Schedule() reference += instructions.Delay(10, d0) self.assertEqual(schedule, reference)
def test_inline(self): """Test the inlining context.""" d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) with pulse.build() as schedule: pulse.delay(3, d0) with pulse.inline(): # this alignment will be ignored due to inlining. with pulse.align_right(): pulse.delay(5, d1) pulse.delay(7, d0) reference = pulse.Schedule() # d0 reference += instructions.Delay(3, d0) reference += instructions.Delay(7, d0) # d1 reference += instructions.Delay(5, d1) self.assertEqual(schedule, reference)
def test_call_schedule(self): """Test calling schedule instruction.""" schedule = pulse.Schedule() d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) reference = pulse.Schedule() reference = reference.insert(10, instructions.Delay(10, d0)) reference += instructions.Delay(20, d1) with pulse.build() as schedule: with pulse.align_right(): builder.call_schedule(reference) self.assertEqual(schedule, reference) with pulse.build() as schedule: with pulse.align_right(): pulse.call(reference) self.assertEqual(schedule, reference)
def test_flatten(self): """Test the flatten transform.""" d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) schedule = pulse.Schedule() schedule += instructions.Delay(3, d0) grouped = pulse.Schedule() grouped += instructions.Delay(5, d1) grouped += instructions.Delay(7, d0) # include a grouped schedule grouped = schedule + grouped # flatten the schedule inline internal groups flattened = transforms.flatten(grouped) # align all the instructions to the left after flattening flattened = transforms.align_left(flattened) grouped = transforms.align_left(grouped) reference = pulse.Schedule() # d0 reference.insert(0, instructions.Delay(3, d0), inplace=True) reference.insert(3, instructions.Delay(7, d0), inplace=True) # d1 reference.insert(0, instructions.Delay(5, d1), inplace=True) self.assertEqual(flattened, reference) self.assertNotEqual(grouped, reference)
def convert_delay(self, instruction): """Return converted `Delay`. Args: instruction (Delay): Delay qobj instruction Returns: Schedule: Converted and scheduled Instruction """ t0 = instruction.t0 channel = self.get_channel(instruction.ch) duration = instruction.duration return instructions.Delay(duration, channel) << t0
def test_frequency_offset(self): """Test the frequency offset context.""" d0 = pulse.DriveChannel(0) with pulse.build() as schedule: with pulse.frequency_offset(1e9, d0): pulse.delay(10, d0) reference = pulse.Schedule() reference += instructions.ShiftFrequency(1e9, d0) # pylint: disable=no-member reference += instructions.Delay(10, d0) reference += instructions.ShiftFrequency(-1e9, d0) # pylint: disable=no-member self.assertEqual(schedule, reference)
def test_phase_offset(self): """Test the phase offset context.""" d0 = pulse.DriveChannel(0) with pulse.build() as schedule: with pulse.phase_offset(3.14, d0): pulse.delay(10, d0) reference = pulse.Schedule() reference += instructions.ShiftPhase(3.14, d0) reference += instructions.Delay(10, d0) reference += instructions.ShiftPhase(-3.14, d0) self.assertEqual(schedule, reference)
def test_align_right(self): """Test the right alignment context.""" d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) d2 = pulse.DriveChannel(2) with pulse.build() as schedule: with pulse.align_right(): with pulse.align_right(): pulse.delay(11, d2) pulse.delay(3, d0) pulse.delay(13, d0) pulse.delay(5, d1) reference = pulse.Schedule() # d0 reference.insert(8, instructions.Delay(3, d0), inplace=True) reference.insert(11, instructions.Delay(13, d0), inplace=True) # d1 reference.insert(19, instructions.Delay(5, d1), inplace=True) # d2 reference.insert(0, instructions.Delay(11, d2), inplace=True) self.assertEqual(schedule, reference)
def test_phase_compensated_frequency_offset(self): """Test that the phase offset context properly compensates for phase accumulation.""" d0 = pulse.DriveChannel(0) with pulse.build(self.backend) as schedule: with pulse.frequency_offset(1e9, d0, compensate_phase=True): pulse.delay(10, d0) reference = pulse.Schedule() reference += instructions.ShiftFrequency(1e9, d0) # pylint: disable=no-member reference += instructions.Delay(10, d0) reference += instructions.ShiftPhase( -(1e9*10*self.configuration.dt % (2*np.pi)), d0) reference += instructions.ShiftFrequency(-1e9, d0) # pylint: disable=no-member self.assertEqual(schedule, reference)
def test_scheduler_settings(self): """Test the circuit scheduler settings context.""" inst_map = pulse.InstructionScheduleMap() d0 = pulse.DriveChannel(0) test_x_sched = pulse.Schedule() test_x_sched += instructions.Delay(10, d0) inst_map.add('x', (0,), test_x_sched) x_qc = circuit.QuantumCircuit(2) x_qc.x(0) with pulse.build(backend=self.backend) as schedule: with pulse.transpiler_settings(basis_gates=['x']): with pulse.circuit_scheduler_settings(inst_map=inst_map): builder.call_circuit(x_qc) self.assertEqual(schedule, test_x_sched)
def test_align_sequential(self): """Test sequential alignment without a barrier.""" d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) schedule = pulse.Schedule() schedule.insert(1, instructions.Delay(3, d0), inplace=True) schedule.insert(4, instructions.Delay(5, d1), inplace=True) schedule.insert(12, instructions.Delay(7, d0), inplace=True) schedule = transforms.align_sequential(schedule) reference = pulse.Schedule() # d0 reference.insert(0, instructions.Delay(3, d0), inplace=True) reference.insert(8, instructions.Delay(7, d0), inplace=True) # d1 reference.insert(3, instructions.Delay(5, d1), inplace=True) self.assertEqual(schedule, reference)
def test_align_sequential_with_barrier(self): """Test sequential alignment with a barrier.""" d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) schedule = pulse.Schedule() schedule.insert(1, instructions.Delay(3, d0), inplace=True) schedule.append(directives.RelativeBarrier(d0, d1), inplace=True) schedule.insert(4, instructions.Delay(5, d1), inplace=True) schedule.insert(12, instructions.Delay(7, d0), inplace=True) schedule = transforms.align_sequential(schedule) reference = pulse.Schedule() reference.insert(0, instructions.Delay(3, d0), inplace=True) reference.insert(3, directives.RelativeBarrier(d0, d1), inplace=True) reference.insert(3, instructions.Delay(5, d1), inplace=True) reference.insert(8, instructions.Delay(7, d0), inplace=True) self.assertEqual(schedule, reference)
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 lower_gates(circuit: QuantumCircuit, schedule_config: ScheduleConfig) -> List[CircuitPulseDef]: """ Return a list of Schedules and the qubits they operate on, for each element encountered in the input circuit. Without concern for the final schedule, extract and return a list of Schedules and the qubits they operate on, for each element encountered in the input circuit. Measures are grouped when possible, so ``qc.measure(q0, c0)`` or ``qc.measure(q1, c1)`` will generate a synchronous measurement pulse. Args: circuit: The quantum circuit to translate. schedule_config: Backend specific parameters used for building the Schedule. Returns: A list of CircuitPulseDefs: the pulse definition for each circuit element. Raises: QiskitError: If circuit uses a command that isn't defined in config.inst_map. """ from qiskit.pulse.transforms.base_transforms import target_qobj_transform circ_pulse_defs = [] inst_map = schedule_config.inst_map qubit_mem_slots = {} # Map measured qubit index to classical bit index # convert the unit of durations from SI to dt before lowering circuit = convert_durations_to_dt(circuit, dt_in_sec=schedule_config.dt, inplace=False) 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) ], ) qubit_indices = {bit: idx for idx, bit in enumerate(circuit.qubits)} clbit_indices = {bit: idx for idx, bit in enumerate(circuit.clbits)} for inst, qubits, clbits in circuit.data: inst_qubits = [qubit_indices[qubit] for qubit in qubits] if any(q in qubit_mem_slots for q in inst_qubits): # If we are operating on a qubit that was scheduled to be measured, process that first circ_pulse_defs.append(get_measure_schedule(qubit_mem_slots)) if isinstance(inst, Barrier): circ_pulse_defs.append( CircuitPulseDef(schedule=inst, qubits=inst_qubits)) elif isinstance(inst, Delay): sched = Schedule(name=inst.name) for qubit in inst_qubits: for channel in [DriveChannel]: sched += pulse_inst.Delay(duration=inst.duration, channel=channel(qubit)) circ_pulse_defs.append( CircuitPulseDef(schedule=sched, qubits=inst_qubits)) elif isinstance(inst, Measure): if len(inst_qubits) != 1 and len(clbits) != 1: raise QiskitError( "Qubit '{}' or classical bit '{}' errored because the " "circuit Measure instruction only takes one of " "each.".format(inst_qubits, clbits)) qubit_mem_slots[inst_qubits[0]] = clbit_indices[clbits[0]] else: try: gate_cals = circuit.calibrations[inst.name] schedule = gate_cals[( tuple(inst_qubits), tuple(p if getattr(p, "parameters", None) else float(p) for p in inst.params), )] schedule = target_qobj_transform(schedule) circ_pulse_defs.append( CircuitPulseDef(schedule=schedule, qubits=inst_qubits)) continue except KeyError: pass # Calibration not defined for this operation try: schedule = inst_map.get(inst, inst_qubits, *inst.params) schedule = target_qobj_transform(schedule) circ_pulse_defs.append( CircuitPulseDef(schedule=schedule, qubits=inst_qubits)) except PulseError as ex: raise QiskitError( f"Operation '{inst.name}' on qubit(s) {inst_qubits} not supported by the " "backend command definition. Did you remember to transpile your input " "circuit for the same backend?") from ex if qubit_mem_slots: circ_pulse_defs.append(get_measure_schedule(qubit_mem_slots)) return circ_pulse_defs