def test_same_time_equal(self):
        """Test equal if instruction at same time."""

        self.assertEqual(Schedule((0, ShiftPhase(0, DriveChannel(1)))),
                         Schedule((0, ShiftPhase(0, DriveChannel(1)))))
    def test_filter_inst_types(self):
        """Test filtering on instruction types."""
        lp0 = self.linear(duration=3, slope=0.2, intercept=0.1)
        sched = Schedule(name='fake_experiment')
        sched = sched.insert(0, Play(lp0, self.config.drive(0)))
        sched = sched.insert(10, Play(lp0, self.config.drive(1)))
        sched = sched.insert(30, ShiftPhase(-1.57, self.config.drive(0)))
        sched = sched.insert(40, SetFrequency(8.0, self.config.drive(0)))
        sched = sched.insert(50, ShiftFrequency(4.0e6, self.config.drive(0)))
        sched = sched.insert(55, SetPhase(3.14, self.config.drive(0)))
        for i in range(2):
            sched = sched.insert(60, Acquire(5, self.config.acquire(i), MemorySlot(i)))
        sched = sched.insert(90, Play(lp0, self.config.drive(0)))

        # test on Acquire
        only_acquire, no_acquire = \
            self._filter_and_test_consistency(sched, instruction_types=[Acquire])
        for _, inst in only_acquire.instructions:
            self.assertIsInstance(inst, Acquire)
        for _, inst in no_acquire.instructions:
            self.assertFalse(isinstance(inst, Acquire))

        # test two instruction types
        only_pulse_and_fc, no_pulse_and_fc = \
            self._filter_and_test_consistency(sched, instruction_types=[Play,
                                                                        ShiftPhase])
        for _, inst in only_pulse_and_fc.instructions:
            self.assertIsInstance(inst, (Play, ShiftPhase))
        for _, inst in no_pulse_and_fc.instructions:
            self.assertFalse(isinstance(inst, (Play, ShiftPhase)))
        self.assertEqual(len(only_pulse_and_fc.instructions), 4)
        self.assertEqual(len(no_pulse_and_fc.instructions), 5)

        # test on ShiftPhase
        only_fc, no_fc = \
            self._filter_and_test_consistency(sched, instruction_types={ShiftPhase})
        self.assertEqual(len(only_fc.instructions), 1)
        self.assertEqual(len(no_fc.instructions), 8)

        # test on SetPhase
        only_setp, no_setp = \
            self._filter_and_test_consistency(sched, instruction_types={SetPhase})
        self.assertEqual(len(only_setp.instructions), 1)
        self.assertEqual(len(no_setp.instructions), 8)

        # test on SetFrequency
        only_setf, no_setf = self._filter_and_test_consistency(
            sched, instruction_types=[SetFrequency])
        for _, inst in only_setf.instructions:
            self.assertTrue(isinstance(inst, SetFrequency))
        self.assertEqual(len(only_setf.instructions), 1)
        self.assertEqual(len(no_setf.instructions), 8)

        # test on ShiftFrequency
        only_shiftf, no_shiftf = \
            self._filter_and_test_consistency(sched,
                                              instruction_types=[ShiftFrequency])
        for _, inst in only_shiftf.instructions:
            self.assertTrue(isinstance(inst, ShiftFrequency))
        self.assertEqual(len(only_shiftf.instructions), 1)
        self.assertEqual(len(no_shiftf.instructions), 8)
 def test_different_channels(self):
     """Test equality is False if different channels."""
     self.assertNotEqual(Schedule(ShiftPhase(0, DriveChannel(0))),
                         Schedule(ShiftPhase(0, DriveChannel(1))))
Пример #4
0
 def test_negative_time_raises(self):
     """Test that a negative time will raise an error."""
     sched = Schedule()
     sched += Delay(1, DriveChannel(0))
     with self.assertRaises(PulseError):
         sched.shift(-10)
