#
# .. rst-class:: docstable
#
# +------------------+-------------------------------+
# | Observable | Rotation gate |
# +==================+===============================+
# | :math:`X` | :math:`RY(-\pi/2) = H` |
# +------------------+-------------------------------+
# | :math:`Y` | :math:`RX(\pi/2)=HS^{-1}=HSZ` |
# +------------------+-------------------------------+
# | :math:`Z` | :math:`I` |
# +------------------+-------------------------------+
# | :math:`I` | :math:`I` |
# +------------------+-------------------------------+
#
# .. raw:: html
#
#

#
# Therefore, in this particular example:
#
# * Wire 0: we are measuring both terms in the :math:`X` basis, apply the Hadamard gate
# * Wire 1: we are measuring both terms in the :math:`Y` basis, apply a :math:`RX(\pi/2)` gate
# * Wire 2: we are measuring both terms in the :math:`Z` basis (the computational basis), no gate needs to be applied.
#
# Let's use PennyLane to verify this.
obs = [
qml.PauliX(0) @ qml.PauliY(1),
qml.PauliX(0) @ qml.PauliZ(2)
]
##############################################################################
# First, let's naively use two separate circuit evaluations to measure
# the two QWC terms.
dev = qml.device("default.qubit", wires=3)
@qml.qnode(dev)
def circuit1(weights):
qml.templates.StronglyEntanglingLayers(weights, wires=range(3))
return qml.expval(obs[0])
@qml.qnode(dev)
def circuit2(weights):
qml.templates.StronglyEntanglingLayers(weights, wires=range(3))
return qml.expval(obs[1])
weights = qml.init.strong_ent_layers_normal(n_layers=3, n_wires=3)
print("Expectation value of XYI = ", circuit1(weights))
print("Expectation value of XIZ = ", circuit2(weights))
##############################################################################
# Now, let's use our QWC approach to reduce this down to a *single* measurement
# of the probabilities in the shared eigenbasis of both QWC observables:
@qml.qnode(dev)
def circuit_qwc(weights):
qml.templates.StronglyEntanglingLayers(weights, wires=range(3))
# rotate wire 0 into the shared eigenbasis
qml.RY(-np.pi / 2, wires=0)
# rotate wire 1 into the shared eigenbasis
qml.RX(np.pi / 2, wires=1)
# wire 2 does not require a rotation
# measure probabilities in the computational basis
return qml.probs(wires=range(3))
rotated_probs = circuit_qwc(weights)
print(rotated_probs)
##############################################################################
# We're not quite there yet; we have only calculated the probabilities of the variational circuit
# rotated into the shared eigenbasis---the :math:`|\langle \phi_n |\psi\rangle|^2`. To recover the
# *expectation values* of the two QWC observables from the probabilities, recall that we need one
# final piece of information: their eigenvalues :math:`\lambda_{A, n}` and :math:`\lambda_{B, n}`.
#
# We know that the single-qubit Pauli operators each have eigenvalues :math:`(1, -1)`, while the identity
# operator has eigenvalues :math:`(1, 1)`. We can make use of ``np.kron`` to quickly
# generate the eigenvalues of the full Pauli terms, making sure that the order
# of the eigenvalues in the Kronecker product corresponds to the tensor product.
eigenvalues_XYI = np.kron(np.kron([1, -1], [1, -1]), [1, 1])
eigenvalues_XIZ = np.kron(np.kron([1, -1], [1, 1]), [1, -1])
# Taking the linear combination of the eigenvalues and the probabilities
print("Expectation value of XYI = ", np.dot(eigenvalues_XYI, rotated_probs))
print("Expectation value of XIZ = ", np.dot(eigenvalues_XIZ, rotated_probs))
##############################################################################
# Compare this to the result when we used two circuit evaluations. We have successfully used a
# single circuit evaluation to recover both expectation values!
#
# Luckily, PennyLane automatically performs this QWC grouping under the hood. We simply
# return the two QWC Pauli terms from the QNode:
@qml.qnode(dev)
def circuit(weights):
qml.templates.StronglyEntanglingLayers(weights, wires=range(3))
return [
qml.expval(qml.PauliX(0) @ qml.PauliY(1)),
qml.expval(qml.PauliX(0) @ qml.PauliZ(2))
]
print(circuit(weights))
##############################################################################
# Behind the scenes, PennyLane is making use of our built-in
# :mod:`qml.grouping