pennylane
pennylane copied to clipboard
[BUG] Incorrect single-shot Hamiltonian expectation
Expected behavior
Consider the following circuit:
dev = qml.device("lightning.qubit", wires=2, shots=1)
H = qml.PauliZ(0) + qml.PauliZ(1)
@qml.qnode(dev)
def cost_function3():
qml.Hadamard(0)
qml.CNOT(wires=[0, 1])
return qml.expval(H)
This circuit will only generate states $|00\rangle$ and $|11\rangle$.
If we print the matrix of the Hamiltonian,
>>> qml.matrix(H)
array([[ 2.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[ 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[ 0.+0.j, 0.+0.j, 0.+0.j, -2.+0.j]])
we see that we should only get expectation values of 2 (corresponding to state $|00\rangle$) and -2 ($|11\rangle$).
Actual behavior
This is not the case:
>>> for i in range(10):
... print(cost_function3(), dev._samples)
0.0 [[1 1]]
2.0 [[0 0]]
-2.0 [[1 1]]
2.0 [[0 0]]
0.0 [[0 0]]
0.0 [[1 1]]
0.0 [[0 0]]
0.0 [[0 0]]
2.0 [[0 0]]
0.0 [[1 1]]
Additional information
Note that if we turn on grouping of the Hamiltonian (H.compute_grouping()
) before creating the QNode, the bug is gone:
dev = qml.device("lightning.qubit", wires=2, shots=1)
H = qml.PauliZ(0) + qml.PauliZ(1)
H.compute_grouping()
@qml.qnode(dev)
def cost_function3():
qml.Hadamard(0)
qml.CNOT(wires=[0, 1])
return qml.expval(H)
>>> for i in range(10):
... print(cost_function3(), dev._samples)
-2.0 [[1 1]]
-2.0 [[1 1]]
2.0 [[0 0]]
-2.0 [[1 1]]
-2.0 [[1 1]]
-2.0 [[1 1]]
-2.0 [[1 1]]
-2.0 [[1 1]]
-2.0 [[1 1]]
2.0 [[0 0]]
Source code
No response
Tracebacks
No response
System information
.
Existing GitHub issues
- [X] I have searched existing GitHub issues to make sure the issue does not already exist.
Update: what is happening is that, in the non-grouped version, two circuits are being executed under the hood, one for each term in the Hamiltonian sum. Since the two circuit executions are not necessarily correlated, it is possible for one circuit to output 2 and the other to output -2, leading to 0.
So this is probably not a bug, and moreso, unexpected behaviour resulting from how PL treats shots. shots=1
does not mean a single shot for the constructed circuit, it means "The device may execute multiple circuits, with each execution taking 1 shot". So it is better to think of the non-grouped example as taking 2 shots.
So the solution to this 'bug'/un-intuitive behaviour is probably more long-term, and involves changing how shots are budgeted in PennyLane.
>>> dev = qml.device("lightning.qubit", wires=2, shots=1)
>>> H = qml.PauliZ(0) + qml.PauliZ(1)
>>> @qml.qnode(dev)
... def cost_function3():
... qml.Hadamard(0)
... qml.CNOT(wires=[0, 1])
... return qml.expval(H)
>>> with qml.Tracker(dev) as tracker:
... cost_function3()
>>> tracker.totals
{'executions': 2, 'shots': 2, 'batches': 1, 'batch_len': 2}