From 053ee324eef0b872e21e1d5e8816ecc0e3c4057f Mon Sep 17 00:00:00 2001 From: Shelly Garion <46566946+ShellyGarion@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:36:26 +0200 Subject: [PATCH] `StabilizerState.expectation_value` can also accept `SparsePauliOp` (#13539) * update ecpectation_value function * add a test * add release notes * revision following code review --- qiskit/quantum_info/states/stabilizerstate.py | 31 +++++++++++++++++-- ...expval-sparsepauliop-3e32a871d8e908ce.yaml | 5 +++ .../states/test_stabilizerstate.py | 14 ++++++++- 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 releasenotes/notes/stabilizerstate-expval-sparsepauliop-3e32a871d8e908ce.yaml diff --git a/qiskit/quantum_info/states/stabilizerstate.py b/qiskit/quantum_info/states/stabilizerstate.py index b6bc8243b40..dfedb285fff 100644 --- a/qiskit/quantum_info/states/stabilizerstate.py +++ b/qiskit/quantum_info/states/stabilizerstate.py @@ -24,7 +24,7 @@ from qiskit.exceptions import QiskitError from qiskit.quantum_info.operators.op_shape import OpShape from qiskit.quantum_info.operators.operator import Operator -from qiskit.quantum_info.operators.symplectic import Clifford, Pauli, PauliList +from qiskit.quantum_info.operators.symplectic import Clifford, Pauli, PauliList, SparsePauliOp from qiskit.quantum_info.operators.symplectic.clifford_circuits import _append_x from qiskit.quantum_info.states.quantum_state import QuantumState from qiskit.circuit import QuantumCircuit, Instruction @@ -259,7 +259,34 @@ def evolve( ret._data = self.clifford.compose(other.clifford, qargs=qargs) return ret - def expectation_value(self, oper: Pauli, qargs: None | list = None) -> complex: + def expectation_value(self, oper: Pauli | SparsePauliOp, qargs: None | list = None) -> complex: + """Compute the expectation value of a Pauli or SparsePauliOp operator. + + Args: + oper: A Pauli or SparsePauliOp operator to evaluate the expectation value. + qargs: Subsystems to apply the operator on. + + Returns: + The expectation value. + + Raises: + QiskitError: if oper is not a Pauli or SparsePauliOp operator. + """ + if isinstance(oper, Pauli): + return self._expectation_value_pauli(oper, qargs) + + if isinstance(oper, SparsePauliOp): + return sum( + coeff * self._expectation_value_pauli(Pauli((z, x)), qargs) + for z, x, coeff in zip(oper.paulis.z, oper.paulis.x, oper.coeffs) + ) + + raise QiskitError( + "Operator for expectation value is not a Pauli or SparsePauliOp operator, " + f"but {type(oper)}." + ) + + def _expectation_value_pauli(self, oper: Pauli, qargs: None | list = None) -> complex: """Compute the expectation value of a Pauli operator. Args: diff --git a/releasenotes/notes/stabilizerstate-expval-sparsepauliop-3e32a871d8e908ce.yaml b/releasenotes/notes/stabilizerstate-expval-sparsepauliop-3e32a871d8e908ce.yaml new file mode 100644 index 00000000000..135156272dc --- /dev/null +++ b/releasenotes/notes/stabilizerstate-expval-sparsepauliop-3e32a871d8e908ce.yaml @@ -0,0 +1,5 @@ +--- +features_quantum_info: + - | + The method :meth:`.StabilizerState.expectation_value` can now accept an operator of type + :class:`.SparsePauliOp`. diff --git a/test/python/quantum_info/states/test_stabilizerstate.py b/test/python/quantum_info/states/test_stabilizerstate.py index 4e1659ff699..f76df1134e8 100644 --- a/test/python/quantum_info/states/test_stabilizerstate.py +++ b/test/python/quantum_info/states/test_stabilizerstate.py @@ -25,7 +25,7 @@ from qiskit.quantum_info.random import random_clifford, random_pauli from qiskit.quantum_info.states import StabilizerState, Statevector from qiskit.circuit.library import IGate, XGate, HGate -from qiskit.quantum_info.operators import Clifford, Pauli, Operator +from qiskit.quantum_info.operators import Clifford, Pauli, Operator, SparsePauliOp from test import combine # pylint: disable=wrong-import-order from test import QiskitTestCase # pylint: disable=wrong-import-order @@ -1101,6 +1101,18 @@ def test_expval_random_subsystem(self, num_qubits): target = Statevector(qc).expectation_value(op, qargs) self.assertAlmostEqual(exp_val, target) + def test_expval_sparsepauliop(self): + """Test expectation_value method of SparsePauliOp""" + cliff = random_clifford(num_qubits=3, seed=1234) + stab = StabilizerState(cliff) + labels = ["XXX", "IXI", "YYY", "III"] + coeffs = [3.0, 5.5, -1j, 23] + spp_op = SparsePauliOp.from_list(list(zip(labels, coeffs))) + expval = stab.expectation_value(spp_op) + qc = cliff.to_circuit() + target = Statevector(qc).expectation_value(spp_op) + self.assertAlmostEqual(expval, target) + def test_stabilizer_bell_equiv(self): """Test that two circuits produce the same stabilizer group."""