Skip to content

Commit

Permalink
[WIP] Renaming DeviceSpecs and refactoring state_options (#121)
Browse files Browse the repository at this point in the history
* changing DeviceSpecs to CircuitSpecs

* circuitspecs docs, glossary updated.

* Missing module docstring added.

* Renamed backend_specs to circuit_db, added a test.

* LocalEngine.run(): modes moved to state_options, run_options added. Docs updated. eval_params kwarg removed.

* Pylint.

* Re-run the tests...

* added extra printout to sf.about() & travis debugging

* [debug] test now seem to pass on travis??

* expanding to all integration tests

* removing stateful defaults which cause unexpected behaviour; added new element to state_optiosn

* putting all tests back on travis

* Apply suggestions from code review [ci skip]

* combining various options dictionaries and kwargs

* fixing up frontend tests and docs

* Apply suggestions from code review
  • Loading branch information
co9olguy authored and josh146 committed Jul 10, 2019
1 parent 416e92d commit 9b46f82
Show file tree
Hide file tree
Showing 38 changed files with 431 additions and 361 deletions.
25 changes: 16 additions & 9 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,21 @@
- Introduced the `BaseEngine` abstract base class and the `LocalEngine` child class. `Engine` is kept as an alias for `LocalEngine`.
- The Engine API has been changed slightly:
- `LocalEngine.run()` returns a `Result` object that contains both a state object and measurement samples.
- The way kwargs were used has been simplified by introducing the new kwargs-like arguments `backend_options` and `state_options`. `LocalEngine.run()` passes the actual kwargs only to `Operation.apply()`.
- The Gaussian backend now officially supports Fock-basis measurements (`MeasureFock`/`Measure`/`measure_fock`), but does not update the quantum state.
- New `shots` keyword argument added to `Engine.run()`, enabling multi-shot sampling. Supported only in the Gaussian backend, and only for Fock measurements.
- Added the ability to compile quantum programs to match a desired circuit target.
- Included a number of compilation targets, including Gaussian Boson Sampling circuits.
- Added a frontend validation database, the `devicespecs` submodule, for validating that quantum programs can be executed on certain backends and providing compilation methods.
- Added the `sf.io` module, which is used to save/load standalone Blackbird scripts from/into Strawberry Fields. Note that the Blackbird DSL has been spun off as an independent package and is now a dependency of Strawberry Fields.
- Added a new decomposition `mach_zehnder` to the decompositions module.
- The way kwargs were used has been simplified by introducing the kwargs-like arguments:
- `backend_options` are provided upon initialization of the `LocalEngine`, and passed on to the corresponding backend when it is created.
- `compile_options` can be provided when calling `LocalEngine.run()`. These are passed to the `compile()` method of the program before execution.
- `run_options` can be provided when calling `LocalEngine.run()`. These are used to determine the characteristics of the measurements and state contained in the `Results` object returned after the program is finished executing.
- The Gaussian backend now officially supports Fock-basis measurements (`MeasureFock`/`Measure`/
`measure_fock`), but does not update the quantum state after a Fock measurement.
- `shots` keyword argument added to `Engine.run()`, enabling multi-shot sampling. Supported only
in the Gaussian backend, and only for Fock measurements.
- Added the `circuitspecs` subpackage, containing the `CircuitSpecs` class and a quantum circuit database.
The database can be used to
- Validate that a `Program` belongs in a specific circuit class.
- Compile a `Program` for a desired circuit target, e.g., so that it can be executed on a given backend.
The database includes a number of compilation targets, including Gaussian Boson Sampling circuits.
- Added the `io` module, which is used to save/load standalone Blackbird scripts from/into Strawberry Fields. Note that the Blackbird DSL has been spun off as an independent package and is now a dependency of Strawberry Fields.
- Added a new decomposition `mach_zehnder` to the decompositions module.
- Added a `Configuration` class, which is used to load, store, save, and modify configuration options for Strawberry Fields.
- The way hbar is handled has been simplified:
- The backend API is now entirely hbar-independent, i.e., every backend API method is defined in terms of a and a^\dagger only, not x and p.
Expand All @@ -24,7 +31,7 @@
- Added two top-level functions:
- `about()`, which prints human-readable system info including installed versions of various Python packages.
- `cite()`, which prints a bibtex citation for SF.
- Added a glossary to the documentation
- Added a glossary to the documentation.


### Improvements
Expand Down
2 changes: 1 addition & 1 deletion doc/algorithms/gaussian_boson_sampling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ If we wish to simulate Fock measurements, we can additionally include
Measure | q
after the beamsplitter array. After constructing the circuit and running the engine, the values of the Fock state measurements will be available within the :attr:`samples` attribute of the :class:`~.Result` object returned by the engine.
In order to sample from this distribution :math:`N` times, the keyword argument :code:`shots=N` can be provided to the :func:`eng.run()` command (only supported for Gaussian backend).
In order to sample from this distribution :math:`N` times, a :code:`shots` parameter can be included in :code:`run_options` during engine execution, i.e., :func:`eng.run(gbs, run_options={"shots": N})` (only supported for Gaussian backend).

Alternatively, you may omit the measurements, and extract the resulting Fock state probabilities directly via the state methods :meth:`~.BaseFockState.all_fock_probs` (supported by Fock backends) or :meth:`~.BaseState.fock_prob` (supported by all backends).

Expand Down
7 changes: 7 additions & 0 deletions doc/code/circuitspecs.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.. automodule:: strawberryfields.circuitspecs
:members:
:private-members:

.. automodule:: strawberryfields.circuitspecs.circuit_specs
:members:
:private-members:
3 changes: 0 additions & 3 deletions doc/code/devicespecs.rst

This file was deleted.

2 changes: 1 addition & 1 deletion doc/gallery/gate_synthesis/GateSynthesis.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@
" layer(k, q[0])\n",
"\n",
"# Run engine\n",
"state = eng.run(prog, state_options={\"eval\": False}).state\n",
"state = eng.run(prog, run_options={\"eval\": False}).state\n",
"ket = state.ket()"
]
},
Expand Down
62 changes: 31 additions & 31 deletions doc/gallery/minimizing_correlations/minimizing_correlations.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion doc/gallery/state_learner/StateLearning.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@
" layer(k, q[0])\n",
"\n",
"# Run engine\n",
"state = eng.run(prog, state_options={\"eval\": False}).state\n",
"state = eng.run(prog, run_options={\"eval\": False}).state\n",
"ket = state.ket()"
]
},
Expand Down
28 changes: 16 additions & 12 deletions doc/glossary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ Expressions that are grouped together are used synonymously in the Strawberry Fi

