strawberryfields: Blackbird Program Compliation Bug

Issue description

  • Expected behavior: (What you expect to happen)

If I attempt to compile a program, specifying only a portion of a the modes on an X8 chip, for anything other than an identity operation (for I understand SF will fill in unspecified modes with an identity operation) I expect a CircuitError.

  • Actual behavior: (What actually happens)

The program

MZgate(0, 0) | (q[0], q[1])
MZgate(0, 0) | (q[1], q[2])
MZgate(0, 0) | (q[0], q[1])
MZgate(0, 0) | (q[0], q[1])
MZgate(0, 0) | (q[1], q[2])
MZgate(0, 0) | (q[0], q[1])
MeasureFock | (q[0], q[1], q[2], q[3], q[4], q[5], q[6], q[7])

compiles as

S2gate(0, 0) | (q[0], q[4])
S2gate(0, 0) | (q[3], q[7])
S2gate(0, 0) | (q[2], q[6])
S2gate(0, 0) | (q[1], q[5])
MZgate(3.142, 0) | (q[0], q[1])
MZgate(3.142, 0) | (q[2], q[3])
MZgate(3.142, 3.142) | (q[1], q[2])
MZgate(3.142, 3.142) | (q[0], q[1])
MZgate(3.142, 0) | (q[2], q[3])
MZgate(3.142, 3.142) | (q[1], q[2])
Rgate(3.142) | (q[0])
Rgate(0) | (q[1])
Rgate(0) | (q[2])
Rgate(0) | (q[3])
MZgate(3.142, 0) | (q[4], q[5])
MZgate(3.142, 0) | (q[6], q[7])
MZgate(3.142, 3.142) | (q[5], q[6])
MZgate(3.142, 3.142) | (q[4], q[5])
MZgate(3.142, 0) | (q[6], q[7])
MZgate(3.142, 3.142) | (q[5], q[6])
Rgate(3.142) | (q[4])
Rgate(0) | (q[5])
Rgate(0) | (q[6])
Rgate(0) | (q[7])
MeasureFock | (q[0], q[1], q[2], q[3], q[4], q[5], q[6], q[7])

without raising an error.

  • Reproduces how often: (What percentage of the time does it reproduce?)

100% of the time

  • System information: (post the output of import strawberryfields as sf; sf.about())

Strawberry Fields: a Python library for continuous-variable quantum circuits. Copyright 2018-2020 Xanadu Quantum Technologies Inc.

Python version: 3.7.6 Platform info: Linux-5.3.0-46-generic-x86_64-with-debian-buster-sid Installation path: /home/heltluke/anaconda3/envs/sf_latest/lib/python3.7/site-packages/strawberryfields Strawberry Fields version: 0.13.0.rc0 Numpy version: 1.18.1 Scipy version: 1.4.1 SymPy version: 1.5.1 NetworkX version: 2.4 The Walrus version: 0.12.0 Blackbird version: 0.2.3 TensorFlow version: None

Source code and tracebacks

This happened due to a bug in a script I wanted to use to generate a program using MZI gates from an array of phases. I thought I was creating an “anti-identity” operation on modes 0-4, instead I created the program above

phases = np.zeros(12)

prog = sf.Program(8)
with prog.context as q:
    for mzi_index in range(6):
        in_block_index = mzi_index % (4 - 1)
        upper_mode = in_block_index % 2
        sf.ops.MZgate(
            phases[mzi_index * 2], phases[mzi_index * 2 + 1]
        ) | (q[upper_mode], q[upper_mode + 1])
    sf.ops.MeasureFock() | q

prog.compile("X8").print()

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 16 (9 by maintainers)

Most upvoted comments

Thanks @shreyapkumar. I think it’s OK to close this then, as it’s more user error than a “bug”. If one wants to specify phases, they must specify a complete sequence in the form of

MZgate(phi1, phi2) | (q[0], q[1])
MZgate(phi3, phi4) | (q[2], q[3])
MZgate(phi5, phi6) | (q[1], q[2])
MZgate(phi7, phi8) | (q[0], q[1])
MZgate(phi9, phi10) | (q[2], q[3])
MZgate(phi11, phi12) | (q[1], q[2])
Rgate(0) | (q[0])
Rgate(0) | (q[1])
Rgate(0) | (q[2])
Rgate(0) | (q[3])
MZgate(phi1, phi2) | (q[4], q[5])
MZgate(phi3, phi4) | (q[6], q[7])
MZgate(phi5, phi6) | (q[5], q[6])
MZgate(phi7, phi8) | (q[4], q[5])
MZgate(phi9, phi10) | (q[6], q[7])
MZgate(phi11, phi12) | (q[5], q[6])
Rgate(0) | (q[4])
Rgate(0) | (q[5])
Rgate(0) | (q[6])
Rgate(0) | (q[7])

and if they accidentally specify a subset of the gates as ANY version of the identity, the result will always be

MZgate(pi, 0) | (q[0], q[1])
MZgate(pi, 0) | (q[2], q[3])
MZgate(pi, pi) | (q[1], q[2])
MZgate(pi, pi) | (q[0], q[1])
MZgate(pi, 0) | (q[2], q[3])
MZgate(pi, pi) | (q[1], q[2])
Rgate(pi) | (q[0])
Rgate(0) | (q[1])
Rgate(0) | (q[2])
Rgate(0) | (q[3])
MZgate(pi, 0) | (q[4], q[5])
MZgate(pi, 0) | (q[6], q[7])
MZgate(pi, pi) | (q[5], q[6])
MZgate(pi, pi) | (q[4], q[5])
MZgate(pi, 0) | (q[6], q[7])
MZgate(pi, pi) | (q[5], q[6])
Rgate(pi) | (q[4])
Rgate(0) | (q[5])
Rgate(0) | (q[6])
Rgate(0) | (q[7])

Actually, reading @heltluke first post: https://github.com/XanaduAI/strawberryfields/issues/368#issue-600426936 more carefully, this is the behaviour one would expect (except for some of the external phases which are pi), isn’t it? The input was a series of swaps which all cancel one another, so the output is just “bars” in all the MZIs.

My understanding is that if you dont have access to the low level interface, SF compiles everything. So a series of “swap and swap back” would first get compiled and become the identity. Then the rectangular decomposition gives identical results for such a series of MZIs and the identity.

When I tried to fix the identity decomposition, I was only able to fix the internal phases (now hopefully they are all pi), but the external phases are somewhat arbitrary.

So unless you have access to the low level interface where the compilation does not happen, I think you can never get “the” identity.