Skip to content

Commit

Permalink
Fix interaction graph vf2 scoring to include 1q component (#10084) (#…
Browse files Browse the repository at this point in the history
…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 0e44c5e)

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
  • Loading branch information
mergify[bot] and mtreinish authored May 8, 2023
1 parent a259fd8 commit 7967ab1
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 18 deletions.
28 changes: 13 additions & 15 deletions crates/accelerate/src/vf2_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<f64>()
} 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::<f64>()
} else {
bit_counts
.par_iter()
.enumerate()
.filter_map(bit_filter_map)
.product()
};
Ok(1. - fidelity)
}

Expand Down
9 changes: 7 additions & 2 deletions qiskit/transpiler/passes/layout/vf2_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down
6 changes: 6 additions & 0 deletions releasenotes/notes/fix-vf2-scoring-1q-e2ac29075831d64d.yaml
Original file line number Diff line number Diff line change
@@ -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.
42 changes: 41 additions & 1 deletion test/python/transpiler/test_vf2_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 7967ab1

Please sign in to comment.