backend
Executes quantum :term:`programs <program>`. Can be either a classical simulator or a
quantum hardware device, local or remote.
quantum hardware device, local or remote. Different backends can have different capabilities
in terms of efficiency and which :term:`class of circuits <circuit class>` they can execute.
See: :class:`.BaseBackend`

circuit
Expand All @@ -19,21 +20,24 @@ Expressions that are grouped together are used synonymously in the Strawberry Fi
Represents a quantum computation.
See: :class:`.Program`

compilation
The process of converting a quantum :term:`program` into an :term:`equivalent program` that
can be run on a specific :term:`device`. The compilation can fail if the device is incapable
of running the program.
circuit class
circuit family
A well-defined subset of :term:`quantum circuits <circuit>`.
Members of a given circuit class can potentially be evaluated
on more than one :term:`backend`, and each backend has an associated circuit class it
can execute.
See: :class:`~.strawberryfields.circuitspecs.CircuitSpecs`

device
Something that can run a well-defined subclass of quantum :term:`programs <program>`.
The same device can potentially be evaluated on more than one :term:`backend`, and each
:term:`backend` can implement one or more devices.
See: :class:`.DeviceSpecs`
compilation
The process of converting a `source` quantum :term:`program` into an :term:`equivalent program`
that belongs in the `target` :term:`circuit class`.
The compilation can fail if the program cannot be made equivalent to the target circuit class.

equivalent circuit
equivalent program
Two quantum :term:`circuits <circuit>` are equivalent iff they produce the same output
probability distributions.
probability distributions. Two equivalent circuits are not necessarily in the same
:term:`circuit class`.

engine
A class for executing quantum :term:`programs <program>` on a specific :term:`backend`.
Expand Down Expand Up @@ -70,6 +74,6 @@ Expressions that are grouped together are used synonymously in the Strawberry Fi

