Experiment

Experiments behave the same way as Processors and RemoteProcessors, except that they don’t know how or where to simulate them (they don’t have backend or platform); they simply describe the elements of an optical table and the post-processing rules.

>>> import perceval as pcvl
>>> e = pcvl.Experiment(2, noise=pcvl.NoiseModel(0.8), name="my experiment").add(0, pcvl.BS())
>>> e.add_herald(0, 1)
>>> p = pcvl.Processor("SLOS", e)
>>> rp = pcvl.RemoteProcessor("sim:slos").add(e)

Experiments have two main purposes that Processor and RemoteProcessor can’t fulfill:

  • They can be used to create several Processors describing the same experiment with different backends.

  • They can be serialized using perceval serialization, so they can be stored and retrieved easily.

>>> from perceval.serialization import serialize, deserialize
>>> e_str = serialize(e)  # This is a regular string
>>> e_copy = deserialize(e_str)
class perceval.components.experiment.Experiment(m_circuit=None, noise=None, name='Experiment')

This class represents an optical table containing:

  • A circuit and/or components that represent the operations that will operate on photons. Can contain non-unitary components

  • The input state for the experiment.

  • Detectors to detect photons.

  • Ports to define groups of modes

  • Heralds

  • A post-selection method

  • A NoiseModel

Parameters:
  • m_circuit (int | ACircuit) – Number of spatial modes (int), first part of the circuit (Circuit) or None. If a circuit is passed, its size is used as the experiment size.

  • noise (NoiseModel) – A NoiseModel

  • name (str) – The experiment name

add(mode_mapping, component, keep_port=True)

Add a component to the experiment (unitary or non-unitary).

Parameters:
  • mode_mapping

    Describe how the new component is connected to the existing experiment. Can be:

    • an int: composition uses consecutive modes starting from mode_mapping

    • a list or a dict: describes the full mapping of length the input mode count of component

  • component

    The component to append to the experiment. Can be:

    • A unitary circuit

    • A non-unitary component

    • A processor

    • An experiment

    • A detector

  • keep_port (bool) – if True, saves self’s output ports on modes impacted by the new component, otherwise removes them.

Adding a component on non-ordered, non-consecutive modes computes the right permutation (PERM component) which fits into the existing experiment and the new component.

Example:

>>> e = Experiment(6)
>>> e.add(0, BS())  # Modes (0, 1) connected to (0, 1) of the added beam splitter
>>> e.add([2,5], BS())  # Modes (2, 5) of the experiment's output connected to (0, 1) of the added beam splitter
>>> e.add({2:0, 5:1}, BS())  # Same as above

If the added component is a processor or an experiment with modes having heralds only on one side, no permutation will be added at the end, and the “in-between” modes will be pushed to the bottom.

add_herald(mode, expected, name=None, location=PortLocation.IN_OUT)

Add a heralded mode

Parameters:
  • mode (int) – Mode index of the herald

  • expected (int) – number of expected photon as input AND output on the given mode (must be 0 or 1)

  • name (Optional[str]) – Herald port name. If none is passed, the name is auto-generated

  • location (PortLocation) – Port location of the herald (input, output or both)

are_modes_free(mode_range, location=PortLocation.OUTPUT)
Return type:

bool

Returns:

True if all modes in mode_range are free of ports, for a given location (input, output or both)

check_input(input_state)

Check if a basic state input matches with the current experiment configuration

property circuit_size: int
Returns:

Total size of the enclosed circuit (i.e. self.m + ancillary mode count)

copy(subs=None)

Performs a deep copy of the current experiment.

Return type:

Experiment

flatten(max_depth=None)

List all the components in the experiment where recursive circuits have been flattened.

Parameters:

max_depth – The maximum depth of recursion. The remaining sub-circuits at this depth are listed as a component.

Return type:

list[tuple]

property has_feedforward: bool
Returns:

True if the circuit contains at least one feed-forward layer, False otherwise.

property has_td: bool
Returns:

True if the circuit contains at least one time delay, False otherwise.

property in_port_names
Returns:

A list of the input port names. Names are repeated for ports connected to more than one mode

property is_unitary: bool
Returns:

True if the circuit is composed of only unitary components, False otherwise.

property m: int
Returns:

Number of modes of interest (MOI) at the output of the experiment

property m_in
Returns:

Number of modes of interest (MOI) at the input the experiment

min_detected_photons_filter(n)

Sets-up a state post-selection on the number of detected photons. With thresholded detectors, this will actually filter on “click” count.

Parameters:

n (int) – Minimum expected photons

This post-selection has an impact on the output physical performance

property out_port_names
Returns:

A list of the output port names. Names are repeated for ports connected to more than one mode

set_circuit(circuit)

Removes all components and replace them by the given circuit.

Parameters:

circuit (ACircuit) – The circuit to start the experiment with

Returns:

Self to allow direct chain this with .add()

set_postselection(postselect)

Set a logical post-selection function. Along with the heralded modes, this function has an impact on the logical performance of the processor holding this experiment

Parameters:

postselect (PostSelect) – Sets a post-selection function. Its signature must be func(s: BasicState) -> bool. If None is passed as parameter, removes the previously defined post-selection function.

unitary_circuit(flatten=False, use_phase_noise=False)

Creates a unitary circuit from internal components, if all internal components are unitary.

Parameters:

flatten (bool) – if True, the component recursive hierarchy is discarded, making the output circuit “flat”.

Return type:

Circuit