Computing custom obsevables in Pennylane

I wanted to compute the expectation value of the projector |000><000|+|111><111| in Pennylane. So I wrote down the representing matrix and used the qml.Hermitian function which worked as expected, but when I tried to measure the projector |100><100|+|011><011|.

I got an error message because the operator do not commute (which is weird, since the project on different spaces):

dev = qml.device("default.mixed", wires=3)

@qml.qnode(dev) def circuit():
    return qml.expval(P1(wires=[0,1,2])),qml.expval(P0(wires=[0,1,2]))

def P0(wires):
    down = np.array([1, 0])
    up = np.array([0, 1])
    m1 = np.kron(down, np.kron(down, down))
    m2 = np.kron(up, np.kron(up, up))
    p0 = np.outer(m1 + m2, np.conj(m1 + m2))

    return qml.Hermitian(p0, wires)

def P1(wires):
    p0 = P0(wires)
    X = np.array([[0, 1], [1, 0]])
    I = np.array([[1, 0], [0, 1]])
    X1 = np.kron(np.kron(X, I), I)
    p1 = np.matmul(X1, np.matmul(p0, X1))

    return qml.Hermitian(p1, wires=wires)

How can I fix this? And what is the proper way of measuring expectation values <\hat{O}>=Tr(O\rho) of a custom operator for a state \rho? Writing the matrix by hand everytime seems a bit too complicated.

Hey @ofir.arzi! One approach could be to directly use the qml.Projector observable:

def H(wires):
    P100 = qml.Projector(np.array([1, 0, 0]), wires=wires)
    P011 = qml.Projector(np.array([0, 1, 1]), wires=wires)
    return qml.Hamiltonian([1.0, 1.0], [P100, P011], simplify=False)

@qml.qnode(dev)
def circuit():
    return qml.expval(H(wires=[0, 1, 2]))

Note that I disable Hamiltonian simplification, since it seems to not currently work with the projector observable yet (likely a bug!)

Thanks @josh! How come I can’t return with simply qml.expval(P100+P011) or qml.expval(P100) + qml.expval(P011)?

Furthermore, trying to return as follows fails:

def H1(wires):
    P100 = qml.Projector(np.array([1, 0, 0]), wires=wires)
    P011 = qml.Projector(np.array([0, 1, 1]), wires=wires)
    return qml.Hamiltonian([1.0, 1.0], [P100, P011], simplify=False)


def H2(wires):
    P100 = qml.Projector(np.array([0, 0, 1]), wires=wires)
    P011 = qml.Projector(np.array([1, 1, 0]), wires=wires)
    return qml.Hamiltonian([1.0, 1.0], [P100, P011], simplify=False)

@qml.qnode(dev)
def circuit():
    return qml.expval(H1(wires=[0, 1, 2])), qml.expval(H2(wires=[0, 1, 2]))

The error is pennylane.QuantumFunctionError: Only observables that are qubit-wise commuting Pauli words can be returned on the same wire. But as far as I understand the two observables are commuting!

@ofir.arzi after some investigation, the two cases above appear to be two separate bugs in PennyLane:

  • The first is that addition of Projectors doesn’t seem to be natively supported

  • The second is that the current logic for computing commutation of Hamiltonians assumes that the Hamiltonian is composed purely of Pauli words.

Thanks for catching these, this is very useful feedback that I will take back to the development team!

1 Like