diff --git a/crates/qpy/src/formats.rs b/crates/qpy/src/formats.rs index ae3370d64b96..ace17a32cb82 100644 --- a/crates/qpy/src/formats.rs +++ b/crates/qpy/src/formats.rs @@ -506,21 +506,21 @@ pub struct SparsePauliOpListElemPack { #[derive(Debug)] pub struct SparsePauliObservableElemPack { pub num_qubits: u32, - #[bw(calc = coeff_data.len() as u64)] + #[bw(calc = (coeff_data.len() * std::mem::size_of::()) as u64)] pub coeff_data_size: u64, - #[bw(calc = bitterm_data.len() as u64)] + #[bw(calc = (bitterm_data.len() * std::mem::size_of::()) as u64)] pub bitterm_data_size: u64, - #[bw(calc = inds_data.len() as u64)] + #[bw(calc = (inds_data.len() * std::mem::size_of::()) as u64)] pub inds_data_size: u64, - #[bw(calc = bounds_data.len() as u64)] + #[bw(calc = (bounds_data.len() * std::mem::size_of::()) as u64)] pub bounds_data_size: u64, - #[br(count = coeff_data_size)] + #[br(count = coeff_data_size / std::mem::size_of::() as u64)] pub coeff_data: Vec, // complex numbers stored in format [re1, im1, re2, im2,...] - #[br(count = bitterm_data_size)] + #[br(count = bitterm_data_size / std::mem::size_of::() as u64)] pub bitterm_data: Vec, - #[br(count = inds_data_size)] + #[br(count = inds_data_size / std::mem::size_of::() as u64)] pub inds_data: Vec, - #[br(count = bounds_data_size)] + #[br(count = bounds_data_size / std::mem::size_of::() as u64)] pub bounds_data: Vec, } diff --git a/releasenotes/notes/fix-qpy-sparse_pauli-095b5c3e6ef4f5e8.yaml b/releasenotes/notes/fix-qpy-sparse_pauli-095b5c3e6ef4f5e8.yaml new file mode 100644 index 000000000000..6fec556dbe9e --- /dev/null +++ b/releasenotes/notes/fix-qpy-sparse_pauli-095b5c3e6ef4f5e8.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixed a bug with the QPY serialization and deserialization of instructions + containing :class:`.SparseObservable` data. + Fixed `#16722 `__. diff --git a/test/python/qpy/test_roundtrip.py b/test/python/qpy/test_roundtrip.py index 2e459621d394..b43d18d23ec4 100644 --- a/test/python/qpy/test_roundtrip.py +++ b/test/python/qpy/test_roundtrip.py @@ -22,7 +22,7 @@ from qiskit.circuit.random import random_circuit from qiskit.circuit.parameter import Parameter from qiskit.circuit.parametervector import ParameterVector -from qiskit.quantum_info import SparsePauliOp +from qiskit.quantum_info import SparsePauliOp, SparseObservable from qiskit.circuit.classical import expr from qiskit.synthesis import LieTrotter from qiskit.qpy.common import QPY_RUST_READ_MIN_VERSION, QPY_RUST_WRITE_MIN_VERSION, QPY_VERSION @@ -283,3 +283,16 @@ def test_literal_integers_in_for(self, version, write_with, read_with): with qc.for_loop((2, 5, (1 << 60))) as _: qc.x(0) self.assert_roundtrip_equal(qc, version=version, read_with=read_with, write_with=write_with) + + @all_qpy_combinations(17) + def test_evolutiongate_sparse_observable(self, version, write_with, read_with): + """Test loading a circuit with an evolution gate over a SparseObservable works. + + ``SparseObservable`` support was added to QPY in version 17. + """ + op = SparseObservable.from_list([("XIX", 0.1), ("ZIZ", 0.3)]) + evo = PauliEvolutionGate(op, time=2, synthesis=LieTrotter(reps=2)) + + qc = QuantumCircuit(op.num_qubits) + qc.append(evo, range(op.num_qubits)) + self.assert_roundtrip_equal(qc, version=version, read_with=read_with, write_with=write_with)