From c7d83bec895b4f6674dd8e6bbfa4d6819d6d7896 Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Sun, 8 Dec 2024 09:30:27 -0600 Subject: [PATCH 1/4] update ecpectation_value function --- qiskit/quantum_info/states/stabilizerstate.py | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/qiskit/quantum_info/states/stabilizerstate.py b/qiskit/quantum_info/states/stabilizerstate.py index b6bc8243b407..6b76cac52a12 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 (Pauli or SparsePauliOp): a Pauli or SparsePauliOp operator to evaluate expval. + qargs (None or list): subsystems to apply the operator on. + + Returns: + complex: 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) + ) + + else: + raise QiskitError( + "Operator for expectation value is not a Pauli or SparsePauliOp operator." + ) + + def _expectation_value_pauli(self, oper: Pauli, qargs: None | list = None) -> complex: """Compute the expectation value of a Pauli operator. Args: From 8dc1655035ebd153bcf1c9f5e58be7a1f199457c Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Sun, 8 Dec 2024 09:30:42 -0600 Subject: [PATCH 2/4] add a test --- .../quantum_info/states/test_stabilizerstate.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/python/quantum_info/states/test_stabilizerstate.py b/test/python/quantum_info/states/test_stabilizerstate.py index 4e1659ff6999..f76df1134e8a 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.""" From d39fd646c878dbe2d0e166f90f482f88c3740917 Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Sun, 8 Dec 2024 09:30:53 -0600 Subject: [PATCH 3/4] add release notes --- ...tabilizerstate-expval-sparsepauliop-3e32a871d8e908ce.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 releasenotes/notes/stabilizerstate-expval-sparsepauliop-3e32a871d8e908ce.yaml diff --git a/releasenotes/notes/stabilizerstate-expval-sparsepauliop-3e32a871d8e908ce.yaml b/releasenotes/notes/stabilizerstate-expval-sparsepauliop-3e32a871d8e908ce.yaml new file mode 100644 index 000000000000..b90ca958827d --- /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`. From 03d1d90588060c82a8e391d9e2a6f96eb5b97f83 Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Tue, 17 Dec 2024 08:11:53 -0600 Subject: [PATCH 4/4] revision following code review --- qiskit/quantum_info/states/stabilizerstate.py | 14 +++++++------- ...tate-expval-sparsepauliop-3e32a871d8e908ce.yaml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/qiskit/quantum_info/states/stabilizerstate.py b/qiskit/quantum_info/states/stabilizerstate.py index 6b76cac52a12..dfedb285fffa 100644 --- a/qiskit/quantum_info/states/stabilizerstate.py +++ b/qiskit/quantum_info/states/stabilizerstate.py @@ -263,11 +263,11 @@ def expectation_value(self, oper: Pauli | SparsePauliOp, qargs: None | list = No """Compute the expectation value of a Pauli or SparsePauliOp operator. Args: - oper (Pauli or SparsePauliOp): a Pauli or SparsePauliOp operator to evaluate expval. - qargs (None or list): subsystems to apply the operator on. + oper: A Pauli or SparsePauliOp operator to evaluate the expectation value. + qargs: Subsystems to apply the operator on. Returns: - complex: the expectation value. + The expectation value. Raises: QiskitError: if oper is not a Pauli or SparsePauliOp operator. @@ -281,10 +281,10 @@ def expectation_value(self, oper: Pauli | SparsePauliOp, qargs: None | list = No for z, x, coeff in zip(oper.paulis.z, oper.paulis.x, oper.coeffs) ) - else: - raise QiskitError( - "Operator for expectation value is not a Pauli or SparsePauliOp operator." - ) + 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. diff --git a/releasenotes/notes/stabilizerstate-expval-sparsepauliop-3e32a871d8e908ce.yaml b/releasenotes/notes/stabilizerstate-expval-sparsepauliop-3e32a871d8e908ce.yaml index b90ca958827d..135156272dc4 100644 --- a/releasenotes/notes/stabilizerstate-expval-sparsepauliop-3e32a871d8e908ce.yaml +++ b/releasenotes/notes/stabilizerstate-expval-sparsepauliop-3e32a871d8e908ce.yaml @@ -2,4 +2,4 @@ features_quantum_info: - | The method :meth:`.StabilizerState.expectation_value` can now accept an operator of type - :class:`SparsePauliOp`. + :class:`.SparsePauliOp`.