Skip to content

StabilizerState.expectation_value should accept SparsePauliOp #12422

@kevinsung

Description

@kevinsung

What should we add?

Currently, it only accepts Pauli. See

def expectation_value(self, oper: Pauli, qargs: None | list = None) -> complex:
"""Compute the expectation value of a Pauli operator.
Args:
oper (Pauli): a Pauli operator to evaluate expval.
qargs (None or list): subsystems to apply the operator on.
Returns:
complex: the expectation value (only 0 or 1 or -1 or i or -i).
Raises:
QiskitError: if oper is not a Pauli operator.
"""
if not isinstance(oper, Pauli):
raise QiskitError("Operator for expectation value is not a Pauli operator.")
num_qubits = self.clifford.num_qubits
if qargs is None:
qubits = range(num_qubits)
else:
qubits = qargs
# Construct Pauli on num_qubits
pauli = Pauli(num_qubits * "I")
phase = 0
pauli_phase = (-1j) ** oper.phase if oper.phase else 1
for pos, qubit in enumerate(qubits):
pauli.x[qubit] = oper.x[pos]
pauli.z[qubit] = oper.z[pos]
phase += pauli.x[qubit] & pauli.z[qubit]
# Check if there is a stabilizer that anti-commutes with an odd number of qubits
# If so the expectation value is 0
for p in range(num_qubits):
num_anti = 0
num_anti += np.count_nonzero(pauli.z & self.clifford.stab_x[p])
num_anti += np.count_nonzero(pauli.x & self.clifford.stab_z[p])
if num_anti % 2 == 1:
return 0
# Otherwise pauli is (-1)^a prod_j S_j^b_j for Clifford stabilizers
# If pauli anti-commutes with D_j then b_j = 1.
# Multiply pauli by stabilizers with anti-commuting destabilizers
pauli_z = (pauli.z).copy() # Make a copy of pauli.z
for p in range(num_qubits):
# Check if destabilizer anti-commutes
num_anti = 0
num_anti += np.count_nonzero(pauli.z & self.clifford.destab_x[p])
num_anti += np.count_nonzero(pauli.x & self.clifford.destab_z[p])
if num_anti % 2 == 0:
continue
# If anti-commutes multiply Pauli by stabilizer
phase += 2 * self.clifford.stab_phase[p]
phase += np.count_nonzero(self.clifford.stab_z[p] & self.clifford.stab_x[p])
phase += 2 * np.count_nonzero(pauli_z & self.clifford.stab_x[p])
pauli_z = pauli_z ^ self.clifford.stab_z[p]
# For valid stabilizers, `phase` can only be 0 (= 1) or 2 (= -1) at this point.
if phase % 4 != 0:
return -pauli_phase
return pauli_phase

Metadata

Metadata

Assignees

No one assigned

    Labels

    mod: quantum infoRelated to the Quantum Info module (States & Operators)type: feature requestNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions