Hi @Benjamin_Gregory, I had a look through your code, and you’re right, qml.Interferometer
is currently not working with strawberryfields.fock
. I’ll make a pull request on GitHub to fix that.
However, to train an arbitrary interferometer, you probably don’t want this operation. Note that we have two similar operations:

qml.Interferometer(U, wires)
: accepts a numeric unitary matrix, determining a fixed interferometer.

qml.templates.layers.Interferometer(theta, phi, varphi, wires)
: accepts an array of parameters theta
, phi
, and varphi
, and creates a mesh of beamsplitters and rotation gates for applying a parametrized unitary.
In this case, it is probably the latter function you want. Check out the documentation for more details on this function and its arguments.
Here is a quick example using the Interferometer layer template:
import numpy as np
import pennylane as qml
from pennylane.templates.layers import Interferometer
from pennylane.init import interferometer_uniform
import tensorflow as tf
import tensorflow.contrib.eager as tfe
tf.enable_eager_execution()
M = 5
GBS_dev = qml.device("strawberryfields.gaussian", wires=M)
@qml.qnode(GBS_dev, interface="tf")
def device(params, input_squeeze):
# get beamsplitter angles
theta = params[:M*(M1)//2]
# get beamsplitter phases
phi = params[M*(M1)//2:2*M*(M1)//2]
# get local rotations
varphi = params[M:]
for w in range(M):
qml.Squeezing(1, input_squeeze, wires=w)
Interferometer(theta, phi, varphi, wires=range(M))
return [qml.expval(qml.NumberOperator(i)) for i in range(M)]
input_squeeze = 0.4*np.pi
params = tfe.Variable(np.concatenate(interferometer_uniform(M)))
print(device(params, input_squeeze))