diff --git a/qiskit/transpiler/passes/layout/vf2_layout.py b/qiskit/transpiler/passes/layout/vf2_layout.py index 4e3077eb1d4d..626f8f2b0fa3 100644 --- a/qiskit/transpiler/passes/layout/vf2_layout.py +++ b/qiskit/transpiler/passes/layout/vf2_layout.py @@ -104,15 +104,21 @@ def __init__( limit on the number of trials will be set. target (Target): A target representing the backend device to run ``VF2Layout`` on. If specified it will supersede a set value for ``properties`` and - ``coupling_map``. + ``coupling_map`` if the :class:`.Target` contains connectivity constraints. If the value + of ``target`` models an ideal backend without any constraints then the value of + ``coupling_map`` + will be used. Raises: TypeError: At runtime, if neither ``coupling_map`` or ``target`` are provided. """ super().__init__() self.target = target - if target is not None: - self.coupling_map = self.target.build_coupling_map() + if ( + target is not None + and (target_coupling_map := self.target.build_coupling_map()) is not None + ): + self.coupling_map = target_coupling_map else: self.coupling_map = coupling_map self.properties = properties @@ -145,7 +151,7 @@ def run(self, dag): ) # Filter qubits without any supported operations. If they don't support any operations # They're not valid for layout selection - if self.target is not None: + if self.target is not None and self.target.qargs is not None: has_operations = set(itertools.chain.from_iterable(self.target.qargs)) to_remove = set(range(len(cm_nodes))).difference(has_operations) if to_remove: diff --git a/qiskit/transpiler/passes/layout/vf2_utils.py b/qiskit/transpiler/passes/layout/vf2_utils.py index 99006017482c..c5d420127f88 100644 --- a/qiskit/transpiler/passes/layout/vf2_utils.py +++ b/qiskit/transpiler/passes/layout/vf2_utils.py @@ -145,7 +145,7 @@ def score_layout( def build_average_error_map(target, properties, coupling_map): """Build an average error map used for scoring layouts pre-basis translation.""" num_qubits = 0 - if target is not None: + if target is not None and target.qargs is not None: num_qubits = target.num_qubits avg_map = ErrorMap(len(target.qargs)) elif coupling_map is not None: @@ -157,7 +157,7 @@ def build_average_error_map(target, properties, coupling_map): # object avg_map = ErrorMap(0) built = False - if target is not None: + if target is not None and target.qargs is not None: for qargs in target.qargs: if qargs is None: continue diff --git a/releasenotes/notes/fix-vf2-aer-a7306ce07ea81700.yaml b/releasenotes/notes/fix-vf2-aer-a7306ce07ea81700.yaml new file mode 100644 index 000000000000..52ea96d0984b --- /dev/null +++ b/releasenotes/notes/fix-vf2-aer-a7306ce07ea81700.yaml @@ -0,0 +1,4 @@ +fixes: + - | + The :class:`.VF2Layout` pass would raise an exception when provided with a :class:`.Target` instance without connectivity constraints. + This would be the case with targets from Aer 0.13. The issue is now fixed. diff --git a/test/python/transpiler/test_vf2_layout.py b/test/python/transpiler/test_vf2_layout.py index b0957c824688..716e49d35009 100644 --- a/test/python/transpiler/test_vf2_layout.py +++ b/test/python/transpiler/test_vf2_layout.py @@ -570,6 +570,26 @@ def test_3_q_gate(self): pass_1.property_set["VF2Layout_stop_reason"], VF2LayoutStopReason.MORE_THAN_2Q ) + def test_target_without_coupling_map(self): + """When a target has no coupling_map but it is provided as argument. + See: https://github.com/Qiskit/qiskit/pull/11585""" + + circuit = QuantumCircuit(3) + circuit.cx(0, 1) + dag = circuit_to_dag(circuit) + + target = Target(num_qubits=3) + target.add_instruction(CXGate()) + + vf2_pass = VF2Layout( + coupling_map=CouplingMap([[0, 2], [1, 2]]), target=target, seed=42, max_trials=1 + ) + vf2_pass.run(dag) + + self.assertEqual( + vf2_pass.property_set["VF2Layout_stop_reason"], VF2LayoutStopReason.SOLUTION_FOUND + ) + class TestMultipleTrials(QiskitTestCase): """Test the passes behavior with >1 trial."""