Skip to content

Commit

Permalink
Passive compiler, finishing up (#602)
Browse files Browse the repository at this point in the history
* new passive circuit compiler

* add PassiveChannel as valid gate for passive compiler

* generalise channel merging to multimode channels (ie PassiveChannel)

* PassiveChannel tests

* tests for passive compiler

* tests for passive compiler auxillary functions

* code factor stuff

* flip the conj in the apply_u method

* now featuring relevant docstrings

* dev version of thewalrus

* run black

* remove dependency on dev version of thewalrus

* fix docstring

* remove expand_passive from backend

* trailing whitespace

* remove numba

* remove numba imports

* minor comments

* minor comments

* minor comments

* black

* black

* declare hbar

* more functional gate application

* hbar in test args

* local tests are more happy

* run black

* better test coverage

* run black

* implement some josh comments

* passive backend tidying

* add to __all__

* update changelog

* allow for float args to PassiveChannel

* update docs

* first attempt at adding decomposition of passive channel

* handle parameter properly

* revert changes, maybe save those for a new PR

* black

* Update .github/CHANGELOG.md

Co-authored-by: Josh Izaac <josh146@gmail.com>

* Update .github/CHANGELOG.md

Co-authored-by: Josh Izaac <josh146@gmail.com>

Co-authored-by: Nicolas Quesada <zeitus@gmail.com>
Co-authored-by: Josh Izaac <josh146@gmail.com>
  • Loading branch information
3 people committed Jun 29, 2021
1 parent b4d9153 commit 9f6debb
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 13 deletions.
51 changes: 51 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,57 @@
prog_merged = prog.compile(compiler="gaussian_merge")
```

* A new operation, ``PassiveChannel`` has been added. It allows for arbitrary linear/passive transformations
(i.e., any operation which is linear in creation operators). Currently only supported by the ``gaussian``
backend. [(#600)](https://github.com/XanaduAI/strawberryfields/pull/600)

```python
from strawberryfields.ops import PassiveChannel, Sgate
import strawberryfields as sf
from scipy.stats import unitary_group
import numpy as np

M = 4

circuit = sf.Program(M)
U1 = unitary_group.rvs(M)
U2 = unitary_group.rvs(M)
losses = np.random.random(M)

T = U2 @ np.diag(losses) @ U1

eng = sf.Engine(backend='gaussian')
circuit = sf.Program(M)
with circuit.context as q:
for i in range(M):
ops.Sgate(1) | q[i]
ops.PassiveChannel(T) | q

cov = eng.run(circuit).state.cov()
```

* A new compiler, ``passive``, allows for a circuit which only consists of passive
elements to be compiled into a single ``PassiveChannel``.
[(#600)](https://github.com/XanaduAI/strawberryfields/pull/600)

```python
from strawberryfields.ops import BSgate, LossChannel, Rgate
import strawberryfields as sf

circuit = sf.Program(2)
with circuit.context as q:
Rgate(np.pi) | q[0]
BSgate(0.25 * np.pi, 0) | (q[0], q[1])
LossChannel(0.9) | q[1]

compiled_circuit = circuit.compile(compiler="passive")
```
```pycon
>>> print(compiled_circuit)
PassiveChannel([[-0.7071+8.6596e-17j -0.7071+0.0000e+00j]
[-0.6708+8.2152e-17j 0.6708+0.0000e+00j]]) | (q[0], q[1])
```


<h3>Improvements</h3>

Expand Down
1 change: 1 addition & 0 deletions doc/introduction/ops.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ Channels
LossChannel
ThermalLossChannel
MSgate
PassiveChannel

:html:`</div>`

Expand Down
18 changes: 18 additions & 0 deletions strawberryfields/backends/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,24 @@ def prepare_gaussian_state(self, r, V, modes):
"""
raise NotImplementedError

def passive(self, T, modes):
r"""
Perform an arbitrary multimode passive operation
Args:
T (array): an NxN matrix acting on a N mode state
modes (int or Sequence[int]): Which modes to prepare the state in.
.. details::
Acts the following transformation on the state:
.. math::
a^{\dagger}_i \to \sum_j T_{ij} a^{\dagger}_j
"""
raise NotImplementedError

def get_cutoff_dim(self):
raise NotApplicableError

Expand Down
7 changes: 2 additions & 5 deletions strawberryfields/backends/gaussianbackend/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,13 +198,10 @@ def is_vacuum(self, tol=0.0, **kwargs):
def loss(self, T, mode):
self.circuit.loss(T, mode)

def passive(self, T, *modes):
"""
linear optical passive transformations
"""
def passive(self, T, modes):
T_expand = identity(self.circuit.nlen, dtype=T.dtype)
T_expand[ix_(modes, modes)] = T
self.circuit.passive(T_expand)
self.circuit.apply_u(T_expand)

def thermal_loss(self, T, nbar, mode):
self.circuit.thermal_loss(T, nbar, mode)
Expand Down
4 changes: 0 additions & 4 deletions strawberryfields/backends/gaussianbackend/gaussiancircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,3 @@ def apply_u(self, U):
self.mean = U @ self.mean
self.nmat = U.conj() @ self.nmat @ U.T
self.mmat = U @ self.mmat @ U.T

def passive(self, T):
"""Transforms the state according to the arbitrary linear transformation that maps a[i] \to T[i, j]^*a[j]"""
self.apply_u(T)
8 changes: 7 additions & 1 deletion strawberryfields/compilers/passive.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ def _apply_one_mode_gate(G, T, i):
"""In-place applies a one mode gate G into the process matrix T in mode i
Args:
G (complex/float): one mode gate
G (complex or float): one mode gate
T (array): passive transformation
i (int): index of one mode gate
Returns:
T (array): updated passive transformation
"""

T[i] *= G
Expand All @@ -42,6 +45,9 @@ def _apply_two_mode_gate(G, T, i, j):
T (array): passive transformation
i (int): index of first mode of gate
j (int): index of second mode of gate
Returns:
T (array): updated passive transformation
"""
(T[i], T[j]) = (G[0, 0] * T[i] + G[0, 1] * T[j], G[1, 0] * T[i] + G[1, 1] * T[j])
return T
Expand Down
8 changes: 5 additions & 3 deletions strawberryfields/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -1424,16 +1424,18 @@ class PassiveChannel(Channel):
Acts the following transformation on the state:
.. math::
a^{\dagger}_i \to \sum_j T_{ij} a^{\dagger}j
a^{\dagger}_i \to \sum_j T_{ij} a^{\dagger}_j
"""

def __init__(self, T):
T = np.atleast_2d(T)
super().__init__([T])
self.ns = T.shape[0]

def _apply(self, reg, backend, **kwargs):
p = par_evaluate(self.p)
backend.passive(p[0], *reg)
backend.passive(p[0], reg)


# ====================================================================
Expand Down Expand Up @@ -3032,7 +3034,7 @@ def _decompose(self, reg, **kwargs):
two_args_gates = (Dgate, Sgate, BSgate, MZgate, S2gate)
gates = zero_args_gates + one_args_gates + two_args_gates

channels = (LossChannel, ThermalLossChannel, MSgate)
channels = (LossChannel, ThermalLossChannel, MSgate, PassiveChannel)

simple_state_preparations = (
Vacuum,
Expand Down

0 comments on commit 9f6debb

Please sign in to comment.