Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 96c3b94

Browse files
dieriskt474
andauthored
Option to dynamically decouple qubits regardless of their state (#776)
* include_clean_qubits option To apply DD on all (non-idle) qubits * Add tests * Consider reset qubits as clean * Update block duration * Formatting * Fold clean qubits option into skip_reset_qubits * Fix test_insert_dd_ghz_everywhere apply DD also on initial delays if skip_reset_qubits = False --------- Co-authored-by: Kevin Tian <kevin.tian@ibm.com>
1 parent c05e7b8 commit 96c3b94

File tree

4 files changed

+108
-2
lines changed

4 files changed

+108
-2
lines changed

qiskit_ibm_provider/transpiler/passes/scheduling/block_base_padder.py

+1
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ def _visit_block(
363363
prev_block_duration = self._block_duration
364364
prev_block_idx = self._current_block_idx
365365
self._terminate_block(self._block_duration, self._current_block_idx)
366+
new_block_dag.duration = prev_block_duration
366367

367368
# Edge-case: Add a barrier if the final node is a fast-path
368369
if self._prev_node in self._fast_path_nodes:

qiskit_ibm_provider/transpiler/passes/scheduling/dynamical_decoupling.py

+4
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,10 @@ def _pad(
420420
)
421421
return
422422

423+
if not self._skip_reset_qubits and qubit not in self._dirty_qubits:
424+
# mark all qubits as dirty if skip_reset_qubits is False
425+
self._dirty_qubits.update([qubit])
426+
423427
if (
424428
not isinstance(prev_node, DAGInNode)
425429
and self._skip_reset_qubits
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
upgrade:
3+
- |
4+
Modify ``skip_reset_qubits`` optional flag to the constructor for :class:`.PadDynamicalDecoupling`. If ``False``, dynamical decoupling is applied on qubits regardless of their state, even on delays that are at the beginning of a circuit. This option now matches the behavior in qiskit.

test/unit/transpiler/passes/scheduling/test_dynamical_decoupling.py

+99-2
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,17 @@ def test_insert_dd_ghz_everywhere(self):
185185
expected = expected.compose(YGate(), [1])
186186
expected = expected.compose(Delay(50), [1])
187187

188-
expected = expected.compose(Delay(750), [2], front=True)
189-
expected = expected.compose(Delay(950), [3], front=True)
188+
expected = expected.compose(Delay(162), [2], front=True)
189+
expected = expected.compose(YGate(), [2], front=True)
190+
expected = expected.compose(Delay(326), [2], front=True)
191+
expected = expected.compose(YGate(), [2], front=True)
192+
expected = expected.compose(Delay(162), [2], front=True)
193+
194+
expected = expected.compose(Delay(212), [3], front=True)
195+
expected = expected.compose(YGate(), [3], front=True)
196+
expected = expected.compose(Delay(426), [3], front=True)
197+
expected = expected.compose(YGate(), [3], front=True)
198+
expected = expected.compose(Delay(212), [3], front=True)
190199

191200
self.assertEqual(ghz4_dd, expected)
192201

@@ -1095,3 +1104,91 @@ def test_no_unused_qubits(self):
10951104
dont_use = qc_dd.qubits[-2:]
10961105
for op in qc_dd.data:
10971106
self.assertNotIn(dont_use, op.qubits)
1107+
1108+
def test_dd_include_clean_qubits(self):
1109+
"""Test DD applied to all non-idle qubits, including those
1110+
that are clean"""
1111+
1112+
qc = QuantumCircuit(3, 1)
1113+
qc.delay(800, 1)
1114+
with qc.if_test((0, True)):
1115+
qc.x(1)
1116+
qc.delay(1000, 2)
1117+
1118+
dd_sequence = [XGate(), XGate()]
1119+
pm = PassManager(
1120+
[
1121+
ASAPScheduleAnalysis(self.durations),
1122+
PadDynamicalDecoupling(
1123+
self.durations,
1124+
dd_sequence,
1125+
pulse_alignment=1,
1126+
sequence_min_length_ratios=[0.0],
1127+
skip_reset_qubits=False,
1128+
),
1129+
]
1130+
)
1131+
1132+
qc_dd = pm.run(qc)
1133+
1134+
expected = qc.copy_empty_like()
1135+
for ind in range(1, 3):
1136+
expected.compose(Delay(175), [ind], front=True, inplace=True)
1137+
expected.compose(XGate(), [ind], inplace=True)
1138+
expected.compose(Delay(350), [ind], inplace=True)
1139+
expected.compose(XGate(), [ind], inplace=True)
1140+
expected.compose(Delay(175), [ind], inplace=True)
1141+
expected.barrier([1, 2])
1142+
with expected.if_test((0, True)):
1143+
expected.x(1)
1144+
expected.delay(50, 2)
1145+
expected.barrier([1, 2])
1146+
for ind in range(1, 3):
1147+
expected.compose(Delay(225), [ind], inplace=True)
1148+
expected.compose(XGate(), [ind], inplace=True)
1149+
expected.compose(Delay(450), [ind], inplace=True)
1150+
expected.compose(XGate(), [ind], inplace=True)
1151+
expected.compose(Delay(225), [ind], inplace=True)
1152+
1153+
self.assertEqual(qc_dd, expected)
1154+
1155+
def test_dd_exclude_clean_qubits(self):
1156+
"""Exclude DD on clean qubits (default)"""
1157+
1158+
qc = QuantumCircuit(3, 1)
1159+
qc.delay(800, 1)
1160+
with qc.if_test((0, True)):
1161+
qc.x(1)
1162+
qc.delay(1000, 2)
1163+
1164+
dd_sequence = [XGate(), XGate()]
1165+
pm = PassManager(
1166+
[
1167+
ASAPScheduleAnalysis(self.durations),
1168+
PadDynamicalDecoupling(
1169+
self.durations,
1170+
dd_sequence,
1171+
pulse_alignment=1,
1172+
sequence_min_length_ratios=[0.0],
1173+
),
1174+
]
1175+
)
1176+
1177+
qc_dd = pm.run(qc)
1178+
1179+
expected = qc.copy_empty_like()
1180+
expected.compose(Delay(800), [1], front=True, inplace=True)
1181+
expected.compose(Delay(800), [2], inplace=True)
1182+
expected.barrier([1, 2])
1183+
with expected.if_test((0, True)):
1184+
expected.x(1)
1185+
expected.delay(50, 2)
1186+
expected.barrier([1, 2])
1187+
expected.compose(Delay(225), [1], inplace=True)
1188+
expected.compose(XGate(), [1], inplace=True)
1189+
expected.compose(Delay(450), [1], inplace=True)
1190+
expected.compose(XGate(), [1], inplace=True)
1191+
expected.compose(Delay(225), [1], inplace=True)
1192+
expected.compose(Delay(1000), [2], inplace=True)
1193+
1194+
self.assertEqual(qc_dd, expected)

0 commit comments

Comments
 (0)