Skip to content

Commit

Permalink
Fix handling of conditions in SabreDAG creation
Browse files Browse the repository at this point in the history
In Qiskit#8388 we moved all of the SabreSwap pass's processing into rust. To
facilitate that we had to create a rust DAG data structure to represent
the data flow graph solely in Rust to enable analyzing the DAG structure
in rust code without having to callback to python. To do this the
DAGCircuit (which has a nearly identical representation in python) would
export a list of nodes and the bits (both quantum and classical) that
they operated on. This information is then used to create the SabreDAG
used in the rust code. However, in this process an edge case was missed
with classical condtions. If a condition was specified solely as a
property of the operation and not in cargs list the SabreDAG would not
know about the classical bit dependency between any subsequent
operations involving that classical bit. This would cause incorrect
output because the ndoes would not get processed as they were in the
circuit. This commit fixes this issue by explicitly checking if there is
a condition on the operation and there are no cargs and if so adding the
carg bits to the SabreDAG directly. This fixes the incorrect
representation in SabreDAG.
  • Loading branch information
mtreinish committed Sep 12, 2022
1 parent 070b9e2 commit 2697bc9
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 1 deletion.
8 changes: 7 additions & 1 deletion qiskit/transpiler/passes/routing/sabre_swap.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,17 @@ def run(self, dag):

dag_list = []
for node in dag.topological_op_nodes():
cargs = []
if node.op.condition is not None and not node.cargs:
cargs = [self._clbit_indices[x] for x in dag._bits_in_condition(node.op.condition)]
else:
cargs = [self._clbit_indices[x] for x in node.cargs]

dag_list.append(
(
node._node_id,
[self._qubit_indices[x] for x in node.qargs],
[self._clbit_indices[x] for x in node.cargs],
cargs,
)
)
front_layer = np.asarray([x._node_id for x in dag.front_layer()], dtype=np.uintp)
Expand Down
29 changes: 29 additions & 0 deletions test/python/transpiler/test_sabre_swap.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,35 @@ def test_classical_condition(self):
actual = PassManager([TrivialLayout(cm), SabreSwap(cm)]).run(qc)
self.assertEqual(expected, actual)

def test_classical_condition_cargs(self):
"""Test that classical conditions are preserved even if missing from cargs DAGNode field.
Created from reproduction in https://github.com/Qiskit/qiskit-terra/issues/8675
"""
with self.subTest("missing measurement"):
qc = QuantumCircuit(3, 1)
qc.cx(0, 2).c_if(0, 0)
qc.measure(1, 0)
qc.h(2).c_if(0, 0)
expected = QuantumCircuit(3, 1)
expected.swap(1, 2)
expected.cx(0, 1).c_if(0, 0)
expected.measure(2, 0)
expected.h(1).c_if(0, 0)
result = SabreSwap(CouplingMap.from_line(3), seed=12345)(qc)
self.assertEqual(result, expected)
with self.subTest("reordered measurement"):
qc = QuantumCircuit(3, 1)
qc.cx(0, 1).c_if(0, 0)
qc.measure(1, 0)
qc.h(0).c_if(0, 0)
expected = QuantumCircuit(3, 1)
expected.cx(0, 1).c_if(0, 0)
expected.measure(1, 0)
expected.h(0).c_if(0, 0)
result = SabreSwap(CouplingMap.from_line(3), seed=12345)(qc)
self.assertEqual(result, expected)


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

0 comments on commit 2697bc9

Please sign in to comment.