sf.compilers.GaussianMerge

class GaussianMerge[source]

Bases: strawberryfields.compilers.compiler.Compiler

Compiler that merges adjacent Gaussian operations into a single symplectic transformation, to reduce the depth of non-Gaussian programs.

As a result, the Gaussian operations that this compiler returns are GaussianTransform, and Displacement. Meanwhile, non-Gaussian operations remain unchanged.

Example:

Consider the following Strawberry Fields program, compiled using the ‘gaussian_merge’ compiler:

from strawberryfields.ops import Xgate, Zgate, BSgate, Rgate
import strawberryfields as sf

circuit = sf.Program(1)
with circuit.context as q:
    Rgate(0.6)|q[0]
    Rgate(0.2)|q[0]
    Kgate(0.4)|q[0]
    Rgate(0.1)|q[0]
    Rgate(0.6)|q[0]
    Dgate(0.01)|(q[0])

compiled_circuit = circuit.compile(compiler="gaussian_merge")

We can now print the compiled circuit, which has merged adjacent Gaussian operations into singular GaussianTransform operations:

>>> compiled_circuit.print()
GaussianTransform([[ 0.6967 -0.7174]
  [0.7174  0.6967]]) | (q[0])
Kgate(0.4)|q[0]
GaussianTransform([[ 0.7648 -0.6442]
  [0.6442  0.7648]]) | (q[0])
Dgate(0.01, 0) | (q[0])

circuit

A rigid circuit template that defines this circuit specification.

decompositions

gaussian_ops

graph

The allowed circuit topologies or connectivity of the class, modelled as a directed acyclic graph.

interactive

prep_states

primitives

short_name

circuit

A rigid circuit template that defines this circuit specification.

This property is optional. If arbitrary topologies are allowed in the circuit class, do not define this property. In such a case, it will simply return None.

If a backend device expects a specific template for the recieved Blackbird script, this method will return the serialized Blackbird circuit in string form.

Returns

Blackbird program or template representing the circuit

Return type

Union[str, None]

decompositions = {'BipartiteGraphEmbed': {}, 'CXgate': {}, 'CZgate': {}, 'Fouriergate': {}, 'Gaussian': {}, 'GraphEmbed': {}, 'Pgate': {}, 'Xgate': {}, 'Zgate': {}}
gaussian_ops = ['Dgate', 'BSgate', 'S2gate', 'Sgate', 'GaussianTransform', 'Rgate', 'Interferometer', 'MZgate', 'sMZgate']
graph

The allowed circuit topologies or connectivity of the class, modelled as a directed acyclic graph.

This property is optional; if arbitrary topologies are allowed in the circuit class, this will simply return None.

Returns

a directed acyclic graph

Return type

networkx.DiGraph

interactive = True
prep_states = ['Ket']
primitives = {'All', 'BSgate', 'CKgate', 'Dgate', 'GaussianTransform', 'Interferometer', 'Ket', 'Kgate', 'MZgate', 'MeasureFock', 'MeasureHomodyne', 'Rgate', 'S2gate', 'Sgate', 'Vgate', '_Delete', '_New_modes', 'sMZgate'}
short_name = 'gaussian_merge'

add_displacement_gates(gaussian_transform)

Adds displacement gates to new DAG and returns dict with the following format: {1: Dgate|q[1], 2:Dgate|q[2]}

add_gaussian_pre_and_succ_gates(…)

Updated DAG by adding edges between gaussian transform/displacement operations to unmerged gaussian operations.

add_non_gaussian_successor_gates(…)

Updates the DAG by adding edges between new gaussian transform and non-gaussian operations from original operations.

compile(seq, registers)

Attempt to merge Gaussian operations into Gaussian Transforms in a hybrid program.

decompose(seq)

Recursively decompose all gates in a given sequence, as allowed by the circuit specification.

get_valid_gaussian_merge_ops(op)

Obtains the valid gaussian operations that can be merged with op at the current DAG configuration.

is_op_gaussian_or_prep(op)

Helper function that returns True if op is Gaussian or a preparation state else returns False.

is_redundant_merge(op, merged_gaussian_ops)

Helper function that determines if merge will do nothing.

merge_a_gaussian_op(registers)

Main function to merge a gaussian operation with its gaussian neighbours.

non_gaussian_qumodes_dependecy(op)

Get qumodes used in predecessor non-gaussian operations of op.

organize_merge_ops(merged_gaussian_ops)

Organize operations to be merged in order by using the order of the current operation sequence.

recursive_d_gate_successors(gate)

