MPSBackend

The MPSBackend is a strong simulation backend that can compute the whole output distribution at once by using higher dimensional matrices and evolving them through the components of a circuit.

It is efficient to compute the whole output distribution of a circuit. However, this backend has several major downsides:

  • It is not able to process components spanning more than two modes (except Permutation components).

  • It needs a cutoff number that avoids growing the matrices exponentially but leads to approximate results.

  • It’s time complexity scales in the number of components, and not only the number of modes and photons.

  • Although masks work as expected, this backend is not able to make profit of the reduced computation space.

Thus, using it is recommended only for small circuits with small components where the whole distribution is needed but the exact value of the probabilities is not needed. In any other case, other backends like SLOSBackend or NaiveBackend are more suited.

This backend is available in Processor by using the name "MPS".

Unlike other backends, this backend needs a cutoff number that will induce imprecision on the results. Higher values give more accurate results at the cost of a heavier computation. In principle, a high enough value will give exact results, but the computation will be heavier than with a SLOSBackend for example.

>>> import perceval as pcvl
>>> c = pcvl.Circuit(4) // pcvl.BS() // (2, pcvl.BS()) // (1, pcvl.BS())
>>> backend = pcvl.MPSBackend(cutoff=3)
>>> backend.set_circuit(c)
>>> backend.set_input_state(pcvl.BasicState([1, 0, 1, 0]))
>>> print(backend.prob_distribution())
{
  |1,1,0,0>: 0.12500000000000003
  |1,0,1,0>: 0.07775105849101832
  |1,0,0,1>: 0.29017090063073997
  |0,2,0,0>: 0.12500000000000003
  |0,1,1,0>: 0.020833333333333356
  |0,1,0,1>: 0.07775105849101838
  |0,0,2,0>: 0.12500000000000006
  |0,0,1,1>: 0.12500000000000003
}
class perceval.backends._mps.MPSBackend(cutoff=None)

The state of the system is written in form of an MPS and updated step-by-step by a circuit propagation algorithm.

Approximate the probability amplitudes with a cutoff -> bond Dimension in an MPS. - For now only supports components for up to 2 modes (Phase shifters and Beam Splitters already implemented)

Parameters:

cutoff (Optional[int]) – The bond dimension. Higher values mean better precision but slower computation. Default input_state.n + 1

all_prob(input_state=None)

Computes the list of probabilities of all states (respecting the mask if any was set). The order of the states can be retrieved using allstate_iterator()

Return type:

list[float]

clear_mask()

Removes any pre-existing mask

evolve()

Evolves the input BasicState into a StateVector.

Return type:

StateVector

property name: str

Returns the back-end name as a string

prob_amplitude(output_state)

Computes the probability for a given input output state from a circuit with m modes and n photons computed using MPS

Return type:

complex

prob_distribution()

Computes the probability distribution of all states (respecting the mask if any was set) under the form of a BSDistribution.

Return type:

BSDistribution

probability(output_state)

Computes the probability for a given output state. The input state and the circuit must already be set

Return type:

float

set_circuit(circuit)

Sets the circuit to simulate. This circuit must not contain polarized components (use PolarizationSimulator instead, if required).

set_cutoff(cutoff_val)

Cut-off defines the Bond dimension (Schmidt rank of the decomposition of the state) of an MPS; in other words, how well approximated the state is. Default value is the total number of photons + 1.

set_input_state(input_state)

Sets an input state for the simulation. This state has to be a Fock state without annotations.

set_mask(masks, n=None)

Sets new masks, replacing the former ones if they exist. Clear possible cached data that depend on the mask. Masks are useful to limit strong simulation to only a part of the Fock space, ultimately saving memory and computation time.

Parameters:
  • masks (str | list[str]) – Can be a mask or a list of masks. Each mask is expressed as a string where each character is a condition on one mode. Digits are fixing the number of photons whereas spaces or “*” are accepting any number of detections. e.g. using “****00” as a mask limits the simulation to output states ending in two empty modes.

  • n – The number of photons to instantiate the mask with. This corresponds to the total number of photons in your non-separated state.

update_state_1_mode(k, u)

tensor contraction between the corresponding mode’s gamma of the MPS and the transition matrix “U” of phase shifter for that mode [_transition_matrix_1_mode].

update_state_2_mode(k, u)

takes the gamma->kth and (k+1)th + corresponding lambda-s -> contracts the entire thing with 2 mode beam splitter, performs some reshaping and then svd to re-build the corresponding segment of MPS.