diff --git a/perceval/runtime/error_mitigation/__init__.py b/perceval/runtime/error_mitigation/__init__.py index 077c009a1..5cd976e28 100644 --- a/perceval/runtime/error_mitigation/__init__.py +++ b/perceval/runtime/error_mitigation/__init__.py @@ -27,6 +27,7 @@ # 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 +from .loss_balancing import LossBalancing 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 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): 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