state preparation
preparation
An operation where a quantum system or subsystem is prepared in a known fixed state.
An :term:`operation` where a quantum system or subsystem is prepared in a known fixed state.
Typically accomplished by applying a specific sequence of gates to a known
reference state.
2 changes: 1 addition & 1 deletion doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ Strawberry Fields is **free** and **open source**, released under the Apache Lic
code/engine
code/ops
code/io
code/devicespecs
code/circuitspecs
code/decompositions
code/utils
code/circuitdrawer
Expand Down
8 changes: 4 additions & 4 deletions doc/tutorials/tutorial_machine_learning.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ To properly evaluate measurement results, we must therefore do a little more wor
sess.run(tf.global_variables_initializer())
feed_dict = {phi: 0.0}
results = eng.run(prog, state_options={"session": sess, "feed_dict": feed_dict})
results = eng.run(prog, run_options={"session": sess, "feed_dict": feed_dict})
This code will execute without error, and both the output results and the register :code:`q` will contain numeric values based on the given value for the angle phi. We can select measurement results at other angles by supplying different values for :code:`phi` in :code:`feed_dict`.

Expand All @@ -80,7 +80,7 @@ Symbolic computation

Supplying a :code:`Session` and :code:`feed_dict` to :code:`eng.run()` is okay for checking one or two numerical values.
However, each call of :code:`eng.run()` will create additional redundant nodes in the underlying Tensorflow computational graph.
A better method is to make the single call :code:`eng.run(prog, state_options={"eval": False})`. This will carry out the computation symbolically but not numerically.
A better method is to make the single call :code:`eng.run(prog, run_options={"eval": False})`. This will carry out the computation symbolically but not numerically.
The results returned by the engine will instead contain *unevaluted Tensors*. These Tensors can be evaluated numerically by running the :code:`tf.Session` and supplying the desired values for any placeholders:

.. code-block:: python
Expand All @@ -92,7 +92,7 @@ The results returned by the engine will instead contain *unevaluted Tensors*. Th
MeasureHomodyne(phi) | q[0]
eng = sf.Engine(backend="tf", backend_options={"cutoff_dim": 7})
results = eng.run(prog, state_options={"eval": False})
results = eng.run(prog, run_options={"eval": False})
state_density_matrix = results.state.dm()
homodyne_meas = results.samples[0]
Expand Down Expand Up @@ -140,7 +140,7 @@ It is common in machine learning to process data in *batches*. Strawberry Fields
with prog.context as q:
Dgate(tf.Variable([0.1] * batch_size)) | q[0]
result = eng.run(prog, state_options={"eval": False})
result = eng.run(prog, run_options={"eval": False})
.. note:: The batch size should be static, i.e., not changing over the course of a computation.

Expand Down
15 changes: 8 additions & 7 deletions doc/tutorials/tutorial_teleportation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -175,25 +175,26 @@ in our truncated Fock basis. We now have all the parameters ready to initialize
For example, to prepare a squeezed vacuum state in the :math:`x` quadrature with ``cutoff_dim=10``, a squeezing factor of :math:`r=1` provides an acceptable approximation, since :math:`|\braketD{n}{z}|^2<0.02` for :math:`n\geq 10`.


We can now execute our quantum program ``prog`` on the engine via the :func:`Engine.run` method:
We can now execute our quantum program ``program`` on the engine via the :func:`Engine.run` method:

.. code-block:: python
result = eng.run(prog, shots=1, modes=None, state_options={}, compile_options={})
result = eng.run(program, run_options={shots=1, modes=None}, compile_options={})
The :meth:`eng.run <.LocalEngine.run>` method accepts the arguments:

..
..
* ``shots``: A positive integer that specifies the number of times the program measurement evaluation is to be repeated.
* ``program``: The :class:`~.Program` to execute.

..
* ``modes``: A list of integers, that specifies which modes we wish to return in the state object. If the state is a mixed state represented by a density matrix, then the backend will automatically perform a partial trace to return only the modes specified. Note that this only affects the returned state object - all modes remain in the backend circuit.
* ``run_options``: A dictionary of keyword arguments to be passed to the backend when it prepares the returned measurement results and quantum state from a simulator backend. The available options depend on the backend in use; common arguments include:

..
- ``shots``: A positive integer that specifies the number of times the program measurement evaluation is to be repeated.
- ``modes``: An optional list of integers that specifies which modes we wish the backend to return for the quantum state. If the state is a mixed state represented by a density matrix, then the backend will automatically perform a partial trace to return only the modes specified. Note that this only affects the returned state object---all modes remain in the backend circuit.

* ``state_options``: A dictionary of keyword arguments to be passed to the backend when it prepares the returned quantum state from a simulator backend. For example, TensorFlow objects like a ``session`` and a ``feed_dict`` can be passed to the TensorFlow backend.
- ``eval``, ``session``, and ``feed_dict``: These are special keyword arguments used by the TensorFlow backend. See the :ref:`machine_learning_tutorial` for details about what these are used for.