Пример #5
0
def sequence(scheduled_circuit: QuantumCircuit,
             schedule_config: ScheduleConfig) -> Schedule:
    """
    Return the pulse Schedule which implements the input scheduled circuit.

    Assume all measurements are done at once at the last of the circuit.
    Schedules according to the command definition given by the schedule_config.

    Args:
        scheduled_circuit: The scheduled quantum circuit to translate.
        schedule_config: Backend specific parameters used for building the Schedule.

    Returns:
        A schedule corresponding to the input ``circuit``.

    Raises:
        QiskitError: If invalid scheduled circuit is supplied.
    """
    circ_pulse_defs = lower_gates(scheduled_circuit, schedule_config)

    # find the measurement start time (assume measurement once)
    def _meas_start_time():
        _qubit_time_available = defaultdict(int)
        for inst, qubits, _ in scheduled_circuit.data:
            if isinstance(inst, Measure):
                return _qubit_time_available[qubits[0]]
            for q in qubits:
                _qubit_time_available[q] += inst.duration
        return None

    meas_time = _meas_start_time()

    # restore start times
    qubit_time_available = {}
    start_times = []
    out_circ_pulse_defs = []
    for circ_pulse_def in circ_pulse_defs:
        active_qubits = [
            q for q in circ_pulse_def.qubits if q in qubit_time_available
        ]

        start_time = max([qubit_time_available[q] for q in active_qubits],
                         default=0)

        for q in active_qubits:
            if qubit_time_available[q] != start_time:
                # print(q, ":", qubit_time_available[q], "!=", start_time)
                raise QiskitError("Invalid scheduled circuit.")

        stop_time = start_time
        if not isinstance(circ_pulse_def.schedule, Barrier):
            stop_time += circ_pulse_def.schedule.duration

        delay_overlaps_meas = False
        for q in circ_pulse_def.qubits:
            qubit_time_available[q] = stop_time
            if meas_time is not None \
                    and circ_pulse_def.schedule.name == "delay" \
                    and stop_time > meas_time:
                qubit_time_available[q] = meas_time
                delay_overlaps_meas = True
        # skip to delays overlapping measures and barriers
        if not delay_overlaps_meas and not isinstance(circ_pulse_def.schedule,
                                                      Barrier):
            start_times.append(start_time)
            out_circ_pulse_defs.append(circ_pulse_def)

    timed_schedules = [(time, cpd.schedule)
                       for time, cpd in zip(start_times, out_circ_pulse_defs)]
    sched = Schedule(*timed_schedules, name=scheduled_circuit.name)
    return pad(sched)
    def test_different_name_equal(self):
        """Test that names are ignored when checking equality."""

        self.assertEqual(Schedule((0, ShiftPhase(0, DriveChannel(1), name='fc1')), name='s1'),
                         Schedule((0, ShiftPhase(0, DriveChannel(1), name='fc2')), name='s2'))
Пример #7
0
    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)
Пример #8
0
def remove_directives(schedule: Schedule) -> Schedule:
    """Remove directives."""
    return schedule.exclude(instruction_types=[directives.Directive])
Пример #9
0
    def test_flat_instruction_sequence_returns_instructions(self):
        """Test if `flat_instruction_sequence` returns `Instruction`s."""
        device = self.two_qubit_device
        lp0 = self.linear(duration=3, slope=0.2, intercept=0.1)

        # empty schedule with empty schedule
        empty = Schedule().append(Schedule())
        for _, instr in empty.flatten():
            self.assertIsInstance(instr, Instruction)

        # normal schedule
        subsched = Schedule()
        subsched = subsched.insert(20, lp0(device.q[0].drive))  # grand child 1
        subsched = subsched.append(lp0(device.q[0].drive))  # grand child 2

        sched = Schedule()
        sched = sched.append(lp0(device.q[0].drive))  # child
        sched = sched.append(subsched)
        for _, instr in sched.flatten():
            self.assertIsInstance(instr, Instruction)
