Skip to content

Commit

Permalink
Improve SabreSwap error message on unexpanded circuits (Qiskit#9909)
Browse files Browse the repository at this point in the history
`SabreSwap` requires that the input circuit is exactly the same size as
the system implied by the coupling map, since this is used internally in
Rust for the virtual-to-physical mapping.  Failure to ensure this can
lead to panics in the Rust code.  This commit catches the failure case
(for free) in Python space, and attempts to help the user work out what
they needed.
  • Loading branch information
jakelishman authored and king-p3nguin committed May 22, 2023
1 parent ed0ed39 commit 8d9faff
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 4 deletions.
17 changes: 15 additions & 2 deletions qiskit/transpiler/passes/routing/sabre_swap.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,21 @@ def run(self, dag):
if len(dag.qregs) != 1 or dag.qregs.get("q", None) is None:
raise TranspilerError("Sabre swap runs on physical circuits only.")

if len(dag.qubits) > self.coupling_map.size():
raise TranspilerError("More virtual qubits exist than physical.")
num_dag_qubits = len(dag.qubits)
num_coupling_qubits = self.coupling_map.size()
if num_dag_qubits < num_coupling_qubits:
raise TranspilerError(
f"Fewer qubits in the circuit ({num_dag_qubits}) than the coupling map"
f" ({num_coupling_qubits})."
" Have you run a layout pass and then expanded your DAG with ancillas?"
" See `FullAncillaAllocation`, `EnlargeWithAncilla` and `ApplyLayout`."
)
if num_dag_qubits > num_coupling_qubits:
raise TranspilerError(
f"More qubits in the circuit ({num_dag_qubits}) than available in the coupling map"
f" ({num_coupling_qubits})."
" This circuit cannot be routed to this device."
)

if self.heuristic == "basic":
heuristic = Heuristic.Basic
Expand Down
20 changes: 18 additions & 2 deletions test/python/transpiler/test_sabre_swap.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from qiskit.circuit.library import CCXGate, HGate, Measure, SwapGate
from qiskit.converters import circuit_to_dag
from qiskit.transpiler.passes import SabreSwap, TrivialLayout
from qiskit.transpiler import CouplingMap, PassManager
from qiskit.transpiler import CouplingMap, PassManager, TranspilerError
from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit
from qiskit.test import QiskitTestCase
from qiskit.utils import optionals
Expand Down Expand Up @@ -159,7 +159,7 @@ def test_do_not_change_cm(self):
coupling = CouplingMap(cm_edges)

passmanager = PassManager(SabreSwap(coupling))
_ = passmanager.run(QuantumCircuit(1))
_ = passmanager.run(QuantumCircuit(coupling.size()))

self.assertEqual(set(cm_edges), set(coupling.get_edges()))

Expand Down Expand Up @@ -339,6 +339,22 @@ def normalize_nodes(dag):
# Check that a re-run with the same seed produces the same circuit in the exact same order.
self.assertEqual(normalize_nodes(dag_0), normalize_nodes(pass_0.run(dag)))

def test_rejects_too_many_qubits(self):
"""Test that a sensible Python-space error message is emitted if the DAG has an incorrect
number of qubits."""
pass_ = SabreSwap(CouplingMap.from_line(4))
qc = QuantumCircuit(QuantumRegister(5, "q"))
with self.assertRaisesRegex(TranspilerError, "More qubits in the circuit"):
pass_(qc)

def test_rejects_too_few_qubits(self):
"""Test that a sensible Python-space error message is emitted if the DAG has an incorrect
number of qubits."""
pass_ = SabreSwap(CouplingMap.from_line(4))
qc = QuantumCircuit(QuantumRegister(3, "q"))
with self.assertRaisesRegex(TranspilerError, "Fewer qubits in the circuit"):
pass_(qc)


if __name__ == "__main__":
unittest.main()

0 comments on commit 8d9faff

Please sign in to comment.