Many people would like to use an optical quantum computer, but are hesitant to do so because the base theory is so different from today's quantum gates and quantum annealing. So, let's give it a try!
I used borealis this time. This is a machine from Xanadu, a Canadian venture company, and it uses a method called photoncis continuous variable. For a detailed explanation and calculation method, please go to blueqat.com and search for continuous quantity.
We will use this area for this tutorial.
Before we run Borealis first, we will first review a brief usage of the continuous variable computation.
import strawberryfields as sf
from strawberryfields.ops import *
import numpy as np
from numpy import pi, sqrt
# set the random seed
np.random.seed(42)
First, prepare the quantum mode corresponding to the qubit.
prog = sf.Program(3)
Then we can start writing the circuit. As previously confirmed in another blog, there are different types of gates that can be used.
from braket.aws import AwsDevice
device = AwsDevice('arn:aws:braket:us-east-1::device/qpu/xanadu/Borealis')
print(device.properties.action['braket.ir.blackbird.program'].supportedOperations)
['s', 'r0', 'r1', 'r2', 'bs0', 'bs1', 'bs2', 'loop0_phase', 'loop1_phase', 'loop2_phase']
I will be writing in StrawberryFields format using the above gate types.
This is taken from the tutorial, but it is probably quantum teleportation.
alpha = 1+0.5j
r = np.abs(alpha)
phi = np.angle(alpha)
with prog.context as q:
# prepare initial states
Coherent(r, phi) | q[0]
Squeezed(-2) | q[1]
Squeezed(2) | q[2]
# apply gates
BS = BSgate(pi/4, pi)
BS | (q[1], q[2])
BS | (q[0], q[1])
# Perform homodyne measurements
MeasureX | q[0]
MeasureP | q[1]
# Displacement gates conditioned on
# the measurements
Xgate(sqrt(2) * q[0].par) | q[2]
Zgate(-sqrt(2) * q[1].par) | q[2]
We will run the simulation in the Fock default simulator with a 5-dimensional cutoff.
There are several simulators available, including Fock simulator and Gaussian simulator.
eng = sf.Engine('fock', backend_options={"cutoff_dim": 5})
Now that the simulator has been specified, execute it.
result = eng.run(prog, shots=1, modes=None, compile_options={})
print(result.samples)
[[1.74371744 0.67170672]]
The results of the calculations are shown below; note that the Fock simulator is relatively heavy in its internal calculations, so care should be taken when using a lightweight simulator.
Next, let's use Borealis. This is a type of loop in which pulses of light are arranged in time order and calculations are performed based on the time difference.
import strawberryfields as sf
import numpy as np
from braket.strawberryfields_plugin import BraketEngine
eng = BraketEngine("arn:aws:braket:us-east-1::device/qpu/xanadu/Borealis")
device = eng.device
It seems that helper functions are used because it is difficult to keep track of every hour.
from strawberryfields.tdm import borealis_gbs, get_mode_indices
gate_args_list = borealis_gbs(device, modes=216, squeezing="high")
delays = [1, 6, 36]
n, N = get_mode_indices(delays)
2022-10-14 01:53:44,917 - WARNING - 133/259 arguments of phase gate 1 have been shifted by pi in order to be compatible with the phase modulators.
2022-10-14 01:53:44,921 - WARNING - 145/259 arguments of phase gate 2 have been shifted by pi in order to be compatible with the phase modulators.
Describe the circuit with the optical continuous variable quantum gate we have just checked.
from strawberryfields.ops import Sgate, Rgate, BSgate, MeasureFock
prog = sf.TDMProgram(N)
with prog.context(*gate_args_list) as (p, q):
Sgate(p[0]) | q[n[0]]
for i in range(len(delays)):
Rgate(p[2 * i + 1]) | q[n[i]]
BSgate(p[2 * i + 2], np.pi / 2) | (q[n[i + 1]], q[n[i]])
MeasureFock() | q[0]
Now it's time to run! (The actual device is not running at the time of writing, so I'll update this later.)
shots = 10_000
results = eng.run(prog, shots=shots, crop=True)
print(results.samples)