Skip to content

Commit

Permalink
adding an option to CouplingMap.reduce to allow disconnected coupling…
Browse files Browse the repository at this point in the history
… maps (Qiskit#10863)

* adding an option to CouplingMap.reduce to allow disconnected coupling maps

* missing 'not'
  • Loading branch information
alexanderivrii authored Sep 20, 2023
1 parent e62c86b commit 01bb111
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 16 deletions.
26 changes: 12 additions & 14 deletions qiskit/transpiler/coupling.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import math
from typing import List

import numpy as np
import rustworkx as rx
from rustworkx.visualization import graphviz_draw

Expand Down Expand Up @@ -252,14 +251,16 @@ def _check_symmetry(self):
"""
return self.graph.is_symmetric()

def reduce(self, mapping):
def reduce(self, mapping, check_if_connected=True):
"""Returns a reduced coupling map that
corresponds to the subgraph of qubits
selected in the mapping.
Args:
mapping (list): A mapping of reduced qubits to device
qubits.
qubits.
check_if_connected (bool): if True, checks that the reduced
coupling map is connected.
Returns:
CouplingMap: A reduced coupling_map for the selected qubits.
Expand All @@ -268,9 +269,6 @@ def reduce(self, mapping):
CouplingError: Reduced coupling map must be connected.
"""

from scipy.sparse import coo_matrix, csgraph

reduced_qubits = len(mapping)
inv_map = [None] * (max(mapping) + 1)
for idx, val in enumerate(mapping):
inv_map[val] = idx
Expand All @@ -281,17 +279,17 @@ def reduce(self, mapping):
if edge[0] in mapping and edge[1] in mapping:
reduced_cmap.append([inv_map[edge[0]], inv_map[edge[1]]])

# Verify coupling_map is connected
rows = np.array([edge[0] for edge in reduced_cmap], dtype=int)
cols = np.array([edge[1] for edge in reduced_cmap], dtype=int)
data = np.ones_like(rows)

mat = coo_matrix((data, (rows, cols)), shape=(reduced_qubits, reduced_qubits)).tocsr()
# Note: using reduced_coupling_map.graph is significantly faster
# than calling add_physical_qubit / add_edge.
reduced_coupling_map = CouplingMap()
for node in range(len(mapping)):
reduced_coupling_map.graph.add_node(node)
reduced_coupling_map.graph.extend_from_edge_list([tuple(x) for x in reduced_cmap])

if csgraph.connected_components(mat)[0] != 1:
if check_if_connected and not reduced_coupling_map.is_connected():
raise CouplingError("coupling_map must be connected.")

return CouplingMap(reduced_cmap)
return reduced_coupling_map

@classmethod
def from_full(cls, num_qubits, bidirectional=True) -> "CouplingMap":
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
features:
- |
The method :meth:`~qiskit.transpiler.CouplingMap.reduce` now accepts an
additional argument ``check_if_connected``, defaulted to ``True``. This
corresponds to the previous behavior, checking whether the reduced coupling
map remains connected and raising a ``CouplingError`` if not so. When set to
``False``, the check is skipped, allowing disconnected reduced coupling maps.
16 changes: 14 additions & 2 deletions test/python/transpiler/test_coupling.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,26 @@ def test_successful_reduced_map(self):
ans = [(1, 2), (3, 2), (0, 1)]
self.assertEqual(set(out), set(ans))

def test_failed_reduced_map(self):
"""Generate a bad disconnected reduced map"""
def test_bad_reduced_map(self):
"""Generate disconnected reduced map"""
fake = FakeRueschlikon()
cmap = fake.configuration().coupling_map
coupling_map = CouplingMap(cmap)
with self.assertRaises(CouplingError):
coupling_map.reduce([12, 11, 10, 3])

def test_disconnected_reduced_map_allowed(self):
"""Generate disconnected reduced map but do not error"""
fake = FakeRueschlikon()
cmap = fake.configuration().coupling_map
coupling_map = CouplingMap(cmap)
reduced_map = coupling_map.reduce([12, 11, 10, 3], check_if_connected=False)
reduced_edges = reduced_map.get_edges()
qubits_expected = [0, 1, 2, 3]
edges_expected = [(0, 1), (1, 2)]
self.assertEqual(qubits_expected, reduced_map.physical_qubits)
self.assertEqual(set(reduced_edges), set(edges_expected))

def test_symmetric_small_true(self):
coupling_list = [[0, 1], [1, 0]]
coupling = CouplingMap(coupling_list)
Expand Down

0 comments on commit 01bb111

Please sign in to comment.