-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Projectors for TensorFlow quantum #4331
Conversation
I would suggest @MichaelBroughton as a first-pass reviewer but happy to get advice from anyone. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This implementation is too general. We want to support just computational bitstrings with these projectors. With the code as it is now I can do this:
q0 = cirq.GridQubit(0, 0)
phi = [<numbers>, <numbers>]
complicated_projector = cirq.ProjectorString({q0: cirq.Projector(phi)})
psi = cirq.Circuit(<lots of gates>)
Using TFQ if I wanted to serialize phi
(with tfq.convert_to_tensor
) it would require exponential memory on the wire to write down the state to project on to. It is very important for performance reasons in TFQ that wire size be kept down.
In addition to this, if I wanted to use a quantum computer to evaluate something like:
For completely arbitrary phi
and psi
I would need to use a swap test which isn't very NiSQY and would introduce complications in trying to preserve the differentiability of TFQ expectation calculations (let alone also trying to write down a circuit that actually prepares an arbitrary state if all you are given is just the state phi
).
If the scope of functionality were to be reduced to:
q0 = cirq.GridQubit(0, 0)
q1 = cirq.GridQubit(0, 1)
q2 = cirq.GridQubit(0, 2)
# !only support computational basis states!
simple_phi = cirq.ProjectorString({q0: 0, q1: 1, q2: 0})
psi = cirq.Circuit(<lots of gates>)
Now, if I wanted to serialize simple_phi
using tfq.convert_to_tensor
all I would need to put on the wire is a mapping from qubits to ints indicating which bitstring projector I have instead of having to write down the full state vector(s) on the qubits.
If I want to evaluate:
It's very cheap to do because it's just:
which boils down to running the circuit you have to prepare psi
, drawing some samples and then counting the number of times you see the 010
bitstring. No swap test or trying to figure out how to prepare an arbitrary phi
. This computational bitstring implementation of Projectors will also make it easier to incorporate differentiability of the Projector type into the tfq.***_expectation
C++ ops without taking any major performance hits.
All that being said I think all we really need here is a way to do things like this:
q0 = cirq.GridQubit(0, 0)
q1 = cirq.GridQubit(0, 1)
q2 = cirq.GridQubit(0, 2)
a = cirq.ProjectorString({q0: 0, q1: 1, q2: 0})
b = cirq.ProjectorString({q1: 1, q2: 1})
c = a + b # type(c) == cirq.ProjectorSum
c.expectation_from_***(<whatever>)
a.expectation_from_***(<whatever>)
c.matrix() # type(c.matrix()) == scipy.sparsematrix
# etc.
Which is a lot simpler than what we have now.
@MichaelBroughton
Note I don't feel very strongly about the decisions I've made. It's mostly decisions I had to make to make progress. Thanks again for the review. PTAL. |
The point is that it look and feel very similar, but give the clear indication that you are dealing with Projectors and not Paulis. We could also surface this for more discussion, but I think this is a pretty uncontroversial approach.
That sounds like a good idea. Let's start with just
This certainly is an important piece . If we go one PR at a time, it shouldn't be that much more work to make sure that when we merge things, the performance is closer to optimal. As an example the def expectation_from_state_vector(
self,
state_vector: np.ndarray,
qid_map: Mapping[raw_types.Qid, int],
*,
atol: float = 1e-7,
check_preconditions: bool = True,
) -> float:
return np.abs(state_vector[<projector_bitstring>]) ** 2 would work |
Thanks, @MichaelBroughton , PTAL when you have some time? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly nits now. After this round of review I think we will be good to merge. The only remaining major item is tightening up the matrix
method (similar to what was done for the expectation_***
methods).
Thanks, @MichaelBroughton PTAL when you can. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
last nit then LGTM.
Thanks @MichaelBroughton! I copied over your suggestion, merged from the main branch, and re-ran the tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This is a follow-up on #4331 which introduced ProjectorString objects. The present PR aims at adding ProjectorSum objects.
TensorFlow Quantum would like to be able to specify projectors in a memory efficient way. This PR attempts to provide such a facility.
This is a follow-up on quantumlib#4331 which introduced ProjectorString objects. The present PR aims at adding ProjectorSum objects.
TensorFlow Quantum would like to be able to specify projectors in a memory efficient way. This PR attempts to provide such a facility.
This is a follow-up on quantumlib#4331 which introduced ProjectorString objects. The present PR aims at adding ProjectorSum objects.
TensorFlow Quantum would like to be able to specify projectors in a memory efficient way. This PR attempts to provide such a facility.