..
Expand Down
4 changes: 2 additions & 2 deletions examples/QuantumTeleportation.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,9 @@
"To execute a program on the backend, we simply call `eng.run`:\n",
"\n",
"```python3\n",
" results = eng.run(prog, state_options)\n",
" results = eng.run(prog, run_options)\n",
"```\n",
"Here, `prog` is a Strawberry Fields `Program` object (like the one we created above), and `state_options` is a dictionary of keyword arguments which can be used to specify additional options for the returned object. \n",
"Here, `prog` is a Strawberry Fields `Program` object (like the one we created above), and `run_options` is a dictionary of keyword arguments which can be used to specify additional options for the returned object. \n",
"\n",
"`eng.run()` returns a `Results` object which contains both measurement results and -- for local simulators -- a `State` object which contains the simulated quantum state of the circuit after execution of the program. Depending on backend used, the state returned might be a BaseFockState, which represents the state using the Fock/number basis, or might be a BaseGaussianState, which represents the state using Gaussian representation, as a vector of means and a covariance matrix. Many methods are provided for state manipulation, see [Quantum States API](https://strawberryfields.readthedocs.io/en/stable/code/backend.states.html) for more details.\n",
"\n",
Expand Down
4 changes: 2 additions & 2 deletions examples/gaussian_cloning.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
# end circuit

# run the engine
results = eng.run(gaussian_cloning, modes=[0, 3])
results = eng.run(gaussian_cloning, run_options={"modes": [0, 3]})

# return the cloning fidelity
fidelity = sqrt(results.state.fidelity_coherent([0.7+1.2j, 0.7+1.2j]))
Expand All @@ -45,7 +45,7 @@

for i in range(reps):
eng.reset()
results = eng.run(gaussian_cloning, modes=[0])
results = eng.run(gaussian_cloning, run_options={"modes": [0]})
f[i] = results.state.fidelity_coherent([0.7+1.2j])
a[i] = results.state.displacement()

Expand Down
2 changes: 1 addition & 1 deletion examples/optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
alpha = tf.Variable(0.1)
with circuit.context as q:
Dgate(alpha) | q[0]
results = eng.run(circuit, state_options={"eval": False})
results = eng.run(circuit, run_options={"eval": False})

# loss is probability for the Fock state n=1
prob = results.state.fock_prob([1])
Expand Down
2 changes: 1 addition & 1 deletion examples/quantum_neural_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def layer(q):
layer(q)

# starting the engine
results = eng.run(qnn, state_options={"eval": False})
results = eng.run(qnn, run_options={"eval": False})
ket = results.state.ket()

# defining cost function
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
'license': 'Apache License 2.0',
'packages': [
'strawberryfields',
'strawberryfields.devicespecs',
'strawberryfields.circuitspecs',
'strawberryfields.backends',
'strawberryfields.backends.tfbackend',
'strawberryfields.backends.fockbackend',
Expand Down
6 changes: 5 additions & 1 deletion strawberryfields/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
* Quantum execution and compilation engine: :mod:`strawberryfields.engine`
* Quantum operations: :mod:`strawberryfields.ops`
* Input/output functions: :mod:`strawberryfields.io`
* Circuit specifications: :mod:`strawberryfields.devicespecs`
* Circuit specifications: :mod:`strawberryfields.circuitspecs`
* Decompositions: :mod:`strawberryfields.decompositions`
* Utilities: :mod:`strawberryfields.utils`
* Circuit drawer: :mod:`strawberryfields.circuitdrawer`
Expand Down Expand Up @@ -98,6 +98,8 @@ def about():
import os
import numpy
import scipy
import hafnian
import blackbird

# a QuTiP-style infobox
print('\nStrawberry Fields: a Python library for continuous-variable quantum circuits.')
Expand All @@ -109,6 +111,8 @@ def about():
print('Strawberry Fields version: {}'.format(__version__))
print('Numpy version: {}'.format(numpy.__version__))
print('Scipy version: {}'.format(scipy.__version__))
print('Hafnian version: {}'.format(hafnian.__version__))
print('Blackbird version: {}'.format(blackbird.__version__))
try:
import tensorflow
tf_version = tensorflow.__version__
Expand Down
Loading

0 comments on commit 9b46f82

Please sign in to comment.