In Strawberry Fields, photonic quantum circuits are represented as Program objects. By creating a program, quantum operations can be applied, measurements performed, and the program can then be simulated using the various Strawberry Fields backends.

See also

New to photonic quantum computing? See the Glossary for a glossary of some of the terms used in Strawberry Fields.

Creating a quantum program

To construct a photonic quantum circuit in Strawberry Fields, a Program object must be created, and operations applied.

import strawberryfields as sf
from strawberryfields import ops

# create a 3 mode quantum program
prog = sf.Program(3)

with prog.context as q:
    ops.Sgate(0.54) | q[0]
    ops.Sgate(0.54) | q[1]
    ops.Sgate(0.54) | q[2]
    ops.BSgate(0.43, 0.1) | (q[0], q[2])
    ops.BSgate(0.43, 0.1) | (q[1], q[2])
    ops.MeasureFock() | q

Here, we are creating a 3-mode program, and applying a Sgate and a BSgate to various modes. Constructing quantum circuits always follows the same structure as the above example; in particular,

  • A with statement is used to populate the program with quantum operations.

  • Program.context is used within the with statement to return q, a representation of the quantum registers (qumodes or modes).

  • Quantum operations are applied to the modes of the program using the syntax

    ops.GateName(arg1, arg2) | (q[i], q[j], ...)


The contents of a program can be viewed by calling Program.print() method, or output as a qcircuit \(\LaTeX{}\) document by using the Program.draw_circuit() method.

See also

Visit the Operations page to see an overview of available quantum operations.

Simulating your program

Strawberry Fields provides several backend simulators for simulating your quantum program. To access the simulators, an engine must be initialized, which is responsible for executing the program on a specified backend (which can be either a local simulator, or a remote simulator/hardware device).

# intialize the fock backend with a
# Fock cutoff dimension (truncation) of 5
eng = sf.Engine("fock", backend_options={"cutoff_dim": 5})

Engine accepts two arguments, the backend name, and a dictionary of backend options. Available backends include:

  • The 'fock' backend, written in NumPy.

    This backend represents the quantum state and operations via the Fock basis, so can represent all possible CV states and operations. However numerical error is also introduced due to truncation of the Fock space—increasing the cutoff results in higher accuracy at a cost of increased memory consumption.

  • The 'gaussian' backend, written in NumPy.

    This backend represents the quantum state as a Gaussian, and operations as quantum operations. It is numerically exact, and consumes less memory and is less computationally intensive then the Fock backends. However, it cannot represent non-Gaussian operations and states, with the exception of terminal Fock measurements.

  • The 'tf' backend, written in TensorFlow 1.3.

    This backend represents the quantum state and operations via the Fock basis, but allows for backpropagation and optimization using TensorFlow.

Once the engine has been initialized, the quantum program can be executed on the selected backend via run():

result =

Execution results

The returned Result object provides several useful properties for accessing the results of your program execution:

  • results.state: The quantum state object contains details and methods for manipulation of the final circuit state. Not available for remote backends.

    >>> print(result.state)
    <FockState: num_modes=3, cutoff=15, pure=False, hbar=2.0>
    >>> state = result.state
    >>> state.trace()    # trace of the quantum state
    >>> # density matrix
    [5, 5, 5]
  • results.samples: Measurement samples from any measurements performed.

    >>> results.samples
    [0, 0, 2]

See also

Visit the States page to see an overview of available quantum state methods.


Measured modes will always be returned to the vacuum state.


To avoid significant numerical error when working with Fock backends, ensure that the trace of your program after simulation remains reasonably close to 1, by calling state.trace(). If the trace is much less than 1, you will need to increase the cutoff dimension.


The Program object also provides compilation methods, that automatically transform your circuit into an equivalent circuit with a particular layout or topology. For example, the gbs compile target will compile a circuit consisting of Gaussian operations and Fock measurements into canonical Gaussian boson sampling form.

prog2 = prog.compile('gbs')