Skip to content

Commit

Permalink
Consider unit in Delay comparisons (#13816)
Browse files Browse the repository at this point in the history
The `unit` field was previously ignored, allowing delays in `dt` units
to compare equal to those in `s`. This commit does not add additional
on-the-fly unit conversion to the comparison: if the user specified
durations in different time multiples, they may have had a reason to
consider them non-equal.  This could be revisiting after the new system
for duration handling lands (i.e. the new functionality for `stretch`
and other delayed scheduling).
  • Loading branch information
jakelishman authored Feb 11, 2025
1 parent 288d2f4 commit 32eae98
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 0 deletions.
5 changes: 5 additions & 0 deletions qiskit/circuit/delay.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ def to_matrix(self) -> np.ndarray:
"""
return self.__array__(dtype=complex)

def __eq__(self, other):
return (
isinstance(other, Delay) and self.unit == other.unit and self._compare_parameters(other)
)

def __repr__(self):
"""Return the official string representing the delay."""
return f"{self.__class__.__name__}(duration={self.params[0]}[unit={self.unit}])"
Expand Down
5 changes: 5 additions & 0 deletions releasenotes/notes/delay-compare-b7ecb26b94ff0cd3.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
fixes:
- |
Comparisons of :class:`~.circuit.Delay` instructions, including within circuits, now require the
units to be equal as well as the duration value.
37 changes: 37 additions & 0 deletions test/python/circuit/test_delay.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,43 @@ def test_to_matrix_return_identity_matrix(self):
expected = np.array([[1, 0], [0, 1]], dtype=complex)
self.assertTrue(np.array_equal(actual, expected))

def test_equality(self):
# At the time `__eq__` was specialised for `Delay`, the class was undergoing changes and
# moving to Rust, so we didn't also modify the Python-space semantics to declare equality
# between (say) 1000ms and 1s. We could revisit that decision once the data model settles.
#
# This test then deliberately doesn't assert about mixed-scale comparisons, only comparisons
# between the same units, and 'dt' to absolute times.
def circuit_from(delay):
out = QuantumCircuit(1)
out.append(delay, [0], [])
return out

a = Parameter("a")
left_instructions, right_instructions = [], []
left_circuits, right_circuits = [], []
for unit in ("s", "ms", "us", "ns", "ps", "dt"):
for base in (left_instructions, right_instructions):
base.append(Delay(1, unit))
base.append(Delay(5.0, unit))
base.append(Delay(a, unit))
for base in (left_circuits, right_circuits):
base.append(circuit_from(Delay(1, unit)))
base.append(circuit_from(Delay(5.0, unit)))
base.append(circuit_from(Delay(a, unit)))
self.assertEqual(left_instructions, right_instructions)
self.assertEqual(left_circuits, right_circuits)

# We can't do all the non-equal tests in a single list comparison, since any single list
# failure would mask any spurious successes.
for unit in ("s", "ms", "us", "ns", "ps"):
self.assertNotEqual(Delay(2, unit), Delay(2, "dt"))
self.assertNotEqual(circuit_from(Delay(2, unit)), circuit_from(Delay(2, "dt")))
self.assertNotEqual(Delay(2, "dt"), Delay(2, unit))
self.assertNotEqual(circuit_from(Delay(2, "dt")), circuit_from(Delay(2, unit)))
self.assertNotEqual(Delay(a, unit), Delay(a, "dt"))
self.assertNotEqual(circuit_from(Delay(a, unit)), circuit_from(Delay(a, "dt")))


class TestParameterizedDelay(QiskitTestCase):
"""Test delay instruction with parameterized duration."""
Expand Down

0 comments on commit 32eae98

Please sign in to comment.