diff --git a/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py b/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py index 8c3ea87c8578..0e351161f7df 100644 --- a/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +++ b/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py @@ -20,7 +20,7 @@ from qiskit.circuit.delay import Delay from qiskit.circuit.library.standard_gates import IGate, UGate, U3Gate from qiskit.circuit.reset import Reset -from qiskit.dagcircuit import DAGCircuit, DAGNode, DAGInNode, DAGOpNode +from qiskit.dagcircuit import DAGCircuit, DAGNode, DAGInNode, DAGOpNode, DAGOutNode from qiskit.quantum_info.operators.predicates import matrix_equal from qiskit.synthesis.one_qubit import OneQubitEulerDecomposer from qiskit.transpiler.exceptions import TranspilerError @@ -331,8 +331,7 @@ def _pad( if time_interval % self._alignment != 0: raise TranspilerError( f"Time interval {time_interval} is not divisible by alignment {self._alignment} " - f"between DAGNode {prev_node.name} on qargs {prev_node.qargs} and {next_node.name} " - f"on qargs {next_node.qargs}." + f"between {_format_node(prev_node)} and {_format_node(next_node)}." ) if not self.__is_dd_qubit(dag.qubits.index(qubit)): @@ -430,3 +429,10 @@ def _resolve_params(gate: Gate) -> tuple: else: params.append(p) return tuple(params) + + +def _format_node(node: DAGNode) -> str: + """Util to format the DAGNode, DAGInNode, and DAGOutNode.""" + if isinstance(node, (DAGInNode, DAGOutNode)): + return f"{node.__class__.__name__} on qarg {node.wire}" + return f"DAGNode {node.name} on qargs {node.qargs}" diff --git a/releasenotes/notes/fix-dd-misalignment-msg-76fe16e5eb4ae670.yaml b/releasenotes/notes/fix-dd-misalignment-msg-76fe16e5eb4ae670.yaml new file mode 100644 index 000000000000..4634fe48ae9b --- /dev/null +++ b/releasenotes/notes/fix-dd-misalignment-msg-76fe16e5eb4ae670.yaml @@ -0,0 +1,7 @@ +--- +fixes: + - | + Fixed a bug in :class:`.PadDynamicalDecoupling`, which previously + did not correctly display the error message that a delay is not + pulse-aligned, if the previous or following node was an input/output + node. Now, the error message is correctly displayed. diff --git a/test/python/transpiler/test_dynamical_decoupling.py b/test/python/transpiler/test_dynamical_decoupling.py index 5f11ede3a3e8..38c5c3c2d4ab 100644 --- a/test/python/transpiler/test_dynamical_decoupling.py +++ b/test/python/transpiler/test_dynamical_decoupling.py @@ -1051,6 +1051,23 @@ def test_paramaterized_global_phase(self): self.assertEqual(qc.global_phase + np.pi, pm.run(qc).global_phase) + def test_misalignment_at_boundaries(self): + """Test the correct error message is raised for misalignments at In/Out nodes.""" + # a circuit where the previous node is DAGInNode, and the next DAGOutNode + circuit = QuantumCircuit(1) + circuit.delay(101) + + dd_sequence = [XGate(), XGate()] + pm = PassManager( + [ + ALAPScheduleAnalysis(self.durations), + PadDynamicalDecoupling(self.durations, dd_sequence, pulse_alignment=2), + ] + ) + + with self.assertRaises(TranspilerError): + _ = pm.run(circuit) + if __name__ == "__main__": unittest.main()