XanaduAI / strawberryfields

Strawberry Fields is a full-stack Python library for designing, simulating, and optimizing continuous variable (CV) quantum optical circuits.
https://strawberryfields.ai
Apache License 2.0
754 stars 191 forks source link

Invalid Blackbird circuit is generated from a Program #595

Closed Mandrenkov closed 3 years ago

Mandrenkov commented 3 years ago

Issue description

Running a Program loaded from a Blackbird circuit which was generated by another Program does not always work. For example, consider the "Teleportatation" example from Strawberry Fields Interactive:

import math
import strawberryfields as sf
from strawberryfields.ops import *
​
sf_prog = sf.Program(3)
​
# See the "Teleportation" algorithm in https://strawberryfields.ai/interactive/.
with sf_prog.context as q:
    Coherent(math.sqrt(5/4), math.atan(1/2)) | q[0]
    Sgate(2, 0) | q[2]
    Sgate(-2, 0) | q[1]
    BSgate(0.7854, 0) | (q[1], q[2])
    BSgate(0.7854, 0) | (q[0], q[1])
    MeasureP | q[1]
    MeasureX | q[0]
    Xgate(q[0].par*1.41421356237000) | q[2]
    Zgate(q[1].par*1.41421356237000) | q[2]

# Convert the SF program ​into a Blackbird program.
bb_prog = sf.io.to_blackbird(sf_prog)
bb_prog._name = "Teleportation"
bb_prog._version = 1.0
bb_prog._target["name"] = "gaussian"

# Recover the SF program from the Blackbird program.
bb_circuit = bb_prog.serialize()​
re_prog  = sf.io.loads(bb_circuit)

# Run the recovered SF program with the Gaussian engine.
eng = sf.LocalEngine("gaussian")
results = eng.run(re_prog)

Python version: 3.9.5 Platform info: Linux-5.4.72-microsoft-standard-WSL2-x86_64-with-glibc2.31 Installation path: /home/mikhail/.local/lib/python3.9/site-packages/strawberryfields Strawberry Fields version: 0.18.0 Numpy version: 1.20.3 Scipy version: 1.6.3 SymPy version: 1.8 NetworkX version: 2.5.1 The Walrus version: 0.15.1 Blackbird version: 0.3.0 TensorFlow version: None


#### Source code and tracebacks

Running the script above yields the following error:

```python
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-16-da60180d5e6d> in <module>
     28 # Run the recovered SF program using the Gaussian backend.
     29 eng = sf.LocalEngine("gaussian")
---> 30 results = eng.run(re_prog)

~/.local/lib/python3.9/site-packages/strawberryfields/engine.py in run(self, program, args, compile_options, **kwargs)
    492                     )
    493 
--> 494         result = super()._run(
    495             program, args=args, compile_options=compile_options, **eng_run_options
    496         )

~/.local/lib/python3.9/site-packages/strawberryfields/engine.py in _run(self, program, args, compile_options, **kwargs)
    272             target = self.backend.compiler
    273             if target is not None:
--> 274                 p = p.compile(compiler=target, **compile_options)
    275             p.lock()
    276 

~/.local/lib/python3.9/site-packages/strawberryfields/program.py in compile(self, device, compiler, **kwargs)
    610             target = compiler.short_name
    611 
--> 612         seq = compiler.decompose(self.circuit)
    613 
    614         if kwargs.get("warn_connected", True):

~/.local/lib/python3.9/site-packages/strawberryfields/compilers/compiler.py in decompose(self, seq)
    222                 try:
    223                     kwargs = self.decompositions[op_name]
--> 224                     temp = cmd.op.decompose(cmd.reg, **kwargs)
    225                     # now compile the decomposition
    226                     temp = self.decompose(temp)

~/.local/lib/python3.9/site-packages/strawberryfields/ops.py in decompose(self, reg, **kwargs)
    450         Like :func:`Operation.decompose`, but applies self.dagger.
    451         """
--> 452         seq = self._decompose(reg, **kwargs)
    453         if self.dagger:
    454             # apply daggers, reverse the Command sequence

~/.local/lib/python3.9/site-packages/strawberryfields/ops.py in _decompose(self, reg, **kwargs)
   1500     def _decompose(self, reg, **kwargs):
   1501         # into a displacement
-> 1502         r = self.p[0] / np.sqrt(2 * sf.hbar)
   1503         return [Command(Dgate(r, 0), reg)]
   1504 

TypeError: ufunc 'true_divide' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''

Additional information

The issue appears to have something to do with the final two lines of the generated Blackbird circuit:

name Teleportation
version 1.0
target gaussian

Coherent(1.118033988749895, 0.4636476090008061) | 0
Sgate(2, 0) | 2
Sgate(-2, 0) | 1
BSgate(0.7854, 0) | [1, 2]
BSgate(0.7854, 0) | [0, 1]
MeasureHomodyne(phi=1.5707963267948966) | 1
MeasureHomodyne(phi=0) | 0
Xgate("1.41421356237*q0") | 2
Zgate("1.41421356237*q1") | 2
Mandrenkov commented 3 years ago

Do you mind looking into this, @thisac ?