Пример #10
0
def align_measures(
    schedules: Iterable[interfaces.ScheduleComponent],
    inst_map: Optional[InstructionScheduleMap] = None,
    cal_gate: str = 'u3',
    max_calibration_duration: Optional[int] = None,
    align_time: Optional[int] = None,
    align_all: Optional[bool] = True,
) -> List[Schedule]:
    """Return new schedules where measurements occur at the same physical time.

    This transformation will align the first :class:`qiskit.pulse.Acquire` on
    every channel to occur at the same time.

    Minimum measurement wait time (to allow for calibration pulses) is enforced
    and may be set with ``max_calibration_duration``.

    By default only instructions containing a :class:`~qiskit.pulse.AcquireChannel`
    or :class:`~qiskit.pulse.MeasureChannel` will be shifted. If you wish to keep
    the relative timing of all instructions in the schedule set ``align_all=True``.

    This method assumes that ``MeasureChannel(i)`` and ``AcquireChannel(i)``
    correspond to the same qubit and the acquire/play instructions
    should be shifted together on these channels.

    .. jupyter-kernel:: python3
        :id: align_measures

    .. jupyter-execute::

        from qiskit import pulse
        from qiskit.pulse import transforms

        with pulse.build() as sched:
            with pulse.align_sequential():
                pulse.play(pulse.Constant(10, 0.5), pulse.DriveChannel(0))
                pulse.play(pulse.Constant(10, 1.), pulse.MeasureChannel(0))
                pulse.acquire(20, pulse.AcquireChannel(0), pulse.MemorySlot(0))

        sched_shifted = sched << 20

        aligned_sched, aligned_sched_shifted = transforms.align_measures([sched, sched_shifted])

        assert aligned_sched == aligned_sched_shifted

    If it is desired to only shift acqusition and measurement stimulus instructions
    set the flag ``align_all=False``:

    .. jupyter-execute::

        aligned_sched, aligned_sched_shifted = transforms.align_measures(
            [sched, sched_shifted],
            align_all=False,
        )

        assert aligned_sched != aligned_sched_shifted


    Args:
        schedules: Collection of schedules to be aligned together
        inst_map: Mapping of circuit operations to pulse schedules
        cal_gate: The name of the gate to inspect for the calibration time
        max_calibration_duration: If provided, inst_map and cal_gate will be ignored
        align_time: If provided, this will be used as final align time.
        align_all: Shift all instructions in the schedule such that they maintain
            their relative alignment with the shifted acqusition instruction.
            If ``False`` only the acqusition and measurement pulse instructions
            will be shifted.
    Returns:
        The input list of schedules transformed to have their measurements aligned.

    Raises:
        PulseError: If the provided alignment time is negative.
    """
    def get_first_acquire_times(schedules):
        """Return a list of first acquire times for each schedule."""
        acquire_times = []
        for schedule in schedules:
            visited_channels = set()
            qubit_first_acquire_times = defaultdict(lambda: None)

            for time, inst in schedule.instructions:
                if (isinstance(inst, instructions.Acquire)
                        and inst.channel not in visited_channels):
                    visited_channels.add(inst.channel)
                    qubit_first_acquire_times[inst.channel.index] = time

            acquire_times.append(qubit_first_acquire_times)
        return acquire_times

    def get_max_calibration_duration(inst_map, cal_gate):
        """Return the time needed to allow for readout discrimination calibration pulses."""
        max_calibration_duration = 0
        for qubits in inst_map.qubits_with_instruction(cal_gate):
            cmd = inst_map.get(cal_gate, qubits, np.pi, 0, np.pi)
            max_calibration_duration = max(cmd.duration,
                                           max_calibration_duration)
        return max_calibration_duration

    if align_time is not None and align_time < 0:
        raise exceptions.PulseError("Align time cannot be negative.")

    first_acquire_times = get_first_acquire_times(schedules)
    # Extract the maximum acquire in every schedule across all acquires in the schedule.
    # If there are no acquires in the schedule default to 0.
    max_acquire_times = [
        max(0, *times.values()) for times in first_acquire_times
    ]
    if align_time is None:
        if max_calibration_duration is None:
            if inst_map:
                max_calibration_duration = get_max_calibration_duration(
                    inst_map, cal_gate)
            else:
                max_calibration_duration = 0
        align_time = max(max_calibration_duration, *max_acquire_times)

    # Shift acquires according to the new scheduled time
    new_schedules = []
    for sched_idx, schedule in enumerate(schedules):
        new_schedule = Schedule(name=schedule.name)
        stop_time = schedule.stop_time

        if align_all:
            if first_acquire_times[sched_idx]:
                shift = align_time - max_acquire_times[sched_idx]
            else:
                shift = align_time - stop_time
        else:
            shift = 0

        for time, inst in schedule.instructions:
            measurement_channels = {
                chan.index
                for chan in inst.channels
                if isinstance(chan, (chans.MeasureChannel,
                                     chans.AcquireChannel))
            }
            if measurement_channels:
                sched_first_acquire_times = first_acquire_times[sched_idx]
                max_start_time = max(sched_first_acquire_times[chan]
                                     for chan in measurement_channels
                                     if chan in sched_first_acquire_times)
                shift = align_time - max_start_time

            if shift < 0:
                warnings.warn(
                    "The provided alignment time is scheduling an acquire instruction "
                    "earlier than it was scheduled for in the original Schedule. "
                    "This may result in an instruction being scheduled before t=0 and "
                    "an error being raised.")
            new_schedule.insert(time + shift, inst, inplace=True)

        new_schedules.append(new_schedule)

    return new_schedules
