Skip to content

Commit

Permalink
Change simulon target to simulon_gaussian (#576)
Browse files Browse the repository at this point in the history
**Context:**
The Xanadu Quantum Cloud simulator, formerly called `simulon`, now has the target name `simulon_gaussian`. This change was made to support many different simulon types in the future.

**Description of the Change:**
- References to `simulon` in documentation and tests have been changed to `simulon_gaussian`.
- A formatting change is made in `strawberryfields/backends/gaussianbackend/gaussiancircuit.py`. It appears that the black version on CI has been upgraded since the last commit, which now checks new elements in docstrings. This change has been made here instead of in a separate PR.

**Benefits:**
People reading the docs will not try to submit jobs to a simulator that doesn't exist 🙂

**Possible Drawbacks:**
n/a

**Related GitHub Issues:**
n/a
  • Loading branch information
Jeremy Swinarton committed Apr 30, 2021
1 parent 896557c commit e552d07
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 55 deletions.
66 changes: 41 additions & 25 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,39 @@
# Release 0.18.0 (current release)
# Release 0.18.0-post1 (current release)

<h3>Documentation</h3>

* References to the ``simulon`` simulator target have been rewritten to
``simulon_gaussian`` to reflect changes made on the Xanadu Quantum Cloud. The
language has been modified to imply that multiple simulators could be
available on XQC.
[(#576)](https://github.com/XanaduAI/strawberryfields/pull/576)

<h3>Contributors</h3>

This release contains contributions from (in alphabetical order):

Jeremy Swinarton.

# Release 0.18.0

<h3>New features since last release</h3>

* Adds the Bosonic backend, which can simulate states represented as linear
* Adds the Bosonic backend, which can simulate states represented as linear
combinations of Gaussian functions in phase space.
[(#533)](https://github.com/XanaduAI/strawberryfields/pull/533)
[(#538)](https://github.com/XanaduAI/strawberryfields/pull/538)
[(#539)](https://github.com/XanaduAI/strawberryfields/pull/539)
[(#541)](https://github.com/XanaduAI/strawberryfields/pull/541)
[(#546)](https://github.com/XanaduAI/strawberryfields/pull/546)
[(#549)](https://github.com/XanaduAI/strawberryfields/pull/549)
It can be regarded as a generalization of the Gaussian backend, since
transformations on states correspond to modifications of the means and
covariances of each Gaussian in the linear combination, along with changes to
the coefficients of the linear combination. Example states that can be
expressed using the new backend include all Gaussian, Gottesman-Kitaev-Preskill,

It can be regarded as a generalization of the Gaussian backend, since
transformations on states correspond to modifications of the means and
covariances of each Gaussian in the linear combination, along with changes to
the coefficients of the linear combination. Example states that can be
expressed using the new backend include all Gaussian, Gottesman-Kitaev-Preskill,
cat and Fock states.

```python
prog = sf.Program(1)
eng = sf.Engine('bosonic')
Expand All @@ -41,42 +57,42 @@
GKP states are qubits, with the qubit state defined by:

.. math:: \ket{\psi}\_{gkp} = \cos\frac{\theta}{2}\ket{0}\_{gkp} + e^{-i\phi}\sin\frac{\theta}{2}\ket{1}\_{gkp},

where the computational basis states are :math:`\ket{\mu}_{gkp} = \sum_{n} \ket{(2n+\mu)\sqrt{\pi\hbar}}_{q}`.
* Adds the measurement-based squeezing gate `MSgate`; a new front-end operation

* Adds the measurement-based squeezing gate `MSgate`; a new front-end operation
for the Bosonic backend.
[(#538)](https://github.com/XanaduAI/strawberryfields/pull/538)
[(#539)](https://github.com/XanaduAI/strawberryfields/pull/539)
[(#541)](https://github.com/XanaduAI/strawberryfields/pull/541)
`MSgate` is an implementation of inline squeezing that can be performed by
interacting the target state with an ancillary squeezed vacuum state at a
beamsplitter, measuring the ancillary mode with homodyne, and then applying
a feed-forward displacement. The channel is implemented either on average
(as a Gaussian CPTP map) or in the single-shot implementation. If the

`MSgate` is an implementation of inline squeezing that can be performed by
interacting the target state with an ancillary squeezed vacuum state at a
beamsplitter, measuring the ancillary mode with homodyne, and then applying
a feed-forward displacement. The channel is implemented either on average
(as a Gaussian CPTP map) or in the single-shot implementation. If the
single-shot implementation is used, the measurement outcome of the ancillary
mode is stored in the results object.

```python
prog = sf.Program(1)
eng = sf.Engine('bosonic')

with prog.context as q:
sf.ops.Catstate(alpha=2) | q
r = 0.3
# Average map
sf.ops.MSgate(r, phi=0, r_anc=1.2, eta_anc=1, avg=True) | q
# Single-shot map
sf.ops.MSgate(r, phi=0, r_anc=1.2, eta_anc=1, avg=False) | q

results = eng.run(prog)
ancilla_samples = results.ancilla_samples

xvec = np.arange(-5, 5, 0.01)
pvec = np.arange(-5, 5, 0.01)
wigner = results.state.wigner(0, xvec, pvec)

plt.contourf(xvec, pvec, wigner)
plt.show()
```
Expand Down Expand Up @@ -138,7 +154,7 @@
instead of the incorrect version number `1.0.0`.
[(#540)](https://github.com/XanaduAI/strawberryfields/pull/540)

* TDM programs now expect a flat (not nested) dictionary of `modes` in device
* TDM programs now expect a flat (not nested) dictionary of `modes` in device
specifications obtained from the XQC platform API.
[(#566)](https://github.com/XanaduAI/strawberryfields/pull/566)

Expand All @@ -165,7 +181,7 @@
This release contains contributions from (in alphabetical order):

J. Eli Bourassa, Guillaume Dauphinais, Ish Dhand, Theodor Isacsson, Josh Izaac,
Leonhard Neuhaus, Nicolás Quesada, Aaron Robertson, Krishna Kumar Sabapathy,
Leonhard Neuhaus, Nicolás Quesada, Aaron Robertson, Krishna Kumar Sabapathy,
Jeremy Swinarton, Antal Száva, Ilan Tzitrin.

# Release 0.17.0
Expand Down
31 changes: 18 additions & 13 deletions doc/introduction/photonic_hardware.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,26 +133,31 @@ You can also omit the ``--output`` parameter to print the result to the screen.
Cloud simulator
---------------

In addition to submitting jobs to be run on quantum hardware, it is also possible to run jobs on
the Xanadu Quantum Cloud simulator Simulon. The process is very similar to running jobs on hardware. You
will need to configure your account, as described above, and submit a job via the ``RemoteEngine``,
using ``"simulon"`` as the target instead of a specific chip:

>>> eng = sf.RemoteEngine("simulon")
In addition to submitting jobs to be run on quantum hardware, it is also
possible to run jobs on cloud simulators (which we refer to as "simulons") via
the Xanadu Quantum Cloud. The process is very similar to running jobs on
hardware. You will need to configure your account, as described above, and
submit a job via the ``RemoteEngine``, using a simulator as the target instead
of a specific chip:

>>> eng = sf.RemoteEngine("simulon_gaussian")
>>> result = eng.run(prog)

Simulon jobs can also be submitted asynchronously using ``eng.run_async``, or by submitting a
Blackbird script with the ``target`` set to ``simulon`` in the Blackbird header.
Simulator jobs can also be submitted asynchronously using ``eng.run_async``, or
by submitting a Blackbird script with the ``target`` set to a simulator target
in the Blackbird header.

See the `Submitting jobs on hardware`_ section above for more details.

.. note::

Simulon runs on the ``gaussian`` backend (see :ref:`simulating_your_program`) and thus only supports
Gaussian operations, including homodyne and heterodyne measurements, as well terminal
Fock measurements. Note that there are limits to how many measurements a circuit can have depending
on the type of measurement. These can be retrieved by calling ``engine.device_spec.modes`` with
``engine = sf.RemoteEngine("simulon")``.
The ``simulon_gaussian`` simulator runs on the ``gaussian`` backend (see
:ref:`simulating_your_program`) and thus only supports Gaussian operations,
including homodyne and heterodyne measurements, as well terminal Fock
measurements. Note that there are limits to how many measurements a circuit
can have depending on the type of measurement. These can be retrieved by
calling ``engine.device_spec.modes`` with ``engine =
sf.RemoteEngine("simulon_gaussian")``.

Tutorials
---------
Expand Down
2 changes: 1 addition & 1 deletion strawberryfields/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
Version number (major.minor.patch[-label])
"""

__version__ = "0.18.0"
__version__ = "0.18.0-post1"
26 changes: 13 additions & 13 deletions strawberryfields/backends/gaussianbackend/gaussiancircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def add_mode(self, n=1):
self.nlen = newnlen

def del_mode(self, modes):
""" delete mode from the circuit"""
"""delete mode from the circuit"""
if isinstance(modes, int):
modes = [modes]

Expand Down Expand Up @@ -110,15 +110,15 @@ def get_modes(self):
return [x for x in self.active if x is not None]

def displace(self, r, phi, i):
""" Implements a displacement operation by the complex number `beta = r * np.exp(1j * phi)` in mode i"""
"""Implements a displacement operation by the complex number `beta = r * np.exp(1j * phi)` in mode i"""
# Update displacement of mode i by the complex amount bet
if self.active[i] is None:
raise ValueError("Cannot displace mode, mode does not exist")

self.mean[i] += r * np.exp(1j * phi)

def squeeze(self, r, phi, k):
""" Implements a squeezing operation in mode k by the amount z = r*exp(1j*phi)."""
"""Implements a squeezing operation in mode k by the amount z = r*exp(1j*phi)."""
if self.active[k] is None:
raise ValueError("Cannot squeeze mode, mode does not exist")

Expand Down Expand Up @@ -158,7 +158,7 @@ def squeeze(self, r, phi, k):
self.mmat[:, k] = self.mmat[k]

def phase_shift(self, phi, k):
""" Implements a phase shift in mode k by the amount phi."""
"""Implements a phase shift in mode k by the amount phi."""
if self.active[k] is None:
raise ValueError("Cannot phase shift mode, mode does not exist")

Expand All @@ -181,7 +181,7 @@ def phase_shift(self, phi, k):
self.mmat[:, k] = self.mmat[k]

def beamsplitter(self, theta, phi, k, l):
""" Implements a beam splitter operation between modes k and l by the amount theta, phi"""
"""Implements a beam splitter operation between modes k and l by the amount theta, phi"""
if self.active[k] is None or self.active[l] is None:
raise ValueError("Cannot perform beamsplitter, mode(s) do not exist")

Expand Down Expand Up @@ -358,7 +358,7 @@ def fromscovmat(self, V, modes=None):
self.mmat[rows, cols] = 0.25 * (A - C + 1j * (B + Bt))

def qmat(self, modes=None):
""" Construct the covariance matrix for the Q function"""
"""Construct the covariance matrix for the Q function"""
if modes is None:
modes = list(range(self.nlen))

Expand All @@ -382,7 +382,7 @@ def qmat(self, modes=None):
return sigmaq

def fidelity_coherent(self, alpha, modes=None):
""" Returns a function that evaluates the Q function of the given state """
"""Returns a function that evaluates the Q function of the given state"""
if modes is None:
modes = list(range(self.nlen))

Expand All @@ -404,7 +404,7 @@ def fidelity_vacuum(self, modes=None):
return self.fidelity_coherent(alpha)

def Amat(self):
""" Constructs the A matrix from Hamilton's paper"""
"""Constructs the A matrix from Hamilton's paper"""
######### this needs to be conjugated
sigmaq = (
np.concatenate(
Expand Down Expand Up @@ -446,12 +446,12 @@ def thermal_loss(self, T, nbar, k):
self.nmat += (1 - T) * nbar

def init_thermal(self, population, mode):
""" Initializes a state of mode in a thermal state with the given population"""
"""Initializes a state of mode in a thermal state with the given population"""
self.loss(0.0, mode)
self.nmat[mode][mode] = population

def is_vacuum(self, tol=0.0):
""" Checks if the state is vacuum by calculating its fidelity with vacuum """
"""Checks if the state is vacuum by calculating its fidelity with vacuum"""
fid = self.fidelity_vacuum()
return np.abs(fid - 1) <= tol

Expand Down Expand Up @@ -495,7 +495,7 @@ def homodyne(self, n, shots=1, eps=0.0002):
return res

def post_select_homodyne(self, n, val, eps=0.0002):
""" Performs a homodyne measurement but postelecting on the value vals for mode n """
"""Performs a homodyne measurement but postelecting on the value vals for mode n"""
if self.active[n] is None:
raise ValueError("Cannot apply homodyne measurement, mode does not exist")
covmat = np.diag(np.array([eps ** 2, 1.0 / eps ** 2]))
Expand All @@ -517,7 +517,7 @@ def post_select_homodyne(self, n, val, eps=0.0002):
return val

def post_select_heterodyne(self, n, alpha_val):
""" Performs a homodyne measurement but postelecting on the value vals for mode n """
"""Performs a homodyne measurement but postelecting on the value vals for mode n"""
if self.active[n] is None:
raise ValueError("Cannot apply heterodyne measurement, mode does not exist")

Expand All @@ -539,7 +539,7 @@ def post_select_heterodyne(self, n, alpha_val):
return alpha_val

def apply_u(self, U):
""" Transforms the state according to the linear optical unitary that maps a[i] \to U[i, j]^*a[j]"""
"""Transforms the state according to the linear optical unitary that maps a[i] \to U[i, j]^*a[j]"""
self.mean = np.dot(np.conj(U), self.mean)
self.nmat = np.dot(np.dot(U, self.nmat), np.conj(np.transpose(U)))
self.mmat = np.dot(np.dot(np.conj(U), self.mmat), np.conj(np.transpose(U)))
6 changes: 3 additions & 3 deletions tests/frontend/test_program.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def test_assert_max_number_of_measurements(self, measure_op, measure_name):
},
"layout": None, "gate_parameters": {}, "compiler": [None]
}
spec = sf.api.DeviceSpec(target="simulon", connection=None, spec=device_dict)
spec = sf.api.DeviceSpec(target="simulon_gaussian", connection=None, spec=device_dict)

prog = sf.Program(3)
with prog.context as q:
Expand All @@ -256,7 +256,7 @@ def test_assert_max_number_of_measurements_wrong_entry(self):
"""Check that the correct error is raised when calling `prog.assert_number_of_measurements`
with the incorrect type of device spec mode entry."""
device_dict = {"modes": 2, "layout": None, "gate_parameters": None, "compiler": [None]}
spec = sf.api.DeviceSpec(target="simulon", connection=None, spec=device_dict)
spec = sf.api.DeviceSpec(target="simulon_gaussian", connection=None, spec=device_dict)

prog = sf.Program(3)
with prog.context as q:
Expand Down Expand Up @@ -500,7 +500,7 @@ class DummyCompiler(Compiler):
},
"layout": None, "gate_parameters": {}, "compiler": [None]
}
spec = sf.api.DeviceSpec(target="simulon", connection=None, spec=device_dict)
spec = sf.api.DeviceSpec(target="simulon_gaussian", connection=None, spec=device_dict)

prog = sf.Program(3)
with prog.context as q:
Expand Down

0 comments on commit e552d07

Please sign in to comment.