Function to compute expected value from counts

Hi!

I’m trying to implement (just to understand the math and the concepts better) a function that computes the expected value of a circuit given the counts collected in the computational basis and an observable.

I tried to search on the Internet and on the documentation but could not find anything related, so I decided to implement it from scratch.

However, I’m not able to reproduce the theoretical expected value. What I’m doing wrong? Can you help me?

Thank you!!

import numpy as np

OBS = qml.PauliY(0)  @ qml.Identity(1)

dev = qml.device("default.qubit", wires=2, shots=1000)

@qml.qnode(dev)
def circuit(x):
    qml.RX(x, wires=0)
    qml.Hadamard(wires=1)
    qml.CNOT(wires=[0, 1])
    return qml.expval(OBS), qml.counts()

def state_to_vector(state):
    """Convert a binary string state to a computational basis vector."""
    num_qubits = len(state)
    index = int(state, 2)
    state_vector = np.zeros((2**num_qubits,))
    state_vector[index] = 1
    return state_vector

def compute_expected_value(counts, observable):
    probabilities = {k:v / sum(counts.values()) for k,v in counts.items()}
    
    expected_value = 0
    
    for state, probability in probabilities.items():
        # Convert the state string to a state vector
        statevector = state_to_vector(state)
        
        # Compute the inner product <psi_i|O|psi_i>
        expectation = np.dot(statevector.conj().T, np.dot(observable, statevector))
        
        # Add the weighted expectation to the total expected value
        expected_value += probability * expectation
    
    return expected_value


expval, counts = circuit(0.5)
print(compute_expected_value(counts, OBS.matrix()))
print(expval)

Hi @fortytwo , welcome to the Forum!

I think the issue here is in understanding what qml.expval() is returning.

qml.expval() returns the “Expectation value of the supplied observable”. But what are you measuring here? When you measure you always get an eigenvalue of your observable so this expectation value is with respect to those measurements. In the case of Pauli X, Y and Z, their eigenvalues are 1 and -1. So if you had a circuit where you did nothing and you measured the expectation value of the PauliZ observable you would see that the expectation value is 1 but the counts are all 0. This is indeed correct because measuring a 1 in the PauliZ basis is equivalent to the north pole of the Bloch sphere, which is interpreted as a classical zero. On the other hand measuring a -1 in the PauliZ basis is equivalent to the south pole of the Bloch sphere, which is interpreted as a classical one. You can perform a similar experiment with the code below. When you add a Hadamard and measure the expval of the PauliZ observable you get zero, meaning that half of the time you get a 1 and half of the time you get -1. If you changed the observable to PauliX then the expval would always be 1.

import pennylane as qml

dev1 = qml.device("default.qubit", wires=1, shots=1000)

@qml.qnode(dev1)
def test_circuit():
    qml.Hadamard(wires=0)
    return qml.expval(qml.PauliZ(0)), qml.counts()
    
test_circuit()

I cannot tell whether the rest of your code is correct but I think at least this can give you some clarity on something that can definitely be confusing.

I think you’ll also like this Codebook Module on processing measurement outcomes, where the theory and coding exercises are there to make it easier and fun to learn about this!

Let me know if this clarifies things for you or if you have more questions.