From fc1162a109250092d554a5846d67f262b019750e Mon Sep 17 00:00:00 2001 From: Anthony Walsh Date: Mon, 29 Jun 2026 11:46:34 +0200 Subject: [PATCH 1/4] Rename loss_mitigation.py to photon_recycling.py --- perceval/runtime/error_mitigation/__init__.py | 2 +- .../{loss_mitigation.py => photon_recycling.py} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename perceval/runtime/error_mitigation/{loss_mitigation.py => photon_recycling.py} (98%) diff --git a/perceval/runtime/error_mitigation/__init__.py b/perceval/runtime/error_mitigation/__init__.py index 077c009a1..d71b3e670 100644 --- a/perceval/runtime/error_mitigation/__init__.py +++ b/perceval/runtime/error_mitigation/__init__.py @@ -27,6 +27,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from .loss_mitigation import photon_recycling, PhotonRecycling +from .photon_recycling import photon_recycling, PhotonRecycling from .abstract_mitigation import AbstractMitigation from .compilation_averaging import CompilationAveraging diff --git a/perceval/runtime/error_mitigation/loss_mitigation.py b/perceval/runtime/error_mitigation/photon_recycling.py similarity index 98% rename from perceval/runtime/error_mitigation/loss_mitigation.py rename to perceval/runtime/error_mitigation/photon_recycling.py index 75a696a38..e3c605dd0 100644 --- a/perceval/runtime/error_mitigation/loss_mitigation.py +++ b/perceval/runtime/error_mitigation/photon_recycling.py @@ -39,7 +39,7 @@ from ..computation import Computation from .abstract_mitigation import AbstractMitigation -from ._loss_mitigation_utils import _gen_lossy_dists, _get_avg_exp_from_uni_dist, _generate_one_photon_per_mode_mapping +from .utils._photon_recycling import _gen_lossy_dists, _get_avg_exp_from_uni_dist, _generate_one_photon_per_mode_mapping def _validate_noisy_input(noisy_input: BSCount | BSDistribution, ideal_photon_count: int): From 2bd48998232626b398e58ba626525197fa331ff0 Mon Sep 17 00:00:00 2001 From: Anthony Walsh Date: Mon, 29 Jun 2026 11:49:30 +0200 Subject: [PATCH 2/4] Move photon recycling utils file to utils folder. --- .../{_loss_mitigation_utils.py => utils/_photon_recycling.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename perceval/runtime/error_mitigation/{_loss_mitigation_utils.py => utils/_photon_recycling.py} (100%) diff --git a/perceval/runtime/error_mitigation/_loss_mitigation_utils.py b/perceval/runtime/error_mitigation/utils/_photon_recycling.py similarity index 100% rename from perceval/runtime/error_mitigation/_loss_mitigation_utils.py rename to perceval/runtime/error_mitigation/utils/_photon_recycling.py From 80658b0e148062c6ae1ababb38f76a651da1434a Mon Sep 17 00:00:00 2001 From: Anthony Walsh Date: Mon, 29 Jun 2026 15:56:04 +0200 Subject: [PATCH 3/4] Add LossBalancing. --- .../error_mitigation/loss_balancing.py | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 perceval/runtime/error_mitigation/loss_balancing.py diff --git a/perceval/runtime/error_mitigation/loss_balancing.py b/perceval/runtime/error_mitigation/loss_balancing.py new file mode 100644 index 000000000..2ebd44dc0 --- /dev/null +++ b/perceval/runtime/error_mitigation/loss_balancing.py @@ -0,0 +1,90 @@ +# MIT License +# +# Copyright (c) 2022 Quandela +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# As a special exception, the copyright holders of exqalibur library give you +# permission to combine exqalibur with code included in the standard release of +# Perceval under the MIT license (or modified versions of such code). You may +# copy and distribute such a combined system following the terms of the MIT +# license for both exqalibur and Perceval. This exception for the usage of +# exqalibur is limited to the python bindings used by Perceval. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from copy import copy +from math import prod + +from perceval.utils import BSDistribution, ConversionHelper, NoiseModel +from perceval.utils.constants import KEY_RESULTS + +from ..computation import Computation +from .abstract_mitigation import AbstractMitigation + + +class LossBalancing(AbstractMitigation): + """ + Output loss balancing + + Correct biasing in results due to non-uniform loss at the output of the PIC. + """ + + APPLY_MIN_PHOTONS = False + APPLY_LOGICAL_SELECTION = False + + def extend_computation( + self, + computation: Computation, + noise: NoiseModel + ) -> list[Computation]: + return [computation] + + def _parse_results( + self, + computation: Computation, + results: list[dict], + noise: NoiseModel + ) -> dict: + res = copy(results[0]) + ratios = ... # TODO: Get the loss ratios data from QPU + + assert all(ratio > 0 for ratio in ratios), ( + "Bad calibration has led to invalid output transmittances." + ) + + dist = ConversionHelper.convert_to( + "probs", + res[KEY_RESULTS], + **computation.parameters, + ) + + # LossBalancing should be applied before the results are de-compiled + assert len(ratios) == dist.m, "Loss ratios do not match the distribution lengths." + + balanced = BSDistribution() + for state, prob in dist.items(): + balanced.add( + state, prob * prod( + (1 / ratios[i]) ** n for i, n in enumerate(state) + ), + ) + + if len(balanced): + balanced.normalize() + res[KEY_RESULTS] = balanced + return res From ddb0e6030ce0c3315964e85ae9e260dafe71fb02 Mon Sep 17 00:00:00 2001 From: Anthony Walsh Date: Mon, 29 Jun 2026 16:05:08 +0200 Subject: [PATCH 4/4] Add LossBalancing to __init__ --- perceval/runtime/error_mitigation/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/perceval/runtime/error_mitigation/__init__.py b/perceval/runtime/error_mitigation/__init__.py index d71b3e670..5cd976e28 100644 --- a/perceval/runtime/error_mitigation/__init__.py +++ b/perceval/runtime/error_mitigation/__init__.py @@ -30,3 +30,4 @@ from .photon_recycling import photon_recycling, PhotonRecycling from .abstract_mitigation import AbstractMitigation from .compilation_averaging import CompilationAveraging +from .loss_balancing import LossBalancing