Repository: XanaduAI/strawberryfields

Issue:
`measure_homodyne` sometimes constructs a probability vector with p<0, p>1 in the Fock backend, resulting in an exception.
```
pvals < 0, pvals > 1 or pvals contains NaNs
```

When I try to run the circuit (mentioned below) I occasionally end up with the error mentioned above.

```python
prog = sf.Program(2)

with prog.context as q:
    Catstate(complex(a,0)) | q[0]
    Catstate(complex(0,a)) | q[1]
    
    BSgate() | (q[0], q[1])
    MeasureX | q[0]
    MeasureX | q[1]

result = eng.run(prog)
 x, y = result.samples
```

 *Expected behaviour: Ideally when it works, it is supposed to give me the two quadrature values.

* *Reproduces how often:* 30-40% of the time.

* *System information:
```
Strawberry Fields: a Python library for continuous-variable quantum circuits.
Copyright 2018-2019 Xanadu Quantum Technologies Inc.

Python version:            3.7.4
Platform info:             Darwin-19.4.0-x86_64-i386-64bit
Installation path:         /Users/biveenshajilal/opt/anaconda3/lib/python3.7/site-packages/strawberryfields
Strawberry Fields version: 0.12.1
Numpy version:             1.18.2
Scipy version:             1.3.1
The Walrus version:           0.12.0
Blackbird version:         0.2.3
TensorFlow version:        None
```
#### Source code and tracebacks
```python
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-27-d8f9402683f5> in <module>
      2 
      3 for x in pbar(flag):
----> 4     dummy = xaxb()
      5 
      6     x_vals[i]=dummy[0]

<ipython-input-22-64fa305c29f6> in xaxb()
     12         MeasureX | q[1]
     13 
---> 14     result = eng.run(prog)
     15 
     16     x, y = result.samples

~/opt/anaconda3/lib/python3.7/site-packages/strawberryfields/engine.py in run(self, program, args, compile_options, run_options)
    479         eng_run_options = {key: temp_run_options[key] for key in temp_run_options.keys() & eng_run_keys}
    480 
--> 481         result = super()._run(program, args=args, compile_options=compile_options, **eng_run_options)
    482 
    483         modes = temp_run_options["modes"]

~/opt/anaconda3/lib/python3.7/site-packages/strawberryfields/engine.py in _run(self, program, args, compile_options, **kwargs)
    347             p.lock()
    348 
--> 349             self._run_program(p, **kwargs)
    350             self.run_progs.append(p)
    351             # store the latest measurement results

~/opt/anaconda3/lib/python3.7/site-packages/strawberryfields/engine.py in _run_program(self, prog, **kwargs)
    421             try:
    422                 # try to apply it to the backend
--> 423                 cmd.op.apply(cmd.reg, self.backend, **kwargs)  # NOTE we could also handle storing measured vals here
    424                 applied.append(cmd)
    425             except NotApplicableError:

~/opt/anaconda3/lib/python3.7/site-packages/strawberryfields/ops.py in apply(self, reg, backend, **kwargs)
    285                 Only applies to Measurements.
    286         """
--> 287         values = super().apply(reg, backend, **kwargs)
    288         # convert the returned values into an iterable with the measured modes indexed along
    289         # the first axis and shots along second axis (if larger than 1), so that we can assign

~/opt/anaconda3/lib/python3.7/site-packages/strawberryfields/ops.py in apply(self, reg, backend, **kwargs)
    217         temp = [rr.ind for rr in reg]
    218         # call the child class specialized _apply method
--> 219         return self._apply(temp, backend, **kwargs)
    220 
    221 

~/opt/anaconda3/lib/python3.7/site-packages/strawberryfields/ops.py in _apply(self, reg, backend, shots, **kwargs)
    806             select = select / s
    807 
--> 808         return s * backend.measure_homodyne(p[0], *reg, shots=shots, select=select, **kwargs)
    809 
    810     def __str__(self):

~/opt/anaconda3/lib/python3.7/site-packages/strawberryfields/backends/fockbackend/backend.py in measure_homodyne(self, phi, mode, shots, select, **kwargs)
    187             raise NotImplementedError("fock backend currently does not support "
    188                                       "shots != 1 for homodyne measurement")
--> 189         return self.circuit.measure_homodyne(phi, self._remap_modes(mode), select=select, **kwargs)
    190 
    191     def loss(self, T, mode):

~/opt/anaconda3/lib/python3.7/site-packages/strawberryfields/backends/fockbackend/circuit.py in measure_homodyne(self, phi, mode, select, **kwargs)
    498             probs = rho_dist.flatten().real
    499             probs /= np.sum(probs)
--> 500             sample_hist = np.random.multinomial(1, probs)
    501             sample_idx = list(sample_hist).index(1)
    502             homodyne_sample = q_tensor[sample_idx]

mtrand.pyx in numpy.random.mtrand.RandomState.multinomial()

_common.pyx in numpy.random._common.check_array_constraint()

ValueError: pvals < 0, pvals > 1 or pvals contains NaNs
```
#### Additional information

To reproduce this, I didn't have to particularly do anything. I just have to repeat the process multiple times. I tried it on multiple devices, both on Linux and macOS. I get the same error.



Discussion:
Thanks @biveenslal for catching this, we'll look into it and see where this bug might be occuring.

From the traceback, it looks like you are using the Fock backend. Could you send through:

* the backend options (i.e., what is your value of `cutoff_dim`?)

* The value of `a` used in creating your cat state.
the value of `a` used in creating my cate state is 2 and the `cutoff_dim` is 30. 
I had tried it with several other lower and higher values and still ends up with the same error.
Thanks @biveenslal --- a value of `a=2` is certainly reasonable, so this looks like it might be a bug in the `MeasureHomodyne` implementation in the Fock backend.
@josh146 Yeah. Seems like that. I started off with a large value of `a` and thought it would've been causing trouble. I reduced it and still manage to reproduce the error. 
Hey @josh146 , any updates on the problem?

Thank you.

Resolving patch:
diff --git a/strawberryfields/backends/fockbackend/circuit.py b/strawberryfields/backends/fockbackend/circuit.py
--- a/strawberryfields/backends/fockbackend/circuit.py
+++ b/strawberryfields/backends/fockbackend/circuit.py
@@ -763,6 +763,12 @@ def measure_homodyne(self, phi, mode, select=None, **kwargs):
             # Numpy also does not use the log probabilities
             probs = rho_dist.flatten().real
             probs /= np.sum(probs)
+
+            # Due to floating point precision error, values in the calculated probability distribution
+            # may have a very small negative value of -epsilon. The following sets
+            # these small negative values to 0.
+            probs[np.abs(probs) < 1e-10] = 0
+
             sample_hist = np.random.multinomial(1, probs)
             sample_idx = list(sample_hist).index(1)
             homodyne_sample = q_tensor[sample_idx]


Test patch: