Quantum compiler engine

Module name: strawberryfields.engine

This module implements the quantum compiler engine. The Engine class provides the toolchain that starts with the user inputting a quantum circuit and ends with a backend that could be e.g. a simulator, a hardware quantum processor, or a circuit drawer.

Syntactically, the compiler engine acts as the context for the quantum circuit. A typical use looks like

eng, q = sf.Engine(num_subsystems)
with eng:
  Coherent(0.5)  | q[0]
  Vac            | q[1]
  Sgate(2)       | q[1]
  Dgate(0.5)     | q[0]
  BSgate(1)      | q
  Dgate(0.5).H   | q[0]
  Measure        | q
eng.run(backend[,cutoff_dim])
v1 = q[1].val

Engine methods

register Return symbolic references to all the currently valid register subsystems.
reset([keep_history]) Re-initialize the backend state to vacuum.
reset_queue() Clear the command queue.
append(op, reg) Append a quantum circuit command to the engine command queue.
print_queue([print_fn]) Print the command queue.
print_applied([print_fn]) Print all commands applied to the qumodes since the backend was first initialized.
draw_circuit([print_queued_ops, tex_dir, …]) Draw the circuit using the Qcircuit \(\LaTeX\) package.
run([backend, return_state, modes, …]) Execute the circuit in the command queue by sending it to the backend.
return_state([modes]) Return the backend state object.
optimize() Try to simplify and optimize the circuit in the command queue.

Helper classes

Command(op, reg[, decomp]) Represents a quantum operation applied on specific subsystems of the register.
RegRef(ind) Quantum register reference.
RegRefTransform(refs[, func, func_str]) Represents a scalar function of one or more register references.

Optimizer

The purpose of the optimizer part of the compiler engine is to simplify the circuit to make it cheaper and faster to execute. Different backends might require different types of optimization, but in general the fewer operations a circuit has, the faster it should run. The optimizer thus should convert the circuit into a simpler but otherwise equivalent version of itself, preserving the probability distributions of the measurement results. The optimization utilizes the abstract algebraic properties of the gates, and in no point should require a matrix representation.

Currently the optimization is somewhat simple, being able to merge neighboring gates belonging to the same gate family and sharing the same set of subsystems, and canceling pairs of a gate and its inverse.

Exceptions

MergeFailure Exception raised by merge() when an attempted merge fails.
CircuitError Exception raised by Engine when it encounters an illegal operation in the quantum circuit.
RegRefError Exception raised by Engine when it encounters an invalid register reference.
NotApplicableError Exception raised by the backend when the user attempts an unsupported operation.

Code details

exception strawberryfields.engine.CircuitError[source]

Exception raised by Engine when it encounters an illegal operation in the quantum circuit.

E.g. trying to use a measurement result before it is available.

exception strawberryfields.engine.RegRefError[source]

Exception raised by Engine when it encounters an invalid register reference.

E.g. trying to apply a gate to a nonexistent or deleted subsystem.

exception strawberryfields.engine.MergeFailure[source]

Exception raised by merge() when an attempted merge fails.

E.g. trying to merge two gates of different families.

class strawberryfields.engine.Command(op, reg, decomp=False)[source]

Represents a quantum operation applied on specific subsystems of the register.

Parameters:
  • op (Operation) – quantum operation to apply
  • reg (Sequence[RegRef]) – Subsystems to which the operation is applied. Note that the order matters here.
op = None

quantum operation to apply

Type:Operation
reg = None

subsystems to which the operation is applied

Type:Sequence[RegRef]
decomp = None

is this Command a part of a decomposition?

Type:bool
get_dependencies()[source]

Subsystems the command depends on.

Combination of self.reg and self.op.extra_deps.

Note

extra_deps are used to ensure that the measurement happens before the result is used, but this is a bit too strict: two gates depending on the same measurement result but otherwise acting on different subsystems commute.

Returns:set of subsystems the command depends on
Return type:set[RegRef]
class strawberryfields.engine.RegRef(ind)[source]

Quantum register reference.

The objects of this class refer to a specific subsystem (mode) of a quantum register.

Only one RegRef instance should exist per subsystem: Engine keeps the authoritative mapping of subsystem indices to RegRef instances. Subsystem measurement results are stored in the “official” RegRef object. If other RegRefs objects referring to the same subsystem exist, they will not be updated. Once a RegRef is assigned a subsystem index it will never change, not even if the subsystem is deleted.

The RegRefs are constructed in Engine._add_subsystems().

Parameters:ind (int) – index of the register subsystem referred to
ind = None

subsystem index

Type:int
val = None

measured eigenvalue. None if the subsystem has not been measured yet

Type:Real
active = None

True at construction, False when the subsystem is deleted

Type:bool
class strawberryfields.engine.RegRefTransform(refs, func=None, func_str=None)[source]

Represents a scalar function of one or more register references.

A RegRefTransform instance, given as a parameter to a Operation constructor, represents a dependence of the Operation on classical information obtained by measuring one or more subsystems.

Used for deferred measurements, i.e., using a measurement’s value symbolically in defining a gate before the numeric value of that measurement is available.

Parameters:
  • r (Sequence[RegRef]) – register references that act as parameters for the function
  • func (None, function) – Scalar function that takes the values of the register references in r as parameters. None is equivalent to the identity transformation lambda x: x.
  • func_str (str) – an optional argument containing the string representation of the function. This is useful if a lambda function is passed to the RegRefTransform, which would otherwise it show in the engine queue as RegRefTransform(q[0], <lambda>).
regrefs = None

register references that act as parameters for the function

Type:list[RegRef]
func = None

the transformation itself, returns a scalar

Type:None, function
evaluate()[source]

Evaluates the numeric value of the function if all the measurement values are available.

Returns:function value
Return type:Number
class strawberryfields.engine.Engine(num_subsystems, hbar=2)[source]

Quantum compiler engine.

Acts as a context manager (and the context itself) for quantum circuits. The contexts may not be nested.

The quantum circuit is inputted by using the __or__() methods of the quantum operations, which call the append() method of the Engine. append() checks that the register references are valid and then adds a new Command instance to the Engine command queue.

run() executes the command queue on the chosen backend, and makes measurement results available via the RegRef instances.

The New and Del operations modify the quantum register itself by adding and deleting subsystems. The Engine keeps track of these changes as they enter the command queue in order to be able to report register reference errors as soon as they happen.

The backend, however, only becomes aware of subsystem changes when the circuit is run. See reset_queue() and reset().

Parameters:num_subsystems (int) – Number of subsystems in the quantum register.
Keyword Arguments:
 hbar (float) – The value of \(\hbar\) to initialise the engine with, depending on the conventions followed. By default, \(\hbar=2\). See Conventions and formulas for more details.
init_num_subsystems = None

initial number of subsystems

Type:int
cmd_queue = None

command queue

Type:list[Command]
cmd_applied = None

list of lists of commands that have been run (one list per run)

Type:list[list[Command]]
backend = None

backend for executing the quantum circuit

Type:BaseBackend
hbar = None

Numerical value of hbar in the (implicit) units of position and momentum.

Type:float
reg_refs = None

mapping from subsystem indices to corresponding RegRef objects

Type:dict[int->RegRef]
unused_indices = None

created subsystem indices that have not been used (operated on) yet

Type:set[int]
register

Return symbolic references to all the currently valid register subsystems.

Returns:valid subsystem references
Return type:tuple[RegRef]
num_subsystems

Return the current number of valid register subsystems.

Returns:number of currently valid register subsystems
Return type:int
reset(keep_history=False, **kwargs)[source]

Re-initialize the backend state to vacuum.

