Source code for qurry.process.utils.randomized

"""Post Processing - Utils - Randomized (:mod:`qurry.process.utils.randomized`)"""

import warnings
from typing import Union
import numpy as np

from ..availability import availablility
from ..exceptions import PostProcessingRustImportError, PostProcessingRustUnavailableWarning

try:
    from ...boorust import randomized  # type: ignore

    ensemble_cell_rust_source = randomized.ensemble_cell_rust  # type: ignore
    hamming_distance_rust_source = randomized.hamming_distance_rust  # type: ignore

    RUST_AVAILABLE = True
    FAILED_RUST_IMPORT = None
except ImportError as err:
    RUST_AVAILABLE = False
    FAILED_RUST_IMPORT = err

    def ensemble_cell_rust_source(*args, **kwargs):
        """Dummy function for ensemble_cell_rust."""
        raise PostProcessingRustImportError(
            "Rust is not available, using python to calculate ensemble cell."
        ) from FAILED_RUST_IMPORT

    def hamming_distance_rust_source(*args, **kwargs):
        """Dummy function for hamming_distance_rust."""
        raise PostProcessingRustImportError(
            "Rust is not available, using python to calculate hamming distance."
        ) from FAILED_RUST_IMPORT


BACKEND_AVAILABLE = availablility(
    "utils.randomized",
    [
        ("Rust", RUST_AVAILABLE, FAILED_RUST_IMPORT),
        ("Cython", "Depr.", None),
    ],
)


[docs] def hamming_distance(str1: str, str2: str) -> int: """Calculate the Hamming distance between two bit strings. Args: str1 (str): First string. str2 (str): Second string. Returns: int: Distance between strings. Raises: ValueError: Strings not same length. """ if len(str1) != len(str2): raise ValueError("Strings not same length.") return sum(s1 != s2 for s1, s2 in zip(str1, str2))
[docs] def hamming_distance_rust(str1: str, str2: str) -> int: """Calculate the Hamming distance between two bit strings. Args: str1 (str): First string. str2 (str): Second string. Returns: int: Distance between strings. Raises: VisualizationError: Strings not same length. """ if RUST_AVAILABLE: return hamming_distance_rust_source(str1, str2) warnings.warn( "Rust is not available, using python to calculate ensemble cell." + f" Check: {FAILED_RUST_IMPORT}", PostProcessingRustUnavailableWarning, ) return hamming_distance(str1, str2)
[docs] def ensemble_cell( s_i: str, s_i_meas: int, s_j: str, s_j_meas: int, a_num: int, shots: int, ) -> np.float64: """Calculate the value of two counts from qubits in ensemble average. Args: s_i (str): First count's qubits arrange. s_i_meas (int): First count. s_j (str): Second count's qubits arrange. s_j_meas (int): Second count. a_num (int): Degree of freedom. shots (int): Shots of executation. Returns: float: the value of two counts from qubits in ensemble average. """ diff = sum(s1 != s2 for s1, s2 in zip(s_i, s_j)) # hamming_distance(sAi, sAj) tmp = ( np.float_power(2, a_num, dtype=np.float64) * np.float_power(-2, -diff, dtype=np.float64) * (np.float64(s_i_meas) / shots) * (np.float64(s_j_meas) / shots) ) return tmp
[docs] def ensemble_cell_rust( s_i: str, s_i_meas: int, s_j: str, s_j_meas: int, a_num: int, shots: int, ) -> Union[float, np.float64]: """Calculate the value of two counts from qubits in ensemble average by Rust. Args: s_i (str): First count's qubits arrange. s_i_meas (int): First count. s_j (str): Second count's qubits arrange. s_j_meas (int): Second count. a_num (int): Degree of freedom. shots (int): Shots of executation. Returns: float: the value of two counts from qubits in ensemble average. """ if RUST_AVAILABLE: return ensemble_cell_rust_source(s_i, s_i_meas, s_j, s_j_meas, a_num, shots) warnings.warn( "Rust is not available, using python to calculate ensemble cell." + f" Check: {FAILED_RUST_IMPORT}", PostProcessingRustUnavailableWarning, ) return ensemble_cell(s_i, s_i_meas, s_j, s_j_meas, a_num, shots)