Control of a quantum state

I am going to define a quantum circuit for distance classifier. i was wondering if it is possible to define a controlled-Mottonen state preparation.

Hi @sassan_moradi,

Thanks for the question!

At the moment this is not feasible by using a dedicated state preparation, unfortunately.

One way to implement a controlled state preparation is by using the QubitUnitary operation and explicitly passing the matrix representation of the unitary for the transformation.

We are further exploring the possibilities of adding conditional operations which could help such controlled operations in certain use cases.

i checked the Qubitunitary operation. it has two inputs. A unitary matrix and a wires. So i have wires=0 as control and wires=[1, 2,3, 4] as targets, how can i use class Qubitunitary operation? I mean these wires_control = 0 and wires_target=[1, 2, 3, 4] in class QubitUnitary?

Hey @sassan_moradi! Actually, one of the things I’m hoping to add shortly is a ControlledQubitUnitary(unitary, control_wire, unitary_wires). Until then, you have to “hack in” the control through QubitUnitary. If your first wire is the control wire, and you want to apply U, then you can make a block matrix:
[[identity, 0], [0, U]],
where identity and 0 are of the same dimension as U. The result will be a matrix that is twice as large. Note that this is only simple when control is on the first wire.

Also just to add, you can make the block matrix more easily using scipy.linalg.block_diag!

Thanks a lot Tom. i could design a single controlled y rotation gate. another question that i might have: I am going to design a single control rotation y but this time rotation operation is applied if control qubit is |0> not |1>. Or a more complex, a two controlled y rotation but rotation operation applied: 1) if control in state |10>, 2) if control in state |01>, and 3) if control in state |11>.

Hi @sassan_moradi,

I am going to design a single control rotation y but this time rotation operation is applied if control qubit is |0> not |1>

This could go as [[RY, 0], [0, identity]] in a block representation.

Or a more complex, a two controlled y rotation but rotation operation applied: 1) if control in state |10>

This will be an 8x8 matrix with block diagonal representation of [[identity, identity], [RY, identity]], the remaining entries are all zeros.

Will leave the rest for you, but let us know if you’d like us to help out! :slightly_smiling_face:

More context

The reason why the technique that Tom suggested works, is because the matrix representation of the unitary in the computational basis transforms basis states in a particular way.

Let me elaborate.

The CNOT_{12} gate (first qubit being the control and the second qubit being the target) flips the second qubit if and only if the first qubit was in |1\rangle.

Its matrix representation in the computational basis is:

CNOT_{12} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1\\ 0 & 0 & 1 & 0 \end{bmatrix}.

Let’s consider the two-qubit computational basis states in the following order: |00\rangle, |01\rangle,|10\rangle and |11\rangle. The effect of the CNOT_{12} operator on the computational basis states can be summarized as:

1.|00\rangle -> |00\rangle
2. |01\rangle -> |01\rangle
3. |10\rangle -> |11\rangle
4. |11\rangle -> |10\rangle

Now, one neat thing is that if we assign the basis states in this order to the columns and rows of the matrix, we can observe the transformation by looking at the columns as the |\psi\rangle before applying the unitary and the rows as the result of CNOT_{12}|\psi\rangle.

(Note: this is just another way of looking at the matrix-vector multiplication between the unitary matrix and our state vector.)

CNOT_{12} = \begin{bmatrix} & |00\rangle & |01\rangle & |10\rangle & |11\rangle \\ |00\rangle & 1 & 0 & 0 & 0 \\ |01\rangle & 0 & 1 & 0 & 0\\ |10\rangle & 0 & 0 & 0 & 1\\ |11\rangle & 0 & 0 & 1 & 0 \end{bmatrix}.

So, for example, the 4th column of CNOT_{12} tells us that we’ll get the |10\rangle state when computing CNOT_{12}|11\rangle.

This technique could help coming up with the matrix representation of other operations too.

Note: we used a qubit ordering as used in textbooks and in PennyLane, but some sources may use a different qubit ordering.

1 Like

thanks a lot, Antalszava . very useful and helpful. i will try with it. If i have any further question, i will ask you again.

Thanks a lot for your useful and helpful answers. i have another question about the control of a quantum state. I am going to design a very simple distance classifier. Something like this:

def circuit(x1, x2):
    C= qml.templates.MottonenStatePreparation(x1, wires=[1, 2, 3])
    qml.QubitUnitary(C, wires=[1,2,3])
    D = qml.templates.MottonenStatePreparation(x2, wires=[1, 2, 3])
    qml.QubitUnitary(D, wires=[1,2,3])
    return qml.expval(qml.PauliZ(0))

Is it possible to do it with Pennylane? i tried but couldn’t.

Thanks in advance.

Hi @sassan_moradi,

As I think you’ve already noticed, it’s not possible to mix continuous and discrete variables (as noted here). The issue in the circuit you’ve defined is qml.X, which isn’t compatible with the other qubit operations.

There’s a demo for creating a Variational Classifier, which perhaps could help you in creating a circuit. You also have the full list of operations which you can use; just make sure to stick with either continuous or discrete variables.

Let us know if you encounter any other issues, and we’ll do our best to help you out!

Hi, sorry further on this, I wonder with ControlledQubitUnitary(unitary, control_wire, unitary_wires), is it possible to implement a controlled-Mottonen state preparation without having to specify the unitary itself? Thank you for your help!

Hi @leongfy!

Yes, you can perform a controlled state preparation just by specifying the target wires, the control wires, and the state to be prepared. The code block below gives an example of how this is done:

import pennylane as qml
from scipy.stats import unitary_group

total_wires = 3
ctrl_wires = [0]
prep_wires = [1, 2]

dev = qml.device("default.qubit", wires=total_wires)
psi = unitary_group.rvs(2 ** len(prep_wires))[0]

def prep(psi, wires):
    qml.templates.MottonenStatePreparation(psi, wires=wires)

def circuit(psi):
    qml.ctrl(prep, control=ctrl_wires)(psi, wires=prep_wires)
    return qml.state()

print("Prepared state:\n", circuit(psi))
print("\n Circuit:")