diff --git a/crates/circuit/src/duration.rs b/crates/circuit/src/duration.rs index 6e87a2783848..0d27dd8d49a5 100644 --- a/crates/circuit/src/duration.rs +++ b/crates/circuit/src/duration.rs @@ -12,6 +12,7 @@ use pyo3::prelude::*; use pyo3::IntoPyObjectExt; +use pyo3::PyTypeInfo; /// A length of time used to express circuit timing. /// @@ -74,9 +75,7 @@ impl Duration { } } } -} -impl Duration { fn __repr__(&self) -> String { match self { Duration::ns(t) => format!("Duration.ns({})", t), @@ -86,4 +85,12 @@ impl Duration { Duration::dt(t) => format!("Duration.dt({})", t), } } + + fn __reduce__(&self, py: Python) -> PyResult> { + ( + Duration::type_object(py).getattr(self.unit())?, + (self.py_value(py)?,), + ) + .into_py_any(py) + } } diff --git a/crates/circuit/src/lib.rs b/crates/circuit/src/lib.rs index c88791bc8c6a..fab369657635 100644 --- a/crates/circuit/src/lib.rs +++ b/crates/circuit/src/lib.rs @@ -35,6 +35,7 @@ mod rustworkx_core_vnext; use pyo3::prelude::*; use pyo3::types::{PySequence, PyTuple}; +use pyo3::PyTypeInfo; pub type BitType = u32; #[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq, FromPyObject)] @@ -169,7 +170,31 @@ pub fn circuit(m: &Bound) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; + + // We need to explicitly add the auto-generated Python subclasses of Duration + // to the module so that pickle can find them during deserialization. m.add_class::()?; + m.add( + "Duration_ns", + duration::Duration::type_object(m.py()).getattr("ns")?, + )?; + m.add( + "Duration_us", + duration::Duration::type_object(m.py()).getattr("us")?, + )?; + m.add( + "Duration_ms", + duration::Duration::type_object(m.py()).getattr("ms")?, + )?; + m.add( + "Duration_s", + duration::Duration::type_object(m.py()).getattr("s")?, + )?; + m.add( + "Duration_dt", + duration::Duration::type_object(m.py()).getattr("dt")?, + )?; + m.add_class::()?; m.add_class::()?; m.add_class::()?; diff --git a/releasenotes/notes/fix-duration-props-0543fe1d5e6e2820.yaml b/releasenotes/notes/fix-duration-props-0543fe1d5e6e2820.yaml new file mode 100644 index 000000000000..5ca18a62a6e0 --- /dev/null +++ b/releasenotes/notes/fix-duration-props-0543fe1d5e6e2820.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Added missing ``repr`` support for :class:`qiskit.circuit.Duration`. + - | + Added missing support for Python pickling of :class:`qiskit.circuit.Duration`. + This was preventing parallel transpilation of circuits with + :meth:`~.QuantumCircuit.delay` instructions that use duration + expressions. diff --git a/test/python/circuit/test_delay.py b/test/python/circuit/test_delay.py index fb989789e97d..1d747d46c112 100644 --- a/test/python/circuit/test_delay.py +++ b/test/python/circuit/test_delay.py @@ -13,12 +13,15 @@ # pylint: disable=missing-function-docstring """Test delay instruction for quantum circuits.""" +import copy +import pickle import numpy as np -from qiskit.circuit import Delay +from qiskit.circuit import Delay, Duration from qiskit.circuit import Parameter, ParameterVector from qiskit.circuit import QuantumCircuit, CircuitInstruction +from qiskit.circuit.classical import expr from qiskit.circuit.exceptions import CircuitError from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -136,6 +139,21 @@ def circuit_from(delay): self.assertNotEqual(Delay(a, unit), Delay(a, "dt")) self.assertNotEqual(circuit_from(Delay(a, unit)), circuit_from(Delay(a, "dt"))) + def test_delay_clone(self): + """Test that circuits with delays can be copied or pickled.""" + qc = QuantumCircuit(3) + stretch = qc.add_stretch("a") + qc.delay(100, qc.qubits[0]) + qc.delay(expr.lift(Duration.us(1)), 0) + qc.delay(expr.lift(Duration.ns(2)), 0) + qc.delay(expr.lift(Duration.ms(3)), 0) + qc.delay(expr.lift(Duration.s(4)), 0) + qc.delay(expr.lift(Duration.dt(5)), 0) + qc.delay(stretch, [0, 1]) + self.assertEqual(qc, pickle.loads(pickle.dumps(qc))) + self.assertEqual(qc, copy.copy(qc)) + self.assertEqual(qc, copy.deepcopy(qc)) + class TestParameterizedDelay(QiskitTestCase): """Test delay instruction with parameterized duration."""