Skip to content

Commit

Permalink
Fix SetLayout to error with invalid int list input (#11653)
Browse files Browse the repository at this point in the history
* Fix SetLayout to error with invalid int list input

This commit fixes an issue in the SetLayout transpiler pass when an
integer list is specified nothing was checking that the integer list
contained unique entries. Previously if a list containing duplciate
entries was passed in this would result in an invalid Layout object
being set on the property set. This would cause a cryptic error message
by later transpiler passes that would try and use that invalid Layout.
This commit fixes this by detecting if there are duplicate entries in
the int list and raising an exception directly.

* Use new exception class in test
  • Loading branch information
mtreinish authored Jan 29, 2024
1 parent c9f1e75 commit 8af340c
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 4 deletions.
2 changes: 2 additions & 0 deletions qiskit/transpiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,7 @@
.. autoexception:: CouplingError
.. autoexception:: LayoutError
.. autoexception:: CircuitTooWideForTarget
.. autoexception:: InvalidLayoutError
"""

Expand All @@ -1266,6 +1267,7 @@
CouplingError,
LayoutError,
CircuitTooWideForTarget,
InvalidLayoutError,
)
from .basepasses import AnalysisPass, TransformationPass
from .coupling import CouplingMap
Expand Down
4 changes: 4 additions & 0 deletions qiskit/transpiler/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,7 @@ def __str__(self):

class CircuitTooWideForTarget(TranspilerError):
"""Error raised if the circuit is too wide for the target."""


class InvalidLayoutError(TranspilerError):
"""Error raised when a user provided layout is invalid."""
11 changes: 8 additions & 3 deletions qiskit/transpiler/passes/layout/set_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
# that they have been altered from the originals.

"""Set the ``layout`` property to the given layout."""
from qiskit.transpiler import Layout, TranspilerError
from qiskit.transpiler import Layout
from qiskit.transpiler.exceptions import InvalidLayoutError
from qiskit.transpiler.basepasses import AnalysisPass


Expand Down Expand Up @@ -47,17 +48,21 @@ def run(self, dag):
"""
if isinstance(self.layout, list):
if len(self.layout) != len(dag.qubits):
raise TranspilerError(
raise InvalidLayoutError(
"The length of the layout is different than the size of the "
f"circuit: {len(self.layout)} <> {len(dag.qubits)}"
)
if len(set(self.layout)) != len(self.layout):
raise InvalidLayoutError(
f"The provided layout {self.layout} contains duplicate qubits"
)
layout = Layout({phys: dag.qubits[i] for i, phys in enumerate(self.layout)})
elif isinstance(self.layout, Layout):
layout = self.layout.copy()
elif self.layout is None:
layout = None
else:
raise TranspilerError(
raise InvalidLayoutError(
f"SetLayout was intialized with the layout type: {type(self.layout)}"
)
self.property_set["layout"] = layout
Expand Down
13 changes: 13 additions & 0 deletions releasenotes/notes/add-invalid-layout-error-d0d64086748d4b54.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
features:
- |
Added a new exception class :class:`.InvalidLayoutError` that is a :class:`.TranspilerError`
subclass which is raised when a user provided layout is invalid (mismatched size, duplicate
qubits, etc).
fixes:
- |
Fixed an issue with the :class:`.SetLayout` transpiler pass where an invalid integer list input
that contained duplicate entries which would result in an invalid :class:`.Layout` being
generated and subsequent transpiler passes would fail with a cryptic error. This is now caught
when :meth:`.SetLayout.run` is called an :class:`.InvalidLayoutError` error will be raised
indicating there are duplicate entries in the integer list.
9 changes: 8 additions & 1 deletion test/python/transpiler/test_setlayout.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from qiskit.transpiler import CouplingMap, Layout
from qiskit.transpiler.passes import SetLayout, ApplyLayout, FullAncillaAllocation
from qiskit.test import QiskitTestCase
from qiskit.transpiler import PassManager, TranspilerError
from qiskit.transpiler import PassManager, TranspilerError, InvalidLayoutError


class TestSetLayout(QiskitTestCase):
Expand Down Expand Up @@ -109,6 +109,13 @@ def test_raise_when_layout_len_does_not_match(self):
with self.assertRaises(TranspilerError):
pass_manager.run(circuit)

def test_raise_if_int_list_layout_contains_duplicates(self):
"""Test the error is raised if the specified intlist contains duplicates"""
circuit = QuantumCircuit(4)
layout_pass = SetLayout([0, 1, 1, 2])
with self.assertRaises(InvalidLayoutError):
layout_pass(circuit)


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

0 comments on commit 8af340c

Please sign in to comment.