Skip to content

Commit d53bbc4

Browse files
Fix VF2PostLayout with uncoupled qubits in strict_direction=True (Qiskit#14998) (Qiskit#15001)
When `VF2PostLayout` is set in strict mode, we have to include even active but uncoupled qubits in the interaction graph, because of the semantic constraints. We need to limit the number of these uncoupled qubits we'll consider, though, because there's a factorial overhead to handling them. A previous commit[^1] added this skip to `strict_direction=False`, but didn't correctly handle the continuation case where we're within the limit. This commit correctly clears out the uncoupled-qubit metadata that was causing problems in later layout reconstruction. [^1]: b4094dd: Fix calls to `VF2PostLayout` after optimization loop at O3 (cherry picked from commit 2d73e5d) Co-authored-by: Jake Lishman <[email protected]>
1 parent d4537c1 commit d53bbc4

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

qiskit/transpiler/passes/layout/vf2_post_layout.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,19 @@ def run(self, dag):
153153
self.property_set["VF2PostLayout_stop_reason"] = VF2PostLayoutStopReason.MORE_THAN_2Q
154154
return
155155
im_graph, im_graph_node_map, reverse_im_graph_node_map, free_nodes = result
156-
if len(free_nodes) > 1 and self.strict_direction:
157-
self.property_set["VF2PostLayout_stop_reason"] = (
158-
VF2PostLayoutStopReason.NO_BETTER_SOLUTION_FOUND
159-
)
160-
return
156+
if self.strict_direction and free_nodes:
157+
# If there are uncoupled qubits, in non-strict modes we just allocate them to the
158+
# lowest-error states at the end. However, in strict mode, we have to consider them at
159+
# the same time to handle heterogeneous targets correctly. This risks a factorial
160+
# combinatoric explosion in complexity, though, so we put a limit on how many we'll
161+
# handle. The builder still builds the graph entirely, it just returns the free nodes
162+
# for us to check on, so we clear that out after we've checked it.
163+
if len(free_nodes) > 1:
164+
self.property_set["VF2PostLayout_stop_reason"] = (
165+
VF2PostLayoutStopReason.NO_BETTER_SOLUTION_FOUND
166+
)
167+
return
168+
free_nodes.clear()
161169
scoring_bit_list = vf2_utils.build_bit_list(im_graph, im_graph_node_map)
162170
scoring_edge_list = vf2_utils.build_edge_list(im_graph)
163171

test/python/transpiler/test_vf2_post_layout.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from qiskit import QuantumRegister, QuantumCircuit
1919
from qiskit.circuit import ControlFlowOp
2020
from qiskit.circuit.library import CXGate, XGate
21-
from qiskit.transpiler import Layout, TranspilerError
21+
from qiskit.transpiler import Layout, TranspilerError, PassManager, passes
2222
from qiskit.transpiler.passes.layout.vf2_post_layout import VF2PostLayout, VF2PostLayoutStopReason
2323
from qiskit.converters import circuit_to_dag
2424
from qiskit.providers.fake_provider import GenericBackendV2
@@ -352,6 +352,33 @@ def test_complete_layout_with_idle_qubits(self, seed, strict_direction):
352352
}
353353
self.assertEqual(unallocated, set())
354354

355+
@ddt.data(-1, 12)
356+
def test_complete_layout_with_one_uncoupled_qubit(self, seed):
357+
"""Test that a single uncoupled qubit is handled correctly.
358+
359+
Regression test of https://github.com/Qiskit/qiskit/issues/14997."""
360+
qc = QuantumCircuit(3)
361+
qc.x(0)
362+
qc.cx(1, 2)
363+
364+
bad = InstructionProperties(error=1e-1)
365+
good = InstructionProperties(error=1e-5)
366+
367+
target = Target()
368+
target.add_instruction(XGate(), {(0,): bad, (1,): good, (2,): good})
369+
target.add_instruction(CXGate(), {(0, 1): good, (1, 2): bad})
370+
371+
pm = PassManager(
372+
[
373+
passes.TrivialLayout(target),
374+
passes.ApplyLayout(),
375+
passes.VF2PostLayout(target, seed=seed, strict_direction=True),
376+
passes.ApplyLayout(),
377+
]
378+
)
379+
out = pm.run(qc)
380+
self.assertEqual(out.layout.final_index_layout(), [2, 0, 1])
381+
355382

356383
class TestVF2PostLayoutScoring(QiskitTestCase):
357384
"""Test scoring heuristic function for VF2PostLayout."""

0 commit comments

Comments
 (0)