diff --git a/qiskit/transpiler/passes/scheduling/alignments/reschedule.py b/qiskit/transpiler/passes/scheduling/alignments/reschedule.py index b53d0f864cef..8aa89601b84a 100644 --- a/qiskit/transpiler/passes/scheduling/alignments/reschedule.py +++ b/qiskit/transpiler/passes/scheduling/alignments/reschedule.py @@ -17,6 +17,7 @@ from qiskit.circuit.gate import Gate from qiskit.circuit.delay import Delay from qiskit.circuit.measure import Measure +from qiskit.circuit.reset import Reset from qiskit.dagcircuit import DAGCircuit, DAGOpNode, DAGOutNode from qiskit.transpiler.basepasses import AnalysisPass from qiskit.transpiler.exceptions import TranspilerError @@ -113,7 +114,7 @@ def _push_node_back(self, dag: DAGCircuit, node: DAGOpNode): if isinstance(node.op, Gate): alignment = self.pulse_align - elif isinstance(node.op, Measure): + elif isinstance(node.op, (Measure, Reset)): alignment = self.acquire_align elif isinstance(node.op, Delay) or getattr(node.op, "_directive", False): # Directive or delay. These can start at arbitrary time. @@ -135,7 +136,7 @@ def _push_node_back(self, dag: DAGCircuit, node: DAGOpNode): # Compute shifted t1 of this node separately for qreg and creg new_t1q = this_t0 + node.op.duration this_qubits = set(node.qargs) - if isinstance(node.op, Measure): + if isinstance(node.op, (Measure, Reset)): # creg access ends at the end of instruction new_t1c = new_t1q this_clbits = set(node.cargs) @@ -153,7 +154,7 @@ def _push_node_back(self, dag: DAGCircuit, node: DAGOpNode): # Compute next node start time separately for qreg and creg next_t0q = node_start_time[next_node] next_qubits = set(next_node.qargs) - if isinstance(next_node.op, Measure): + if isinstance(next_node.op, (Measure, Reset)): # creg access starts after write latency next_t0c = next_t0q + clbit_write_latency next_clbits = set(next_node.cargs) diff --git a/qiskit/transpiler/passes/scheduling/base_scheduler.py b/qiskit/transpiler/passes/scheduling/base_scheduler.py index 78e2660e505d..4085844a4709 100644 --- a/qiskit/transpiler/passes/scheduling/base_scheduler.py +++ b/qiskit/transpiler/passes/scheduling/base_scheduler.py @@ -11,11 +11,13 @@ # that they have been altered from the originals. """Base circuit scheduling pass.""" +import warnings + from qiskit.transpiler import InstructionDurations from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.passes.scheduling.time_unit_conversion import TimeUnitConversion -from qiskit.dagcircuit import DAGOpNode, DAGCircuit -from qiskit.circuit import Delay, Gate +from qiskit.dagcircuit import DAGOpNode, DAGCircuit, DAGOutNode +from qiskit.circuit import Delay, Gate, Measure, Reset from qiskit.circuit.parameterexpression import ParameterExpression from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.target import Target @@ -269,6 +271,23 @@ def _get_node_duration( else: duration = node.op.duration + if isinstance(node.op, Reset): + warnings.warn( + "Qiskit scheduler assumes Reset works similarly to Measure instruction. " + "Actual behavior depends on the control system of your quantum backend. " + "Your backend may provide a plugin scheduler pass." + ) + elif isinstance(node.op, Measure): + is_mid_circuit = not any( + isinstance(x, DAGOutNode) for x in dag.quantum_successors(node) + ) + if is_mid_circuit: + warnings.warn( + "Qiskit scheduler assumes mid-circuit measurement works as a standard instruction. " + "Actual backend may apply custom scheduling. " + "Your backend may provide a plugin scheduler pass." + ) + if isinstance(duration, ParameterExpression): raise TranspilerError( f"Parameterized duration ({duration}) " diff --git a/releasenotes/notes/add-scheduler-warnings-da6968a39fd8e6e7.yaml b/releasenotes/notes/add-scheduler-warnings-da6968a39fd8e6e7.yaml new file mode 100644 index 000000000000..be2c94140300 --- /dev/null +++ b/releasenotes/notes/add-scheduler-warnings-da6968a39fd8e6e7.yaml @@ -0,0 +1,11 @@ +fixes: + - | + Fixed an issue where the :class:`.ConstrainedReschedule` transpiler pass would previously error + if the circuit contained a :class:`~.circuit.Reset` instruction. This has been corrected so that the + pass no longer errors, however an actual hardware may behave differently from + what Qiskit scheduler assumes especially for + mid-circuit measurements and resets. + Qiskit scheduler raises ``RuntimeWarning`` if + it encounters circuit containing either. + Fixed `#10354 `__ +