diff --git a/qiskit/compiler/transpiler.py b/qiskit/compiler/transpiler.py index dd6758acc161..9812d3143db5 100644 --- a/qiskit/compiler/transpiler.py +++ b/qiskit/compiler/transpiler.py @@ -24,6 +24,7 @@ from qiskit.circuit.quantumregister import Qubit from qiskit.dagcircuit import DAGCircuit from qiskit.providers.backend import Backend +from qiskit.providers.backend_compat import BackendV2Converter from qiskit.providers.models import BackendProperties from qiskit.pulse import Schedule, InstructionScheduleMap from qiskit.transpiler import Layout, CouplingMap, PropertySet @@ -33,7 +34,7 @@ from qiskit.transpiler.passes.synthesis.high_level_synthesis import HLSConfig from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager from qiskit.transpiler.timing_constraints import TimingConstraints -from qiskit.transpiler.target import Target, target_to_backend_properties +from qiskit.transpiler.target import Target, target_to_backend_properties, InstructionProperties logger = logging.getLogger(__name__) @@ -293,6 +294,12 @@ def callback_func(**kwargs): config = user_config.get_config() optimization_level = config.get("transpile_optimization_level", 1) + if backend is not None and getattr(backend, "version", 0) <= 1: + # This is a temporary conversion step to allow for a smoother transition + # to a fully target-based transpiler pipeline while maintaining the behavior + # of `transpile` with BackendV1 inputs. + backend = BackendV2Converter(backend) + if ( scheduling_method is not None and backend is None @@ -325,8 +332,14 @@ def callback_func(**kwargs): backend_properties = target_to_backend_properties(target) # If target is not specified and any hardware constraint object is # manually specified then do not use the target from the backend as - # it is invalidated by a custom basis gate list or a custom coupling map - elif basis_gates is not None or coupling_map is not None: + # it is invalidated by a custom basis gate list, custom coupling map, + # custom dt or custom instruction_durations + elif ( + basis_gates is not None + or coupling_map is not None + or dt is not None + or instruction_durations is not None + ): _skip_target = True else: target = getattr(backend, "target", None) @@ -440,14 +453,8 @@ def _check_circuits_coupling_map(circuits, cmap, backend): if cmap is not None: max_qubits = cmap.size() elif backend is not None: - backend_version = getattr(backend, "version", 0) - if backend_version <= 1: - if not backend.configuration().simulator: - max_qubits = backend.configuration().n_qubits - else: - max_qubits = None - else: - max_qubits = backend.num_qubits + max_qubits = backend.num_qubits + for circuit in circuits: # If coupling_map is not None or num_qubits == 1 num_qubits = len(circuit.qubits) @@ -465,27 +472,15 @@ def _log_transpile_time(start_time, end_time): def _parse_inst_map(inst_map, backend): # try getting inst_map from user, else backend - if inst_map is None: - backend_version = getattr(backend, "version", 0) - if backend_version <= 1: - if hasattr(backend, "defaults"): - inst_map = getattr(backend.defaults(), "instruction_schedule_map", None) - else: - inst_map = backend.target.instruction_schedule_map() + if inst_map is None and backend is not None: + inst_map = backend.target.instruction_schedule_map() return inst_map def _parse_coupling_map(coupling_map, backend): # try getting coupling_map from user, else backend - if coupling_map is None: - backend_version = getattr(backend, "version", 0) - if backend_version <= 1: - if getattr(backend, "configuration", None): - configuration = backend.configuration() - if hasattr(configuration, "coupling_map") and configuration.coupling_map: - coupling_map = CouplingMap(configuration.coupling_map) - else: - coupling_map = backend.coupling_map + if coupling_map is None and backend is not None: + coupling_map = backend.coupling_map # coupling_map could be None, or a list of lists, e.g. [[0, 1], [2, 1]] if coupling_map is None or isinstance(coupling_map, CouplingMap): @@ -522,14 +517,8 @@ def _parse_instruction_durations(backend, inst_durations, dt, circuit): take precedence over backend durations, but be superceded by ``inst_duration``s. """ if not inst_durations: - backend_version = getattr(backend, "version", 0) - if backend_version <= 1: - backend_durations = InstructionDurations() - try: - backend_durations = InstructionDurations.from_backend(backend) - except AttributeError: - pass - else: + backend_durations = InstructionDurations() + if backend is not None: backend_durations = backend.instruction_durations circ_durations = InstructionDurations() @@ -598,13 +587,6 @@ def _parse_timing_constraints(backend, timing_constraints): return timing_constraints if backend is None and timing_constraints is None: timing_constraints = TimingConstraints() - else: - backend_version = getattr(backend, "version", 0) - if backend_version <= 1: - if timing_constraints is None: - # get constraints from backend - timing_constraints = getattr(backend.configuration(), "timing_constraints", {}) - timing_constraints = TimingConstraints(**timing_constraints) - else: - timing_constraints = backend.target.timing_constraints() + elif backend is not None: + timing_constraints = backend.target.timing_constraints() return timing_constraints diff --git a/qiskit/providers/backend_compat.py b/qiskit/providers/backend_compat.py index de57f3f09fa2..e567c330a958 100644 --- a/qiskit/providers/backend_compat.py +++ b/qiskit/providers/backend_compat.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2020. +# (C) Copyright IBM 2020, 2024. # # 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 @@ -57,7 +57,7 @@ def convert_to_target( A ``Target`` instance. """ - # importing pacakges where they are needed, to avoid cyclic-import. + # importing packages where they are needed, to avoid cyclic-import. # pylint: disable=cyclic-import from qiskit.transpiler.target import ( Target, @@ -82,7 +82,7 @@ def convert_to_target( "switch_case": SwitchCaseOp, } - in_data = {"num_qubits": configuration.n_qubits} + in_data = {"num_qubits": configuration.num_qubits} # Parse global configuration properties if hasattr(configuration, "dt"): @@ -97,7 +97,6 @@ def convert_to_target( all_instructions = set.union( basis_gates, set(required), supported_instructions.intersection(CONTROL_FLOW_OP_NAMES) ) - inst_name_map = {} # type: Dict[str, Instruction] faulty_ops = set() @@ -244,10 +243,8 @@ def _get_value(prop_dict, prop_name): for name in inst_sched_map.instructions: for qubits in inst_sched_map.qubits_with_instruction(name): - if not isinstance(qubits, tuple): qubits = (qubits,) - if ( name not in all_instructions or name not in prop_name_map @@ -267,17 +264,18 @@ def _get_value(prop_dict, prop_name): continue entry = inst_sched_map._get_calibration_entry(name, qubits) - try: prop_name_map[name][qubits].calibration = entry except AttributeError: + # if instruction properties are "None", add entry + prop_name_map[name].update({qubits: InstructionProperties(None, None, entry)}) logger.info( "The PulseDefaults payload received contains an instruction %s on " - "qubits %s which is not present in the configuration or properties payload.", + "qubits %s which is not present in the configuration or properties payload." + "A new properties entry will be added to include the new calibration data.", name, qubits, ) - # Add parsed properties to target target = Target(**in_data) for inst_name in all_instructions: @@ -384,7 +382,7 @@ def __init__( super().__init__( provider=backend.provider, name=backend.name(), - description=self._config.description, + description=getattr(self._config, "description", None), online_date=getattr(self._config, "online_date", None), backend_version=self._config.backend_version, ) diff --git a/qiskit/providers/fake_provider/fake_1q.py b/qiskit/providers/fake_provider/fake_1q.py index 07589476149e..09959620bc92 100644 --- a/qiskit/providers/fake_provider/fake_1q.py +++ b/qiskit/providers/fake_provider/fake_1q.py @@ -32,7 +32,7 @@ def __init__(self): configuration = BackendProperties( backend_name="fake_1q", backend_version="0.0.0", - n_qubits=1, + num_qubits=1, basis_gates=["u1", "u2", "u3", "cx"], simulator=False, local=True, diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index e18f483fb959..30b95bc41404 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -74,10 +74,11 @@ from qiskit.dagcircuit import DAGOpNode, DAGOutNode from qiskit.exceptions import QiskitError from qiskit.providers.backend import BackendV2 -from qiskit.providers.fake_provider import Fake20QV1, GenericBackendV2 +from qiskit.providers.backend_compat import BackendV2Converter +from qiskit.providers.fake_provider import Fake20QV1, Fake27QPulseV1, GenericBackendV2 from qiskit.providers.basic_provider import BasicSimulator from qiskit.providers.options import Options -from qiskit.pulse import InstructionScheduleMap +from qiskit.pulse import InstructionScheduleMap, Schedule, Play, Gaussian, DriveChannel from qiskit.quantum_info import Operator, random_unitary from qiskit.utils import parallel from qiskit.transpiler import CouplingMap, Layout, PassManager, TransformationPass @@ -85,7 +86,13 @@ from qiskit.transpiler.passes import BarrierBeforeFinalMeasurements, GateDirection, VF2PostLayout from qiskit.transpiler.passmanager_config import PassManagerConfig from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager, level_0_pass_manager -from qiskit.transpiler.target import InstructionProperties, Target +from qiskit.transpiler.target import ( + InstructionProperties, + Target, + TimingConstraints, + InstructionDurations, +) + from test import QiskitTestCase, combine, slow_test # pylint: disable=wrong-import-order from ..legacy_cmaps import MELBOURNE_CMAP, RUESCHLIKON_CMAP @@ -1498,6 +1505,86 @@ def test_scheduling_backend_v2(self): self.assertIn("delay", out[0].count_ops()) self.assertIn("delay", out[1].count_ops()) + def test_scheduling_timing_constraints(self): + """Test that scheduling-related loose transpile constraints + work with both BackendV1 and BackendV2.""" + + backend_v1 = Fake27QPulseV1() + backend_v2 = BackendV2Converter(backend_v1) + # the original timing constraints are granularity = min_length = 16 + timing_constraints = TimingConstraints(granularity=32, min_length=64) + error_msgs = { + 65: "Pulse duration is not multiple of 32", + 32: "Pulse gate duration is less than 64", + } + + for backend, duration in zip([backend_v1, backend_v2], [65, 32]): + with self.subTest(backend=backend, duration=duration): + qc = QuantumCircuit(2) + qc.h(0) + qc.cx(0, 1) + qc.measure_all() + qc.add_calibration( + "h", [0], Schedule(Play(Gaussian(duration, 0.2, 4), DriveChannel(0))), [0, 0] + ) + qc.add_calibration( + "cx", + [0, 1], + Schedule(Play(Gaussian(duration, 0.2, 4), DriveChannel(1))), + [0, 0], + ) + with self.assertRaisesRegex(TranspilerError, error_msgs[duration]): + _ = transpile( + qc, + backend=backend, + timing_constraints=timing_constraints, + ) + + def test_scheduling_instruction_constraints(self): + """Test that scheduling-related loose transpile constraints + work with BackendV1.""" + + backend_v1 = Fake27QPulseV1() + backend_v2 = BackendV2Converter(backend_v1) + qc = QuantumCircuit(2) + qc.h(0) + qc.delay(500, 1, "dt") + qc.cx(0, 1) + # update durations + durations = InstructionDurations.from_backend(backend_v1) + durations.update([("cx", [0, 1], 1000, "dt")]) + + for backend in [backend_v1, backend_v2]: + with self.subTest(backend=backend): + scheduled = transpile( + qc, + backend=backend, + scheduling_method="alap", + instruction_durations=durations, + layout_method="trivial", + ) + self.assertEqual(scheduled.duration, 1500) + + def test_scheduling_dt_constraints(self): + """Test that scheduling-related loose transpile constraints + work with BackendV1.""" + + backend_v1 = Fake27QPulseV1() + backend_v2 = BackendV2Converter(backend_v1) + qc = QuantumCircuit(1, 1) + qc.x(0) + qc.measure(0, 0) + original_dt = 2.2222222222222221e-10 + original_duration = 3504 + + for backend in [backend_v1, backend_v2]: + with self.subTest(backend=backend): + # halve dt in sec = double duration in dt + scheduled = transpile( + qc, backend=backend, scheduling_method="asap", dt=original_dt / 2 + ) + self.assertEqual(scheduled.duration, original_duration * 2) + @data(1, 2, 3) def test_no_infinite_loop(self, optimization_level): """Verify circuit cost always descends and optimization does not flip flop indefinitely.""" diff --git a/test/python/transpiler/test_1q.py b/test/python/transpiler/test_1q.py index 31975456f346..50bdc7b24643 100644 --- a/test/python/transpiler/test_1q.py +++ b/test/python/transpiler/test_1q.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2019. +# (C) Copyright IBM 2019, 2024. # # 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 @@ -17,6 +17,7 @@ from qiskit import QuantumCircuit from qiskit.compiler import transpile from qiskit.providers.fake_provider import Fake1Q +from qiskit.providers.basic_provider import BasicSimulator from qiskit.transpiler import TranspilerError from test import combine # pylint: disable=wrong-import-order from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -76,9 +77,7 @@ def test_device(self, circuit, level): name="{circuit.__name__}_level{level}_valid", ) def test_simulator(self, circuit, level): - """All the levels with all the 1Q simulator backend""" - # Set fake backend config to simulator - backend = Fake1Q() - backend._configuration.simulator = True + """All the levels with a simulator backend""" + backend = BasicSimulator() result = transpile(circuit(), backend=backend, optimization_level=level, seed_transpiler=42) self.assertIsInstance(result, QuantumCircuit) diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py index 0382c83ab754..c0f2dde59040 100644 --- a/test/python/transpiler/test_preset_passmanagers.py +++ b/test/python/transpiler/test_preset_passmanagers.py @@ -324,7 +324,7 @@ def test_backend(self, level): qc = QuantumCircuit(qr) qc.cx(qr[2], qr[4]) - backend = GenericBackendV2(num_qubits=14, coupling_map=MELBOURNE_CMAP) + backend = GenericBackendV2(num_qubits=14, coupling_map=MELBOURNE_CMAP, seed=42) _ = transpile(qc, backend, optimization_level=level, callback=self.callback) @@ -413,7 +413,7 @@ def get_translation_stage_plugin(self): """Custom post translation stage.""" return "custom_stage_for_test" - target = TargetBackend(num_qubits=7) + target = TargetBackend(num_qubits=7, seed=42) qr = QuantumRegister(2, "q") qc = QuantumCircuit(qr) qc.h(qr[0]) @@ -425,7 +425,7 @@ def get_translation_stage_plugin(self): def test_level1_runs_vf2post_layout_when_routing_required(self): """Test that if we run routing as part of sabre layout VF2PostLayout runs.""" - target = GenericBackendV2(num_qubits=7, coupling_map=LAGOS_CMAP) + target = GenericBackendV2(num_qubits=7, coupling_map=LAGOS_CMAP, seed=42) qc = QuantumCircuit(5) qc.h(0) qc.cy(0, 1) @@ -448,7 +448,7 @@ def test_level1_runs_vf2post_layout_when_routing_required(self): def test_level1_runs_vf2post_layout_when_routing_method_set_and_required(self): """Test that if we run routing as part of sabre layout VF2PostLayout runs.""" - target = GenericBackendV2(num_qubits=7, coupling_map=LAGOS_CMAP) + target = GenericBackendV2(num_qubits=7, coupling_map=LAGOS_CMAP, seed=42) qc = QuantumCircuit(5) qc.h(0) qc.cy(0, 1) @@ -473,7 +473,10 @@ def test_level1_runs_vf2post_layout_when_routing_method_set_and_required(self): def test_level1_not_runs_vf2post_layout_when_layout_method_set(self): """Test that if we don't run VF2PostLayout with custom layout_method.""" target = GenericBackendV2( - num_qubits=7, basis_gates=["cx", "id", "rz", "sx", "x"], coupling_map=LAGOS_CMAP + num_qubits=7, + basis_gates=["cx", "id", "rz", "sx", "x"], + coupling_map=LAGOS_CMAP, + seed=42, ) qc = QuantumCircuit(5) qc.h(0) @@ -495,7 +498,10 @@ def test_level1_not_runs_vf2post_layout_when_layout_method_set(self): def test_level1_not_run_vf2post_layout_when_trivial_is_perfect(self): """Test that if we find a trivial perfect layout we don't run vf2post.""" target = GenericBackendV2( - num_qubits=7, basis_gates=["cx", "id", "rz", "sx", "x"], coupling_map=LAGOS_CMAP + num_qubits=7, + basis_gates=["cx", "id", "rz", "sx", "x"], + coupling_map=LAGOS_CMAP, + seed=42, ) qc = QuantumCircuit(2) qc.h(0) @@ -512,7 +518,10 @@ def test_level1_not_run_vf2post_layout_when_trivial_is_perfect(self): def test_level1_not_run_vf2post_layout_when_vf2layout_is_perfect(self): """Test that if we find a vf2 perfect layout we don't run vf2post.""" target = GenericBackendV2( - num_qubits=7, basis_gates=["cx", "id", "rz", "sx", "x"], coupling_map=LAGOS_CMAP + num_qubits=7, + basis_gates=["cx", "id", "rz", "sx", "x"], + coupling_map=LAGOS_CMAP, + seed=42, ) qc = QuantumCircuit(4) qc.h(0) @@ -531,7 +540,10 @@ def test_level1_not_run_vf2post_layout_when_vf2layout_is_perfect(self): def test_level1_runs_vf2post_layout_when_routing_required_control_flow(self): """Test that if we run routing as part of sabre layout VF2PostLayout runs.""" target = GenericBackendV2( - num_qubits=7, basis_gates=["cx", "id", "rz", "sx", "x"], coupling_map=LAGOS_CMAP + num_qubits=7, + basis_gates=["cx", "id", "rz", "sx", "x"], + coupling_map=LAGOS_CMAP, + seed=42, ) _target = target.target target._target.add_instruction(ForLoopOp, name="for_loop") @@ -558,7 +570,10 @@ def test_level1_runs_vf2post_layout_when_routing_required_control_flow(self): def test_level1_not_runs_vf2post_layout_when_layout_method_set_control_flow(self): """Test that if we don't run VF2PostLayout with custom layout_method.""" target = GenericBackendV2( - num_qubits=7, basis_gates=["cx", "id", "rz", "sx", "x"], coupling_map=LAGOS_CMAP + num_qubits=7, + basis_gates=["cx", "id", "rz", "sx", "x"], + coupling_map=LAGOS_CMAP, + seed=42, ) _target = target.target target._target.add_instruction(ForLoopOp, name="for_loop") @@ -584,7 +599,10 @@ def test_level1_not_runs_vf2post_layout_when_layout_method_set_control_flow(self def test_level1_not_run_vf2post_layout_when_trivial_is_perfect_control_flow(self): """Test that if we find a trivial perfect layout we don't run vf2post.""" target = GenericBackendV2( - num_qubits=7, basis_gates=["cx", "id", "rz", "sx", "x"], coupling_map=LAGOS_CMAP + num_qubits=7, + basis_gates=["cx", "id", "rz", "sx", "x"], + coupling_map=LAGOS_CMAP, + seed=42, ) _target = target.target target._target.add_instruction(ForLoopOp, name="for_loop") @@ -604,7 +622,10 @@ def test_level1_not_run_vf2post_layout_when_trivial_is_perfect_control_flow(self def test_level1_not_run_vf2post_layout_when_vf2layout_is_perfect_control_flow(self): """Test that if we find a vf2 perfect layout we don't run vf2post.""" target = GenericBackendV2( - num_qubits=7, basis_gates=["cx", "id", "rz", "sx", "x"], coupling_map=LAGOS_CMAP + num_qubits=7, + basis_gates=["cx", "id", "rz", "sx", "x"], + coupling_map=LAGOS_CMAP, + seed=42, ) _target = target.target target._target.add_instruction(ForLoopOp, name="for_loop") @@ -630,7 +651,7 @@ class TestInitialLayouts(QiskitTestCase): @data(0, 1, 2, 3) def test_layout_1711(self, level): - """Test that a user-given initial layout is respected, + """Test that a user-given initial layout is respected in the qobj. See: https://github.com/Qiskit/qiskit-terra/issues/1711 @@ -661,9 +682,7 @@ def test_layout_1711(self, level): 14: ancilla[12], 15: qr[2], } - - backend = Fake20QV1() - backend.configuration().coupling_map = RUESCHLIKON_CMAP + backend = GenericBackendV2(num_qubits=16, coupling_map=RUESCHLIKON_CMAP, seed=42) qc_b = transpile(qc, backend, initial_layout=initial_layout, optimization_level=level) qobj = assemble(qc_b) @@ -672,7 +691,7 @@ def test_layout_1711(self, level): compiled_ops = qobj.experiments[0].instructions for operation in compiled_ops: if operation.name == "cx": - self.assertIn(operation.qubits, backend.configuration().coupling_map) + self.assertIn(tuple(operation.qubits), backend.coupling_map) self.assertIn(operation.qubits, [[15, 0], [15, 2]]) @data(0, 1, 2, 3) @@ -711,10 +730,8 @@ def test_layout_2532(self, level): 12: ancilla[7], 13: ancilla[8], } - backend = Fake20QV1() - backend.configuration().coupling_map = MELBOURNE_CMAP + backend = GenericBackendV2(num_qubits=14, coupling_map=MELBOURNE_CMAP, seed=42) qc_b = transpile(qc, backend, initial_layout=initial_layout, optimization_level=level) - self.assertEqual(qc_b._layout.initial_layout._p2v, final_layout) output_qr = qc_b.qregs[0] @@ -766,7 +783,6 @@ def test_layout_2503(self, level): } backend = Fake20QV1() - qc_b = transpile(qc, backend, initial_layout=initial_layout, optimization_level=level) self.assertEqual(qc_b._layout.initial_layout._p2v, final_layout) @@ -825,21 +841,21 @@ def test_layout_tokyo_2845(self, level): 2: Qubit(QuantumRegister(15, "ancilla"), 2), 3: Qubit(QuantumRegister(15, "ancilla"), 3), 4: Qubit(QuantumRegister(15, "ancilla"), 4), - 5: Qubit(QuantumRegister(15, "ancilla"), 5), - 6: Qubit(QuantumRegister(15, "ancilla"), 6), - 7: Qubit(QuantumRegister(15, "ancilla"), 7), - 8: Qubit(QuantumRegister(3, "qr1"), 1), - 9: Qubit(QuantumRegister(15, "ancilla"), 8), - 10: Qubit(QuantumRegister(15, "ancilla"), 9), - 11: Qubit(QuantumRegister(15, "ancilla"), 10), - 12: Qubit(QuantumRegister(3, "qr1"), 0), - 13: Qubit(QuantumRegister(3, "qr1"), 2), - 14: Qubit(QuantumRegister(2, "qr2"), 1), - 15: Qubit(QuantumRegister(15, "ancilla"), 11), - 16: Qubit(QuantumRegister(15, "ancilla"), 12), - 17: Qubit(QuantumRegister(15, "ancilla"), 13), - 18: Qubit(QuantumRegister(15, "ancilla"), 14), - 19: Qubit(QuantumRegister(2, "qr2"), 0), + 5: Qubit(QuantumRegister(3, "qr1"), 2), + 6: Qubit(QuantumRegister(2, "qr2"), 0), + 7: Qubit(QuantumRegister(2, "qr2"), 1), + 8: Qubit(QuantumRegister(15, "ancilla"), 5), + 9: Qubit(QuantumRegister(15, "ancilla"), 6), + 10: Qubit(QuantumRegister(3, "qr1"), 1), + 11: Qubit(QuantumRegister(3, "qr1"), 0), + 12: Qubit(QuantumRegister(15, "ancilla"), 7), + 13: Qubit(QuantumRegister(15, "ancilla"), 8), + 14: Qubit(QuantumRegister(15, "ancilla"), 9), + 15: Qubit(QuantumRegister(15, "ancilla"), 10), + 16: Qubit(QuantumRegister(15, "ancilla"), 11), + 17: Qubit(QuantumRegister(15, "ancilla"), 12), + 18: Qubit(QuantumRegister(15, "ancilla"), 13), + 19: Qubit(QuantumRegister(15, "ancilla"), 14), } # Trivial layout @@ -856,8 +872,8 @@ def test_layout_tokyo_2845(self, level): expected_layout_level2, expected_layout_level3, ] - backend = Fake20QV1() - backend.configuration().coupling_map = TOKYO_CMAP + + backend = GenericBackendV2(num_qubits=20, coupling_map=TOKYO_CMAP, seed=42) result = transpile(qc, backend, optimization_level=level, seed_transpiler=42) self.assertEqual(result._layout.initial_layout._p2v, expected_layouts[level]) @@ -899,78 +915,32 @@ def test_layout_tokyo_fully_connected_cx(self, level): } sabre_layout = { - 0: ancilla[0], - 1: ancilla[1], - 2: ancilla[2], - 3: ancilla[3], - 4: ancilla[4], - 5: qr[2], - 6: qr[1], - 7: ancilla[6], - 8: ancilla[7], - 9: ancilla[8], - 10: qr[3], - 11: qr[0], - 12: ancilla[9], - 13: ancilla[10], - 14: ancilla[11], - 15: ancilla[5], - 16: qr[4], - 17: ancilla[12], - 18: ancilla[13], - 19: ancilla[14], - } - - sabre_layout_lvl_2 = { - 0: ancilla[0], - 1: ancilla[1], - 2: ancilla[2], - 3: ancilla[3], - 4: ancilla[4], - 5: qr[2], - 6: qr[1], - 7: ancilla[6], - 8: ancilla[7], - 9: ancilla[8], - 10: qr[3], - 11: qr[0], - 12: ancilla[9], - 13: ancilla[10], - 14: ancilla[11], - 15: ancilla[5], - 16: qr[4], - 17: ancilla[12], - 18: ancilla[13], - 19: ancilla[14], - } - - sabre_layout_lvl_3 = { - 0: ancilla[0], - 1: ancilla[1], - 2: ancilla[2], - 3: ancilla[3], - 4: ancilla[4], - 5: qr[2], - 6: qr[1], - 7: ancilla[6], - 8: ancilla[7], - 9: ancilla[8], - 10: qr[3], - 11: qr[0], - 12: ancilla[9], - 13: ancilla[10], - 14: ancilla[11], - 15: ancilla[5], - 16: qr[4], - 17: ancilla[12], - 18: ancilla[13], - 19: ancilla[14], + 0: Qubit(QuantumRegister(15, "ancilla"), 0), + 1: Qubit(QuantumRegister(15, "ancilla"), 1), + 2: Qubit(QuantumRegister(15, "ancilla"), 2), + 3: Qubit(QuantumRegister(15, "ancilla"), 3), + 4: Qubit(QuantumRegister(15, "ancilla"), 4), + 5: Qubit(QuantumRegister(5, "qr"), 1), + 6: Qubit(QuantumRegister(5, "qr"), 0), + 7: Qubit(QuantumRegister(5, "qr"), 4), + 8: Qubit(QuantumRegister(15, "ancilla"), 6), + 9: Qubit(QuantumRegister(15, "ancilla"), 7), + 10: Qubit(QuantumRegister(5, "qr"), 2), + 11: Qubit(QuantumRegister(5, "qr"), 3), + 12: Qubit(QuantumRegister(15, "ancilla"), 5), + 13: Qubit(QuantumRegister(15, "ancilla"), 8), + 14: Qubit(QuantumRegister(15, "ancilla"), 9), + 15: Qubit(QuantumRegister(15, "ancilla"), 10), + 16: Qubit(QuantumRegister(15, "ancilla"), 11), + 17: Qubit(QuantumRegister(15, "ancilla"), 12), + 18: Qubit(QuantumRegister(15, "ancilla"), 13), + 19: Qubit(QuantumRegister(15, "ancilla"), 14), } expected_layout_level0 = trivial_layout expected_layout_level1 = sabre_layout - expected_layout_level2 = sabre_layout_lvl_2 - expected_layout_level3 = sabre_layout_lvl_3 + expected_layout_level2 = sabre_layout + expected_layout_level3 = sabre_layout expected_layouts = [ expected_layout_level0, @@ -978,9 +948,7 @@ def test_layout_tokyo_fully_connected_cx(self, level): expected_layout_level2, expected_layout_level3, ] - backend = Fake20QV1() - backend.configuration().coupling_map = TOKYO_CMAP - + backend = GenericBackendV2(num_qubits=20, coupling_map=TOKYO_CMAP, seed=42) result = transpile(qc, backend, optimization_level=level, seed_transpiler=42) self.assertEqual(result._layout.initial_layout._p2v, expected_layouts[level]) @@ -991,12 +959,10 @@ def test_all_levels_use_trivial_if_perfect(self, level): See: https://github.com/Qiskit/qiskit-terra/issues/5694 for more details """ - backend = Fake20QV1() - backend.configuration().coupling_map = TOKYO_CMAP - config = backend.configuration() + backend = GenericBackendV2(num_qubits=20, coupling_map=TOKYO_CMAP, seed=42) - rows = [x[0] for x in config.coupling_map] - cols = [x[1] for x in config.coupling_map] + rows = [x[0] for x in backend.coupling_map] + cols = [x[1] for x in backend.coupling_map] adjacency_matrix = np.zeros((20, 20)) adjacency_matrix[rows, cols] = 1 @@ -1255,7 +1221,7 @@ def test_with_backend(self, optimization_level): @data(0, 1, 2, 3) def test_with_no_backend(self, optimization_level): """Test a passmanager is constructed with no backend and optimization level.""" - target = GenericBackendV2(num_qubits=7, coupling_map=LAGOS_CMAP) + target = GenericBackendV2(num_qubits=7, coupling_map=LAGOS_CMAP, seed=42) pm = generate_preset_pass_manager( optimization_level, coupling_map=target.coupling_map, @@ -1270,7 +1236,7 @@ def test_with_no_backend(self, optimization_level): @data(0, 1, 2, 3) def test_with_no_backend_only_target(self, optimization_level): """Test a passmanager is constructed with a manual target and optimization level.""" - target = GenericBackendV2(num_qubits=7, coupling_map=LAGOS_CMAP) + target = GenericBackendV2(num_qubits=7, coupling_map=LAGOS_CMAP, seed=42) pm = generate_preset_pass_manager(optimization_level, target=target.target) self.assertIsInstance(pm, PassManager) @@ -1299,7 +1265,7 @@ def get_translation_stage_plugin(self): """Custom post translation stage.""" return "custom_stage_for_test" - target = TargetBackend(num_qubits=7, coupling_map=LAGOS_CMAP) + target = TargetBackend(num_qubits=7, coupling_map=LAGOS_CMAP, seed=42) pm = generate_preset_pass_manager(optimization_level, backend=target) self.assertIsInstance(pm, PassManager) @@ -1331,7 +1297,7 @@ def get_translation_stage_plugin(self): """Custom post translation stage.""" return "custom_stage_for_test" - target = TargetBackend(num_qubits=7, coupling_map=LAGOS_CMAP) + target = TargetBackend(num_qubits=7, coupling_map=LAGOS_CMAP, seed=42) pm = generate_preset_pass_manager(optimization_level, backend=target) self.assertIsInstance(pm, PassManager) @@ -1363,7 +1329,7 @@ def get_translation_stage_plugin(self): """Custom post translation stage.""" return "custom_stage_for_test" - target = TargetBackend(num_qubits=7, coupling_map=LAGOS_CMAP) + target = TargetBackend(num_qubits=7, coupling_map=LAGOS_CMAP, seed=42) pm = generate_preset_pass_manager(optimization_level, backend=target) self.assertIsInstance(pm, PassManager) @@ -1395,7 +1361,7 @@ def get_translation_stage_plugin(self): """Custom post translation stage.""" return "custom_stage_for_test" - target = TargetBackend(num_qubits=7, coupling_map=LAGOS_CMAP) + target = TargetBackend(num_qubits=7, coupling_map=LAGOS_CMAP, seed=42) pm = generate_preset_pass_manager(optimization_level, backend=target) self.assertIsInstance(pm, PassManager) diff --git a/test/python/transpiler/test_pulse_gate_pass.py b/test/python/transpiler/test_pulse_gate_pass.py index 8de8ceb66ef8..a11d4c4a6b53 100644 --- a/test/python/transpiler/test_pulse_gate_pass.py +++ b/test/python/transpiler/test_pulse_gate_pass.py @@ -16,6 +16,7 @@ from qiskit import pulse, circuit, transpile from qiskit.providers.fake_provider import Fake27QPulseV1, GenericBackendV2 +from qiskit.providers.models import GateConfig from qiskit.quantum_info.random import random_unitary from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -185,6 +186,12 @@ def test_transpile_with_custom_gate(self): backend.defaults().instruction_schedule_map.add( "my_gate", (1,), self.my_gate_q1, arguments=["P0"] ) + # Add gate to backend configuration + backend.configuration().basis_gates.append("my_gate") + dummy_config = GateConfig( + name="my_gate", parameters=[], qasm_def="", coupling_map=[(0,), (1,)] + ) + backend.configuration().gates.append(dummy_config) # Remove timing constraints to avoid triggering # scheduling passes. backend.configuration().timing_constraints = {} @@ -212,6 +219,10 @@ def test_transpile_with_parameterized_custom_gate(self): backend.defaults().instruction_schedule_map.add( "my_gate", (0,), self.my_gate_q0, arguments=["P0"] ) + # Add gate to backend configuration + backend.configuration().basis_gates.append("my_gate") + dummy_config = GateConfig(name="my_gate", parameters=[], qasm_def="", coupling_map=[(0,)]) + backend.configuration().gates.append(dummy_config) # Remove timing constraints to avoid triggering # scheduling passes. backend.configuration().timing_constraints = {} @@ -237,6 +248,10 @@ def test_transpile_with_multiple_circuits(self): backend.defaults().instruction_schedule_map.add( "my_gate", (0,), self.my_gate_q0, arguments=["P0"] ) + # Add gate to backend configuration + backend.configuration().basis_gates.append("my_gate") + dummy_config = GateConfig(name="my_gate", parameters=[], qasm_def="", coupling_map=[(0,)]) + backend.configuration().gates.append(dummy_config) # Remove timing constraints to avoid triggering # scheduling passes. backend.configuration().timing_constraints = {} @@ -263,6 +278,10 @@ def test_multiple_instructions_with_different_parameters(self): backend.defaults().instruction_schedule_map.add( "my_gate", (0,), self.my_gate_q0, arguments=["P0"] ) + # Add gate to backend configuration + backend.configuration().basis_gates.append("my_gate") + dummy_config = GateConfig(name="my_gate", parameters=[], qasm_def="", coupling_map=[(0,)]) + backend.configuration().gates.append(dummy_config) # Remove timing constraints to avoid triggering # scheduling passes. backend.configuration().timing_constraints = {}