Conditional gate implementation

I’m curious if I can design a circuit in which I apply a gate on a qumode based on the outcome of a measurement on another qumode, something like this:

device = qml.device('strawberryfields.fock', cutoff_dim=5, wires=2)

@qml.qnode(device, interface='torch')
def circ(x, theta, phi):
    qml.Displacement(4.0, x, wires=[0])
    qml.Displacement(4.0, x, wires=[1])
    qml.Beamsplitter(theta, phi, wires=[0,1])
    qml.Squeezing( qml.expval(qml.P(0)), np.pi, wires=[1] )
    return qml.expval(qml.X(1))

x = torch.tensor(.0991, requires_grad=True)
theta = torch.tensor(.744, requires_grad=True)
phi = torch.tensor(.655, requires_grad=True)

circ(x, theta, phi)

When running the code above, I get an error:

TypeError: Squeezing: Real scalar parameter expected, got <class 'pennylane.ops.cv.P'>.

Hey @dnnagy,

This behaviour is currently not supported in PennyLane.

It’s something we could think about implementing in the future. However, it is not clear that it plays well with the automatic differentiation which is the core feature of the library (because you can’t usually compute a gradient of a conditioning step), so depending on your use-case, it may or may not be of value to have this in the library.

In the meantime, this is supported in our sister library, Strawberry Fields:

import strawberryfields as sf
from strawberryfields import ops

prog = sf.Program(2)

x = .0991
theta = .744
phi = .655

with prog.context as q:
    ops.Dgate(4.0, x)          | q[0]
    ops.Dgate(4.0, x)          | q[1]
    ops.BSgate(theta, phi)     | q
    MeasureP                   | q[0]
    ops.Sgate(q[0].par, np.pi) | q[1]
    MeasureX                   | q[1]

eng = sf.Engine("gaussian", backend_options={"cutoff_dim": 5})
results = eng.run(prog)

Check out the Strawberry Fields teleportation tutorial for more details on photonic feed-forward.

1 Like

@josh

In case of two qubit gates, first param is the control qubit and later one is the target (in qiskit).

In Pennylane, this is reverse in order or same?

i

Hi @Amandeep, yep it’s the same order :slight_smile:

For example,

qml.CNOT(wires=[0, 1])

Here, wire 0 is the control, and wire 1 is the target.