Skip to content

Commit

Permalink
Symmetrize coupling map in qubit_subset_finders.find_lines (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
Durd3nT authored Jan 26, 2024
1 parent 793d47c commit 5cb134a
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 27 deletions.
10 changes: 6 additions & 4 deletions qopt_best_practices/qubit_selection/backend_evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from collections.abc import Callable

from qiskit.transpiler import CouplingMap
from qiskit.providers import Backend

from .metric_evaluators import evaluate_fidelity
from .qubit_subset_finders import find_lines
Expand All @@ -17,10 +18,11 @@ class BackendEvaluator:
transpiler pass.
"""

def __init__(self, backend):

def __init__(self, backend: Backend):
self.backend = backend
self.coupling_map = CouplingMap(backend.configuration().coupling_map)
self.coupling_map = CouplingMap(backend.coupling_map)
if not self.coupling_map.is_symmetric:
self.coupling_map.make_symmetric()

def evaluate(
self,
Expand All @@ -42,7 +44,7 @@ def evaluate(
subset_finder = find_lines

# TODO: add callbacks
qubit_subsets = subset_finder(num_qubits, self.backend, self.coupling_map)
qubit_subsets = subset_finder(num_qubits, self.backend)

# evaluating the subsets
scores = [
Expand Down
26 changes: 13 additions & 13 deletions qopt_best_practices/qubit_selection/metric_evaluators.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
to evaluate 2-qubit gate fidelity."""

from __future__ import annotations
from qiskit.providers import Backend
import rustworkx as rx

# TODO: backend & edges typehint. Currently, only BackendV1 is supported
# Might make sense to extend to BackendV2 for generality
def evaluate_fidelity(path: list[int], backend, edges) -> float:
TWO_Q_GATES = ["cx", "ecr", "cz"]


def evaluate_fidelity(path: list[int], backend: Backend, edges: rx.EdgeList) -> float:
"""Evaluates fidelity on a given list of qubits based on the two-qubit gate error
for a specific backend.
Expand All @@ -14,21 +17,18 @@ def evaluate_fidelity(path: list[int], backend, edges) -> float:
"""

two_qubit_fidelity = {}
props = backend.properties()
target = backend.target

if "cx" in backend.configuration().basis_gates:
gate_name = "cx"
elif "ecr" in backend.configuration().basis_gates:
gate_name = "ecr"
else:
raise ValueError("Could not identify two-qubit gate")
try:
gate_name = list(set(TWO_Q_GATES).intersection(backend.operation_names))[0]
except IndexError as exc:
raise ValueError("Could not identify two-qubit gate") from exc

for edge in edges:
try:
cx_error = props.gate_error(gate_name, edge)

cx_error = target[gate_name][edge].error
except: # pylint: disable=bare-except
cx_error = props.gate_error(gate_name, edge[::-1])
cx_error = target[gate_name][edge[::-1]].error

two_qubit_fidelity[tuple(edge)] = 1 - cx_error

Expand Down
12 changes: 6 additions & 6 deletions qopt_best_practices/qubit_selection/qubit_subset_finders.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
import rustworkx as rx

from qiskit.transpiler import CouplingMap
from qiskit.providers import Backend

# TODO: backend typehint. Currently, only BackendV1 is supported
# Might make sense to extend to BackendV2 for generality
def find_lines(length: int, backend, coupling_map: CouplingMap | None = None) -> list[int]:

def find_lines(length: int, backend: Backend) -> list[int]:
"""Finds all possible lines of length `length` for a specific backend topology.
This method can take quite some time to run on large devices since there
Expand All @@ -19,9 +19,9 @@ def find_lines(length: int, backend, coupling_map: CouplingMap | None = None) ->
The found paths.
"""

# might make sense to make backend the only input for simplicity
if coupling_map is None:
coupling_map = CouplingMap(backend.configuration().coupling_map)
coupling_map = CouplingMap(backend.coupling_map)
if not coupling_map.is_symmetric:
coupling_map.make_symmetric()

all_paths = rx.all_pairs_all_simple_paths(
coupling_map.graph,
Expand Down
20 changes: 16 additions & 4 deletions test/test_qubit_selection.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import os
from unittest import TestCase

from qiskit.providers.fake_provider import FakeWashington
from qiskit.providers.fake_provider import FakeSherbrooke, ConfigurableFakeBackend


from qopt_best_practices.utils import build_max_cut_graph
from qopt_best_practices.qubit_selection import BackendEvaluator, find_lines
Expand All @@ -24,24 +25,35 @@ def setUp(self):

self.mapped_paulis = [tuple(pauli) for pauli in data["paulis"]]
self.mapped_graph = build_max_cut_graph(self.mapped_paulis)
self.backend = FakeWashington()
self.backend = FakeSherbrooke()

def test_find_lines(self):
"""Test backend evaluation"""

paths = find_lines(len(self.mapped_graph), self.backend)

self.assertEqual(len(paths), 1237)
self.assertEqual(len(paths), 1336)
self.assertEqual(len(paths[0]), len(self.mapped_graph))
self.assertIsInstance(paths[0][0], int)

def test_find_lines_directed(self):
"Test backend with directed (asymmetric) coupling map"

directed_fake_backend = ConfigurableFakeBackend(
"test", 4, coupling_map=[[0, 1], [1, 2], [3, 2], [3, 0]]
)
lines = find_lines(3, backend=directed_fake_backend)

expected_lines = [[0, 1, 2], [0, 3, 2], [1, 2, 3], [1, 0, 3]]
self.assertEqual(set(tuple(i) for i in lines), set(tuple(i) for i in expected_lines))

def test_qubit_selection(self):
"""Test backend evaluation"""

path_finder = BackendEvaluator(self.backend)

path, _, _ = path_finder.evaluate(len(self.mapped_graph))

expected_path = [30, 31, 32, 36, 51, 50, 49, 48, 47, 35]
expected_path = [45, 46, 47, 48, 49, 55, 68, 69, 70, 74]

self.assertEqual(set(path), set(expected_path))

0 comments on commit 5cb134a

Please sign in to comment.