From f2047f5cc99900754ae50d905e5aabaaceb71ab6 Mon Sep 17 00:00:00 2001 From: ElePT Date: Wed, 17 Sep 2025 11:06:06 +0200 Subject: [PATCH 1/9] Add target as input to scheduling passes, adapt test to use target as input, deprecate DynamicCircuitInstructionDurations --- .../fake_provider/fake_backend.py | 2 +- .../passes/scheduling/block_base_padder.py | 21 +- .../passes/scheduling/dynamical_decoupling.py | 21 +- .../transpiler/passes/scheduling/pad_delay.py | 5 +- .../transpiler/passes/scheduling/scheduler.py | 56 +- .../transpiler/passes/scheduling/utils.py | 8 + test/ibm_test_case.py | 10 + .../scheduling/test_dynamical_decoupling.py | 1188 +++++--- .../passes/scheduling/test_scheduler.py | 2576 +++++++++++++---- .../passes/scheduling/test_utils.py | 50 +- 10 files changed, 2987 insertions(+), 950 deletions(-) diff --git a/qiskit_ibm_runtime/fake_provider/fake_backend.py b/qiskit_ibm_runtime/fake_provider/fake_backend.py index 769123201..105e8901a 100644 --- a/qiskit_ibm_runtime/fake_provider/fake_backend.py +++ b/qiskit_ibm_runtime/fake_provider/fake_backend.py @@ -351,7 +351,7 @@ def _get_noise_model_from_backend_v2( # type: ignore # Add gate errors with warnings.catch_warnings(): - warnings.filterwarnings( + warnings.rnings( "ignore", module="qiskit_aer.noise.device.models", ) diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/block_base_padder.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/block_base_padder.py index b8d33c48e..94611ad99 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/block_base_padder.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/block_base_padder.py @@ -30,6 +30,7 @@ from qiskit.circuit.parameterexpression import ParameterExpression from qiskit.converters import dag_to_circuit from qiskit.dagcircuit import DAGCircuit, DAGNode, DAGOpNode +from qiskit.transpiler import Target from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.exceptions import TranspilerError from qiskit.circuit.controlflow import condition_resources @@ -68,6 +69,7 @@ def __init__( self, schedule_idle_qubits: bool = False, block_ordering_callable: Optional[BlockOrderingCallableType] = None, + target: Optional[Target] = None, ) -> None: self._node_start_time = None @@ -99,6 +101,7 @@ def __init__( block_order_op_nodes if block_ordering_callable is None else block_ordering_callable ) + self._target = target super().__init__() def run(self, dag: DAGCircuit) -> DAGCircuit: @@ -270,7 +273,23 @@ def _get_node_duration(self, node: DAGNode) -> int: indices = [self._bit_indices[qarg] for qarg in self._map_wires(node.qargs)] - duration = self._durations.get(node.op, indices, unit="dt") + if node.name == "delay": + duration = node.op.duration + elif node.name == "barrier": + duration = 0 + elif self._target: + props_dict = self._target.get(node.name) + if not props_dict: + duration = None + props = props_dict.get(tuple(indices)) + if not props: + duration = None + if self._target.dt is None: + duration = props.duration + else: + duration = self._target.seconds_to_dt(props.duration) + else: + duration = self._durations.get(node.op, indices, unit="dt") if isinstance(duration, ParameterExpression): raise TranspilerError( diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py index 7c7cbc10b..cfc674023 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py @@ -23,6 +23,7 @@ from qiskit.circuit.reset import Reset from qiskit.dagcircuit import DAGCircuit, DAGNode, DAGInNode, DAGOpNode from qiskit.quantum_info.operators.predicates import matrix_equal +from qiskit.transpiler import Target from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.instruction_durations import InstructionDurations from qiskit.transpiler.passes.optimization import Optimize1qGates @@ -119,8 +120,8 @@ def uhrig_pulse_location(k): def __init__( self, - durations: InstructionDurations, - dd_sequences: Union[List[Gate], List[List[Gate]]], + durations: InstructionDurations = None, + dd_sequences: Union[List[Gate], List[List[Gate]]] = None, qubits: Optional[List[int]] = None, spacings: Optional[Union[List[List[float]], List[float]]] = None, skip_reset_qubits: bool = True, @@ -133,6 +134,7 @@ def __init__( schedule_idle_qubits: bool = False, dd_barrier: Optional[str] = None, block_ordering_callable: Optional[BlockOrderingCallableType] = None, + target: Optional[Target] = None, ): """Dynamical decoupling initializer. @@ -204,6 +206,7 @@ def __init__( block_ordering_callable=block_ordering_callable, ) self._durations = durations + self._target = target # Enforce list of DD sequences if dd_sequences: @@ -348,7 +351,19 @@ def _pre_runhook(self, dag: DAGCircuit) -> None: continue for index, gate in enumerate(seq): - gate_length = self._durations.get(gate, physical_index) + if self._target: + try: + gate_length = self._target[gate.name].get((physical_index,)).duration + except: + gate_length = None + else: + gate_length = self._durations.get(gate, physical_index) + + if gate_length is None: + raise TranspilerError( + f"Duration of {gate} on qubits {physical_index} is not found." + ) + seq_length_.append(gate_length) # Update gate duration. # This is necessary for current timeline drawer, i.e. scheduled. diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/pad_delay.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/pad_delay.py index d73fb7680..92b47d708 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/pad_delay.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/pad_delay.py @@ -17,6 +17,7 @@ from qiskit.circuit import Qubit from qiskit.circuit.delay import Delay from qiskit.dagcircuit import DAGNode, DAGOutNode +from qiskit.transpiler import Target from qiskit.transpiler.instruction_durations import InstructionDurations from .block_base_padder import BlockBasePadder @@ -56,10 +57,11 @@ class PadDelay(BlockBasePadder): def __init__( self, - durations: InstructionDurations, + durations: InstructionDurations = None, fill_very_end: bool = True, schedule_idle_qubits: bool = False, block_ordering_callable: Optional[BlockOrderingCallableType] = None, + target: Target = None, ): """Create new padding delay pass. @@ -78,6 +80,7 @@ def __init__( block_ordering_callable=block_ordering_callable, ) self._durations = durations + self._target = target self.fill_very_end = fill_very_end def _pad( diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py index cd0514d81..96c0eb967 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py @@ -17,15 +17,14 @@ import itertools import qiskit -from qiskit.circuit import Bit +from qiskit.circuit import Bit, Barrier, Clbit, ControlFlowOp, Measure, Qubit, Reset from qiskit.circuit.parameterexpression import ParameterExpression from qiskit.converters import circuit_to_dag -from qiskit.transpiler.basepasses import TransformationPass -from qiskit.transpiler.passes.scheduling.time_unit_conversion import TimeUnitConversion - -from qiskit.circuit import Barrier, Clbit, ControlFlowOp, Measure, Qubit, Reset from qiskit.dagcircuit import DAGCircuit, DAGNode +from qiskit.transpiler import Target from qiskit.transpiler.exceptions import TranspilerError +from qiskit.transpiler.basepasses import TransformationPass +from qiskit.transpiler.passes.scheduling.time_unit_conversion import TimeUnitConversion from .utils import BlockOrderingCallableType, block_order_op_nodes @@ -50,8 +49,9 @@ class BaseDynamicCircuitAnalysis(TransformationPass): def __init__( self, - durations: qiskit.transpiler.instruction_durations.InstructionDurations, + durations: Optional[qiskit.transpiler.instruction_durations.InstructionDurations] = None, block_ordering_callable: Optional[BlockOrderingCallableType] = None, + target: Optional[Target] = None, ) -> None: """Scheduler for dynamic circuit backends. @@ -62,6 +62,7 @@ def __init__( used. """ self._durations = durations + self._target = target self._block_ordering_callable = ( block_order_op_nodes if block_ordering_callable is None else block_ordering_callable ) @@ -201,7 +202,7 @@ def _init_run(self, dag: DAGCircuit) -> None: self._node_tied_to = {} self._bit_indices = {q: index for index, q in enumerate(dag.qubits)} - def _get_duration(self, node: DAGNode, dag: Optional[DAGCircuit] = None) -> int: + def _get_duration(self, node: DAGNode) -> int: if isinstance(node.op, ControlFlowOp): # As we cannot currently schedule through conditionals model # as zero duration to avoid padding. @@ -209,10 +210,25 @@ def _get_duration(self, node: DAGNode, dag: Optional[DAGCircuit] = None) -> int: indices = [self._bit_indices[qarg] for qarg in self._map_qubits(node)] - # Fall back to current block dag if not specified. - dag = dag or self._block_dag - - duration = self._durations.get(node.op, indices, unit="dt") + if node.name == "delay": + duration = node.op.duration + elif node.name == "barrier": + duration = 0 + elif self._target: + props_dict = self._target.get(node.name) + if not props_dict: + duration = None + else: + props = props_dict.get(tuple(indices)) + if not props: + duration = None + else: + if self._target.dt is None: + duration = props.duration + else: + duration = self._target.seconds_to_dt(props.duration) + else: + duration = self._durations.get(node.op, indices, unit="dt") if isinstance(duration, ParameterExpression): raise TranspilerError( @@ -383,12 +399,7 @@ def _visit_measure(self, node: DAGNode) -> None: for measure in self._current_block_measures: t0 = t0q # pylint: disable=invalid-name - bit_indices = {bit: index for index, bit in enumerate(self._block_dag.qubits)} - measure_duration = self._durations.get( - Measure(), - [bit_indices[qarg] for qarg in self._map_qubits(measure)], - unit="dt", - ) + measure_duration = self._get_duration(measure) t1 = t0 + measure_duration # pylint: disable=invalid-name self._update_bit_times(measure, t0, t1) @@ -514,12 +525,7 @@ def _visit_measure(self, node: DAGNode) -> None: for measure in self._current_block_measures: t0 = t0q # pylint: disable=invalid-name - bit_indices = {bit: index for index, bit in enumerate(self._block_dag.qubits)} - measure_duration = self._durations.get( - Measure(), - [bit_indices[qarg] for qarg in self._map_qubits(measure)], - unit="dt", - ) + measure_duration = self._get_duration(measure) t1 = t0 + measure_duration # pylint: disable=invalid-name self._update_bit_times(measure, t0, t1) @@ -573,7 +579,7 @@ def order_ops(item: Tuple[DAGNode, Tuple[int, int]]) -> Tuple[int, int, bool, in item[1][0], -item[1][1], not isinstance(item[0].op, Barrier), - self._get_duration(item[0], dag=self._block_idx_dag_map[item[1][0]]), + self._get_duration(item[0]), ) iterate_nodes = sorted(self._node_stop_time.items(), key=order_ops) @@ -606,7 +612,7 @@ def _update_time( new_node_start_time[node] = (block, new_time) new_node_stop_time[node] = ( block, - new_time + self._get_duration(node, dag=self._block_idx_dag_map[block]), + new_time + self._get_duration(node), ) # Update available times by bit diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/utils.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/utils.py index 514d7e119..f348230b7 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/utils.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/utils.py @@ -156,6 +156,14 @@ def __init__( enable_patching: bool = True, ): """Dynamic circuit instruction durations.""" + warnings.warn( + "The DynamicCircuitInstructionDurations class is deprecated as of qiskit_ibm_runtime v0.42.0 " + "and will be removed in a future release. If you are using one of the scheduling passes defined " + "in qiskit_ibm_runtime, provide a `target` instance instead. ex: PadDelay(target=backend.target).", + DeprecationWarning, + stacklevel=2, + ) + self._enable_patching = enable_patching super().__init__(instruction_durations=instruction_durations, dt=dt) diff --git a/test/ibm_test_case.py b/test/ibm_test_case.py index 1bb8208c8..e027ad219 100644 --- a/test/ibm_test_case.py +++ b/test/ibm_test_case.py @@ -49,6 +49,16 @@ def setUpClass(cls): filename = "%s.log" % os.path.splitext(inspect.getfile(cls))[0] setup_test_logging(cls.log, filename) cls._set_logging_level(logging.getLogger(QISKIT_IBM_RUNTIME_LOGGER_NAME)) + + # ignore deprecation warnings for .unit and .duration coming from qiskit + # as no suitable migration alternative has been found yet + warnings.filterwarnings( + "ignore", + category=DeprecationWarning, + message=r"The property " + "``qiskit\.dagcircuit\.dagcircuit\.DAGCircuit\.(unit|duration)`` is deprecated", + ) + # fail test on deprecation warnings from qiskit warnings.filterwarnings("error", category=DeprecationWarning, module=r"^qiskit$") diff --git a/test/unit/transpiler/passes/scheduling/test_dynamical_decoupling.py b/test/unit/transpiler/passes/scheduling/test_dynamical_decoupling.py index b5f344bdf..666ce9245 100644 --- a/test/unit/transpiler/passes/scheduling/test_dynamical_decoupling.py +++ b/test/unit/transpiler/passes/scheduling/test_dynamical_decoupling.py @@ -15,10 +15,12 @@ import numpy as np from numpy import pi -from ddt import ddt, data -from qiskit.circuit import QuantumCircuit, Delay +from ddt import ddt, data, unpack +from qiskit.circuit import QuantumCircuit, Delay, Parameter from qiskit.circuit.library import XGate, YGate, RXGate, UGate +from qiskit.circuit.library import Measure, Reset, CXGate, RZGate, HGate from qiskit.quantum_info import Operator +from qiskit.transpiler import Target, InstructionProperties from qiskit.transpiler.passmanager import PassManager from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.coupling import CouplingMap @@ -75,24 +77,76 @@ def setUp(self): ("reset", None, 1340), ] ) - + self.target = Target(num_qubits=5, dt=1) + self.target.add_instruction( + XGate(), + {(i,): InstructionProperties(duration=50) for i in range(5)}, + ) + self.target.add_instruction( + HGate(), + {(i,): InstructionProperties(duration=50) for i in range(5)}, + ) + self.target.add_instruction( + CXGate(), + { + (0, 1): InstructionProperties(duration=700), + (1, 2): InstructionProperties(duration=200), + (2, 3): InstructionProperties(duration=300), + }, + ) + self.target.add_instruction( + YGate(), + {(i,): InstructionProperties(duration=50) for i in range(5)}, + ) + self.target.add_instruction( + UGate(Parameter("theta"), Parameter("phi"), Parameter("lambda")), + {(i,): InstructionProperties(duration=100) for i in range(5)}, + ) + self.target.add_instruction( + RXGate(Parameter("phi")), + {(i,): InstructionProperties(duration=100) for i in range(5)}, + ) + self.target.add_instruction( + Measure(), + {(i,): InstructionProperties(duration=1000) for i in range(5)}, + ) + self.target.add_instruction( + Reset(), + {(i,): InstructionProperties(duration=1000) for i in range(5)}, + ) self.coupling_map = CouplingMap([[0, 1], [1, 2], [2, 3]]) - def test_insert_dd_ghz(self): + @data(True, False) + def test_insert_dd_ghz(self, use_target): """Test DD gates are inserted in correct spots.""" dd_sequence = [XGate(), XGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - pulse_alignment=1, - sequence_min_length_ratios=[1.0], - schedule_idle_qubits=True, - ), - ] - ) + + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + pulse_alignment=1, + sequence_min_length_ratios=[1.0], + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + pulse_alignment=1, + sequence_min_length_ratios=[1.0], + schedule_idle_qubits=True, + ), + ] + ) ghz4_dd = pm.run(self.ghz4) @@ -115,8 +169,9 @@ def test_insert_dd_ghz(self): self.assertEqual(ghz4_dd, expected) - @data(True, False) - def test_insert_dd_ghz_one_qubit(self, use_topological_ordering): + @data([(True, False), (True, False)]) + @unpack + def test_insert_dd_ghz_one_qubit(self, use_topological_ordering, use_target): """Test DD gates are inserted on only one qubit.""" dd_sequence = [XGate(), XGate()] @@ -129,22 +184,40 @@ def _top_ord(dag): else: block_ordering_callable = None - pm = PassManager( - [ - ASAPScheduleAnalysis( - durations=self.durations, - block_ordering_callable=block_ordering_callable, - ), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - qubits=[0], - pulse_alignment=1, - schedule_idle_qubits=True, - block_ordering_callable=block_ordering_callable, - ), - ] - ) + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis( + target=self.target, + block_ordering_callable=block_ordering_callable, + ), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + qubits=[0], + pulse_alignment=1, + schedule_idle_qubits=True, + block_ordering_callable=block_ordering_callable, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis( + durations=self.durations, + block_ordering_callable=block_ordering_callable, + ), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + qubits=[0], + pulse_alignment=1, + schedule_idle_qubits=True, + block_ordering_callable=block_ordering_callable, + ), + ] + ) ghz4_dd = pm.run(self.ghz4.measure_all(inplace=False)) @@ -165,22 +238,39 @@ def _top_ord(dag): self.assertEqual(ghz4_dd, expected) - def test_insert_dd_ghz_everywhere(self): + @data(True, False) + def test_insert_dd_ghz_everywhere(self, use_target): """Test DD gates even on initial idle spots.""" dd_sequence = [YGate(), YGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - skip_reset_qubits=False, - pulse_alignment=1, - sequence_min_length_ratios=[0.0], - schedule_idle_qubits=True, - ), - ] - ) + + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + skip_reset_qubits=False, + pulse_alignment=1, + sequence_min_length_ratios=[0.0], + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + skip_reset_qubits=False, + pulse_alignment=1, + sequence_min_length_ratios=[0.0], + schedule_idle_qubits=True, + ), + ] + ) ghz4_dd = pm.run(self.ghz4) @@ -213,21 +303,36 @@ def test_insert_dd_ghz_everywhere(self): self.assertEqual(ghz4_dd, expected) - def test_insert_dd_ghz_xy4(self): + @data(True, False) + def test_insert_dd_ghz_xy4(self, use_target): """Test XY4 sequence of DD gates.""" dd_sequence = [XGate(), YGate(), XGate(), YGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - pulse_alignment=1, - sequence_min_length_ratios=[1.0], - schedule_idle_qubits=True, - ), - ] - ) + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + pulse_alignment=1, + sequence_min_length_ratios=[1.0], + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + pulse_alignment=1, + sequence_min_length_ratios=[1.0], + schedule_idle_qubits=True, + ), + ] + ) ghz4_dd = pm.run(self.ghz4) @@ -258,8 +363,9 @@ def test_insert_dd_ghz_xy4(self): self.assertEqual(ghz4_dd, expected) - @data(True, False) - def test_insert_midmeas_hahn(self, use_topological_ordering): + @data([(True, False), (True, False)]) + @unpack + def test_insert_midmeas_hahn(self, use_topological_ordering, use_target): """Test a single X gate as Hahn echo can absorb in the upstream circuit.""" dd_sequence = [RXGate(pi / 4)] @@ -272,21 +378,37 @@ def _top_ord(dag): else: block_ordering_callable = None - pm = PassManager( - [ - ASAPScheduleAnalysis( - durations=self.durations, - block_ordering_callable=block_ordering_callable, - ), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - pulse_alignment=1, - schedule_idle_qubits=True, - block_ordering_callable=block_ordering_callable, - ), - ] - ) + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis( + target=self.target, block_ordering_callable=block_ordering_callable + ), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + pulse_alignment=1, + schedule_idle_qubits=True, + block_ordering_callable=block_ordering_callable, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis( + durations=self.durations, + block_ordering_callable=block_ordering_callable, + ), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + pulse_alignment=1, + schedule_idle_qubits=True, + block_ordering_callable=block_ordering_callable, + ), + ] + ) midmeas_dd = pm.run(self.midmeas) @@ -314,7 +436,8 @@ def _top_ord(dag): ) ) - def test_insert_ghz_uhrig(self): + @data(True, False) + def test_insert_ghz_uhrig(self, use_target): """Test custom spacing (following Uhrig DD [1]). [1] Uhrig, G. "Keeping a quantum bit alive by optimized π-pulse sequences." Physical Review Letters 98.10 (2007): 100504.""" @@ -331,20 +454,36 @@ def uhrig(k): spacing.append(uhrig(k) - sum(spacing)) spacing.append(1 - sum(spacing)) - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - qubits=[0], - spacings=spacing, - sequence_min_length_ratios=[0.0], - pulse_alignment=1, - schedule_idle_qubits=True, - ), - ] - ) + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + qubits=[0], + spacings=spacing, + sequence_min_length_ratios=[0.0], + pulse_alignment=1, + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + qubits=[0], + spacings=spacing, + sequence_min_length_ratios=[0.0], + pulse_alignment=1, + schedule_idle_qubits=True, + ), + ] + ) ghz4_dd = pm.run(self.ghz4) @@ -375,22 +514,38 @@ def uhrig(k): self.assertEqual(ghz4_dd, expected) - def test_asymmetric_xy4_in_t2(self): + @data(True, False) + def test_asymmetric_xy4_in_t2(self, use_target): """Test insertion of XY4 sequence with unbalanced spacing.""" dd_sequence = [XGate(), YGate()] * 2 spacing = [0] + [1 / 4] * 4 - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - pulse_alignment=1, - spacings=spacing, - schedule_idle_qubits=True, - ), - ] - ) + + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + pulse_alignment=1, + spacings=spacing, + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + pulse_alignment=1, + spacings=spacing, + schedule_idle_qubits=True, + ), + ] + ) t2 = QuantumCircuit(1) t2.h(0) @@ -416,24 +571,42 @@ def test_asymmetric_xy4_in_t2(self): # check global phase is correct self.assertEqual(Operator(t2), Operator(expected)) - def test_dd_after_reset(self): + @data(True, False) + def test_dd_after_reset(self, use_target): """Test skip_reset_qubits option works.""" dd_sequence = [XGate(), XGate()] spacing = [0.1, 0.9] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - spacings=spacing, - skip_reset_qubits=True, - pulse_alignment=1, - sequence_min_length_ratios=[0.0], - schedule_idle_qubits=True, - ), - ] - ) + + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + spacings=spacing, + skip_reset_qubits=True, + pulse_alignment=1, + sequence_min_length_ratios=[0.0], + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + spacings=spacing, + skip_reset_qubits=True, + pulse_alignment=1, + sequence_min_length_ratios=[0.0], + schedule_idle_qubits=True, + ), + ] + ) t2 = QuantumCircuit(1) t2.reset(0) @@ -460,35 +633,61 @@ def test_dd_after_reset(self): self.assertEqual(t2_dd, expected) - def test_insert_dd_bad_sequence(self): + @data(True, False) + def test_insert_dd_bad_sequence(self, use_target): """Test DD raises when non-identity sequence is inserted.""" dd_sequence = [XGate(), YGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling(self.durations, dd_sequence, schedule_idle_qubits=True), - ] - ) - + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, schedule_idle_qubits=True, target=self.target + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling(self.durations, dd_sequence, schedule_idle_qubits=True), + ] + ) with self.assertRaises(TranspilerError): pm.run(self.ghz4) - def test_insert_dd_ghz_xy4_with_alignment(self): + @data(True, False) + def test_insert_dd_ghz_xy4_with_alignment(self, use_target): """Test DD with pulse alignment constraints.""" dd_sequence = [XGate(), YGate(), XGate(), YGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - pulse_alignment=10, - extra_slack_distribution="edges", - sequence_min_length_ratios=[1.0], - schedule_idle_qubits=True, - ), - ] - ) + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + pulse_alignment=10, + extra_slack_distribution="edges", + sequence_min_length_ratios=[1.0], + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + pulse_alignment=10, + extra_slack_distribution="edges", + sequence_min_length_ratios=[1.0], + schedule_idle_qubits=True, + ), + ] + ) ghz4_dd = pm.run(self.ghz4) @@ -519,7 +718,8 @@ def test_insert_dd_ghz_xy4_with_alignment(self): self.assertEqual(ghz4_dd, expected) - def test_dd_can_sequentially_called(self): + @data(True, False) + def test_dd_can_sequentially_called(self, use_target): """Test if sequentially called DD pass can output the same circuit. This test verifies: - if global phase is properly propagated from the previous padding node. @@ -527,50 +727,94 @@ def test_dd_can_sequentially_called(self): """ dd_sequence = [XGate(), YGate(), XGate(), YGate()] - pm1 = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, dd_sequence, qubits=[0], schedule_idle_qubits=True - ), - PadDynamicalDecoupling( - self.durations, dd_sequence, qubits=[1], schedule_idle_qubits=True - ), - ] - ) - circ1 = pm1.run(self.ghz4) + if use_target: + pm1 = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + qubits=[0], + schedule_idle_qubits=True, + target=self.target, + ), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + qubits=[1], + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + pm2 = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + qubits=[0, 1], + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm1 = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, dd_sequence, qubits=[0], schedule_idle_qubits=True + ), + PadDynamicalDecoupling( + self.durations, dd_sequence, qubits=[1], schedule_idle_qubits=True + ), + ] + ) + pm2 = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + qubits=[0, 1], + schedule_idle_qubits=True, + ), + ] + ) - pm2 = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - qubits=[0, 1], - schedule_idle_qubits=True, - ), - ] - ) + circ1 = pm1.run(self.ghz4) circ2 = pm2.run(self.ghz4) - self.assertEqual(circ1, circ2) - def test_back_to_back_if_test(self): + @data(True, False) + def test_back_to_back_if_test(self, use_target): """Test DD with if_test circuit back to back.""" dd_sequence = [XGate(), XGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - pulse_alignment=1, - sequence_min_length_ratios=[0.0], - schedule_idle_qubits=True, - ), - ] - ) + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + pulse_alignment=1, + sequence_min_length_ratios=[0.0], + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + pulse_alignment=1, + sequence_min_length_ratios=[0.0], + schedule_idle_qubits=True, + ), + ] + ) qc = QuantumCircuit(3, 1) qc.delay(800, 1) @@ -612,22 +856,38 @@ def test_back_to_back_if_test(self): self.assertEqual(expected, qc_dd) - def test_dd_if_test(self): + @data(True, False) + def test_dd_if_test(self, use_target): """Test DD with if_test circuit.""" dd_sequence = [XGate(), XGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - pulse_alignment=1, - sequence_min_length_ratios=[0.0], - schedule_idle_qubits=True, - ), - ] - ) + + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + pulse_alignment=1, + sequence_min_length_ratios=[0.0], + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + pulse_alignment=1, + sequence_min_length_ratios=[0.0], + schedule_idle_qubits=True, + ), + ] + ) qc = QuantumCircuit(3, 1) qc.measure(0, 0) @@ -688,7 +948,8 @@ def test_dd_if_test(self): self.assertEqual(expected, qc_dd) - def test_reproducible(self): + @data(True, False) + def test_reproducible(self, use_target): """Test DD calls are reproducible.""" qc = QuantumCircuit(3, 1) @@ -705,40 +966,75 @@ def test_reproducible(self): qc.x(2) dd_sequence = [XGate(), XGate()] - pm0 = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling(self.durations, dd_sequence, schedule_idle_qubits=True), - ] - ) - pm1 = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling(self.durations, dd_sequence, schedule_idle_qubits=True), - ] - ) + if use_target: + pm0 = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, schedule_idle_qubits=True, target=self.target + ), + ] + ) + pm1 = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, schedule_idle_qubits=True, target=self.target + ), + ] + ) + else: + pm0 = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling(self.durations, dd_sequence, schedule_idle_qubits=True), + ] + ) + + pm1 = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling(self.durations, dd_sequence, schedule_idle_qubits=True), + ] + ) qc_dd0 = pm0.run(qc) qc_dd1 = pm1.run(qc) self.assertEqual(qc_dd0, qc_dd1) - def test_nested_block_dd(self): + @data(True, False) + def test_nested_block_dd(self, use_target): """Test DD applied within a block.""" dd_sequence = [XGate(), XGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - pulse_alignment=1, - sequence_min_length_ratios=[0.0], - schedule_idle_qubits=True, - ), - ] - ) + + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + pulse_alignment=1, + sequence_min_length_ratios=[0.0], + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + pulse_alignment=1, + sequence_min_length_ratios=[0.0], + schedule_idle_qubits=True, + ), + ] + ) qc = QuantumCircuit(3, 1) qc.x(1) @@ -769,7 +1065,8 @@ def test_nested_block_dd(self): self.assertEqual(expected, qc_dd) - def test_multiple_dd_sequences(self): + @data(True, False) + def test_multiple_dd_sequences(self, use_target): """Test multiple DD sequence can be submitted""" qc = QuantumCircuit(2, 0) @@ -784,18 +1081,32 @@ def test_multiple_dd_sequences(self): [XGate(), XGate()], ] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - pulse_alignment=1, - sequence_min_length_ratios=[1.5, 0.0], - schedule_idle_qubits=True, - ), - ] - ) + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + pulse_alignment=1, + sequence_min_length_ratios=[1.5, 0.0], + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + pulse_alignment=1, + sequence_min_length_ratios=[1.5, 0.0], + schedule_idle_qubits=True, + ), + ] + ) qc_dd = pm.run(qc) @@ -850,7 +1161,8 @@ def test_multiple_dd_sequences(self): self.assertEqual(qc_dd, expected) - def test_multiple_dd_sequence_cycles(self): + @data(True, False) + def test_multiple_dd_sequence_cycles(self, use_target): """Test a single DD sequence can be inserted for multiple cycles in a single delay.""" qc = QuantumCircuit(1, 0) @@ -861,20 +1173,36 @@ def test_multiple_dd_sequence_cycles(self): [XGate(), XGate()], ] # cycle has length of 100 cycles - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - extra_slack_distribution="edges", - pulse_alignment=1, - sequence_min_length_ratios=[10.0], - insert_multiple_cycles=True, - schedule_idle_qubits=True, - ), - ] - ) + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + extra_slack_distribution="edges", + pulse_alignment=1, + sequence_min_length_ratios=[10.0], + insert_multiple_cycles=True, + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + extra_slack_distribution="edges", + pulse_alignment=1, + sequence_min_length_ratios=[10.0], + insert_multiple_cycles=True, + schedule_idle_qubits=True, + ), + ] + ) qc_dd = pm.run(qc) @@ -892,21 +1220,37 @@ def test_multiple_dd_sequence_cycles(self): expected.delay(225, 0) self.assertEqual(qc_dd, expected) - def test_staggered_dd(self): + @data(True, False) + def test_staggered_dd(self, use_target): """Test that timing on DD can be staggered if coupled with each other""" dd_sequence = [XGate(), XGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - coupling_map=self.coupling_map, - alt_spacings=[0.1, 0.8, 0.1], - schedule_idle_qubits=True, - ), - ] - ) + + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + coupling_map=self.coupling_map, + alt_spacings=[0.1, 0.8, 0.1], + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + coupling_map=self.coupling_map, + alt_spacings=[0.1, 0.8, 0.1], + schedule_idle_qubits=True, + ), + ] + ) qc_barriers = QuantumCircuit(4, 1) qc_barriers.x(0) @@ -953,23 +1297,41 @@ def test_staggered_dd(self): self.assertEqual(qc_dd, expected) - def test_staggered_dd_multiple_cycles(self): + @data(True, False) + def test_staggered_dd_multiple_cycles(self, use_target): """Test staggered DD with multiple cycles in a single delay""" dd_sequence = [XGate(), XGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - coupling_map=self.coupling_map, - alt_spacings=[0.1, 0.8, 0.1], - sequence_min_length_ratios=[4.0], - insert_multiple_cycles=True, - schedule_idle_qubits=True, - ), - ] - ) + + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + coupling_map=self.coupling_map, + alt_spacings=[0.1, 0.8, 0.1], + sequence_min_length_ratios=[4.0], + insert_multiple_cycles=True, + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + coupling_map=self.coupling_map, + alt_spacings=[0.1, 0.8, 0.1], + sequence_min_length_ratios=[4.0], + insert_multiple_cycles=True, + schedule_idle_qubits=True, + ), + ] + ) qc_barriers = QuantumCircuit(3, 1) qc_barriers.x(0) @@ -1016,60 +1378,103 @@ def test_staggered_dd_multiple_cycles(self): expected.barrier() self.assertEqual(qc_dd, expected) - def test_insert_dd_bad_spacings(self): + @data(True, False) + def test_insert_dd_bad_spacings(self, use_target): """Test DD raises when spacings don't add up to 1.""" dd_sequence = [XGate(), XGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - spacings=[0.1, 0.9, 0.1], - coupling_map=self.coupling_map, - ), - ] - ) + + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + spacings=[0.1, 0.9, 0.1], + coupling_map=self.coupling_map, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + spacings=[0.1, 0.9, 0.1], + coupling_map=self.coupling_map, + ), + ] + ) with self.assertRaises(TranspilerError): pm.run(self.ghz4) - def test_insert_dd_bad_alt_spacings(self): + @data(True, False) + def test_insert_dd_bad_alt_spacings(self, use_target): """Test DD raises when alt_spacings don't add up to 1.""" dd_sequence = [XGate(), XGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - alt_spacings=[0.1, 0.9, 0.1], - coupling_map=self.coupling_map, - ), - ] - ) + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + alt_spacings=[0.1, 0.9, 0.1], + coupling_map=self.coupling_map, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + alt_spacings=[0.1, 0.9, 0.1], + coupling_map=self.coupling_map, + ), + ] + ) with self.assertRaises(TranspilerError): pm.run(self.ghz4) - def test_unsupported_coupling_map(self): + @data(True, False) + def test_unsupported_coupling_map(self, use_target): """Test DD raises if coupling map is not supported.""" dd_sequence = [XGate(), XGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - coupling_map=CouplingMap([[0, 1], [0, 2], [1, 2], [2, 3]]), - ), - ] - ) + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + coupling_map=CouplingMap([[0, 1], [0, 2], [1, 2], [2, 3]]), + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + coupling_map=CouplingMap([[0, 1], [0, 2], [1, 2], [2, 3]]), + ), + ] + ) with self.assertRaises(TranspilerError): pm.run(self.ghz4) - def test_disjoint_coupling_map(self): + @data(True, False) + def test_disjoint_coupling_map(self, use_target): """Test staggered DD with disjoint coupling map.""" qc = QuantumCircuit(5) for q in range(5): @@ -1079,17 +1484,31 @@ def test_disjoint_coupling_map(self): qc.delay(1600, q) qc.barrier() dd_sequence = [XGate(), XGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - coupling_map=CouplingMap([[0, 1], [1, 2], [3, 4]]), - schedule_idle_qubits=True, - ), - ] - ) + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + coupling_map=CouplingMap([[0, 1], [1, 2], [3, 4]]), + schedule_idle_qubits=True, + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + coupling_map=CouplingMap([[0, 1], [1, 2], [3, 4]]), + schedule_idle_qubits=True, + ), + ] + ) + dd_qc = pm.run(qc) # ensure that delays for nearest neighbors are staggered @@ -1103,7 +1522,8 @@ def test_disjoint_coupling_map(self): self.assertNotEqual(delay_dict[3], delay_dict[4]) self.assertEqual(delay_dict[0], delay_dict[2]) - def test_no_unused_qubits(self): + @data(True, False) + def test_no_unused_qubits(self, use_target): """Test DD with if_test circuit that unused qubits are untouched and not scheduled. Unused qubits may also have missing durations when not operational. @@ -1112,30 +1532,66 @@ def test_no_unused_qubits(self): Which might hurt performance in later execution stages. """ - # Here "x" on qubit 3 is not defined - durations = DynamicCircuitInstructionDurations( - [ - ("h", 0, 50), - ("x", 0, 50), - ("x", 1, 50), - ("x", 2, 50), - ("measure", 0, 840), - ("reset", 0, 1340), - ] - ) - dd_sequence = [XGate(), XGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - durations, - dd_sequence, - pulse_alignment=1, - sequence_min_length_ratios=[0.0], - ), - ] - ) + + if use_target: + target = Target(num_qubits=5, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=50), + (1,): InstructionProperties(duration=50), + (2,): InstructionProperties(duration=50), + }, + ) + target.add_instruction( + HGate(), + {(i,): InstructionProperties(duration=50) for i in range(5)}, + ) + target.add_instruction( + Measure(), + {(i,): InstructionProperties(duration=1000) for i in range(5)}, + ) + target.add_instruction( + Reset(), + {(i,): InstructionProperties(duration=1000) for i in range(5)}, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + pulse_alignment=1, + sequence_min_length_ratios=[0.0], + target=self.target, + ), + ] + ) + else: + # Here "x" on qubit 3 is not defined + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [ + ("h", 0, 50), + ("x", 0, 50), + ("x", 1, 50), + ("x", 2, 50), + ("measure", 0, 840), + ("reset", 0, 1340), + ] + ) + + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + durations, + dd_sequence, + pulse_alignment=1, + sequence_min_length_ratios=[0.0], + ), + ] + ) qc = QuantumCircuit(4, 1) qc.measure(0, 0) @@ -1148,21 +1604,35 @@ def test_no_unused_qubits(self): for op in qc_dd.data: self.assertNotIn(dont_use, op.qubits) - def test_dd_named_barriers(self): + @data(True, False) + def test_dd_named_barriers(self, use_target): """Test DD applied on delays ending on named barriers.""" dd_sequence = [XGate(), XGate()] - pm = PassManager( - [ - ASAPScheduleAnalysis(self.durations), - PadDynamicalDecoupling( - self.durations, - dd_sequence, - pulse_alignment=1, - dd_barrier="dd", - ), - ] - ) + if use_target: + pm = PassManager( + [ + ASAPScheduleAnalysis(target=self.target), + PadDynamicalDecoupling( + dd_sequences=dd_sequence, + pulse_alignment=1, + dd_barrier="dd", + target=self.target, + ), + ] + ) + else: + pm = PassManager( + [ + ASAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling( + self.durations, + dd_sequence, + pulse_alignment=1, + dd_barrier="dd", + ), + ] + ) qc = QuantumCircuit(2, 2) qc.h(0) diff --git a/test/unit/transpiler/passes/scheduling/test_scheduler.py b/test/unit/transpiler/passes/scheduling/test_scheduler.py index 51d3fc7f2..d18a1bb69 100644 --- a/test/unit/transpiler/passes/scheduling/test_scheduler.py +++ b/test/unit/transpiler/passes/scheduling/test_scheduler.py @@ -12,11 +12,15 @@ """Test the dynamic circuits scheduling analysis""" +from ddt import ddt, data + from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister, transpile -from qiskit.transpiler.passmanager import PassManager -from qiskit.transpiler.exceptions import TranspilerError +from qiskit.circuit import Delay, Parameter +from qiskit.circuit.library import XGate, Measure, Reset, CXGate, RZGate from qiskit.converters import circuit_to_dag -from qiskit.circuit import Delay +from qiskit.transpiler.exceptions import TranspilerError +from qiskit.transpiler.passmanager import PassManager +from qiskit.transpiler.target import Target, InstructionProperties from qiskit_ibm_runtime.fake_provider import FakeJakartaV2 from qiskit_ibm_runtime.transpiler.passes.scheduling.pad_delay import PadDelay @@ -33,10 +37,12 @@ # pylint: disable=invalid-name,not-context-manager +@ddt class TestASAPSchedulingAndPaddingPass(IBMTestCase): """Tests the ASAP Scheduling passes""" - def test_if_test_gate_after_measure(self): + @data(True, False) + def test_if_test_gate_after_measure(self, use_target): """Test if schedules circuits with if_test after measure with a common clbit. See: https://github.com/Qiskit/qiskit-terra/issues/7654""" qc = QuantumCircuit(2, 1) @@ -46,13 +52,40 @@ def test_if_test_gate_after_measure(self): with else_: qc.x(0) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) + scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) @@ -67,7 +100,8 @@ def test_if_test_gate_after_measure(self): self.assertEqual(expected, scheduled) - def test_measure_after_measure(self): + @data(True, False) + def test_measure_after_measure(self, use_target): """Test if schedules circuits with measure after measure with a common clbit. Note: There is no delay to write into the same clbit with IBM backends.""" @@ -76,13 +110,39 @@ def test_measure_after_measure(self): qc.measure(0, 0) qc.measure(1, 0) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) @@ -92,7 +152,8 @@ def test_measure_after_measure(self): expected.measure(1, 0) self.assertEqual(expected, scheduled) - def test_measure_block_not_end(self): + @data(True, False) + def test_measure_block_not_end(self, use_target): """Tests that measures trigger do not trigger the end of a scheduling block.""" qc = QuantumCircuit(3, 1) qc.x(0) @@ -102,13 +163,41 @@ def test_measure_block_not_end(self): qc.measure(1, 0) qc.measure(2, 0) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -124,7 +213,8 @@ def test_measure_block_not_end(self): self.assertEqual(expected, scheduled) - def test_reset_block_end(self): + @data(True, False) + def test_reset_block_end(self, use_target): """Tests that measures trigger do trigger the end of a scheduling block.""" qc = QuantumCircuit(3, 1) qc.x(0) @@ -134,15 +224,49 @@ def test_reset_block_end(self): qc.measure(1, 0) qc.measure(2, 0) - durations = DynamicCircuitInstructionDurations( - [("x", None, 200), ("measure", None, 840), ("reset", None, 840)] - ) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + target.add_instruction( + Reset(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840), ("reset", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -159,7 +283,8 @@ def test_reset_block_end(self): self.assertEqual(expected, scheduled) - def test_if_test_on_different_qubits(self): + @data(True, False) + def test_if_test_on_different_qubits(self, use_target): """Test if schedules circuits with `if_test`s on different qubits.""" qc = QuantumCircuit(3, 1) qc.measure(0, 0) @@ -167,13 +292,41 @@ def test_if_test_on_different_qubits(self): qc.x(1) qc.x(2) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -188,7 +341,8 @@ def test_if_test_on_different_qubits(self): self.assertEqual(expected, scheduled) - def test_shorter_measure_after_measure(self): + @data(True, False) + def test_shorter_measure_after_measure(self, use_target): """Test if schedules circuits with shorter measure after measure with a common clbit. @@ -198,15 +352,32 @@ def test_shorter_measure_after_measure(self): qc.measure(0, 0) qc.measure(1, 0) - durations = DynamicCircuitInstructionDurations( - [("measure", [0], 840), ("measure", [1], 540)] - ) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=700), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("measure", [0], 840), ("measure", [1], 540)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -217,7 +388,8 @@ def test_shorter_measure_after_measure(self): self.assertEqual(expected, scheduled) - def test_measure_after_if_test(self): + @data(True, False) + def test_measure_after_if_test(self, use_target): """Test if schedules circuits with if_test after measure with a common clbit.""" qc = QuantumCircuit(3, 1) qc.measure(0, 0) @@ -225,13 +397,49 @@ def test_measure_after_if_test(self): qc.x(1) qc.measure(2, 0) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + target.add_instruction( + Reset(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840), ("reset", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -251,7 +459,8 @@ def test_measure_after_if_test(self): self.assertEqual(expected, scheduled) - def test_parallel_gate_different_length(self): + @data(True, False) + def test_parallel_gate_different_length(self, use_target): """Test circuit having two parallel instruction with different length.""" qc = QuantumCircuit(2, 2) qc.x(0) @@ -259,16 +468,39 @@ def test_parallel_gate_different_length(self): qc.measure(0, 0) qc.measure(1, 1) - durations = DynamicCircuitInstructionDurations( - [("x", [0], 200), ("x", [1], 400), ("measure", None, 840)] - ) - - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=400), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", [0], 200), ("x", [1], 400), ("measure", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 2) @@ -280,7 +512,8 @@ def test_parallel_gate_different_length(self): self.assertEqual(scheduled, expected) - def test_parallel_gate_different_length_with_barrier(self): + @data(True, False) + def test_parallel_gate_different_length_with_barrier(self, use_target): """Test circuit having two parallel instruction with different length with barrier.""" qc = QuantumCircuit(2, 2) qc.x(0) @@ -289,16 +522,40 @@ def test_parallel_gate_different_length_with_barrier(self): qc.measure(0, 0) qc.measure(1, 1) - durations = DynamicCircuitInstructionDurations( - [("x", [0], 200), ("x", [1], 400), ("measure", None, 840)] - ) - - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=400), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", [0], 200), ("x", [1], 400), ("measure", None, 840)] + ) + + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 2) @@ -311,7 +568,8 @@ def test_parallel_gate_different_length_with_barrier(self): self.assertEqual(scheduled, expected) - def test_active_reset_circuit(self): + @data(True, False) + def test_active_reset_circuit(self, use_target): """Test practical example of reset circuit. Because of the stimulus pulse overlap with the previous XGate on the q register, @@ -328,14 +586,38 @@ def test_active_reset_circuit(self): with qc.if_test((0, 1)): qc.x(0) - durations = DynamicCircuitInstructionDurations([("x", None, 100), ("measure", None, 840)]) - - scheduled = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ).run(qc) + if use_target: + target = Target(num_qubits=1, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=100), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 100), ("measure", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) + scheduled = pm.run(qc) expected = QuantumCircuit(1, 1) expected.measure(0, 0) @@ -351,7 +633,8 @@ def test_active_reset_circuit(self): self.assertEqual(expected, scheduled) - def test_dag_introduces_extra_dependency_between_conditionals(self): + @data(True, False) + def test_dag_introduces_extra_dependency_between_conditionals(self, use_target): """Test dependency between conditional operations in the scheduling. In the below example circuit, the conditional x on q1 could start at time 0, @@ -366,13 +649,30 @@ def test_dag_introduces_extra_dependency_between_conditionals(self): with qc.if_test((0, 1)): qc.x(1) - durations = DynamicCircuitInstructionDurations([("x", None, 160)]) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=160), + (1,): InstructionProperties(duration=160), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations([("x", None, 160)]) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) @@ -388,18 +688,27 @@ def test_dag_introduces_extra_dependency_between_conditionals(self): self.assertEqual(expected, scheduled) - def test_padding_not_working_without_scheduling(self): + @data(True, False) + def test_padding_not_working_without_scheduling(self, use_target): """Test padding fails when un-scheduled DAG is input.""" qc = QuantumCircuit(1, 1) qc.delay(100, 0) qc.x(0) qc.measure(0, 0) - durations = DynamicCircuitInstructionDurations() - with self.assertRaises(TranspilerError): - PassManager(PadDelay(durations)).run(qc) + if use_target: + target = Target(num_qubits=2, dt=1) + with self.assertRaises(TranspilerError): + PassManager(PadDelay(target=target)).run(qc) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations() + + with self.assertRaises(TranspilerError): + PassManager(PadDelay(durations)).run(qc) - def test_no_pad_very_end_of_circuit(self): + @data(True, False) + def test_no_pad_very_end_of_circuit(self, use_target): """Test padding option that inserts no delay at the very end of circuit. This circuit will be unchanged after scheduling/padding.""" @@ -408,20 +717,48 @@ def test_no_pad_very_end_of_circuit(self): qc.x(1) qc.measure(0, 0) - durations = DynamicCircuitInstructionDurations([("x", None, 160), ("measure", None, 840)]) - - scheduled = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, fill_very_end=False, schedule_idle_qubits=True), - ] - ).run(qc) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=160), + (1,): InstructionProperties(duration=160), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, fill_very_end=False, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 160), ("measure", None, 840)] + ) + + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, fill_very_end=False, schedule_idle_qubits=True), + ] + ) + scheduled = pm.run(qc) expected = qc.copy() self.assertEqual(expected, scheduled) - def test_reset_terminates_block(self): + @data(True, False) + def test_reset_terminates_block(self, use_target): """Test if reset operations terminate the block scheduled. Note: For dynamic circuits support we currently group resets @@ -432,29 +769,62 @@ def test_reset_terminates_block(self): qc.measure(1, 0) qc.x(0) - durations = DynamicCircuitInstructionDurations( - [ - ("x", None, 200), - ( - "reset", - [0], - 840, - ), # ignored as only the duration of the measurement is used for scheduling - ( - "reset", - [1], - 740, - ), # ignored as only the duration of the measurement is used for scheduling - ("measure", [0], 440), - ("measure", [1], 540), - ] - ) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=600), + (1,): InstructionProperties(duration=700), + }, + ) + target.add_instruction( + Reset(), + { + # when using DynamicCircuitInstructionDurations, + # the duration of "reset" gets replaced with "measure" + (0,): InstructionProperties(duration=600), + (1,): InstructionProperties(duration=700), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [ + ("x", None, 200), + ( + "reset", + [0], + 840, + ), # ignored as only the duration of the measurement is used for scheduling + ( + "reset", + [1], + 740, + ), # ignored as only the duration of the measurement is used for scheduling + ("measure", [0], 440), + ("measure", [1], 540), + ] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -471,7 +841,8 @@ def test_reset_terminates_block(self): self.assertEqual(expected, scheduled) - def test_reset_merged_with_measure(self): + @data(True, False) + def test_reset_merged_with_measure(self, use_target): """Test if reset operations terminate the block scheduled. Note: For dynamic circuits support we currently group resets to start @@ -481,29 +852,62 @@ def test_reset_merged_with_measure(self): qc.reset(0) qc.measure(1, 0) - durations = DynamicCircuitInstructionDurations( - [ - ("x", None, 200), - ( - "reset", - [0], - 840, - ), # ignored as only the duration of the measurement is used for scheduling - ( - "reset", - [1], - 740, - ), # ignored as only the duration of the measurement is used for scheduling - ("measure", [0], 440), - ("measure", [1], 540), - ] - ) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=600), + (1,): InstructionProperties(duration=700), + }, + ) + target.add_instruction( + Reset(), + { + # when using DynamicCircuitInstructionDurations, + # the duration of "reset" gets replaced with "measure" + (0,): InstructionProperties(duration=600), + (1,): InstructionProperties(duration=700), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [ + ("x", None, 200), + ( + "reset", + [0], + 840, + ), # ignored as only the duration of the measurement is used for scheduling + ( + "reset", + [1], + 740, + ), # ignored as only the duration of the measurement is used for scheduling + ("measure", [0], 440), + ("measure", [1], 540), + ] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -516,7 +920,8 @@ def test_reset_merged_with_measure(self): self.assertEqual(expected, scheduled) - def test_scheduling_is_idempotent(self): + @data(True, False) + def test_scheduling_is_idempotent(self, use_target): """Test that padding can be applied back to back without changing the circuit.""" qc = QuantumCircuit(3, 2) qc.x(2) @@ -532,40 +937,94 @@ def test_scheduling_is_idempotent(self): with qc.if_test((0, 1)): qc.x(0) - durations = DynamicCircuitInstructionDurations( - [("x", None, 100), ("measure", None, 840), ("cx", None, 500)] - ) - - scheduled0 = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ).run(qc) - - scheduled1 = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ).run(scheduled0) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=100), + (1,): InstructionProperties(duration=100), + (2,): InstructionProperties(duration=100), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + target.add_instruction( + CXGate(), + { + (0, 1): InstructionProperties(duration=500), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 100), ("measure", None, 840), ("cx", None, 500)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) + + scheduled0 = pm.run(qc) + + scheduled1 = pm.run(scheduled0) self.assertEqual(scheduled0, scheduled1) - def test_gate_on_measured_qubit(self): + @data(True, False) + def test_gate_on_measured_qubit(self, use_target): """Test that a gate on a previously measured qubit triggers the end of the block""" qc = QuantumCircuit(2, 1) qc.measure(0, 0) qc.x(0) qc.x(1) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) @@ -576,7 +1035,8 @@ def test_gate_on_measured_qubit(self): self.assertEqual(expected, scheduled) - def test_grouped_measurements_prior_control_flow(self): + @data(True, False) + def test_grouped_measurements_prior_control_flow(self, use_target): """Test that measurements are grouped prior to control-flow""" qc = QuantumCircuit(3, 3) qc.measure(0, 0) @@ -587,13 +1047,41 @@ def test_grouped_measurements_prior_control_flow(self): qc.x(2) qc.measure(2, 2) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 3) @@ -616,7 +1104,8 @@ def test_grouped_measurements_prior_control_flow(self): self.assertEqual(expected, scheduled) - def test_back_to_back_if_test(self): + @data(True, False) + def test_back_to_back_if_test(self, use_target): """Test back to back if_test scheduling""" qc = QuantumCircuit(3, 1) @@ -629,13 +1118,41 @@ def test_back_to_back_if_test(self): qc.delay(1000, 2) qc.x(1) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -659,7 +1176,8 @@ def test_back_to_back_if_test(self): self.assertEqual(expected, scheduled) - def test_nested_control_scheduling(self): + @data(True, False) + def test_nested_control_scheduling(self, use_target): """Test scheduling of nested control-flow""" qc = QuantumCircuit(4, 3) @@ -672,13 +1190,43 @@ def test_nested_control_scheduling(self): qc.measure(2, 2) qc.x(3) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=4, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + (3,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + (3,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(4, 3) @@ -712,7 +1260,8 @@ def test_nested_control_scheduling(self): self.assertEqual(expected, scheduled) - def test_while_loop(self): + @data(True, False) + def test_while_loop(self, use_target): """Test scheduling while loop""" qc = QuantumCircuit(2, 1) @@ -722,13 +1271,39 @@ def test_while_loop(self): qc.measure(0, 0) qc.x(0) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) @@ -743,7 +1318,8 @@ def test_while_loop(self): self.assertEqual(expected, scheduled) - def test_for_loop(self): + @data(True, False) + def test_for_loop(self, use_target): """Test scheduling for loop""" qc = QuantumCircuit(2, 1) @@ -753,13 +1329,39 @@ def test_for_loop(self): qc.measure(0, 0) qc.x(0) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) @@ -774,7 +1376,8 @@ def test_for_loop(self): self.assertEqual(expected, scheduled) - def test_registers(self): + @data(True, False) + def test_registers(self, use_target): """Verify scheduling works with registers.""" qr = QuantumRegister(1, name="q") cr = ClassicalRegister(1) @@ -782,13 +1385,39 @@ def test_registers(self): with qc.if_test((cr[0], True)): qc.x(qr[0]) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ASAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ASAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(qr, cr) @@ -798,6 +1427,7 @@ def test_registers(self): self.assertEqual(expected, scheduled) +@ddt class TestALAPSchedulingAndPaddingPass(IBMTestCase): """Tests the ALAP Scheduling passes""" @@ -810,19 +1440,48 @@ def get_delay_dict(self, circ): delay_dict[dag.find_bit(delay.qargs[0]).index] += [delay.op.duration] return delay_dict - def test_alap(self): + @data(True, False) + def test_alap(self, use_target): """Test standard ALAP scheduling""" - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) qc = QuantumCircuit(3, 1) qc.measure(0, 0) qc.x(1) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -833,7 +1492,8 @@ def test_alap(self): self.assertEqual(expected, scheduled) - def test_if_test_gate_after_measure(self): + @data(True, False) + def test_if_test_gate_after_measure(self, use_target): """Test if schedules circuits with if_test after measure with a common clbit. See: https://github.com/Qiskit/qiskit-terra/issues/7654""" qc = QuantumCircuit(2, 1) @@ -843,13 +1503,39 @@ def test_if_test_gate_after_measure(self): with else_: qc.x(0) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) @@ -864,7 +1550,8 @@ def test_if_test_gate_after_measure(self): self.assertEqual(expected, scheduled) - def test_classically_controlled_gate_after_measure(self): + @data(True, False) + def test_classically_controlled_gate_after_measure(self, use_target): """Test if schedules circuits with if_test after measure with a common clbit. See: https://github.com/Qiskit/qiskit-terra/issues/7654""" qc = QuantumCircuit(2, 1) @@ -872,13 +1559,39 @@ def test_classically_controlled_gate_after_measure(self): with qc.if_test((0, True)): qc.x(1) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) @@ -891,7 +1604,8 @@ def test_classically_controlled_gate_after_measure(self): self.assertEqual(expected, scheduled) - def test_measure_after_measure(self): + @data(True, False) + def test_measure_after_measure(self, use_target): """Test if schedules circuits with measure after measure with a common clbit. Note: There is no delay to write into the same clbit with IBM backends.""" @@ -900,13 +1614,39 @@ def test_measure_after_measure(self): qc.measure(0, 0) qc.measure(1, 0) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) @@ -917,7 +1657,8 @@ def test_measure_after_measure(self): self.assertEqual(expected, scheduled) - def test_measure_block_not_end(self): + @data(True, False) + def test_measure_block_not_end(self, use_target): """Tests that measures trigger do not trigger the end of a scheduling block.""" qc = QuantumCircuit(3, 1) qc.x(0) @@ -927,13 +1668,41 @@ def test_measure_block_not_end(self): qc.measure(1, 0) qc.measure(2, 0) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -949,7 +1718,8 @@ def test_measure_block_not_end(self): self.assertEqual(expected, scheduled) - def test_reset_block_end(self): + @data(True, False) + def test_reset_block_end(self, use_target): """Tests that measures trigger do trigger the end of a scheduling block.""" qc = QuantumCircuit(3, 1) qc.x(0) @@ -960,15 +1730,49 @@ def test_reset_block_end(self): qc.measure(2, 0) qc.measure(0, 0) - durations = DynamicCircuitInstructionDurations( - [("x", None, 200), ("measure", None, 840), ("reset", None, 840)] - ) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + target.add_instruction( + Reset(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -985,7 +1789,8 @@ def test_reset_block_end(self): self.assertEqual(expected, scheduled) - def test_if_test_on_different_qubits(self): + @data(True, False) + def test_if_test_on_different_qubits(self, use_target): """Test if schedules circuits with `if_test`s on different qubits.""" qc = QuantumCircuit(3, 1) qc.measure(0, 0) @@ -993,13 +1798,41 @@ def test_if_test_on_different_qubits(self): qc.x(1) qc.x(2) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -1014,7 +1847,8 @@ def test_if_test_on_different_qubits(self): self.assertEqual(expected, scheduled) - def test_shorter_measure_after_measure(self): + @data(True, False) + def test_shorter_measure_after_measure(self, use_target): """Test if schedules circuits with shorter measure after measure with a common clbit. @@ -1024,15 +1858,32 @@ def test_shorter_measure_after_measure(self): qc.measure(0, 0) qc.measure(1, 0) - durations = DynamicCircuitInstructionDurations( - [("measure", [0], 840), ("measure", [1], 540)] - ) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=700), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("measure", [0], 840), ("measure", [1], 540)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -1043,7 +1894,8 @@ def test_shorter_measure_after_measure(self): self.assertEqual(expected, scheduled) - def test_measure_after_if_test(self): + @data(True, False) + def test_measure_after_if_test(self, use_target): """Test if schedules circuits with if_test after measure with a common clbit.""" qc = QuantumCircuit(3, 1) qc.measure(0, 0) @@ -1051,13 +1903,41 @@ def test_measure_after_if_test(self): qc.x(1) qc.measure(2, 0) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -1076,7 +1956,8 @@ def test_measure_after_if_test(self): self.assertEqual(expected, scheduled) - def test_parallel_gate_different_length(self): + @data(True, False) + def test_parallel_gate_different_length(self, use_target): """Test circuit having two parallel instruction with different length.""" qc = QuantumCircuit(2, 2) qc.x(0) @@ -1084,16 +1965,40 @@ def test_parallel_gate_different_length(self): qc.measure(0, 0) qc.measure(1, 1) - durations = DynamicCircuitInstructionDurations( - [("x", [0], 200), ("x", [1], 400), ("measure", None, 840)] - ) - - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=400), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", [0], 200), ("x", [1], 400), ("measure", None, 840)] + ) + + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 2) @@ -1105,7 +2010,8 @@ def test_parallel_gate_different_length(self): self.assertEqual(scheduled, expected) - def test_parallel_gate_different_length_with_barrier(self): + @data(True, False) + def test_parallel_gate_different_length_with_barrier(self, use_target): """Test circuit having two parallel instruction with different length with barrier.""" qc = QuantumCircuit(2, 2) qc.x(0) @@ -1114,16 +2020,40 @@ def test_parallel_gate_different_length_with_barrier(self): qc.measure(0, 0) qc.measure(1, 1) - durations = DynamicCircuitInstructionDurations( - [("x", [0], 200), ("x", [1], 400), ("measure", None, 840)] - ) - - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=400), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", [0], 200), ("x", [1], 400), ("measure", None, 840)] + ) + + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 2) @@ -1136,7 +2066,8 @@ def test_parallel_gate_different_length_with_barrier(self): self.assertEqual(scheduled, expected) - def test_active_reset_circuit(self): + @data(True, False) + def test_active_reset_circuit(self, use_target): """Test practical example of reset circuit. Because of the stimulus pulse overlap with the previous XGate on the q register, @@ -1153,14 +2084,43 @@ def test_active_reset_circuit(self): with qc.if_test((0, 1)): qc.x(0) - durations = DynamicCircuitInstructionDurations([("x", None, 100), ("measure", None, 840)]) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) - scheduled = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ).run(qc) + scheduled = pm.run(qc) expected = QuantumCircuit(1, 1) expected.measure(0, 0) @@ -1176,7 +2136,8 @@ def test_active_reset_circuit(self): self.assertEqual(expected, scheduled) - def test_dag_introduces_extra_dependency_between_conditionals(self): + @data(True, False) + def test_dag_introduces_extra_dependency_between_conditionals(self, use_target): """Test dependency between conditional operations in the scheduling. In the below example circuit, the conditional x on q1 could start at time 0, @@ -1191,13 +2152,30 @@ def test_dag_introduces_extra_dependency_between_conditionals(self): with qc.if_test((0, 1)): qc.x(1) - durations = DynamicCircuitInstructionDurations([("x", None, 160)]) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=160), + (1,): InstructionProperties(duration=160), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations([("x", None, 160)]) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) @@ -1213,18 +2191,26 @@ def test_dag_introduces_extra_dependency_between_conditionals(self): self.assertEqual(expected, scheduled) - def test_padding_not_working_without_scheduling(self): + @data(True, False) + def test_padding_not_working_without_scheduling(self, use_target): """Test padding fails when un-scheduled DAG is input.""" qc = QuantumCircuit(1, 1) qc.delay(100, 0) qc.x(0) qc.measure(0, 0) - durations = DynamicCircuitInstructionDurations() - - with self.assertRaises(TranspilerError): - PassManager(PadDelay(durations)).run(qc) - - def test_no_pad_very_end_of_circuit(self): + if use_target: + target = Target(num_qubits=2, dt=1) + with self.assertRaises(TranspilerError): + PassManager(PadDelay(target=target)).run(qc) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations() + + with self.assertRaises(TranspilerError): + PassManager(PadDelay(durations)).run(qc) + + @data(True, False) + def test_no_pad_very_end_of_circuit(self, use_target): """Test padding option that inserts no delay at the very end of circuit. This circuit will be unchanged after scheduling/padding.""" @@ -1233,14 +2219,41 @@ def test_no_pad_very_end_of_circuit(self): qc.x(1) qc.measure(0, 0) - durations = DynamicCircuitInstructionDurations([("x", None, 160), ("measure", None, 840)]) - - scheduled = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, fill_very_end=False, schedule_idle_qubits=True), - ] - ).run(qc) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=160), + (1,): InstructionProperties(duration=160), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, fill_very_end=False, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 160), ("measure", None, 840)] + ) + + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, fill_very_end=False, schedule_idle_qubits=True), + ] + ) + scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) expected.delay(100, 0) @@ -1250,7 +2263,8 @@ def test_no_pad_very_end_of_circuit(self): self.assertEqual(expected, scheduled) - def test_reset_terminates_block(self): + @data(True, False) + def test_reset_terminates_block(self, use_target): """Test if reset operations terminate the block scheduled. Note: For dynamic circuits support we currently group resets @@ -1261,29 +2275,62 @@ def test_reset_terminates_block(self): qc.measure(1, 0) qc.x(0) - durations = DynamicCircuitInstructionDurations( - [ - ("x", None, 200), - ( - "reset", - [0], - 840, - ), # ignored as only the duration of the measurement is used for scheduling - ( - "reset", - [1], - 740, - ), # ignored as only the duration of the measurement is used for scheduling - ("measure", [0], 440), - ("measure", [1], 540), - ] - ) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=600), + (1,): InstructionProperties(duration=700), + }, + ) + target.add_instruction( + Reset(), + { + # when using DynamicCircuitInstructionDurations, + # the duration of "reset" gets replaced with "measure" + (0,): InstructionProperties(duration=600), + (1,): InstructionProperties(duration=700), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [ + ("x", None, 200), + ( + "reset", + [0], + 840, + ), # ignored as only the duration of the measurement is used for scheduling + ( + "reset", + [1], + 740, + ), # ignored as only the duration of the measurement is used for scheduling + ("measure", [0], 440), + ("measure", [1], 540), + ] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -1300,7 +2347,8 @@ def test_reset_terminates_block(self): self.assertEqual(expected, scheduled) - def test_reset_merged_with_measure(self): + @data(True, False) + def test_reset_merged_with_measure(self, use_target): """Test if reset operations terminate the block scheduled. Note: For dynamic circuits support we currently group resets to start @@ -1310,29 +2358,62 @@ def test_reset_merged_with_measure(self): qc.reset(0) qc.measure(1, 0) - durations = DynamicCircuitInstructionDurations( - [ - ("x", None, 200), - ( - "reset", - [0], - 840, - ), # ignored as only the duration of the measurement is used for scheduling - ( - "reset", - [1], - 740, - ), # ignored as only the duration of the measurement is used for scheduling - ("measure", [0], 440), - ("measure", [1], 540), - ] - ) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=600), + (1,): InstructionProperties(duration=700), + }, + ) + target.add_instruction( + Reset(), + { + # when using DynamicCircuitInstructionDurations, + # the duration of "reset" gets replaced with "measure" + (0,): InstructionProperties(duration=600), + (1,): InstructionProperties(duration=700), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [ + ("x", None, 200), + ( + "reset", + [0], + 840, + ), # ignored as only the duration of the measurement is used for scheduling + ( + "reset", + [1], + 740, + ), # ignored as only the duration of the measurement is used for scheduling + ("measure", [0], 440), + ("measure", [1], 540), + ] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -1345,7 +2426,8 @@ def test_reset_merged_with_measure(self): self.assertEqual(expected, scheduled) - def test_already_scheduled(self): + @data(True, False) + def test_already_scheduled(self, use_target): """Test no changes to pre-scheduled""" qc = QuantumCircuit(3, 2) qc.cx(0, 1) @@ -1366,20 +2448,52 @@ def test_already_scheduled(self): qc.delay(1000, 2) qc.barrier() - durations = DynamicCircuitInstructionDurations( - [("x", None, 100), ("measure", None, 840), ("cx", None, 500)] - ) - - scheduled = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ).run(qc) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=100), + (1,): InstructionProperties(duration=100), + (2,): InstructionProperties(duration=100), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + target.add_instruction( + CXGate(), + { + (0, 1): InstructionProperties(duration=500), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 100), ("measure", None, 840), ("cx", None, 500)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) + scheduled = pm.run(qc) self.assertEqual(qc, scheduled) - def test_scheduling_is_idempotent(self): + @data(True, False) + def test_scheduling_is_idempotent(self, use_target): """Test that padding can be applied back to back without changing the circuit.""" qc = QuantumCircuit(3, 2) qc.x(2) @@ -1390,40 +2504,94 @@ def test_scheduling_is_idempotent(self): qc.x(0) qc.measure(0, 0) - durations = DynamicCircuitInstructionDurations( - [("x", None, 100), ("measure", None, 840), ("cx", None, 500)] - ) - - scheduled0 = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ).run(qc) - - scheduled1 = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ).run(scheduled0) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=100), + (1,): InstructionProperties(duration=100), + (2,): InstructionProperties(duration=100), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + target.add_instruction( + CXGate(), + { + (0, 1): InstructionProperties(duration=500), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 100), ("measure", None, 840), ("cx", None, 500)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) + + scheduled0 = pm.run(qc) + + scheduled1 = pm.run(scheduled0) self.assertEqual(scheduled0, scheduled1) - def test_gate_on_measured_qubit(self): + @data(True, False) + def test_gate_on_measured_qubit(self, use_target): """Test that a gate on a previously measured qubit triggers the end of the block""" qc = QuantumCircuit(2, 1) qc.measure(0, 0) qc.x(0) qc.x(1) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) @@ -1434,7 +2602,8 @@ def test_gate_on_measured_qubit(self): self.assertEqual(expected, scheduled) - def test_grouped_measurements_prior_control_flow(self): + @data(True, False) + def test_grouped_measurements_prior_control_flow(self, use_target): """Test that measurements are grouped prior to control-flow""" qc = QuantumCircuit(3, 3) qc.measure(0, 0) @@ -1445,13 +2614,41 @@ def test_grouped_measurements_prior_control_flow(self): qc.x(2) qc.measure(2, 2) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 3) @@ -1474,7 +2671,8 @@ def test_grouped_measurements_prior_control_flow(self): self.assertEqual(expected, scheduled) - def test_fast_path_eligible_scheduling(self): + @data(True, False) + def test_fast_path_eligible_scheduling(self, use_target): """Test scheduling of the fast-path eligible blocks. Verify that no barrier is inserted between measurements and fast-path conditionals. """ @@ -1495,13 +2693,43 @@ def test_fast_path_eligible_scheduling(self): qc.x(1) qc.x(2) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=4, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + (3,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + (3,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(4, 3) @@ -1531,7 +2759,8 @@ def test_fast_path_eligible_scheduling(self): self.assertEqual(expected, scheduled) - def test_back_to_back_if_test(self): + @data(True, False) + def test_back_to_back_if_test(self, use_target): """Test back to back if_test scheduling""" qc = QuantumCircuit(3, 1) @@ -1544,13 +2773,41 @@ def test_back_to_back_if_test(self): qc.delay(1000, 2) qc.x(1) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 1) @@ -1573,7 +2830,8 @@ def test_back_to_back_if_test(self): expected.delay(1000, 2) self.assertEqual(expected, scheduled) - def test_issue_458_extra_idle_bug_0(self): + @data(True, False) + def test_issue_458_extra_idle_bug_0(self, use_target): """Regression test for https://github.com/Qiskit/qiskit-ibm-provider/issues/458 This demonstrates that delays on idle qubits are pushed to the last schedulable @@ -1601,16 +2859,49 @@ def test_issue_458_extra_idle_bug_0(self): qc.delay(1000, 1) qc.measure(2, 2) - durations = DynamicCircuitInstructionDurations( - [("x", None, 160), ("cx", None, 700), ("measure", None, 840)] - ) - - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=4, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=160), + (1,): InstructionProperties(duration=160), + (2,): InstructionProperties(duration=160), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + target.add_instruction( + CXGate(), + { + (0, 1): InstructionProperties(duration=700), + (1, 2): InstructionProperties(duration=700), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 160), ("cx", None, 700), ("measure", None, 840)] + ) + + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(4, 3) @@ -1643,7 +2934,8 @@ def test_issue_458_extra_idle_bug_0(self): self.assertEqual(scheduled, expected) - def test_issue_458_extra_idle_bug_1(self): + @data(True, False) + def test_issue_458_extra_idle_bug_1(self, use_target): """Regression test for https://github.com/Qiskit/qiskit-ibm-provider/issues/458 This demonstrates that a bug with a double-delay insertion has been resolved. @@ -1655,16 +2947,50 @@ def test_issue_458_extra_idle_bug_1(self): qc.barrier() qc.measure(1, 0) - durations = DynamicCircuitInstructionDurations( - [("rz", None, 0), ("cx", None, 700), ("measure", None, 840)] - ) + if use_target: + target = Target(num_qubits=3, dt=1) + target.add_instruction( + RZGate(Parameter("phi")), + { + (0,): InstructionProperties(duration=0), + (1,): InstructionProperties(duration=0), + (2,): InstructionProperties(duration=0), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + }, + ) + target.add_instruction( + CXGate(), + { + (0, 1): InstructionProperties(duration=700), + (1, 2): InstructionProperties(duration=700), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("rz", None, 0), ("cx", None, 700), ("measure", None, 840)] + ) + + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) scheduled = pm.run(qc) expected = QuantumCircuit(3, 3) @@ -1677,7 +3003,8 @@ def test_issue_458_extra_idle_bug_1(self): self.assertEqual(scheduled, expected) - def test_nested_control_scheduling(self): + @data(True, False) + def test_nested_control_scheduling(self, use_target): """Test scheduling of nested control-flow""" qc = QuantumCircuit(4, 3) @@ -1690,13 +3017,43 @@ def test_nested_control_scheduling(self): qc.measure(2, 2) qc.x(3) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=4, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + (2,): InstructionProperties(duration=200), + (3,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + (2,): InstructionProperties(duration=1000), + (3,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(4, 3) @@ -1730,7 +3087,8 @@ def test_nested_control_scheduling(self): self.assertEqual(expected, scheduled) - def test_while_loop(self): + @data(True, False) + def test_while_loop(self, use_target): """Test scheduling while loop""" qc = QuantumCircuit(2, 1) @@ -1740,13 +3098,39 @@ def test_while_loop(self): qc.measure(0, 0) qc.x(0) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) @@ -1761,7 +3145,8 @@ def test_while_loop(self): self.assertEqual(expected, scheduled) - def test_for_loop(self): + @data(True, False) + def test_for_loop(self, use_target): """Test scheduling for loop""" qc = QuantumCircuit(2, 1) @@ -1771,13 +3156,39 @@ def test_for_loop(self): qc.measure(0, 0) qc.x(0) - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) scheduled = pm.run(qc) expected = QuantumCircuit(2, 1) @@ -1792,7 +3203,8 @@ def test_for_loop(self): self.assertEqual(expected, scheduled) - def test_transpile_mock_backend(self): + @data(True, False) + def test_transpile_mock_backend(self, use_target): """Test scheduling works with transpilation.""" backend = FakeJakartaV2() @@ -1840,17 +3252,46 @@ def test_transpile_mock_backend(self): self.assertEqual(expected, scheduled) - def test_transpile_both_paths(self): + @data(True, False) + def test_transpile_both_paths(self, use_target): """Test scheduling works with both fast- and standard path after transpiling.""" backend = FakeJakartaV2() - durations = DynamicCircuitInstructionDurations.from_backend(backend) - pm = PassManager( - [ - ALAPScheduleAnalysis(durations), - PadDelay(durations, schedule_idle_qubits=True), - ] - ) + if use_target: + print("USE TARGET") + # here we would use backend.target, but DynamicCircuitInstructionDurations + # modifies the values so we are adapting the target durations to match the + # resuls. Replace with backend.target once DynamicCircuitInstructionDurations + # is removed (this will change the final output) + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=250), + (1,): InstructionProperties(duration=160), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=24992), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target, schedule_idle_qubits=True), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations.from_backend(backend) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations, schedule_idle_qubits=True), + ] + ) qr = QuantumRegister(3) cr = ClassicalRegister(2) @@ -1880,15 +3321,47 @@ def test_transpile_both_paths(self): expected.delay(160, qr[q_ind]) self.assertEqual(expected, scheduled) - def test_no_unused_qubits(self): + @data(True, False) + def test_no_unused_qubits(self, use_target): """Test DD with if_test circuit that unused qubits are untouched and not scheduled. This ensures that programs don't have unnecessary information for unused qubits. Which might hurt performance in later execution stages. """ - durations = DynamicCircuitInstructionDurations([("x", None, 200), ("measure", None, 840)]) - pm = PassManager([ALAPScheduleAnalysis(durations), PadDelay(durations)]) + if use_target: + target = Target(num_qubits=2, dt=1) + target.add_instruction( + XGate(), + { + (0,): InstructionProperties(duration=200), + (1,): InstructionProperties(duration=200), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=1000), + (1,): InstructionProperties(duration=1000), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 840)] + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(durations), + PadDelay(durations), + ] + ) qc = QuantumCircuit(3, 1) qc.measure(0, 0) @@ -1906,16 +3379,45 @@ def test_no_unused_qubits(self): for op in scheduled.data: self.assertNotIn(dont_use, op.qubits) - def test_scheduling_nonuniform_durations(self): + @data(True, False) + def test_scheduling_nonuniform_durations(self, use_target): """Test that scheduling withing control flow blocks uses the instruction durations on the correct qubit indices""" backend = FakeJakartaV2() - durations = DynamicCircuitInstructionDurations( - [("cx", (0, 1), 250), ("cx", (1, 3), 4000), ("measure", None, 2600)] - ) - pm = PassManager([ALAPScheduleAnalysis(durations), PadDelay(durations)]) + if use_target: + # here we would use backend.target, but DynamicCircuitInstructionDurations + # modifies the values so we are adapting the target durations to match the + # resuls. Replace with backend.target once DynamicCircuitInstructionDurations + # is removed (this will change the final output) + target = Target(num_qubits=2, dt=1) + target.add_instruction( + CXGate(), + { + (0, 1): InstructionProperties(duration=250), + (1, 3): InstructionProperties(duration=4000), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(duration=2760), + (1,): InstructionProperties(duration=2760), + }, + ) + pm = PassManager( + [ + ALAPScheduleAnalysis(target=target), + PadDelay(target=target), + ] + ) + else: + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("cx", (0, 1), 250), ("cx", (1, 3), 4000), ("measure", None, 2600)] + ) + pm = PassManager([ALAPScheduleAnalysis(durations), PadDelay(durations)]) qc = QuantumCircuit(4, 1) qc.barrier() diff --git a/test/unit/transpiler/passes/scheduling/test_utils.py b/test/unit/transpiler/passes/scheduling/test_utils.py index 2bd7138be..2e14de858 100644 --- a/test/unit/transpiler/passes/scheduling/test_utils.py +++ b/test/unit/transpiler/passes/scheduling/test_utils.py @@ -26,36 +26,38 @@ def test_patch_measure(self): """Test if schedules circuits with c_if after measure with a common clbit. See: https://github.com/Qiskit/qiskit-terra/issues/7654""" - durations = DynamicCircuitInstructionDurations( - [ - ("x", None, 200), - ("sx", (0,), 200), - ("measure", None, 1000), - ("measure", (0, 1), 1200), - ("reset", None, 800), - ] - ) + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [ + ("x", None, 200), + ("sx", (0,), 200), + ("measure", None, 1000), + ("measure", (0, 1), 1200), + ("reset", None, 800), + ] + ) self.assertEqual(durations.get("x", (0,)), 200) self.assertEqual(durations.get("measure", (0,)), 1160) self.assertEqual(durations.get("measure", (0, 1)), 1360) self.assertEqual(durations.get("reset", (0,)), 1160) - short_odd_durations = DynamicCircuitInstructionDurations( - [ - ("sx", (0,), 112), - ("measure", None, 1000), - ("reset", None, 800), - ] - ) + with self.assertWarns(DeprecationWarning): + short_odd_durations = DynamicCircuitInstructionDurations( + [ + ("sx", (0,), 112), + ("measure", None, 1000), + ("reset", None, 800), + ] + ) self.assertEqual(short_odd_durations.get("measure", (0,)), 1224) self.assertEqual(short_odd_durations.get("reset", (0,)), 1224) def test_durations_from_backend_v2(self): """Test loading and patching durations from a V2 Backend""" - - durations = DynamicCircuitInstructionDurations.from_backend(FakeKolkataV2()) + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations.from_backend(FakeKolkataV2()) self.assertEqual(durations.get("x", (0,)), 160) self.assertEqual(durations.get("measure", (0,)), 3200) @@ -64,7 +66,8 @@ def test_durations_from_backend_v2(self): def test_durations_from_target(self): """Test loading and patching durations from a target""" - durations = DynamicCircuitInstructionDurations.from_target(FakeKolkataV2().target) + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations.from_target(FakeKolkataV2().target) self.assertEqual(durations.get("x", (0,)), 160) self.assertEqual(durations.get("measure", (0,)), 3200) @@ -74,10 +77,11 @@ def test_patch_disable(self): """Test if schedules circuits with c_if after measure with a common clbit. See: https://github.com/Qiskit/qiskit-terra/issues/7654""" - durations = DynamicCircuitInstructionDurations( - [("x", None, 200), ("measure", None, 1000), ("measure", (0, 1), 1200)], - enable_patching=False, - ) + with self.assertWarns(DeprecationWarning): + durations = DynamicCircuitInstructionDurations( + [("x", None, 200), ("measure", None, 1000), ("measure", (0, 1), 1200)], + enable_patching=False, + ) self.assertEqual(durations.get("x", (0,)), 200) self.assertEqual(durations.get("measure", (0,)), 1000) From f63234d7608b7d68cf7864a525b7331ad5edf116 Mon Sep 17 00:00:00 2001 From: ElePT Date: Wed, 17 Sep 2025 14:40:04 +0200 Subject: [PATCH 2/9] Restore file --- qiskit_ibm_runtime/fake_provider/fake_backend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_ibm_runtime/fake_provider/fake_backend.py b/qiskit_ibm_runtime/fake_provider/fake_backend.py index 105e8901a..769123201 100644 --- a/qiskit_ibm_runtime/fake_provider/fake_backend.py +++ b/qiskit_ibm_runtime/fake_provider/fake_backend.py @@ -351,7 +351,7 @@ def _get_noise_model_from_backend_v2( # type: ignore # Add gate errors with warnings.catch_warnings(): - warnings.rnings( + warnings.filterwarnings( "ignore", module="qiskit_aer.noise.device.models", ) From d80b7a7558d808957e7da335ceff29db6f5a9c67 Mon Sep 17 00:00:00 2001 From: ElePT Date: Wed, 17 Sep 2025 14:49:10 +0200 Subject: [PATCH 3/9] Fix lint --- .../transpiler/passes/scheduling/test_dynamical_decoupling.py | 4 ++-- test/unit/transpiler/passes/scheduling/test_scheduler.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/unit/transpiler/passes/scheduling/test_dynamical_decoupling.py b/test/unit/transpiler/passes/scheduling/test_dynamical_decoupling.py index 666ce9245..3556c2091 100644 --- a/test/unit/transpiler/passes/scheduling/test_dynamical_decoupling.py +++ b/test/unit/transpiler/passes/scheduling/test_dynamical_decoupling.py @@ -12,13 +12,13 @@ """Test dynamical decoupling insertion pass.""" +from ddt import ddt, data, unpack import numpy as np from numpy import pi -from ddt import ddt, data, unpack from qiskit.circuit import QuantumCircuit, Delay, Parameter from qiskit.circuit.library import XGate, YGate, RXGate, UGate -from qiskit.circuit.library import Measure, Reset, CXGate, RZGate, HGate +from qiskit.circuit.library import Measure, Reset, CXGate, HGate from qiskit.quantum_info import Operator from qiskit.transpiler import Target, InstructionProperties from qiskit.transpiler.passmanager import PassManager diff --git a/test/unit/transpiler/passes/scheduling/test_scheduler.py b/test/unit/transpiler/passes/scheduling/test_scheduler.py index d18a1bb69..a9b4370d9 100644 --- a/test/unit/transpiler/passes/scheduling/test_scheduler.py +++ b/test/unit/transpiler/passes/scheduling/test_scheduler.py @@ -3203,8 +3203,7 @@ def test_for_loop(self, use_target): self.assertEqual(expected, scheduled) - @data(True, False) - def test_transpile_mock_backend(self, use_target): + def test_transpile_mock_backend(self): """Test scheduling works with transpilation.""" backend = FakeJakartaV2() From e2be899517fd8619011da30210e2cc28e340749b Mon Sep 17 00:00:00 2001 From: ElePT Date: Wed, 17 Sep 2025 14:54:01 +0200 Subject: [PATCH 4/9] Fix lint --- .../transpiler/passes/scheduling/dynamical_decoupling.py | 2 +- qiskit_ibm_runtime/transpiler/passes/scheduling/utils.py | 9 ++++++--- test/ibm_test_case.py | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py index cfc674023..cd052428b 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py @@ -354,7 +354,7 @@ def _pre_runhook(self, dag: DAGCircuit) -> None: if self._target: try: gate_length = self._target[gate.name].get((physical_index,)).duration - except: + except: # pylint: disable=bare-except gate_length = None else: gate_length = self._durations.get(gate, physical_index) diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/utils.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/utils.py index f348230b7..fc7b05a84 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/utils.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/utils.py @@ -157,9 +157,12 @@ def __init__( ): """Dynamic circuit instruction durations.""" warnings.warn( - "The DynamicCircuitInstructionDurations class is deprecated as of qiskit_ibm_runtime v0.42.0 " - "and will be removed in a future release. If you are using one of the scheduling passes defined " - "in qiskit_ibm_runtime, provide a `target` instance instead. ex: PadDelay(target=backend.target).", + "The DynamicCircuitInstructionDurations class is deprecated " + "as of qiskit_ibm_runtime v0.42.0 " + "and will be removed in a future release. If you are using " + "one of the scheduling passes defined " + "in qiskit_ibm_runtime, provide a `target` instance instead. " + "ex: PadDelay(target=backend.target).", DeprecationWarning, stacklevel=2, ) diff --git a/test/ibm_test_case.py b/test/ibm_test_case.py index e027ad219..34765fce1 100644 --- a/test/ibm_test_case.py +++ b/test/ibm_test_case.py @@ -56,7 +56,7 @@ def setUpClass(cls): "ignore", category=DeprecationWarning, message=r"The property " - "``qiskit\.dagcircuit\.dagcircuit\.DAGCircuit\.(unit|duration)`` is deprecated", + r"``qiskit\.dagcircuit\.dagcircuit\.DAGCircuit\.(unit|duration)`` is deprecated", ) # fail test on deprecation warnings from qiskit From 1c4dbb280df5a2f7f65fd538f6da11c2d510e739 Mon Sep 17 00:00:00 2001 From: ElePT Date: Fri, 10 Oct 2025 16:15:34 +0200 Subject: [PATCH 5/9] Add deprecation warnings to transpiler inputs --- .../transpiler/passes/scheduling/__init__.py | 8 +++----- .../passes/scheduling/dynamical_decoupling.py | 9 +++++++++ .../transpiler/passes/scheduling/pad_delay.py | 11 +++++++++++ .../transpiler/passes/scheduling/scheduler.py | 11 +++++++++++ .../transpiler/passes/scheduling/utils.py | 2 +- 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/__init__.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/__init__.py index 099b49658..e41d74c39 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/__init__.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/__init__.py @@ -59,7 +59,6 @@ from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager from qiskit.transpiler.passmanager import PassManager - from qiskit_ibm_runtime.transpiler.passes.scheduling import DynamicCircuitInstructionDurations from qiskit_ibm_runtime.transpiler.passes.scheduling import ALAPScheduleAnalysis from qiskit_ibm_runtime.transpiler.passes.scheduling import PadDelay from qiskit_ibm_runtime.fake_provider import FakeJakartaV2 @@ -68,11 +67,10 @@ # Use this duration class to get appropriate durations for dynamic # circuit backend scheduling - durations = DynamicCircuitInstructionDurations.from_backend(backend) # Generate the main Qiskit transpile passes. pm = generate_preset_pass_manager(optimization_level=1, backend=backend) # Configure the as-late-as-possible scheduling pass - pm.scheduling = PassManager([ALAPScheduleAnalysis(durations), PadDelay(durations)]) + pm.scheduling = PassManager([ALAPScheduleAnalysis(target=backend.target), PadDelay(target=backend.target)]) qr = QuantumRegister(3) crz = ClassicalRegister(1, name="crz") @@ -117,8 +115,8 @@ pm = generate_preset_pass_manager(optimization_level=1, backend=backend) pm.scheduling = PassManager( [ - ALAPScheduleAnalysis(durations), - PadDynamicalDecoupling(durations, dd_sequence), + ALAPScheduleAnalysis(target=backend.target), + PadDynamicalDecoupling(target=backend.target, dd_sequences=dd_sequence), ] ) diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py index cd052428b..04a865ffd 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py @@ -201,6 +201,15 @@ def __init__( TranspilerError: When the coupling map is not supported (i.e., if degree > 3) """ + if durations: + warnings.warn( + "The `durations` input argument of `PadDynamicalDecoupling` is deprecated " + "as of qiskit_ibm_runtime v0.43.0 and will be removed in a future release. " + "Provide a `target` instance instead ex: PadDynamicalDecoupling(target=backend.target).", + DeprecationWarning, + stacklevel=2, + ) + super().__init__( schedule_idle_qubits=schedule_idle_qubits, block_ordering_callable=block_ordering_callable, diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/pad_delay.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/pad_delay.py index 92b47d708..016913929 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/pad_delay.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/pad_delay.py @@ -13,6 +13,7 @@ """Padding pass to insert Delay into empty timeslots for dynamic circuit backends.""" from typing import Optional +import warnings from qiskit.circuit import Qubit from qiskit.circuit.delay import Delay @@ -75,6 +76,16 @@ def __init__( the number of blocks needed. If not provided, :func:`~block_order_op_nodes` will be used. """ + + if durations: + warnings.warn( + "The `durations` input argument of `PadDelay` is deprecated " + "as of qiskit_ibm_runtime v0.43.0 and will be removed in a future release. " + "Provide a `target` instance instead ex: PadDelay(target=backend.target).", + DeprecationWarning, + stacklevel=2, + ) + super().__init__( schedule_idle_qubits=schedule_idle_qubits, block_ordering_callable=block_ordering_callable, diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py index 96c0eb967..b9fc07bec 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py @@ -15,6 +15,7 @@ from abc import abstractmethod from typing import Dict, List, Optional, Union, Set, Tuple import itertools +import warnings import qiskit from qiskit.circuit import Bit, Barrier, Clbit, ControlFlowOp, Measure, Qubit, Reset @@ -61,6 +62,16 @@ def __init__( the number of blocks needed. If not provided, :func:`~block_order_op_nodes` will be used. """ + + if durations: + warnings.warn( + "The `durations` input argument of `BaseDynamicCircuitAnalysis` is deprecated " + "as of qiskit_ibm_runtime v0.43.0 and will be removed in a future release. " + "Provide a `target` instance instead ex: BaseDynamicCircuitAnalysis(target=backend.target).", + DeprecationWarning, + stacklevel=2, + ) + self._durations = durations self._target = target self._block_ordering_callable = ( diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/utils.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/utils.py index fc7b05a84..29b835402 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/utils.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/utils.py @@ -158,7 +158,7 @@ def __init__( """Dynamic circuit instruction durations.""" warnings.warn( "The DynamicCircuitInstructionDurations class is deprecated " - "as of qiskit_ibm_runtime v0.42.0 " + "as of qiskit_ibm_runtime v0.43.0 " "and will be removed in a future release. If you are using " "one of the scheduling passes defined " "in qiskit_ibm_runtime, provide a `target` instance instead. " From c9bf9925f1df20930a4143b7732e926f08e51388 Mon Sep 17 00:00:00 2001 From: ElePT Date: Fri, 10 Oct 2025 16:22:34 +0200 Subject: [PATCH 6/9] Fix lint --- .../backends/midcircuit/__init__.py | 15 +++ .../backends/midcircuit/conf_midcircuit.json | 66 +++++++++++ .../backends/midcircuit/fake_midcircuit.py | 34 ++++++ .../backends/midcircuit/props_midcircuit.json | 108 ++++++++++++++++++ .../transpiler/passes/scheduling/__init__.py | 5 +- .../transpiler/passes/scheduling/scheduler.py | 3 +- 6 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 qiskit_ibm_runtime/fake_provider/backends/midcircuit/__init__.py create mode 100644 qiskit_ibm_runtime/fake_provider/backends/midcircuit/conf_midcircuit.json create mode 100644 qiskit_ibm_runtime/fake_provider/backends/midcircuit/fake_midcircuit.py create mode 100644 qiskit_ibm_runtime/fake_provider/backends/midcircuit/props_midcircuit.json diff --git a/qiskit_ibm_runtime/fake_provider/backends/midcircuit/__init__.py b/qiskit_ibm_runtime/fake_provider/backends/midcircuit/__init__.py new file mode 100644 index 000000000..db2c0563e --- /dev/null +++ b/qiskit_ibm_runtime/fake_provider/backends/midcircuit/__init__.py @@ -0,0 +1,15 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2019, 2023. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Mock melbourne backend""" + +from .fake_midcircuit import FakeMidcircuit diff --git a/qiskit_ibm_runtime/fake_provider/backends/midcircuit/conf_midcircuit.json b/qiskit_ibm_runtime/fake_provider/backends/midcircuit/conf_midcircuit.json new file mode 100644 index 000000000..f8b36cb87 --- /dev/null +++ b/qiskit_ibm_runtime/fake_provider/backends/midcircuit/conf_midcircuit.json @@ -0,0 +1,66 @@ +{"backend_name": "ibm_midcircuit", +"backend_version": "0.0.0", +"n_qubits": 5, +"basis_gates": ["id", "rz", "sx", "x", "cx"], +"gates": [ + {"name": "id", "parameters": [], "qasm_def": "gate id q { U(0, 0, 0) q; }", "coupling_map": [[0], [1], [2], [3], [4]]}, + {"name": "rz", "parameters": ["theta"], "qasm_def": "gate rz(theta) q { U(0, 0, theta) q; }", "coupling_map": [[0], [1], [2], [3], [4]]}, + {"name": "sx", "parameters": [], "qasm_def": "gate sx q { U(pi/2, 3*pi/2, pi/2) q; }", "coupling_map": [[0], [1], [2], [3], [4]]}, + {"name": "x", "parameters": [], "qasm_def": "gate x q { U(pi, 0, pi) q; }", "coupling_map": [[0], [1], [2], [3], [4]]}, + {"name": "cx", "parameters": [], "qasm_def": "gate cx q0, q1 { CX q0, q1; }", "coupling_map": [[0, 1], [1, 0], [1, 2], [1, 3], [2, 1], [3, 1], [3, 4], [4, 3]]} + ], + "local": false, + "simulator": false, + "conditional": false, + "open_pulse": false, + "memory": true, + "max_shots": 8192, + "coupling_map": [[0, 1], [1, 0], [1, 2], [1, 3], [2, 1], [3, 1], [3, 4], [4, 3]], + "dynamic_reprate_enabled": true, + "supported_instructions": ["delay","reset", "measure", "id", "rz", "sx", "x", "cx", "measure_2", "reset_2", "reset_3", "alternative_rx"], + "instruction_signatures": [ + { + "name": "measure_2", + "num_qubits": 1, + "num_clbits": 1, + "parameters": [], + "return_type" : "Bool" + }, + { + "name": "reset_2", + "num_qubits": 1, + "num_clbits": 1, + "parameters": [], + "return_type" : "Bool" + }, + { + "name": "reset_3", + "num_qubits": 1, + "num_clbits": 0, + "parameters": [], + "return_type" : "None" + }, + { + "name": "alternative_rx", + "num_qubits": 1, + "num_clbits": 0, + "parameters": ["theta"], + "return_type" : "None" + } + ], + "rep_delay_range": [0.0, 500.0], + "default_rep_delay": 250.0, + "max_experiments": 75, + "sample_name": "Giraffe", + "n_registers": 1, + "credits_required": true, + "online_date": "2019-07-03T04:00:00+00:00", + "description": "5 qubit device for FakeMidcircuit", + "dt": 0.2222222222222222, + "dtm": 0.2222222222222222, + "allow_q_object": true, + "meas_map": [[0, 1, 2, 3, 4]], + "multi_meas_enabled": false, + "quantum_volume": 16, + "url": "None", + "allow_object_storage": true} \ No newline at end of file diff --git a/qiskit_ibm_runtime/fake_provider/backends/midcircuit/fake_midcircuit.py b/qiskit_ibm_runtime/fake_provider/backends/midcircuit/fake_midcircuit.py new file mode 100644 index 000000000..3845a5268 --- /dev/null +++ b/qiskit_ibm_runtime/fake_provider/backends/midcircuit/fake_midcircuit.py @@ -0,0 +1,34 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2019, 2023. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +""" +Fake Midcircuit device (5 qubit). +""" + +import os +from qiskit_ibm_runtime.fake_provider import fake_backend + + +class FakeMidcircuit(fake_backend.FakeBackendV2): + """A fake 5 qubit backend. + + .. code-block:: text + + 0 ↔ 1 ↔ 3 ↔ 4 + ↕ + 2 + """ + + dirname = os.path.dirname(__file__) # type: ignore + conf_filename = "conf_midcircuit.json" # type: ignore + props_filename = "props_midcircuit.json" # type: ignore + backend_name = "fake_midcircuit" # type: ignore diff --git a/qiskit_ibm_runtime/fake_provider/backends/midcircuit/props_midcircuit.json b/qiskit_ibm_runtime/fake_provider/backends/midcircuit/props_midcircuit.json new file mode 100644 index 000000000..0d9a528bc --- /dev/null +++ b/qiskit_ibm_runtime/fake_provider/backends/midcircuit/props_midcircuit.json @@ -0,0 +1,108 @@ +{"backend_name": "ibmq_vigo", "backend_version": "1.3.6", "last_update_date": "2021-01-20T03:30:10-05:00", + +"qubits": [ + [{"date": "2021-01-20T02:24:55-05:00", "name": "T1", "unit": "us", "value": 121.70801410836629}, + {"date": "2021-01-19T02:25:29-05:00", "name": "T2", "unit": "us", "value": 17.04998277501956}, + {"date": "2021-01-20T03:30:10-05:00", "name": "frequency", "unit": "GHz", "value": 4.796556901072327}, + {"date": "2021-01-20T03:30:10-05:00", "name": "anharmonicity", "unit": "GHz", "value": -0.3115692205922553}, + {"date": "2021-01-20T02:21:00-05:00", "name": "readout_error", "unit": "", "value": 0.07509999999999994}, + {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas0_prep1", "unit": "", "value": 0.0736}, + {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas1_prep0", "unit": "", "value": 0.0766}, + {"date": "2021-01-20T02:21:00-05:00", "name": "readout_length", "unit": "ns", "value": 5813.333333333333}], + + [{"date": "2021-01-20T02:24:55-05:00", "name": "T1", "unit": "us", "value": 111.68515230748554}, + {"date": "2021-01-20T02:31:52-05:00", "name": "T2", "unit": "us", "value": 132.02334409889457}, + {"date": "2021-01-20T03:30:10-05:00", "name": "frequency", "unit": "GHz", "value": 4.940124055522915}, + {"date": "2021-01-20T03:30:10-05:00", "name": "anharmonicity", "unit": "GHz", "value": -0.30543161039483363}, + {"date": "2021-01-20T02:21:00-05:00", "name": "readout_error", "unit": "", "value": 0.022499999999999964}, + {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas0_prep1", "unit": "", "value": 0.03539999999999999}, + {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas1_prep0", "unit": "", "value": 0.0096}, + {"date": "2021-01-20T02:21:00-05:00", "name": "readout_length", "unit": "ns", "value": 5813.333333333333}], + + [{"date": "2021-01-20T02:24:55-05:00", "name": "T1", "unit": "us", "value": 101.82043779287683}, + {"date": "2021-01-20T02:28:32-05:00", "name": "T2", "unit": "us", "value": 68.98073019654157}, + {"date": "2021-01-20T03:30:10-05:00", "name": "frequency", "unit": "GHz", "value": 4.8335109735072015}, + {"date": "2021-01-20T03:30:10-05:00", "name": "anharmonicity", "unit": "GHz", "value": -0.3102935629600691}, + {"date": "2021-01-20T02:21:00-05:00", "name": "readout_error", "unit": "", "value": 0.014599999999999946}, + {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas0_prep1", "unit": "", "value": 0.0232}, + {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas1_prep0", "unit": "", "value": 0.006}, + {"date": "2021-01-20T02:21:00-05:00", "name": "readout_length", "unit": "ns", "value": 5813.333333333333}], + + [{"date": "2021-01-20T02:24:55-05:00", "name": "T1", "unit": "us", "value": 116.71958434938585}, + {"date": "2021-01-20T02:28:32-05:00", "name": "T2", "unit": "us", "value": 85.88197428799032}, + {"date": "2021-01-20T03:30:10-05:00", "name": "frequency", "unit": "GHz", "value": 4.807961451396523}, + {"date": "2021-01-20T03:30:10-05:00", "name": "anharmonicity", "unit": "GHz", "value": -0.3106927608212116}, + {"date": "2021-01-20T02:21:00-05:00", "name": "readout_error", "unit": "", "value": 0.021500000000000075}, + {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas0_prep1", "unit": "", "value": 0.027000000000000024}, + {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas1_prep0", "unit": "", "value": 0.016}, + {"date": "2021-01-20T02:21:00-05:00", "name": "readout_length", "unit": "ns", "value": 5813.333333333333}], + + [{"date": "2021-01-20T02:24:55-05:00", "name": "T1", "unit": "us", "value": 86.8005228353819}, + {"date": "2021-01-20T02:31:52-05:00", "name": "T2", "unit": "us", "value": 46.85422114328585}, + {"date": "2021-01-20T03:30:10-05:00", "name": "frequency", "unit": "GHz", "value": 4.749674209642721}, + {"date": "2021-01-20T03:30:10-05:00", "name": "anharmonicity", "unit": "GHz", "value": -0.31229624001394773}, + {"date": "2021-01-20T02:21:00-05:00", "name": "readout_error", "unit": "", "value": 0.033299999999999996}, + {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas0_prep1", "unit": "", "value": 0.04400000000000004}, + {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas1_prep0", "unit": "", "value": 0.0226}, + {"date": "2021-01-20T02:21:00-05:00", "name": "readout_length", "unit": "ns", "value": 5813.333333333333}]], + +"gates": [ + {"qubits": [0], "gate": "id", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0004135213478316029}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "id0"}, + {"qubits": [1], "gate": "id", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0005020255558466025}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "id1"}, + {"qubits": [2], "gate": "id", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.00040033040197886486}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "id2"}, + {"qubits": [3], "gate": "id", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0006149355812506126}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "id3"}, + {"qubits": [4], "gate": "id", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0006307673923554075}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "id4"}, + {"qubits": [0], "gate": "rz", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_error", "unit": "", "value": 0}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 0}], "name": "rz0"}, + {"qubits": [1], "gate": "rz", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_error", "unit": "", "value": 0}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 0}], "name": "rz1"}, + {"qubits": [2], "gate": "rz", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_error", "unit": "", "value": 0}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 0}], "name": "rz2"}, + {"qubits": [3], "gate": "rz", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_error", "unit": "", "value": 0}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 0}], "name": "rz3"}, + {"qubits": [4], "gate": "rz", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_error", "unit": "", "value": 0}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 0}], "name": "rz4"}, + {"qubits": [0], "gate": "sx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0004135213478316029}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "sx0"}, + {"qubits": [1], "gate": "sx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0005020255558466025}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "sx1"}, + {"qubits": [2], "gate": "sx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.00040033040197886486}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "sx2"}, + {"qubits": [3], "gate": "sx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0006149355812506126}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "sx3"}, + {"qubits": [4], "gate": "sx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0006307673923554075}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "sx4"}, + {"qubits": [0], "gate": "x", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0004135213478316029}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "x0"}, + {"qubits": [1], "gate": "x", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0005020255558466025}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "x1"}, + {"qubits": [2], "gate": "x", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.00040033040197886486}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "x2"}, + {"qubits": [3], "gate": "x", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0006149355812506126}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "x3"}, + {"qubits": [4], "gate": "x", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0006307673923554075}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "x4"}, + {"qubits": [3, 4], "gate": "cx", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_error", "unit": "", "value": 0.00713013415297073}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 270.22222222222223}], "name": "cx3_4"}, + {"qubits": [4, 3], "gate": "cx", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_error", "unit": "", "value": 0.00713013415297073}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 305.77777777777777}], "name": "cx4_3"}, + {"qubits": [3, 1], "gate": "cx", "parameters": [{"date": "2021-01-20T03:16:21-05:00", "name": "gate_error", "unit": "", "value": 0.0092971260000492}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 462.2222222222222}], "name": "cx3_1"}, + {"qubits": [1, 3], "gate": "cx", "parameters": [{"date": "2021-01-20T03:16:21-05:00", "name": "gate_error", "unit": "", "value": 0.0092971260000492}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 497.77777777777777}], "name": "cx1_3"}, + {"qubits": [1, 2], "gate": "cx", "parameters": [{"date": "2021-01-20T03:01:54-05:00", "name": "gate_error", "unit": "", "value": 0.006589629429362032}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 227.55555555555554}], "name": "cx1_2"}, + {"qubits": [2, 1], "gate": "cx", "parameters": [{"date": "2021-01-20T03:01:54-05:00", "name": "gate_error", "unit": "", "value": 0.006589629429362032}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 263.1111111111111}], "name": "cx2_1"}, + {"qubits": [0, 1], "gate": "cx", "parameters": [{"date": "2021-01-20T02:51:37-05:00", "name": "gate_error", "unit": "", "value": 0.012012477900732316}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 519.1111111111111}], "name": "cx0_1"}, + {"qubits": [1, 0], "gate": "cx", "parameters": [{"date": "2021-01-20T02:51:37-05:00", "name": "gate_error", "unit": "", "value": 0.012012477900732316}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 554.6666666666666}], "name": "cx1_0"}, + {"qubits": [0], "gate": "measure_2", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}], "name": "measure_20"}, + {"qubits": [1], "gate": "measure_2", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}], "name": "measure_21"}, + {"qubits": [2], "gate": "measure_2", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}], "name": "measure_22"}, + {"qubits": [3], "gate": "measure_2", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}], "name": "measure_23"}, + {"qubits": [4], "gate": "measure_2", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}], "name": "measure_24"}, + {"qubits": [0], "gate": "reset_2", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_20"}, + {"qubits": [1], "gate": "reset_2", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_21"}, + {"qubits": [2], "gate": "reset_2", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_22"}, + {"qubits": [3], "gate": "reset_2", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_23"}, + {"qubits": [4], "gate": "reset_2", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_24"}, + {"qubits": [0], "gate": "reset_3", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_30"}, + {"qubits": [1], "gate": "reset_3", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_31"}, + {"qubits": [2], "gate": "reset_3", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_32"}, + {"qubits": [3], "gate": "reset_3", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_33"}, + {"qubits": [4], "gate": "reset_3", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_34"}, + {"qubits": [0], "gate": "alternative_rx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "alternative_rx0"}, + {"qubits": [1], "gate": "alternative_rx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "alternative_rx1"}, + {"qubits": [2], "gate": "alternative_rx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "alternative_rx2"}, + {"qubits": [3], "gate": "alternative_rx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "alternative_rx3"}, + {"qubits": [4], "gate": "alternative_rx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "alternative_rx4"} +], + +"general": [ + {"date": "2021-01-20T03:30:10-05:00", "name": "jq_01", "unit": "GHz", "value": 0.0026561266946048515}, + {"date": "2021-01-20T03:30:10-05:00", "name": "zz_01", "unit": "GHz", "value": -0.0001184033408557246}, + {"date": "2021-01-20T03:30:10-05:00", "name": "jq_13", "unit": "GHz", "value": 0.0014472674400262551}, + {"date": "2021-01-20T03:30:10-05:00", "name": "zz_13", "unit": "GHz", "value": -3.361304564463225e-05}, + {"date": "2021-01-20T03:30:10-05:00", "name": "jq_34", "unit": "GHz", "value": 0.002198866111884803}, + {"date": "2021-01-20T03:30:10-05:00", "name": "zz_34", "unit": "GHz", "value": -6.42498334595851e-05}, + {"date": "2021-01-20T03:30:10-05:00", "name": "jq_12", "unit": "GHz", "value": 0.0034704225601167745}, + {"date": "2021-01-20T03:30:10-05:00", "name": "zz_12", "unit": "GHz", "value": -0.000179053578022909}]} \ No newline at end of file diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/__init__.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/__init__.py index 2c0ca3944..6a6e60423 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/__init__.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/__init__.py @@ -70,7 +70,10 @@ # Generate the main Qiskit transpile passes. pm = generate_preset_pass_manager(optimization_level=1, backend=backend) # Configure the as-late-as-possible scheduling pass - pm.scheduling = PassManager([ALAPScheduleAnalysis(target=backend.target), PadDelay(target=backend.target)]) + pm.scheduling = PassManager([ + ALAPScheduleAnalysis(target=backend.target), + PadDelay(target=backend.target)] + ) qr = QuantumRegister(3) crz = ClassicalRegister(1, name="crz") diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py index b9fc07bec..1bc9adeb0 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py @@ -67,7 +67,8 @@ def __init__( warnings.warn( "The `durations` input argument of `BaseDynamicCircuitAnalysis` is deprecated " "as of qiskit_ibm_runtime v0.43.0 and will be removed in a future release. " - "Provide a `target` instance instead ex: BaseDynamicCircuitAnalysis(target=backend.target).", + "Provide a `target` instance instead ex: " + "BaseDynamicCircuitAnalysis(target=backend.target).", DeprecationWarning, stacklevel=2, ) From 6c8244aa7ebb251962a8d4648b520d80c4376b81 Mon Sep 17 00:00:00 2001 From: ElePT Date: Fri, 10 Oct 2025 16:24:33 +0200 Subject: [PATCH 7/9] Remove oversight --- .../backends/midcircuit/__init__.py | 15 --- .../backends/midcircuit/conf_midcircuit.json | 66 ----------- .../backends/midcircuit/fake_midcircuit.py | 34 ------ .../backends/midcircuit/props_midcircuit.json | 108 ------------------ 4 files changed, 223 deletions(-) delete mode 100644 qiskit_ibm_runtime/fake_provider/backends/midcircuit/__init__.py delete mode 100644 qiskit_ibm_runtime/fake_provider/backends/midcircuit/conf_midcircuit.json delete mode 100644 qiskit_ibm_runtime/fake_provider/backends/midcircuit/fake_midcircuit.py delete mode 100644 qiskit_ibm_runtime/fake_provider/backends/midcircuit/props_midcircuit.json diff --git a/qiskit_ibm_runtime/fake_provider/backends/midcircuit/__init__.py b/qiskit_ibm_runtime/fake_provider/backends/midcircuit/__init__.py deleted file mode 100644 index db2c0563e..000000000 --- a/qiskit_ibm_runtime/fake_provider/backends/midcircuit/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2019, 2023. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Mock melbourne backend""" - -from .fake_midcircuit import FakeMidcircuit diff --git a/qiskit_ibm_runtime/fake_provider/backends/midcircuit/conf_midcircuit.json b/qiskit_ibm_runtime/fake_provider/backends/midcircuit/conf_midcircuit.json deleted file mode 100644 index f8b36cb87..000000000 --- a/qiskit_ibm_runtime/fake_provider/backends/midcircuit/conf_midcircuit.json +++ /dev/null @@ -1,66 +0,0 @@ -{"backend_name": "ibm_midcircuit", -"backend_version": "0.0.0", -"n_qubits": 5, -"basis_gates": ["id", "rz", "sx", "x", "cx"], -"gates": [ - {"name": "id", "parameters": [], "qasm_def": "gate id q { U(0, 0, 0) q; }", "coupling_map": [[0], [1], [2], [3], [4]]}, - {"name": "rz", "parameters": ["theta"], "qasm_def": "gate rz(theta) q { U(0, 0, theta) q; }", "coupling_map": [[0], [1], [2], [3], [4]]}, - {"name": "sx", "parameters": [], "qasm_def": "gate sx q { U(pi/2, 3*pi/2, pi/2) q; }", "coupling_map": [[0], [1], [2], [3], [4]]}, - {"name": "x", "parameters": [], "qasm_def": "gate x q { U(pi, 0, pi) q; }", "coupling_map": [[0], [1], [2], [3], [4]]}, - {"name": "cx", "parameters": [], "qasm_def": "gate cx q0, q1 { CX q0, q1; }", "coupling_map": [[0, 1], [1, 0], [1, 2], [1, 3], [2, 1], [3, 1], [3, 4], [4, 3]]} - ], - "local": false, - "simulator": false, - "conditional": false, - "open_pulse": false, - "memory": true, - "max_shots": 8192, - "coupling_map": [[0, 1], [1, 0], [1, 2], [1, 3], [2, 1], [3, 1], [3, 4], [4, 3]], - "dynamic_reprate_enabled": true, - "supported_instructions": ["delay","reset", "measure", "id", "rz", "sx", "x", "cx", "measure_2", "reset_2", "reset_3", "alternative_rx"], - "instruction_signatures": [ - { - "name": "measure_2", - "num_qubits": 1, - "num_clbits": 1, - "parameters": [], - "return_type" : "Bool" - }, - { - "name": "reset_2", - "num_qubits": 1, - "num_clbits": 1, - "parameters": [], - "return_type" : "Bool" - }, - { - "name": "reset_3", - "num_qubits": 1, - "num_clbits": 0, - "parameters": [], - "return_type" : "None" - }, - { - "name": "alternative_rx", - "num_qubits": 1, - "num_clbits": 0, - "parameters": ["theta"], - "return_type" : "None" - } - ], - "rep_delay_range": [0.0, 500.0], - "default_rep_delay": 250.0, - "max_experiments": 75, - "sample_name": "Giraffe", - "n_registers": 1, - "credits_required": true, - "online_date": "2019-07-03T04:00:00+00:00", - "description": "5 qubit device for FakeMidcircuit", - "dt": 0.2222222222222222, - "dtm": 0.2222222222222222, - "allow_q_object": true, - "meas_map": [[0, 1, 2, 3, 4]], - "multi_meas_enabled": false, - "quantum_volume": 16, - "url": "None", - "allow_object_storage": true} \ No newline at end of file diff --git a/qiskit_ibm_runtime/fake_provider/backends/midcircuit/fake_midcircuit.py b/qiskit_ibm_runtime/fake_provider/backends/midcircuit/fake_midcircuit.py deleted file mode 100644 index 3845a5268..000000000 --- a/qiskit_ibm_runtime/fake_provider/backends/midcircuit/fake_midcircuit.py +++ /dev/null @@ -1,34 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2019, 2023. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -""" -Fake Midcircuit device (5 qubit). -""" - -import os -from qiskit_ibm_runtime.fake_provider import fake_backend - - -class FakeMidcircuit(fake_backend.FakeBackendV2): - """A fake 5 qubit backend. - - .. code-block:: text - - 0 ↔ 1 ↔ 3 ↔ 4 - ↕ - 2 - """ - - dirname = os.path.dirname(__file__) # type: ignore - conf_filename = "conf_midcircuit.json" # type: ignore - props_filename = "props_midcircuit.json" # type: ignore - backend_name = "fake_midcircuit" # type: ignore diff --git a/qiskit_ibm_runtime/fake_provider/backends/midcircuit/props_midcircuit.json b/qiskit_ibm_runtime/fake_provider/backends/midcircuit/props_midcircuit.json deleted file mode 100644 index 0d9a528bc..000000000 --- a/qiskit_ibm_runtime/fake_provider/backends/midcircuit/props_midcircuit.json +++ /dev/null @@ -1,108 +0,0 @@ -{"backend_name": "ibmq_vigo", "backend_version": "1.3.6", "last_update_date": "2021-01-20T03:30:10-05:00", - -"qubits": [ - [{"date": "2021-01-20T02:24:55-05:00", "name": "T1", "unit": "us", "value": 121.70801410836629}, - {"date": "2021-01-19T02:25:29-05:00", "name": "T2", "unit": "us", "value": 17.04998277501956}, - {"date": "2021-01-20T03:30:10-05:00", "name": "frequency", "unit": "GHz", "value": 4.796556901072327}, - {"date": "2021-01-20T03:30:10-05:00", "name": "anharmonicity", "unit": "GHz", "value": -0.3115692205922553}, - {"date": "2021-01-20T02:21:00-05:00", "name": "readout_error", "unit": "", "value": 0.07509999999999994}, - {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas0_prep1", "unit": "", "value": 0.0736}, - {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas1_prep0", "unit": "", "value": 0.0766}, - {"date": "2021-01-20T02:21:00-05:00", "name": "readout_length", "unit": "ns", "value": 5813.333333333333}], - - [{"date": "2021-01-20T02:24:55-05:00", "name": "T1", "unit": "us", "value": 111.68515230748554}, - {"date": "2021-01-20T02:31:52-05:00", "name": "T2", "unit": "us", "value": 132.02334409889457}, - {"date": "2021-01-20T03:30:10-05:00", "name": "frequency", "unit": "GHz", "value": 4.940124055522915}, - {"date": "2021-01-20T03:30:10-05:00", "name": "anharmonicity", "unit": "GHz", "value": -0.30543161039483363}, - {"date": "2021-01-20T02:21:00-05:00", "name": "readout_error", "unit": "", "value": 0.022499999999999964}, - {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas0_prep1", "unit": "", "value": 0.03539999999999999}, - {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas1_prep0", "unit": "", "value": 0.0096}, - {"date": "2021-01-20T02:21:00-05:00", "name": "readout_length", "unit": "ns", "value": 5813.333333333333}], - - [{"date": "2021-01-20T02:24:55-05:00", "name": "T1", "unit": "us", "value": 101.82043779287683}, - {"date": "2021-01-20T02:28:32-05:00", "name": "T2", "unit": "us", "value": 68.98073019654157}, - {"date": "2021-01-20T03:30:10-05:00", "name": "frequency", "unit": "GHz", "value": 4.8335109735072015}, - {"date": "2021-01-20T03:30:10-05:00", "name": "anharmonicity", "unit": "GHz", "value": -0.3102935629600691}, - {"date": "2021-01-20T02:21:00-05:00", "name": "readout_error", "unit": "", "value": 0.014599999999999946}, - {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas0_prep1", "unit": "", "value": 0.0232}, - {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas1_prep0", "unit": "", "value": 0.006}, - {"date": "2021-01-20T02:21:00-05:00", "name": "readout_length", "unit": "ns", "value": 5813.333333333333}], - - [{"date": "2021-01-20T02:24:55-05:00", "name": "T1", "unit": "us", "value": 116.71958434938585}, - {"date": "2021-01-20T02:28:32-05:00", "name": "T2", "unit": "us", "value": 85.88197428799032}, - {"date": "2021-01-20T03:30:10-05:00", "name": "frequency", "unit": "GHz", "value": 4.807961451396523}, - {"date": "2021-01-20T03:30:10-05:00", "name": "anharmonicity", "unit": "GHz", "value": -0.3106927608212116}, - {"date": "2021-01-20T02:21:00-05:00", "name": "readout_error", "unit": "", "value": 0.021500000000000075}, - {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas0_prep1", "unit": "", "value": 0.027000000000000024}, - {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas1_prep0", "unit": "", "value": 0.016}, - {"date": "2021-01-20T02:21:00-05:00", "name": "readout_length", "unit": "ns", "value": 5813.333333333333}], - - [{"date": "2021-01-20T02:24:55-05:00", "name": "T1", "unit": "us", "value": 86.8005228353819}, - {"date": "2021-01-20T02:31:52-05:00", "name": "T2", "unit": "us", "value": 46.85422114328585}, - {"date": "2021-01-20T03:30:10-05:00", "name": "frequency", "unit": "GHz", "value": 4.749674209642721}, - {"date": "2021-01-20T03:30:10-05:00", "name": "anharmonicity", "unit": "GHz", "value": -0.31229624001394773}, - {"date": "2021-01-20T02:21:00-05:00", "name": "readout_error", "unit": "", "value": 0.033299999999999996}, - {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas0_prep1", "unit": "", "value": 0.04400000000000004}, - {"date": "2021-01-20T02:21:00-05:00", "name": "prob_meas1_prep0", "unit": "", "value": 0.0226}, - {"date": "2021-01-20T02:21:00-05:00", "name": "readout_length", "unit": "ns", "value": 5813.333333333333}]], - -"gates": [ - {"qubits": [0], "gate": "id", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0004135213478316029}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "id0"}, - {"qubits": [1], "gate": "id", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0005020255558466025}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "id1"}, - {"qubits": [2], "gate": "id", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.00040033040197886486}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "id2"}, - {"qubits": [3], "gate": "id", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0006149355812506126}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "id3"}, - {"qubits": [4], "gate": "id", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0006307673923554075}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "id4"}, - {"qubits": [0], "gate": "rz", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_error", "unit": "", "value": 0}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 0}], "name": "rz0"}, - {"qubits": [1], "gate": "rz", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_error", "unit": "", "value": 0}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 0}], "name": "rz1"}, - {"qubits": [2], "gate": "rz", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_error", "unit": "", "value": 0}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 0}], "name": "rz2"}, - {"qubits": [3], "gate": "rz", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_error", "unit": "", "value": 0}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 0}], "name": "rz3"}, - {"qubits": [4], "gate": "rz", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_error", "unit": "", "value": 0}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 0}], "name": "rz4"}, - {"qubits": [0], "gate": "sx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0004135213478316029}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "sx0"}, - {"qubits": [1], "gate": "sx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0005020255558466025}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "sx1"}, - {"qubits": [2], "gate": "sx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.00040033040197886486}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "sx2"}, - {"qubits": [3], "gate": "sx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0006149355812506126}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "sx3"}, - {"qubits": [4], "gate": "sx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0006307673923554075}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "sx4"}, - {"qubits": [0], "gate": "x", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0004135213478316029}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "x0"}, - {"qubits": [1], "gate": "x", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0005020255558466025}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "x1"}, - {"qubits": [2], "gate": "x", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.00040033040197886486}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "x2"}, - {"qubits": [3], "gate": "x", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0006149355812506126}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "x3"}, - {"qubits": [4], "gate": "x", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 0.0006307673923554075}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 35.55555555555556}], "name": "x4"}, - {"qubits": [3, 4], "gate": "cx", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_error", "unit": "", "value": 0.00713013415297073}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 270.22222222222223}], "name": "cx3_4"}, - {"qubits": [4, 3], "gate": "cx", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_error", "unit": "", "value": 0.00713013415297073}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 305.77777777777777}], "name": "cx4_3"}, - {"qubits": [3, 1], "gate": "cx", "parameters": [{"date": "2021-01-20T03:16:21-05:00", "name": "gate_error", "unit": "", "value": 0.0092971260000492}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 462.2222222222222}], "name": "cx3_1"}, - {"qubits": [1, 3], "gate": "cx", "parameters": [{"date": "2021-01-20T03:16:21-05:00", "name": "gate_error", "unit": "", "value": 0.0092971260000492}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 497.77777777777777}], "name": "cx1_3"}, - {"qubits": [1, 2], "gate": "cx", "parameters": [{"date": "2021-01-20T03:01:54-05:00", "name": "gate_error", "unit": "", "value": 0.006589629429362032}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 227.55555555555554}], "name": "cx1_2"}, - {"qubits": [2, 1], "gate": "cx", "parameters": [{"date": "2021-01-20T03:01:54-05:00", "name": "gate_error", "unit": "", "value": 0.006589629429362032}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 263.1111111111111}], "name": "cx2_1"}, - {"qubits": [0, 1], "gate": "cx", "parameters": [{"date": "2021-01-20T02:51:37-05:00", "name": "gate_error", "unit": "", "value": 0.012012477900732316}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 519.1111111111111}], "name": "cx0_1"}, - {"qubits": [1, 0], "gate": "cx", "parameters": [{"date": "2021-01-20T02:51:37-05:00", "name": "gate_error", "unit": "", "value": 0.012012477900732316}, {"date": "2021-01-17T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 554.6666666666666}], "name": "cx1_0"}, - {"qubits": [0], "gate": "measure_2", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}], "name": "measure_20"}, - {"qubits": [1], "gate": "measure_2", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}], "name": "measure_21"}, - {"qubits": [2], "gate": "measure_2", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}], "name": "measure_22"}, - {"qubits": [3], "gate": "measure_2", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}], "name": "measure_23"}, - {"qubits": [4], "gate": "measure_2", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}], "name": "measure_24"}, - {"qubits": [0], "gate": "reset_2", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_20"}, - {"qubits": [1], "gate": "reset_2", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_21"}, - {"qubits": [2], "gate": "reset_2", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_22"}, - {"qubits": [3], "gate": "reset_2", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_23"}, - {"qubits": [4], "gate": "reset_2", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_24"}, - {"qubits": [0], "gate": "reset_3", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_30"}, - {"qubits": [1], "gate": "reset_3", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_31"}, - {"qubits": [2], "gate": "reset_3", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_32"}, - {"qubits": [3], "gate": "reset_3", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_33"}, - {"qubits": [4], "gate": "reset_3", "parameters": [{"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "reset_34"}, - {"qubits": [0], "gate": "alternative_rx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "alternative_rx0"}, - {"qubits": [1], "gate": "alternative_rx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "alternative_rx1"}, - {"qubits": [2], "gate": "alternative_rx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "alternative_rx2"}, - {"qubits": [3], "gate": "alternative_rx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "alternative_rx3"}, - {"qubits": [4], "gate": "alternative_rx", "parameters": [{"date": "2021-01-20T02:35:09-05:00", "name": "gate_error", "unit": "", "value": 3.142}, {"date": "2021-01-20T03:30:10-05:00", "name": "gate_length", "unit": "ns", "value": 31.42}], "name": "alternative_rx4"} -], - -"general": [ - {"date": "2021-01-20T03:30:10-05:00", "name": "jq_01", "unit": "GHz", "value": 0.0026561266946048515}, - {"date": "2021-01-20T03:30:10-05:00", "name": "zz_01", "unit": "GHz", "value": -0.0001184033408557246}, - {"date": "2021-01-20T03:30:10-05:00", "name": "jq_13", "unit": "GHz", "value": 0.0014472674400262551}, - {"date": "2021-01-20T03:30:10-05:00", "name": "zz_13", "unit": "GHz", "value": -3.361304564463225e-05}, - {"date": "2021-01-20T03:30:10-05:00", "name": "jq_34", "unit": "GHz", "value": 0.002198866111884803}, - {"date": "2021-01-20T03:30:10-05:00", "name": "zz_34", "unit": "GHz", "value": -6.42498334595851e-05}, - {"date": "2021-01-20T03:30:10-05:00", "name": "jq_12", "unit": "GHz", "value": 0.0034704225601167745}, - {"date": "2021-01-20T03:30:10-05:00", "name": "zz_12", "unit": "GHz", "value": -0.000179053578022909}]} \ No newline at end of file From c6dd463c2e34050784b36741dba0dbba93c8a0a4 Mon Sep 17 00:00:00 2001 From: ElePT Date: Fri, 10 Oct 2025 16:59:02 +0200 Subject: [PATCH 8/9] Address rounding errors caught in docs evaluation --- .../transpiler/passes/scheduling/dynamical_decoupling.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py index 04a865ffd..3937e8c7f 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/dynamical_decoupling.py @@ -372,7 +372,6 @@ def _pre_runhook(self, dag: DAGCircuit) -> None: raise TranspilerError( f"Duration of {gate} on qubits {physical_index} is not found." ) - seq_length_.append(gate_length) # Update gate duration. # This is necessary for current timeline drawer, i.e. scheduled. @@ -567,6 +566,11 @@ def _constrained_length(values: np.array) -> np.array: # Interleave delays with DD sequence operations for tau_idx, tau in enumerate(taus): if tau > 0: + # Delay only accept integer durations if the unit is 'dt', + # but the tau calculation can result in floating-point + # rounding errors (like 4.99999 instead of 5). + if self._dag.unit == "dt": + tau = round(tau) self._apply_scheduled_op( block_idx, idle_after, Delay(tau, self._dag.unit), qubit ) From 0d733c5eed691f338b9a0362d207bdf6b88ea4db Mon Sep 17 00:00:00 2001 From: ElePT Date: Fri, 10 Oct 2025 17:11:02 +0200 Subject: [PATCH 9/9] Add reno --- release-notes/unreleased/2403.deprecation.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 release-notes/unreleased/2403.deprecation.rst diff --git a/release-notes/unreleased/2403.deprecation.rst b/release-notes/unreleased/2403.deprecation.rst new file mode 100644 index 000000000..9326ac110 --- /dev/null +++ b/release-notes/unreleased/2403.deprecation.rst @@ -0,0 +1,13 @@ + +Added a new ``target`` argument to the initializer following transpiler analysis and padding passes: +:class:`.ALAPScheduleAnalysis`, :class:`.PadDelay`, :class:`.PadDynamicalDecoupling`, :class:`.BlockBasePadder`. +This change aligns these passes with the broader Qiskit transpiler architecture, and supersedes the use of the +``durations`` argument. + +The :class:`.DynamicCircuitInstructionDurations` class, used in custom schedulin passes, has been deprecated as of +``qiskit-ibm-runtime`` v0.43. This class was optimized for scheduling operations on Eagle processors, and it +has fallen out of date with the current offering of Heron processors. This class was used to define the ```durations`` +argument in the scheduling passes listed above +(:class:`.ALAPScheduleAnalysis`, :class:`.PadDelay`, :class:`.PadDynamicalDecoupling`, :class:`.BlockBasePadder`). +The argument is also deprecated and will be removed in a future release. Users are encouraged to migrate to +the ``target`` argument. \ No newline at end of file