Perceval: Photonic Quantum Circuit Simulation Toolkit

repository·main·Indexed 41 days ago

https://github.com/quandela/perceval

A Python toolkit for designing and simulating discrete-variable photonic quantum circuits. Perceval allows users to build circuits with linear optics components, model single-photon sources, and execute computations on Quandela's photonic quantum computers. It features multiple simulation back-ends including Clifford, SLOS, Naive, NaiveApprox, MPS, and SLAP, supporting both sampling (weak simulation) and strong simulation to provide probability amplitudes and full distributions.

Tokens
26.9K
Snippets
77
Records
102
Agent score
53%

What's inside Perceval

  1. What is Perceval?

    main

    Perceval is a toolbox for simulating linear optics quantum computing. It is built around an optimized native core and provides tools for:

    • Quantum State Manipulation: Handle pure states (FockState, StateVector) and mixed states (SVDistribution, DensityMatrix) in Fock space.
    • Experiment Building: Construct Experiment objects containing Circuit (unitary components), Non-unitary Components, and Feed-forward Configurators using Parameter and Expression objects.
    • Noise Modeling: Define real-world noise parameters for inputs, circuits, and detectors via a Noise Model.
    • Simulation: Run simulations using different layers, including perfect simulations via Simulation Back-ends or noisy/non-unitary simulations via the Simulator layer.
    • Computation Control: Run computations locally using SimulatedComputer or remotely using RemoteComputer, and manage tasks with ExecutionGroup.
  2. Use the SLAP backend for memory-efficient amplitude computation

    main

    The SLAP (Simulator of LAttice of Polynomials) backend computes all output probability amplitudes simultaneously by iterating over a lattice of intermediary results. It is designed to be more memory-efficient than SLOS (requiring $2^n$ complex values).

    Best for: Scenarios where $m \gg n$ (many more modes than photons) and you need probability amplitudes with lower memory overhead than SLOS. Status: Under development.

  3. Register classes with fixed data members

    main

    If a class can be reconstructed simply by assigning specific attributes, use the 'fixed data members' strategy. This is the simplest form of registration.

    When using this method, Perceval creates an uninitialized instance using Class.__new__ and then assigns the saved attributes. Note that __init__ is not called during deserialization.

    Attributes can be passed directly to register_class or declared within the class itself using class_serial_members.

    from perceval.serialization import Serialization
    
    # Option 1: Pass members to the registration function
    class Point:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
    Serialization.register_class(Point, ["x", "y"], tag="Point")
    
    # Option 2: Declare members within the class
    class Point:
        class_serial_members = ["x", "y"]
        class_tag = "Point"
        class_version = 0
    
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
    Serialization.register_class(Point)
  4. Use the SLOS backend for strong linear optical simulation

    main

    The SLOS (Strong Linear Optical Simulation) backend is designed for computing the full distribution of a circuit. It unfolds the full computation path in memory.

    Best for: High-fidelity strong simulations where you need probability amplitudes. Limitation: Extremely high memory usage. It is typically limited to circuits with $\approx 20$ photons on personal computers and $\approx 24$ photons on super-computers.

  5. How Execution works in Perceval

    main

    An Execution is the object responsible for running a Computation on a Computer and retrieving its results. It abstracts the complexity of execution, manages intermediate variables, and provides monitoring capabilities. It offers a unified interface regardless of whether the Computer is local or remote, supporting both synchronous and asynchronous execution modes.

    Executions are typically created via an ExecutionFactory, which links a Computer and an Experiment (or a specific Computation/ComputationIterator).

    import perceval as pcvl
    
    # Standard way to create an execution via a factory
    experiment = pcvl.Experiment(pcvl.BS())
    experiment.with_input(pcvl.BasicState("|1,1>"))
    computer = pcvl.SimulatedComputer("SLOS")
    factory = pcvl.ExecutionFactory(computer, experiment)
    execution = factory.sample_count
  6. Use the Naive and NaiveApprox backends for single output probabilities

    main

    The Naive backend implements direct permanent calculation (using Ryser's or Glynn's algorithms) and is optimized with multithreading and SIMD vectorization.

    Naive: Best for exact single output probability computation with low memory cost. Supports $n \approx 30$.

    NaiveApprox: Uses the Gurvits estimate to approximate the permanent. It is useful for estimating probabilities at high photon counts where exact calculation is too slow.

    Features of NaiveApprox:

    • Provides a 99% confidence interval on the probability.
    • Provides a 99% sure error bound on the amplitude.
    • Accuracy can be increased by increasing the iteration count.
  7. Manage multiple executions with ExecutionGroup

    main

    The ExecutionGroup class manages a named collection of Execution objects. It allows you to split large experiments into multiple executions that can be launched across different Python sessions.

    Key Capabilities

    • Persistence: Groups are stored locally. Creating an ExecutionGroup with an existing name loads the previously stored group.
    • Hybrid Support: Can contain both local and remote executions.
    • Execution Modes: Supports sequential (run_sequential) or parallel (run_parallel) execution, as well as rerunning failed tasks.
    • Monitoring: Provides methods to track progress and retrieve results.

    Storage Warning

    By default, execution groups are stored in an execution_groups directory under the current directory. These files can grow large and are not automatically removed; you must delete them manually if they are no longer needed. You can specify a custom storage directory during instantiation.

    Retrieval Requirements

    To retrieve an existing group, both the directory and the name must match the original values. Additionally, if the group contains remote executions, you must provide the correct RemoteConfig to access them, as credentials are not stored with the group.

    import perceval as pcvl
    
    # Create a new group
    group = pcvl.ExecutionGroup("my_experiment_group")
    
    # Or load an existing group by name
    existing_group = pcvl.ExecutionGroup("my_experiment_group")
  8. Use the MPS backend for approximate state evolution

    main

    The MPS (Matrix Product State) backend uses tensor network simulation to provide an approximation of the output states. Instead of computing the whole unitary, it performs approximate state evolution component-by-component.

    How it works: States are represented as tensors. The approximation is controlled by the bond dimension (the dimension of the matrices used in the tensors).

    Best for: Large circuits where an approximate simulation is acceptable.

  9. Visualize Experiments with Ports, Detectors, and Heralds

    main

    An Experiment can be visualized using pdisplay. The rendering changes based on the components defined within the experiment:

    • Ports: Defined via exp.add_port(...). Represented by mode numbers encapsulated in rectangles.
    • Detectors: Defined via exp.add(..., pcvl.Detector.type()). They appear on the right of the circuit with specific shapes:
      • PNR: Half-circle
      • PPNR: Polygon
      • Threshold: Triangle
    • Heralds: Displayed using half-circles with their value inside. They hide part of the optical path to stay close to the components they are used in.
    • Input State: If an input state (like BasicState) is provided, photons are displayed at the left of the experiment (typically in SVG format).
    >>> exp = pcvl.Experiment("SLOS", mzi)
    >>> exp.add_port(0, pcvl.Port(pcvl.Encoding.DUAL_RAIL, "two modes"), location=pcvl.PortLocation.INPUT)
    >>> exp.add_port(0, pcvl.Port(pcvl.Encoding.RAW, "one mode"), location=pcvl.PortLocation.OUTPUT)
    >>> pcvl.pdisplay(exp, recursive=True)
  10. Understand the difference between Sampling and Strong Simulation

    main

    Perceval provides two main modes of simulation:

    1. Sampling (Weak Simulation): Produces output states one at a time, mimicking how ideal detectors observe a physical circuit. It does not provide the full output distribution or the nature of the mixture states, but rather individual observations. This is useful for Boson Sampling tasks.

    2. Strong Simulation: Provides access to the complete probability distribution and the exact nature of the output state. This allows you to know the exact expected probability of detecting photons on a specific port, rather than an estimation.

    Key distinction: Probability Amplitude Strong simulations can provide the probability amplitude, which is necessary for further state evolution or analyzing polarization. Some backends only provide probabilities, while others provide the full amplitude.

  11. Use PersistentData to save and store data across launches

    main

    The PersistentData class provides a mechanism to save and retrieve data between different Perceval sessions. It is primarily used by the library to persist RemoteConfig and ExecutionGroup objects.

    Important Considerations:

    • Disk Usage: The folder created by PersistentData is never emptied automatically. Frequent use of features relying on this class can lead to significant disk space consumption over time.
    • Isolation: By default, the storage folder is created within the user's home directory, meaning persistent data is not shared between different system users.
    import perceval as pcvl
    pdata = pcvl.PersistentData()
    # Data is now available across different Perceval launches