Resets the state of the quantum circuit represented by the backend.

  • The original number of modes is restored.
  • All modes are reset to the vacuum state.
  • All known RegRefs are cleared of measured values.
  • A checkpoint is made of the initial register state.
  • If keep_history is False:
    • The command queue and the list of commands that have been run are cleared.
    • Any RegRefs for subsystems that were created after the init are rendered inactive and deleted.
  • If keep_history is True:
    • The command queue is prepended by the list of commands that have been run. The latter is then cleared. The purpose of this is to keep the circuit valid in the cases where previously run program segments have created or deleted subsystems, or made measurement on which the program in the command queue depends.
    • RegRef activity state is unchanged, active RegRefs remain valid.

The keyword args are passed on to strawberryfields.backends.base.BaseBackend.reset().

Parameters:keep_history (bool) – allows the backend to be reset to the vacuum state while retaining the circuit history to be applied on the next call to run().
reset_queue()[source]

Clear the command queue.

Resets the currently queued circuit.

  • Clears all queued Commands, but does not reset the current state of the circuit.
  • self.reg_refs and self.unused_indices are restored to how they were at the last checkpoint.
  • Any extra RegRefs for subsystems that were created after last checkpoint are made inactive.
append(op, reg)[source]

Append a quantum circuit command to the engine command queue.

Parameters:
  • op (Operation) – quantum operation
  • reg (list[int, RegRef]) – register subsystem(s) to apply it to
Returns:

subsystem list as RegRefs

Return type:

list[RegRef]

print_queue(print_fn=<built-in function print>)[source]

Print the command queue.

This contains the gates that will be applied on the next call to run().

Parameters:print_fn (function) – optional custom function to use for string printing.
print_applied(print_fn=<built-in function print>)[source]

Print all commands applied to the qumodes since the backend was first initialized.

This will be blank until the first call to run(). The output may differ compared to print_queue(), due to command decompositions and optimizations supported by the backend.

Parameters:print_fn (function) – optional custom function to use for string printing.
draw_circuit(print_queued_ops=True, tex_dir='./circuit_tex', write_to_file=True)[source]

Draw the circuit using the Qcircuit \(\LaTeX\) package.

This will generate the tex code required to display the queued or applied quantum operations as a quantum circuit.

Parameters:
  • print_queued_ops (bool) – by default, the quantum circuit representing the queued quantum operations is drawn. Set this to False to instead draw the circuit of the previously applied quantum operations.
  • tex_dir (str) – relative directory for latex document output.
  • write_to_file (bool) – if False, no output file is created.
Returns:

the filename of the written tex document and the written tex content.

Return type:

list(str)

return_state(modes=None, **kwargs)[source]

Return the backend state object.

Parameters:modes (Sequence[int]) – integers containing the modes to be returned. If none, all modes are returned.
Returns:object containing details and methods for manipulation of the returned circuit state
Return type:BaseState
run(backend=None, return_state=True, modes=None, apply_history=False, **kwargs)[source]

Execute the circuit in the command queue by sending it to the backend.

The backend state is updated, and a new RegRef checkpoint is created. The circuit queue is emptied, and its contents (possibly decomposed) are appended to self.cmd_applied.

Parameters:
  • backend (str, BaseBackend, None) – Backend for executing the commands. Either a backend name (“gaussian”, “fock”, or “tf”), in which case it is loaded and initialized, or a BaseBackend instance, or None to keep the current backend.
  • return_state (bool) – If True, returns the state of the circuit after the circuit has been run like return_state() was called.
  • modes (Sequence[int]) – Modes to be returned in the state object. If None, returns all modes.
  • apply_history (bool) – If True, all applied operations from the previous calls to eng.run are reapplied to the backend state, before applying recently queued quantum operations.
optimize()[source]

Try to simplify and optimize the circuit in the command queue.

The simplifications are based on the algebraic properties of the gates, e.g., combining two consecutive gates of the same gate family.