Interferometer compatibility with sf device

I am trying to use the Interferometer gate in a qnode running on the strawberry fields.fock device but I’m getting an error “Gate Interferometer not supported on device strawberryfields.fock”

Interferometer is within the pennylane.ops.cv module and is supposed to be compatible. Any ideas why this will never work or is there a clever workaround. I’m really interested in implementing an arbitrary unitary with trainable elements and Interferometer seemed the most elegant way.

Hi @Benjamin_Gregory! That is odd, as far as I can tell the Interferometer gate should work with strawberryfields.fock.

Do you have a minimal (non)-working code example you could share?

import tensorflow as tf
import pennylane as qml
from pennylane import numpy as np
import pennylane.ops.cv as sf

#import tensorflow.contrib.eager as tfe
#tf.enable_eager_execution()


M = int(5)  #modenumber
K = int(M*(M-1)/2)
allmodes =list(range(M))

GBS_dev = qml.device("strawberryfields.fock", wires= M, cutoff_dim=10)

theta = np.random.uniform(0, 2*np.pi, K)
phi = np.random.uniform(0, 2*np.pi, K)
input_squeeze = .4*np.pi

#define device, squeezing first and then interferometer
@qml.qnode(GBS_dev)
def device(theta, input_squeeze):
    qml.Squeezing(1, input_squeeze, wires = 1)
    qml.Interferometer(theta, wires = [0,1])
     return qml.expval(qml.NumberOperator(0))
    

device(theta, input_squeeze)

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*(M-1)//2]
    # get beamsplitter phases
    phi = params[M*(M-1)//2:2*M*(M-1)//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))

Hi @josh
thanks for your help

I am having two problems with your suggestion

  1. NumberOperator not supported with sf.gaussian or sf.fock device
  2. tf.Variable object is not iterable

also is there a reason you switched to sf.gaussian over sf.fock device?

Still not able to get NumberOperator to run with strawberry fields.gaussian or strawberry fields.fock devices. I have tried using other related functions MeanPhoton, mean_photon, NumberState etc.

I can only get NumberOperator to work with the default.gaussian device

dev.observables
{‘Homodyne’, ‘Identity’, ‘MeanPhoton’, ‘NumberState’, ‘P’, ‘PolyXP’, ‘X’}

All the other observables work except MeanPhoton and NumberState

Hi @Benjamin_Gregory, just following up on some of your questions:

NumberOperator not supported with sf.gaussian or sf.fock device

Ah, that’s good to know! We will release a bugfix version of PennyLane-SF at the end of this week, so it will include that fix (and allow NumberOperator to work on both the Fock and Gaussian devices).

tf.Variable object is not iterable

Unfortunately I can’t recreate this error. Can I ask what version of PennyLane and TensorFlow you are using?

We have been working internally on updating PennyLane to work with TensorFlow 2.0. This will be coming out at the end of this week (at the same time as the new plugin releases), and perhaps might solve the issue.

also is there a reason you switched to sf.gaussian over sf.fock device?

Simply due to speed :slightly_smiling_face: Since the NumberOperator is a Gaussian observable (it is only second-order in the \hat{x} and \hat{p} operators), it is supported on both the Gaussian and Fock backends. If you were instead looking to train your optimizer using the probability (as opposed to the mean photon number), you can use the FockStateProjector observable, which is non-Gaussian.

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

from pennylane.templates.layers import Interferometer
from pennylane.init import interferometer_uniform

import tensorflow.contrib.eager as tfe
tf.enable_eager_execution()

M = 4
wires = np.array(range(M))
GBS_dev = qml.device("default.gaussian", wires=M)

@qml.qnode(GBS_dev, interface="tf")
def device(params, input_squeeze):
    theta = params[:M*(M-1)//2]
    phi = params[M*(M-1)//2:2*M*(M-1)//2]
    varphi = params[-M:]

    for i in range(M):
        qml.Squeezing(squeeze, 0, wires = i) 
        Interferometer(theta, phi, varphi, wires=range(M))
        return qml.expval(qml.NumberOperator(0)) 
squeeze = 2.0
params = tf.Variable(np.concatenate(interferometer_uniform(M)))
print(device(params, squeeze))

This is producing the tf.Variable error; if I remove it it works fine

tf version 1.12.0
qml version 0.5.0
sf version 0.11.1

Thanks for your help I’ll look for the bug fixes soon

Hi @Benjamin_Gregory, try changing the line

@qml.qnode(GBS_dev, interface="tf")

to

@qml.qnode(GBS_dev, interface="tfe")

In the latest GitHub version of PennyLane we have changed the interface name to 'tf' alongside supporting TF 2.0. This version will be released at the end of this week.

However, on PennyLane 0.5 (which you are using), it is still 'tfe' for now!

Hi @Benjamin_Gregory, just letting you know that the new releases of both PennyLane and PennyLane-SF v0.6 are now live :slightly_smiling_face:

If you could have a go upgrading, and let me know if that fixes the original bug!