From 9bf6e09d4d107be4cfeacf63a1f0ce5f19f0e7bc Mon Sep 17 00:00:00 2001 From: pollyshaw Date: Thu, 30 Jun 2022 21:53:26 +0100 Subject: [PATCH] Fixes #7078: Add is_schedulable property to qiskit.pulse.Channel and don't apply a delay to it if True RegisterSlot and MemorySlot have this set to False. The default implementation in Channel sets it to True. --- qiskit/pulse/channels.py | 15 +++++++++++++++ qiskit/pulse/instructions/acquire.py | 9 ++------- qiskit/pulse/instructions/instruction.py | 5 ----- qiskit/pulse/schedule.py | 10 +++------- qiskit/scheduler/lowering.py | 8 +++----- 5 files changed, 23 insertions(+), 24 deletions(-) diff --git a/qiskit/pulse/channels.py b/qiskit/pulse/channels.py index c88fddadd77b..8b11d760b0d2 100644 --- a/qiskit/pulse/channels.py +++ b/qiskit/pulse/channels.py @@ -140,6 +140,11 @@ def name(self) -> str: """Return the shorthand alias for this channel, which is based on its type and index.""" return f"{self.__class__.prefix}{self._index}" + @property + def is_schedulable(self) -> bool: + """Return whether this channel can be independently scheduled""" + return True + def __repr__(self): return f"{self.__class__.__name__}({self._index})" @@ -213,6 +218,11 @@ class MemorySlot(ClassicalIOChannel): prefix = "m" + @property + def is_schedulable(self) -> bool: + """Return whether this channel can be independently scheduled""" + return False + class RegisterSlot(ClassicalIOChannel): """Classical resister slot channels represent classical registers (low-latency classical @@ -220,3 +230,8 @@ class RegisterSlot(ClassicalIOChannel): """ prefix = "c" + + @property + def is_schedulable(self) -> bool: + """Return whether this channel can be independently scheduled""" + return False diff --git a/qiskit/pulse/instructions/acquire.py b/qiskit/pulse/instructions/acquire.py index 4e91723f00da..9555e9317938 100644 --- a/qiskit/pulse/instructions/acquire.py +++ b/qiskit/pulse/instructions/acquire.py @@ -88,14 +88,9 @@ def channel(self) -> AcquireChannel: return self.operands[1] @property - def channels(self) -> Tuple[AcquireChannel]: + def channels(self) -> Tuple[Union[AcquireChannel, MemorySlot, RegisterSlot]]: """Returns the channels that this schedule uses.""" - return (self.channel,) - - @property - def slots(self) -> Tuple[Union[MemorySlot, RegisterSlot]]: - """Returns the slots that this schedule uses.""" - return tuple(self.operands[ind] for ind in (2, 3) if self.operands[ind] is not None) + return tuple(self.operands[ind] for ind in (1, 2, 3) if self.operands[ind] is not None) @property def duration(self) -> Union[int, ParameterExpression]: diff --git a/qiskit/pulse/instructions/instruction.py b/qiskit/pulse/instructions/instruction.py index 0585f6dcfa4b..5ddffab05e82 100644 --- a/qiskit/pulse/instructions/instruction.py +++ b/qiskit/pulse/instructions/instruction.py @@ -86,11 +86,6 @@ def start_time(self) -> int: """Relative begin time of this instruction.""" return 0 - @property - def slots(self) -> Tuple[Channel]: - """Returns any slots that this schedule uses""" - return () - @property def stop_time(self) -> int: """Relative end time of this instruction.""" diff --git a/qiskit/pulse/schedule.py b/qiskit/pulse/schedule.py index 687463d9cf90..843e6030ebf3 100644 --- a/qiskit/pulse/schedule.py +++ b/qiskit/pulse/schedule.py @@ -523,9 +523,7 @@ def _add_timeslots(self, time: int, schedule: "ScheduleComponent") -> None: other_timeslots = _get_timeslots(schedule) self._duration = max(self._duration, time + schedule.duration) - for channel in schedule.channels + ( - schedule.slots if isinstance(schedule, Instruction) else () - ): + for channel in schedule.channels: if channel not in self._timeslots: if time == 0: self._timeslots[channel] = copy.copy(other_timeslots[channel]) @@ -577,9 +575,7 @@ def _remove_timeslots(self, time: int, schedule: "ScheduleComponent"): if not isinstance(time, int): raise PulseError("Schedule start time must be an integer.") - for channel in schedule.channels + ( - schedule.slots if isinstance(schedule, Instruction) else () - ): + for channel in schedule.channels: if channel not in self._timeslots: raise PulseError(f"The channel {channel} is not present in the schedule") @@ -1499,7 +1495,7 @@ def _get_timeslots(schedule: "ScheduleComponent") -> TimeSlots: if isinstance(schedule, Instruction): duration = schedule.duration instruction_duration_validation(duration) - timeslots = {channel: [(0, duration)] for channel in schedule.channels + schedule.slots} + timeslots = {channel: [(0, duration)] for channel in schedule.channels} elif isinstance(schedule, Schedule): timeslots = schedule.timeslots else: diff --git a/qiskit/scheduler/lowering.py b/qiskit/scheduler/lowering.py index 5e30e23718d5..4eb4b14b1078 100644 --- a/qiskit/scheduler/lowering.py +++ b/qiskit/scheduler/lowering.py @@ -22,9 +22,9 @@ from qiskit.circuit.measure import Measure from qiskit.circuit.quantumcircuit import QuantumCircuit from qiskit.exceptions import QiskitError -from qiskit.pulse import Schedule, Acquire +from qiskit.pulse import Schedule from qiskit.pulse import instructions as pulse_inst -from qiskit.pulse.channels import AcquireChannel, DriveChannel +from qiskit.pulse.channels import AcquireChannel, MemorySlot, DriveChannel from qiskit.pulse.exceptions import PulseError from qiskit.pulse.macros import measure from qiskit.scheduler.config import ScheduleConfig @@ -79,9 +79,7 @@ def get_measure_schedule(qubit_mem_slots: Dict[int, int]) -> CircuitPulseDef: meas_q = target_qobj_transform(meas_q) acquire_q = meas_q.filter(channels=[AcquireChannel(qubit)]) mem_slot_index = [ - acquire[1].mem_slot.index - for acquire in acquire_q.instructions - if isinstance(acquire[1], Acquire) and not (acquire[1].mem_slot is None) + chan.index for chan in acquire_q.channels if isinstance(chan, MemorySlot) ][0] if mem_slot_index != qubit_mem_slots[qubit]: raise KeyError(