tket
tket copied to clipboard
`QubitPauliString.state_expectation` does not work for named qubits
I'd expect to be able to calculate $\langle X\rangle$ on a qubit named "p" as follows with QubitPauliString.state_expectation.
from pytket import Circuit, Qubit
from pytket.pauli import Pauli, QubitPauliString
circ = Circuit()
qubit_p = Qubit("p", 0)
circ.add_qubit(qubit_p)
pauli_x = QubitPauliString(circ.qubits, [Pauli.X])
print(pauli_x.state_expectation(circ.get_statevector()))
However this gives
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
Cell In[16], line 9
6 circ.add_qubit(qubit_p)
8 pauli_x = QubitPauliString(circ.qubits, [Pauli.X])
----> 9 print(pauli_x.state_expectation(circ.get_statevector()))
RuntimeError: Qubit list given to to_sparse_matrix doesn't contain p[0]
If I simply substitute "p" for the default qubit name "q" everything works fine.
@willsimmons1465 I'm interested in your opinion on this. It feels like it should work with non-default qubits, but should it? If one digs into the code path there are explicit requirements that the qubit register be the default: e.g. here.
This issue has been automatically marked as stale.
Sorry, this completely slipped by me!
Note that QubitPauliString.state_expectation is an overloaded method. In the docs @CalMacCQ linked, there are two overloads:
- The case that he called, which the documentation lists as only working for default register qubits, and so by the documentation is not expected to work here;
- The case that requires passing in an additional list of qubits demonstrating their ordering in the statevector. This is the case that should be used to solve the problem at hand.
The design choice to throw the error here was because it might not always be safe to assume the qubit ordering when they are not in the default register because of the sparsity of the representation. If we have a QubitPauliString with elements (d[0], X) and (r[0], Z), but I give a three qubit statevector, then it is ambiguous which qubits these refer to as the full Pauli string could be any of I@a[0] X@d[0] Z@r[0], X@d[0] I@k[0] Z@r[0], or X@d[0] Z@r[0] I@w[0].
I don't see this as a mistake in functionality, but if you guys think either the docs or error messages are misleading then we should go ahead and change those.
Thanks @willsimmons1465! Indeed if I supply the qubits arg (the second case) I can calculate the expectation value fine. It seems I was using this method improperly in the orignal code snippet.
from pytket import Circuit, Qubit
from pytket.pauli import Pauli, QubitPauliString
circ = Circuit()
qubit_p = Qubit("p", 0)
circ.add_qubit(qubit_p)
pauli_x = QubitPauliString(circ.qubits, [Pauli.X])
print(pauli_x.state_expectation(circ.get_statevector(), qubits=[qubit_p]))
Output
0j
Note the qubits=[qubit_p] arg. The docs do make clear that the first overload is only to be used with the default register name so I think we can close this issue.