The TDMProgram will produce wrong results if the number of timebins is not an integer multiple of the number of concurrent modes. This is because the tdmprogram.unroll() function simpy multiplies the unique circuit with the number of shots, not taking into account which qumode has been measured most recently.
To illustrate the bug, let's consider this TDM program:
theta = [0] * 3
r = 3
shots = 2
prog = sf.TDMProgram(N=2)
with prog.context(theta) as (p, q):
ops.Xgate(50) | q[1]
ops.MeasureHomodyne(p[0]) | q[0]
eng = sf.Engine("gaussian")
res = eng.run(prog, shots=shots)
samples = res.samples
print(samples)
Expected behavior: In average, you would expect samples to look like
[[[ 0 50 50]]
[[50 50 50]]]
And, indeed, for an equivalent program with four timebins (theta = [0] * 4) we get, as expected,
Note that the second mode of the second shot is ~100 as it has undergone the displacement gate twice. This happens because self.circuit = self.unrolled_circuit * shots multiplies the unique circuit with the number of shots where each shot starts with the same qumode index. This can be illustrated by printing the qumode index whenever a gate is applied. The above circuit with two shots yields:
displace mode 1 # shot 1, timebin 0 -> the displacement is applied to mode 1 although the most recently measured mode is 0
measure mode 0 # shot 1, timebin 0
displace mode 0 # shot 1, timebin 1
measure mode 1 # shot 1, timebin 1
displace mode 1 # shot 1, timebin 2
measure mode 0 # shot 1, timebin 2
The second shot starts with displacement of qumode 1. But qumode 1 is the mode that just _has_ been displaced at the end of shot 0! This issue will always occur when the number of timebins is not an integer multiple of the number of concurrent modes.
It took me pretty long to figure this out, and I am available for a chat and/or further demonstrations. I thought I could fix it myself by applying an additional qumode shift at the end of each shot, but I didn't succeed.
* *Reproduces how often:* Always
Issue description
The
TDMProgram
will produce wrong results if the number of timebins is not an integer multiple of the number of concurrent modes. This is because thetdmprogram.unroll()
function simpy multiplies the unique circuit with the number of shots, not taking into account which qumode has been measured most recently.To illustrate the bug, let's consider this TDM program:
Expected behavior: In average, you would expect
samples
to look likeAnd, indeed, for an equivalent program with four timebins (
theta = [0] * 4
) we get, as expected,Actual behavior: However, what we get for three timebins (
theta = [0] * 3
) is:Note that the second mode of the second shot is ~100 as it has undergone the displacement gate twice. This happens because
self.circuit = self.unrolled_circuit * shots
multiplies the unique circuit with the number of shots where each shot starts with the same qumode index. This can be illustrated by printing the qumode index whenever a gate is applied. The above circuit with two shots yields:displace mode 1 # shot 1, timebin 0 -> the displacement is applied to mode 1 although the most recently measured mode is 0 measure mode 0 # shot 1, timebin 0 displace mode 0 # shot 1, timebin 1 measure mode 1 # shot 1, timebin 1 displace mode 1 # shot 1, timebin 2 measure mode 0 # shot 1, timebin 2