Source code for circuit_knitting.utils.conversion

# This code is a Qiskit project.

# (C) Copyright IBM 2022.

# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""
Code for converting types of distributions.

.. currentmodule:: circuit_knitting.utils.conversion

.. autosummary::
   :toctree: ../stubs/

   quasi_to_real
   nearest_probability_distribution
   naive_probability_distribution
   dict_to_array
"""

import numpy as np
from qiskit.utils.deprecation import deprecate_func


[docs] @deprecate_func( removal_timeline="no sooner than CKT v0.8.0", since="0.7.0", package_name="circuit-knitting-toolbox", ) def quasi_to_real(quasiprobability, mode): """ Convert a quasi probability to a valid probability distribution. Args: quasiprobability: The array of quasiprobabilities mode: How to compute the new distribution, either 'nearest' or 'naive' Returns: The converted probability distribution """ if mode == "nearest": return nearest_probability_distribution(quasiprobability=quasiprobability) elif mode == "naive": return naive_probability_distribution(quasiprobability=quasiprobability) else: raise NotImplementedError("%s conversion is not implemented" % mode)
[docs] @deprecate_func( removal_timeline="no sooner than CKT v0.8.0", since="0.7.0", package_name="circuit-knitting-toolbox", ) def nearest_probability_distribution(quasiprobability): """ Convert quasiprobability distribution to the nearest probability distribution. Takes a quasiprobability distribution and maps it to the closest probability distribution as defined by the L2-norm. Method from Smolin et al., Phys. Rev. Lett. 108, 070502 (2012). Args: quasiprobability: The input quasiprobabilities Returns: The converted probability distribution """ sorted_probs, states = zip( *sorted(zip(quasiprobability, range(len(quasiprobability)))) ) num_elems = len(sorted_probs) new_probs = np.zeros(num_elems) beta = 0 diff = 0 for state, prob in zip(states, sorted_probs): temp = prob + beta / num_elems if temp < 0: beta += prob num_elems -= 1 diff += prob * prob else: diff += (beta / num_elems) * (beta / num_elems) new_probs[state] = prob + beta / num_elems return new_probs
[docs] @deprecate_func( removal_timeline="no sooner than CKT v0.8.0", since="0.7.0", package_name="circuit-knitting-toolbox", ) def naive_probability_distribution(quasiprobability): """ Convert quasiprobability dist to probability dist by zero-ing out negative values. Takes a quasiprobability distribution and does the following two steps: 1. Update all negative probabilities to 0 2. Normalize Args: quasiprobability: The input quasiprobabilities Returns: The converted probability distribution """ new_probs = np.where(quasiprobability < 0, 0, quasiprobability) new_probs /= np.sum(new_probs) return new_probs
[docs] @deprecate_func( removal_timeline="no sooner than CKT v0.8.0", since="0.7.0", package_name="circuit-knitting-toolbox", ) def dict_to_array(distribution_dict, force_prob): """ Convert dictionary of shot results to array of distribution. Args: distribution_dict: The dictionary containing the shot information from circuit execution force_prob: Whether to force the distribution to be normalized Returns: The resulting probability information """ state = list(distribution_dict.keys())[0] num_qubits = len(state) num_shots = sum(distribution_dict.values()) cnts = np.zeros(2**num_qubits, dtype=float) for state in distribution_dict: cnts[int(state, 2)] = distribution_dict[state] if abs(sum(cnts) - num_shots) > 1: print( "dict_to_array may be wrong, converted counts = {}, input counts = {}".format( sum(cnts), num_shots ) ) if not force_prob: return cnts else: prob = cnts / num_shots assert abs(sum(prob) - 1) < 1e-10 return prob