Hey, good morning.

I’m having difficulty implementing a beam splitter whose inputs receive alpha and -alpha coherent states, for example. How do I set the input state (alpha or -alpha) to interfere with the BS? Is it possible to place a phase shifter on one of the BS inputs? How do I measure output states?

```
import numpy as np
from mrmustard.lab import *
state = (Coherent(x=[1.0, 2.0], y=[-1.0, -2.0]))
print(state.num_modes) # 2
state >> BSgate(theta=np.pi/4)[0, 1]
results = Gaussian(2) << PNRDetector(efficiency = 0.9, modes = [0])
results[0]
results[1]
```

If you want help with diagnosing an error, please put the full error message below:

```
C:\Users\anton\MrMustard\mrmustard\math\backend_numpy.py:117: RuntimeWarning: invalid value encountered in cast
return np.array(array, dtype=dtype)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
File ~\MrMustard\mrmustard\math\backend_manager.py:105, in BackendManager._apply(self, fn, args)
104 try:
--> 105 attr = getattr(self.backend, fn)
106 except AttributeError:
AttributeError: 'BackendNumpy' object has no attribute 'convolution'
During handling of the above exception, another exception occurred:
NotImplementedError Traceback (most recent call last)
Cell In[3], line 1
----> 1 results = Gaussian(2) << PNRDetector(efficiency = 0.9, modes = [0])
2 results[0]
3 results[1]
File ~\MrMustard\mrmustard\lab\detectors.py:97, in PNRDetector.__init__(self, efficiency, dark_counts, efficiency_trainable, dark_counts_trainable, efficiency_bounds, dark_counts_bounds, stochastic_channel, modes, cutoffs)
90 self._add_parameter(
91 make_parameter(efficiency_trainable, eff, "efficiency", efficiency_bounds)
92 )
93 self._add_parameter(
94 make_parameter(dark_counts_trainable, dk, "dark_counts", dark_counts_bounds)
95 )
---> 97 self.recompute_stochastic_channel()
File ~\MrMustard\mrmustard\lab\detectors.py:126, in PNRDetector.recompute_stochastic_channel(self, cutoffs)
121 dark_prior = math.poisson(max_k=settings.PNR_INTERNAL_CUTOFF, rate=dc)
122 condprob = math.binomial_conditional_prob(
123 success_prob=qe, dim_in=settings.PNR_INTERNAL_CUTOFF, dim_out=c
124 )
125 self._internal_stochastic_channel.append(
--> 126 math.convolve_probs_1d(
127 condprob, [dark_prior, math.eye(settings.PNR_INTERNAL_CUTOFF)[0]]
128 )
129 )
File ~\MrMustard\mrmustard\math\backend_manager.py:1535, in BackendManager.convolve_probs_1d(self, prob, other_probs)
1532 for q_ in other_probs[1:]:
1533 q = q[..., None] * q_[(None,) * q.ndim + (slice(None),)]
-> 1535 return self.convolve_probs(prob, q)
File ~\MrMustard\mrmustard\math\backend_manager.py:1550, in BackendManager.convolve_probs(self, prob, other)
1548 prob_padded = self.pad(prob, [(s - 1, 0) for s in other.shape])
1549 other_reversed = other[(slice(None, None, -1),) * other.ndim]
-> 1550 return self.convolution(
1551 prob_padded[None, ..., None],
1552 other_reversed[..., None, None],
1553 data_format="N"
1554 + ("HD"[: other.ndim - 1])[::-1]
1555 + "WC", # TODO: rewrite this to be more readable (do we need it?)
1556 )[0, ..., 0]
File ~\MrMustard\mrmustard\math\backend_manager.py:449, in BackendManager.convolution(self, array, filters, padding, data_format)
431 def convolution(
432 self,
433 array: Tensor,
(...)
436 data_format="NWC",
437 ) -> Tensor: # TODO: remove strides and data_format?
438 r"""Performs a convolution on array with filters.
439
440 Args:
(...)
447 The convolved array.
448 """
--> 449 return self._apply("convolution", (array, filters, padding, data_format))
File ~\MrMustard\mrmustard\math\backend_manager.py:109, in BackendManager._apply(self, fn, args)
107 msg = f"Function ``{fn}`` not implemented for backend ``{self.backend_name}``."
108 # pylint: disable=raise-missing-from
--> 109 raise NotImplementedError(msg)
110 return attr(*args)
NotImplementedError: Function ``convolution`` not implemented for backend ``numpy``.
```

Anaconda 3

strawberryfields 0.23