diff --git a/qiskit/transpiler/preset_passmanagers/common.py b/qiskit/transpiler/preset_passmanagers/common.py index 8fc1402d322..d59a6271cbf 100644 --- a/qiskit/transpiler/preset_passmanagers/common.py +++ b/qiskit/transpiler/preset_passmanagers/common.py @@ -86,9 +86,12 @@ class _InvalidControlFlowForBackend: def __init__(self, basis_gates=(), target=None): if target is not None: self.unsupported = [op for op in CONTROL_FLOW_OP_NAMES if op not in target] - else: - basis_gates = set(basis_gates) if basis_gates is not None else set() + elif basis_gates is not None: + basis_gates = set(basis_gates) self.unsupported = [op for op in CONTROL_FLOW_OP_NAMES if op not in basis_gates] + else: + # Pass manager without basis gates or target; assume everything's valid. + self.unsupported = [] def message(self, property_set): """Create an error message for the given property set.""" diff --git a/releasenotes/notes/fix-transpile-control-flow-no-hardware-7c00ad733a569bb9.yaml b/releasenotes/notes/fix-transpile-control-flow-no-hardware-7c00ad733a569bb9.yaml new file mode 100644 index 00000000000..f306362c404 --- /dev/null +++ b/releasenotes/notes/fix-transpile-control-flow-no-hardware-7c00ad733a569bb9.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + The preset pass managers of :func:`.transpile` will no longer fail on circuits + with control flow, if no hardware target or basis-gate set is specified. They + will now treat such abstract targets as permitting all control-flow operations. + Fixed `#11906 `__. diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index 6aebaab832a..954eb016e6d 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -1646,6 +1646,27 @@ def test_target_ideal_gates(self, opt_level): self.assertEqual(Operator.from_circuit(result), Operator.from_circuit(qc)) + @data(0, 1, 2, 3) + def test_transpile_control_flow_no_backend(self, opt_level): + """Test `transpile` with control flow and no specified hardware constraints.""" + qc = QuantumCircuit(QuantumRegister(1, "q"), ClassicalRegister(1, "c")) + qc.h(0) + qc.measure(0, 0) + with qc.if_test((qc.clbits[0], False)): + qc.x(0) + with qc.while_loop((qc.clbits[0], True)): + qc.x(0) + with qc.for_loop(range(2)): + qc.x(0) + with qc.switch(qc.cregs[0]) as case: + with case(case.DEFAULT): + qc.x(0) + qc.measure(0, 0) + + transpiled = transpile(qc, optimization_level=opt_level) + # There's nothing that can be optimized here. + self.assertEqual(qc, transpiled) + @data(0, 1, 2, 3) def test_transpile_with_custom_control_flow_target(self, opt_level): """Test transpile() with a target and constrol flow ops."""