You're reading the documentation of the v0.8. For the latest released version, please have a look at v0.11.

Legacy

Perceval has evolved quickly from the initial release, some evolution are introducing breaking changes for existing code. While we are trying hard to avoid unncessary API changes, some of necessary to bring new features and keep a consistent code base.

This section lists the major breaking changes introduced.

Breaking changes in Perceval 0.8

Processors.mode_post_selection changes to min_detected_photons_filter

In Perceval 0.7, you could filter results by setting a minimum number of threshold detector “clicks” (which was translated, in simulators, to the number of modes with at least one photon)

>>> import perceval as pcvl
>>> p = pcvl.Processor("SLOS", 8, pcvl.Source(emission_probability=.8))
>>> p.with_input(pcvl.BasicState([1, 0, 1, 0, 0, 0, 0, 0]))
>>> p.mode_post_selection(2)  # In Perceval 0.7, Processor p would reject results with less than 2 modes with detections

Even though this filtering works well with QPU simulators and actual QPU acquisitions, it implied that more theoretical simulations was impacted by a threshold detection rule when they use perfect detectors. In this case, you could retrieve unexpected results.

Perceval introcudes min_detected_photons_filter to improve its behavior. Updating to Perceval 0.8 and using min_detected_photons_filter as you would have used mode_post_selection, will not change results for threshold detections, and will improve them for perfect simulations (less states will be rejected, improving physical performance).

>>> p.min_detected_photons_filter(2)  # In Perceval 0.8, the new filter rejects states based on photon count

Breaking changes in Perceval 0.7

lib.phys and lib.symb have been removed

Base components, originally duplicated in the two libraries were merged in two modules perceval.components.unitary_components and perceval.components.non_unitary_components. One direct benefit of this change is that the beam splitter definition is now the same (see BS conventions), and does not depend on how it renders (see Display components).

>>> import perceval as pcvl
>>> from perceval.components.unitary_components import PS, BS, PERM
>>> import numpy as np
>>>
>>> c = pcvl.Circuit(2) // PS(np.pi) // BS() // PERM([1, 0]) // (1, PS(np.pi))

Display components

Initially, use of lib.symb or lib.phys was deciding how the circuit was displayed. Now, a skin system is available to use whichever representation you want.

>>> import perceval as pcvl
>>> from perceval.rendering import SymbSkin
>>>
>>> pcvl.pdisplay(c)  # defaults to PhysSkin, similar to lib.phys
>>> pcvl.pdisplay(c, skin=SymbSkin())  # Renders using SymbSkin, similar to lib.symb

see Circuit Rendering for more details.

BS conventions

lib.phys.BS used a different convention from lib.symb.BS. After merging both libs, only one BS class remains, handling 3 different conventions suited to any need. See Beam Splitter for details.

>>> from perceval.components.base_components import BS, BSConvention
>>>
>>> bs = BS()  # Defaults to Rx convention. Ideally, in an upcoming Perceval release, the default could be changed in a persistent user config.
>>> BS.H() == BS(convention=BSConvention.H)  # Both syntaxes give the same result.
>>> BS.Ry() == BS(convention=BSConvention.Ry)  # Same

This new BS class handles only theta (instead of a mutually exclusive theta or R) which is used differently from before: Half of theta is used when computing the unitary matrix (i.e. cos(theta/2) now, cos(theta) before).

Also, the new BS can be configured with 4 phases, one on each mode (phi_tl, phi_tr, phi_bl, phi_br) corresponding respectively to top left, top right, bottom left and bottom right arms of the beam splitter.

There is no direct conversion from former symb.BS or phys.BS.

  • BS conventions - existing code:

In all the existing code base, phys.BS were replaced by BS.H and symb.BS by BS.Rx which have the same unitary matrices when no phase are applied to them.

Create a backend instance

Originally, you would call

>>> backend_type = BackendFactory().get_backend(backend_name)  # For instance backend_name = "SLOS"
>>> simu_backend = backend_type(circuit)

While this is still functional, this can also be misleading. Indeed, simulation backends can provide features that you cannot measure with actual QPU - typically the probability amplitude. This is good for developing theoretical algorithms but using these will not port to actual QPUs. We recommend using the class Processor by default.

AnnotatedBasicState was deprecated

Please use BasicState instead which holds every feature previously held by AnnotatedBasicState

Processor definition and composition

Perceval is getting more and more Processor-centric as we implement more features. The Processor class has got some serious refactoring. You may find examples of Processor created from scratch in perceval.components.core_catalog content. You may use several processors / circuits and compose them : a good example is the QiskitConvert convert method implementation.

Access to circuit parameters

It was possible to access a named parameters on a circuit using [] notation:

>>> c['phi']

This has been replaced by explicit use of params accessor:

>>> c.param('phi')

The __getitem__ notation is now used to access components in a circuit (see Accessing components in a circuit).

New Source in Perceval 0.7.3

A new source model has been introduced in Perceval 0.7.3. The Source class initialization parameters have changed and imperfect simulated sources will return results closer to the actual photonic sources which are used in the QPUs. Backward compatibility with pre-0.7.3 sources is broken.

  • brightness was replaced by emission_probability. Balanced losses from the source output to the circuit output can be modelled with losses paramater.

  • purity and purity_model were respectively replaced by multiphoton_component and multiphoton_model. purity represented the ratio of time when photon is emitted alone whereas multiphoton_component is the \(g^{(2)}\). There is no direct conversion from the former purity to \(g^{(2)}\), note however that the greater the purity, the lower the \(g^{(2)}\).

  • The default distinguishability of multiple emitted photons changed from indistinguishable to distinguishable.

>>> source = pcvl.Source(brightness=0.3, purity=0.95, purity_model="distinguishable")

can be changed to (without returning the same results):

>>> source = pcvl.Source(emission_probability=0.3, multiphoton_component=0.05)

See Source class reference for more information.