Gets all displacement gates in channel if they follow each other.

remove_invalid_operations(op, …)

Helper function that removes operations from merged_gaussian_ops if they are being operated upon a non-gaussian beforehand.

valid_prepend_op_addition(op, pre, …)

Helper function that ensures predecessor operation being added to merger list, did not skip any operations between op (operation being merged) and pre (predecessor operation of op attempted to be merged).

add_displacement_gates(gaussian_transform)[source]

Adds displacement gates to new DAG and returns dict with the following format: {1: Dgate|q[1], 2:Dgate|q[2]}

add_gaussian_pre_and_succ_gates(gaussian_transform, merged_gaussian_ops, displacement_mapping)[source]

Updated DAG by adding edges between gaussian transform/displacement operations to unmerged gaussian operations.

add_non_gaussian_successor_gates(gaussian_transform, successors, displacement_mapping)[source]

Updates the DAG by adding edges between new gaussian transform and non-gaussian operations from original operations.

compile(seq, registers)[source]

Attempt to merge Gaussian operations into Gaussian Transforms in a hybrid program.

Parameters
  • seq (Sequence[Command]) – quantum circuit to modify

  • registers (Sequence[RegRefs]) – quantum registers

Returns

modified circuit

Return type

List[Command]

decompose(seq)

Recursively decompose all gates in a given sequence, as allowed by the circuit specification.

This method follows the directives defined in the primitives and decompositions class attributes to determine whether a command should be decomposed.

The order of precedence to determine whether decomposition should be applied is as follows.

  1. First, we check if the operation is in decompositions. If not, decomposition is skipped, and the operation is applied as a primitive (if supported by the Compiler).

  2. Next, we check if (a) the operation supports decomposition, and (b) if the user has explicitly requested no decomposition.

    • If both (a) and (b) are true, the operation is applied as a primitive (if supported by the Compiler).

    • Otherwise, we attempt to decompose the operation by calling decompose() recursively.

Parameters

list[strawberryfields.program_utils.Command] – list of commands to be decomposed

Returns

list of compiled commands for the circuit specification

Return type

list[strawberryfields.program_utils.Command]

get_valid_gaussian_merge_ops(op)[source]

Obtains the valid gaussian operations that can be merged with op at the current DAG configuration.

is_op_gaussian_or_prep(op)[source]

Helper function that returns True if op is Gaussian or a preparation state else returns False.

is_redundant_merge(op, merged_gaussian_ops)[source]

Helper function that determines if merge will do nothing. i.e. just contains Gaussian Transforms and Displacement operations.

merge_a_gaussian_op(registers)[source]

Main function to merge a gaussian operation with its gaussian neighbours. If merge is achieved, the method updates self.curr_seq and returns True else (merge cannot be achieved), the method returns False.

Program Flow:
  • For each operation (op) check and obtain Gaussian operations that can be merged (get_valid_gaussian_merge_ops).

  • If the operation has successor gaussian operations that can be merged, then merge them using gaussian_unitary.py.

  • Determine displacement gates, from gaussian unitary merge, and map them to the qumodes acted upon (add_displacement_gates).

  • Attach predecessor operations of the main operation (op) to new Gaussian transform operations.

  • Attach successor non Gaussian operations of op to a displacement gate, if present, or a gaussian transform operation from the merged operations (add_non_gaussian_successor_gates).

  • Attach all non-merged predecessor and successor of the merged operations to the new gaussian transform and displacement gates (add_gaussian_pre_and_succ_gates).

  • Remove nodes of operations that were merged in and convert DAG to sequence.

non_gaussian_qumodes_dependecy(op)[source]

Get qumodes used in predecessor non-gaussian operations of op. Returns a list of integers, where the number depicts the qumode index that the non-Gaussian operation operates on.

organize_merge_ops(merged_gaussian_ops)[source]

Organize operations to be merged in order by using the order of the current operation sequence.

recursive_d_gate_successors(gate)[source]

Gets all displacement gates in channel if they follow each other. Returns lists of displacement gates.

remove_invalid_operations(op, merged_gaussian_ops)[source]

Helper function that removes operations from merged_gaussian_ops if they are being operated upon a non-gaussian beforehand. E.X BS | q[0],q[1] has successors Vgate | q[1] & S2gate q[0],q[1] in this case the S2gate is removed.

valid_prepend_op_addition(op, pre, merged_gaussian_ops)[source]

Helper function that ensures predecessor operation being added to merger list, did not skip any operations between op (operation being merged) and pre (predecessor operation of op attempted to be merged).