From 7967ab12cca8ec4ba5aa732590b1c366bf784e57 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 16:45:12 +0000 Subject: [PATCH] Fix interaction graph vf2 scoring to include 1q component (#10084) (#10086) * Fix interaction graph vf2 scoring to include 1q component In #9148 a bug was introduced into the vf2 scoring code. In that PR the vf2 passes were changed to treat standalone qubits as a special case to improve the algorithmic efficiency of the pass. However, that PR broke the scoring algorithm so that it was no longer factoring in the 1q component of the interaction graph when scoring a layout. This meant that when scoring a potential layout only the 2q error rates were been factored into the score and the pass was potentially selecting worse performing qubits. This commit fixes this error and ensures the scoring is looking at all the error rates. * Update qiskit/transpiler/passes/layout/vf2_utils.py (cherry picked from commit 0e44c5e38066c26e06d19fe5fcbc947eb1d25472) Co-authored-by: Matthew Treinish --- crates/accelerate/src/vf2_layout.rs | 28 ++++++------- qiskit/transpiler/passes/layout/vf2_utils.py | 9 +++- .../fix-vf2-scoring-1q-e2ac29075831d64d.yaml | 6 +++ test/python/transpiler/test_vf2_layout.py | 42 ++++++++++++++++++- 4 files changed, 67 insertions(+), 18 deletions(-) create mode 100644 releasenotes/notes/fix-vf2-scoring-1q-e2ac29075831d64d.yaml diff --git a/crates/accelerate/src/vf2_layout.rs b/crates/accelerate/src/vf2_layout.rs index 8ad65cfbcd1f..dbac7e4ab9b7 100644 --- a/crates/accelerate/src/vf2_layout.rs +++ b/crates/accelerate/src/vf2_layout.rs @@ -73,21 +73,19 @@ pub fn score_layout( } else { edge_list.par_iter().filter_map(edge_filter_map).product() }; - if strict_direction { - fidelity *= if bit_list.len() < PARALLEL_THRESHOLD || !run_in_parallel { - bit_counts - .iter() - .enumerate() - .filter_map(bit_filter_map) - .product::() - } else { - bit_counts - .par_iter() - .enumerate() - .filter_map(bit_filter_map) - .product() - }; - } + fidelity *= if bit_list.len() < PARALLEL_THRESHOLD || !run_in_parallel { + bit_counts + .iter() + .enumerate() + .filter_map(bit_filter_map) + .product::() + } else { + bit_counts + .par_iter() + .enumerate() + .filter_map(bit_filter_map) + .product() + }; Ok(1. - fidelity) } diff --git a/qiskit/transpiler/passes/layout/vf2_utils.py b/qiskit/transpiler/passes/layout/vf2_utils.py index ba8c250208c4..ed14df998caa 100644 --- a/qiskit/transpiler/passes/layout/vf2_utils.py +++ b/qiskit/transpiler/passes/layout/vf2_utils.py @@ -111,9 +111,14 @@ def score_layout( size = 0 nlayout = NLayout(layout_mapping, size + 1, size + 1) bit_list = np.zeros(len(im_graph), dtype=np.int32) - if strict_direction: - for node_index in bit_map.values(): + for node_index in bit_map.values(): + try: bit_list[node_index] = sum(im_graph[node_index].values()) + # If node_index not in im_graph that means there was a standalone + # node we will score/sort separately outside the vf2 mapping, so we + # can skip the hole + except IndexError: + pass edge_list = { (edge[0], edge[1]): sum(edge[2].values()) for edge in im_graph.edge_index_map().values() } diff --git a/releasenotes/notes/fix-vf2-scoring-1q-e2ac29075831d64d.yaml b/releasenotes/notes/fix-vf2-scoring-1q-e2ac29075831d64d.yaml new file mode 100644 index 000000000000..b2901ede4489 --- /dev/null +++ b/releasenotes/notes/fix-vf2-scoring-1q-e2ac29075831d64d.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fix a bug in the :class:`~.VF2Layout` and :class:`~.VF2PostLayout` passes + where the passes wer failing to account for the 1 qubit error component when + evaluating a potential layout. diff --git a/test/python/transpiler/test_vf2_layout.py b/test/python/transpiler/test_vf2_layout.py index b25e07edc29b..b1eb02a489d9 100644 --- a/test/python/transpiler/test_vf2_layout.py +++ b/test/python/transpiler/test_vf2_layout.py @@ -36,7 +36,8 @@ FakeYorktown, FakeGuadalupeV2, ) -from qiskit.circuit.library import GraphState, CXGate, XGate +from qiskit.circuit import Measure +from qiskit.circuit.library import GraphState, CXGate, XGate, HGate from qiskit.transpiler import PassManager, AnalysisPass from qiskit.transpiler.target import InstructionProperties from qiskit.transpiler.preset_passmanagers.common import generate_embed_passmanager @@ -84,6 +85,45 @@ def run(dag, wire_map): class TestVF2LayoutSimple(LayoutTestCase): """Tests the VF2Layout pass""" + def test_1q_component_influence(self): + """Assert that the 1q component of a connected interaction graph is scored correctly.""" + target = Target() + target.add_instruction( + CXGate(), + { + (0, 1): InstructionProperties(error=0.0), + (1, 2): InstructionProperties(error=0.0), + (2, 3): InstructionProperties(error=0.0), + }, + ) + target.add_instruction( + HGate(), + { + (0,): InstructionProperties(error=0.0), + (1,): InstructionProperties(error=0.0), + (2,): InstructionProperties(error=0.0), + }, + ) + target.add_instruction( + Measure(), + { + (0,): InstructionProperties(error=0.1), + (1,): InstructionProperties(error=0.1), + (2,): InstructionProperties(error=0.9), + }, + ) + + qc = QuantumCircuit(2, 2) + qc.h(0) + qc.cx(0, 1) + qc.cx(1, 0) + qc.measure(0, 0) + qc.measure(1, 1) + vf2_pass = VF2Layout(target=target, seed=self.seed) + vf2_pass(qc) + layout = vf2_pass.property_set["layout"] + self.assertEqual([1, 0], list(layout._p2v.keys())) + def test_2q_circuit_2q_coupling(self): """A simple example, without considering the direction 0 - 1