Initialize Specific Quantum State without ML

I am optimizing circuits that require thousands of different (very specific and numerically exactly solved) input states. While I’ve read these posts (https://pennylane.ai/qml/demos/tutorial_state_preparation.html , State preparation with pennylane) on how to train circuits for state preparation, I really don’t care about this stage for my purposes and it would be much more efficient for me to cut the preparation stage out and begin directly with my states of choice. Is there a way to implement this?

Hi @taylor, welcome and thanks for the question!

Just so we can help answer your query: are you expecting your inputs states to be differentiable? (i.e., will they be connected to some other upstream neural network or another quantum circuit?)

If not, then you should be able to use the QubitStateVector operation to load the states in. (recommended for simulator backends; if you run this on hardware, there would be a large overhead from compiling the circuit)

Hi @nathan, thanks for your response!

Yes, indeed. I plan to put the specifically initialized qubits into a multilayered circuit, the parameters of which I would then learn by defining a cost function of the circuit output. Is there something that will work for this usecase?

Hi @nathan, thanks for your response!

Yes, indeed. I plan to put the specifically initialized qubits into a multilayered circuit, the parameters of which I would then learn by defining a cost function of the circuit output. Is there something that will work for this usecase?

Hi @taylor,

The simulator "default.qubit.tf" is meant to cover exactly this use-case. As you might guess from the “tf” part, the entire simulation is actually coded in TensorFlow. This means it is only compatible with TensorFlow. Which ML interface are you planning to use?

Hi @nathan,

In principle, TensorFlow should probably do, but I’d prefer/am more familiar with either NumPy or PyTorch.

I read the docs on on “default.qubit” a little more closely though and found the internal variable “_state” and method “_apply_state_vector”, which while beginning with an underscore do not seem to be truly private.

Is there a work-around to use these functions with “default.qubit” to initiate specific states pre-circuit? Admittedly, I must be too fresh and naieve wrt to PennyLane to catch device nuances, because a lot of the state methods are not immediately clear to me. For instance, the public method “state” is set to return “_pre_rotated_state” (vacuum state), not the current one. Moreover, while “_apply_state_vector” updates “_state”, qubit rotations do not, while changes to “_state” do not change the expectation values, so within the device “_state” and the actual qnode updates must be very different thing.

Hi @taylor,

If I may, I’d like to give a tiny technical overview to indicate how things work in this case:

Most (but not all!) operations in PennyLane have a “gradient recipe”, which indicates how one obtains the gradient of a circuit’s output with respect to that operation’s arguments. Unfortunately, QubitStateVector does not have such a rule (at least, not a rule that is compatible with running on hardware).

To deal with cases like this (and for other reasons as well), we have a special object called a PassThruQNode. Your circuit can be converted to a PassThruQNode if you put diff_method="backprop" in the @qml.qnode(...) decorator. What happens in these QNodes is they completely ignore an operation’s differentiation recipe and instead just simulate everything as linear algebraic operations on some compatible simulator.

But only certain simulator devices are compatible with this, such as "default.qubit.tf", which is written in TensorFlow. We’d love to support simulators written in PyTorch, but we’ll have to wait until PyTorch properly supports complex numbers. In principle, we should be able to support autograd/numpy, but we haven’t had a chance to code this up yet.

Here’s an example using TF simulator to show that gradients can “pass through” the QNode safely:

import pennylane as qml
import tensorflow as tf
import numpy as np

dev = qml.device("default.qubit.tf", wires=2)
@qml.qnode(dev, interface="tf", diff_method="backprop")
def circuit(inputs):
    qml.QubitStateVector(inputs, wires=[0,1])
    return qml.expval(qml.PauliZ(0))


state = np.zeros(2**2, dtype=complex)
state[0] = 1.0
inputs = tf.Variable(state)


with tf.GradientTape() as tape:
    expval = circuit(inputs)

t = tape.gradient(expval, inputs)
print(t)
>>> tf.Tensor([2.+0.j 0.+0.j 0.+0.j 0.+0.j], shape=(4,), dtype=complex128)

Note that this is a newer feature, so if you use it and have any questions/issues, be sure to let us know

1 Like

By the way, as you noticed, the _state attribute is semi-official. There is no fixed specification for it, but a number of devices use it. We are planning to make this more directly part of the public-facing API in the future. I’d caution however against trying to hack that. There are ways to “inject” your desired state into this attribute, but if you do that, PennyLane won’t know how to properly compute its gradient, which would undermine what I think you are trying to accomplish.

1 Like

Thanks for the help and I’m excited to see how the library continues to develop.