Skip to content

Commit

Permalink
StabilizerState.expectation_value can also accept SparsePauliOp (Q…
Browse files Browse the repository at this point in the history
…iskit#13539)

* update ecpectation_value function

* add a test

* add release notes

* revision following code review
  • Loading branch information
ShellyGarion authored Dec 18, 2024
1 parent cf5ef03 commit 053ee32
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 3 deletions.
31 changes: 29 additions & 2 deletions qiskit/quantum_info/states/stabilizerstate.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
features_quantum_info:
- |
The method :meth:`.StabilizerState.expectation_value` can now accept an operator of type
:class:`.SparsePauliOp`.
14 changes: 13 additions & 1 deletion test/python/quantum_info/states/test_stabilizerstate.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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."""

Expand Down

0 comments on commit 053ee32

Please sign in to comment.