Пример #11
0
def flatten(schedule: Schedule) -> Schedule:
    """Flatten any called nodes into a Schedule tree with no nested children."""
    return schedule.flatten()
    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(name='test_schedule')
        sched = sched.append(gp0(DriveChannel(0)))
        sched = sched.insert(
            0,
            pulse_lib.Constant(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(70, ShiftFrequency(4.0e6, 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 setUp(self):
     self.schedule = Schedule(name='test_schedule')
Пример #14
0
 def setUp(self):
     self.schedule = Schedule()
     self.device = PulseChannelSpec(n_qubits=2, n_control=1, n_registers=2)
Пример #15
0
 def test_different_time_not_equal(self):
     """Test that not equal if instruction at different time."""
     self.assertNotEqual(Schedule((0, ShiftPhase(0, DriveChannel(1)))),
                         Schedule((1, ShiftPhase(0, DriveChannel(1)))))
Пример #16
0
    def test_filter_intervals(self):
        """Test filtering on intervals."""
        device = self.two_qubit_device
        lp0 = self.linear(duration=3, slope=0.2, intercept=0.1)
        acquire = Acquire(5)
        sched = Schedule(name='fake_experiment')
        sched = sched.insert(0, lp0(device.q[0].drive))
        sched = sched.insert(10, lp0(device.q[1].drive))
        sched = sched.insert(30, FrameChange(phase=-1.57)(device.q[0].drive))
        sched = sched.insert(60, acquire(device.q, device.mem))
        sched = sched.insert(90, lp0(device.q[0].drive))

        intervals_a = sched.filter(time_ranges=((0, 13), ))
        for time, inst in intervals_a.instructions:
            self.assertTrue(0 <= time <= 13)
            self.assertTrue(inst.timeslots.timeslots[0].interval.end <= 13)
        self.assertEqual(len(intervals_a.instructions), 2)

        intervals_b = sched.filter(time_ranges=[(59, 65)])
        self.assertEqual(len(intervals_b.instructions), 1)
        self.assertEqual(intervals_b.instructions[0][0], 60)
        self.assertIsInstance(intervals_b.instructions[0][1],
                              AcquireInstruction)

        non_full_intervals = sched.filter(time_ranges=[(0, 2), (8, 11), (61,
                                                                         70)])
        self.assertEqual(len(non_full_intervals.instructions), 0)

        multi_interval = sched.filter(time_ranges=[(10, 15), (63, 93)])
        self.assertEqual(len(multi_interval.instructions), 2)

        multi_interval = sched.filter(
            intervals=[Interval(10, 15), Interval(63, 93)])
        self.assertEqual(len(multi_interval.instructions), 2)
Пример #17
0
    def test_multiple_channels_out_of_order(self):
        """Test that schedule with multiple channels equal when out of order."""
        instructions = [(0, ShiftPhase(0, DriveChannel(1))),
                        (1, Acquire(10, AcquireChannel(0), MemorySlot(1)))]

        self.assertEqual(Schedule(*instructions), Schedule(*reversed(instructions)))
Пример #18
0
    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.drives[0]))
        sched = sched.insert(
            0,
            PersistentValue(value=0.2 + 0.4j)(device.controls[0]))
        sched = sched.insert(60, FrameChange(phase=-1.57)(device.drives[0]))
        sched = sched.insert(30, gp1(device.drives[1]))
        sched = sched.insert(60, gp0(device.controls[0]))
        sched = sched.insert(80, Snapshot("label", "snap_type"))
        sched = sched.insert(90, fc_pi_2(device.drives[0]))
        sched = sched.insert(
            90,
            acquire(device.acquires[1], device.memoryslots[1],
                    device.registers[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)
Пример #19
0
    def convert_acquire(self, instruction):
        """Return converted `Acquire`.

        Args:
            instruction (PulseQobjInstruction): acquire qobj
        Returns:
            Schedule: Converted and scheduled Instruction
        """
        t0 = instruction.t0
        duration = instruction.duration
        qubits = instruction.qubits
        acquire_channels = [channels.AcquireChannel(qubit) for qubit in qubits]

        mem_slots = [
            channels.MemorySlot(instruction.memory_slot[i])
            for i in range(len(qubits))
        ]

        if hasattr(instruction, 'register_slot'):
            register_slots = [
                channels.RegisterSlot(instruction.register_slot[i])
                for i in range(len(qubits))
            ]
        else:
            register_slots = [None] * len(qubits)

        discriminators = (instruction.discriminators if hasattr(
            instruction, 'discriminators') else None)
        if not isinstance(discriminators, list):
            discriminators = [discriminators]
        if any(discriminators[i] != discriminators[0]
               for i in range(len(discriminators))):
            warnings.warn(
                "Can currently only support one discriminator per acquire. Defaulting "
                "to first discriminator entry.")
        discriminator = discriminators[0]
        if discriminator:
            discriminator = Discriminator(name=discriminators[0].name,
                                          **discriminators[0].params)

        kernels = (instruction.kernels
                   if hasattr(instruction, 'kernels') else None)
        if not isinstance(kernels, list):
            kernels = [kernels]
        if any(kernels[0] != kernels[i] for i in range(len(kernels))):
            warnings.warn(
                "Can currently only support one kernel per acquire. Defaulting to first "
                "kernel entry.")
        kernel = kernels[0]
        if kernel:
            kernel = Kernel(name=kernels[0].name, **kernels[0].params)

        schedule = Schedule()

        for acquire_channel, mem_slot, reg_slot in zip(acquire_channels,
                                                       mem_slots,
                                                       register_slots):
            schedule |= instructions.Acquire(duration,
                                             acquire_channel,
                                             mem_slot=mem_slot,
                                             reg_slot=reg_slot,
                                             kernel=kernel,
                                             discriminator=discriminator) << t0

        return schedule
Пример #20
0
        def my_test_make_schedule(acquire: int, memoryslot: int, shift: int):
            sched1 = Acquire(acquire, AcquireChannel(0), MemorySlot(memoryslot))
            sched2 = Acquire(acquire, AcquireChannel(1), MemorySlot(memoryslot)).shift(shift)

            return Schedule(sched1, sched2)
Пример #21
0
 def test_numpy_integer_input(self):
     """Test that mixed integer duration types can build a schedule (#5754)."""
     sched = Schedule()
     sched += Delay(np.int32(25), DriveChannel(0))
     sched += Play(Constant(duration=30, amp=0.1), DriveChannel(0))
     self.assertEqual(sched.duration, 55)
Пример #22
0
 def test_shift_unshift(self):
     """Test shift and then unshifting of schedule"""
     reference_sched = Schedule()
     reference_sched += Delay(10, DriveChannel(0))
     shifted_sched = reference_sched.shift(10).shift(-10)
     self.assertEqual(shifted_sched, reference_sched)
Пример #23
0
 def test_insert_float_time_raises(self):
     """Test that a floating time will raise an error with insert."""
     sched = Schedule()
     sched += Delay(1, DriveChannel(0))
     with self.assertRaises(PulseError):
         sched.insert(10.1, sched)
Пример #24
0
    def test_filter_intervals(self):
        """Test filtering on intervals."""
        lp0 = self.linear(duration=3, slope=0.2, intercept=0.1)
        sched = Schedule(name="fake_experiment")
        sched = sched.insert(0, Play(lp0, self.config.drive(0)))
        sched = sched.insert(10, Play(lp0, self.config.drive(1)))
        sched = sched.insert(30, ShiftPhase(-1.57, self.config.drive(0)))
        for i in range(2):
            sched = sched.insert(
                60, Acquire(5, self.config.acquire(i), MemorySlot(i)))
        sched = sched.insert(90, Play(lp0, self.config.drive(0)))

        # split schedule into instructions occurring in (0,13), and those outside
        filtered, excluded = self._filter_and_test_consistency(
            sched, time_ranges=((0, 13), ))
        for start_time, inst in filtered.instructions:
            self.assertTrue((start_time >= 0)
                            and (start_time + inst.stop_time <= 13))
        for start_time, inst in excluded.instructions:
            self.assertFalse((start_time >= 0)
                             and (start_time + inst.stop_time <= 13))
        self.assertEqual(len(filtered.instructions), 2)
        self.assertEqual(len(excluded.instructions), 4)

        # split into schedule occurring in and outside of interval (59,65)
        filtered, excluded = self._filter_and_test_consistency(sched,
                                                               time_ranges=[
                                                                   (59, 65)
                                                               ])
        self.assertEqual(len(filtered.instructions), 2)
        self.assertEqual(filtered.instructions[0][0], 60)
        self.assertIsInstance(filtered.instructions[0][1], Acquire)
        self.assertEqual(len(excluded.instructions), 4)
        self.assertEqual(excluded.instructions[3][0], 90)
        self.assertIsInstance(excluded.instructions[3][1], Play)

        # split instructions based on the interval
        # (none should be, though they have some overlap with some of the instructions)
        filtered, excluded = self._filter_and_test_consistency(sched,
                                                               time_ranges=[
                                                                   (0, 2),
                                                                   (8, 11),
                                                                   (61, 70)
                                                               ])
        self.assertEqual(len(filtered.instructions), 0)
        self.assertEqual(len(excluded.instructions), 6)

        # split instructions from multiple non-overlapping intervals, specified
        # as time ranges
        filtered, excluded = self._filter_and_test_consistency(sched,
                                                               time_ranges=[
                                                                   (10, 15),
                                                                   (63, 93)
                                                               ])
        self.assertEqual(len(filtered.instructions), 2)
        self.assertEqual(len(excluded.instructions), 4)

        # split instructions from non-overlapping intervals, specified as Intervals
        filtered, excluded = self._filter_and_test_consistency(sched,
                                                               intervals=[
                                                                   (10, 15),
                                                                   (63, 93)
                                                               ])
        self.assertEqual(len(filtered.instructions), 2)
        self.assertEqual(len(excluded.instructions), 4)