Source code for qurry.process.utils.dummy

"""Post Processing - Utils - Toolkits for Dummy Case
(:mod:`qurry.process.utils.dummy`)

"""

from typing import Callable, Optional
import random
import numpy as np

from ..availability import (
    availablility,
    default_postprocessing_backend,
    PostProcessingBackendLabel,
)
from ..exceptions import PostProcessingRustImportError, PostProcessingRustUnavailableWarning

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

    make_two_bit_str_32_rust_source = dummy.make_two_bit_str_32  # type: ignore
    make_dummy_case_32_rust_source = dummy.make_dummy_case_32  # type: ignore
    make_two_bit_str_unlimit_rust_source = dummy.make_two_bit_str_unlimit  # type: ignore

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

    def make_two_bit_str_32_rust_source(*args, **kwargs):
        """Dummy function for make_two_bit_str_32_rust_source."""
        raise PostProcessingRustImportError(
            "Rust is not available, using python to calculate make_two_bit_str."
            + f" More infomation about this error: {FAILED_RUST_IMPORT}",
        )

    def make_dummy_case_32_rust_source(*args, **kwargs):
        """Dummy function for make_dummy_case_rust_source."""
        raise PostProcessingRustImportError(
            "Rust is not available, using python to calculate make_dummy_case."
            + f" More infomation about this error: {FAILED_RUST_IMPORT}",
        )

    def make_two_bit_str_unlimit_rust_source(*args, **kwargs):
        """Dummy function for make_two_bit_str_unlimit_rust_source."""
        raise PostProcessingRustImportError(
            "Rust is not available, using python to calculate make_two_bit_str."
            + f" More infomation about this error: {FAILED_RUST_IMPORT}",
        )


BACKEND_AVAILABLE = availablility(
    "utils.dummy",
    [
        ("Rust", RUST_AVAILABLE, FAILED_RUST_IMPORT),
    ],
)

DEFAULT_PROCESS_BACKEND = default_postprocessing_backend(
    RUST_AVAILABLE,
    False,
)


[docs] def make_two_bit_str_32_py( bitlen: int, num: Optional[int] = None, ) -> list[str]: """Make a list of bit strings with length of `num`. Args: bitlen (int): bit string length. num (Optional[int]): The number of bit strings. Returns: list[str]: The list of bit strings. """ ultmax = 31 is_less_than_16 = False less_slice = 0 if num is None: logged_num = ultmax real_num = 2**ultmax else: if num < 16: is_less_than_16 = True less_slice = num logged_num = 4 real_num = 16 else: logged_num = np.log2(num) real_num = num if logged_num > ultmax: raise ValueError(f"num should be less than {2**ultmax} for safety reason.") def generate_bits(num: int, bits: Optional[list[str]] = None) -> list[str]: if not isinstance(num, int): raise ValueError("num should be an integer.") bits = [""] if bits is None else bits if num == 0: return bits recursive_bits = generate_bits(num - 1, bits) return ["0" + item for item in recursive_bits] + ["1" + item for item in recursive_bits] if bitlen <= logged_num: result = generate_bits(bitlen) if is_less_than_16: random.shuffle(result) return result[:less_slice] return result less_bitlen = bitlen - int(logged_num) - 1 raw_content = generate_bits(int(logged_num)) len_raw_content = len(raw_content) assert ( 2 ** int(logged_num) == len_raw_content ), f"2**int(logged_num) == len_raw_content: {2**int(logged_num)} == {len_raw_content}" assert 2 * len_raw_content >= real_num >= len_raw_content, ( "2*len_raw_content >= real_num >= len_raw_content: " + f"{2 * len_raw_content} >= {real_num} >= {len_raw_content}" ) first_filler = ["0", "1"] if np.random.rand() > 0.5 else ["1", "0"] filler_h_or_e: Callable[[str, str], str] = lambda ff, item: ( ff + item if np.random.rand() > 0.5 else item + ff ) num_fulfill_content = [filler_h_or_e(first_filler[0], item) for item in raw_content] + [ filler_h_or_e(first_filler[1], item) for item in raw_content[: (real_num - len(raw_content))] ] while less_bitlen >= int(logged_num): num_fulfill_content = [ filler_h_or_e(raw_content[np.random.randint(0, len_raw_content)], item) for item in num_fulfill_content ] less_bitlen -= int(logged_num) if less_bitlen == 0: return num_fulfill_content remain_fillers = generate_bits(less_bitlen) len_remain_fillers = len(remain_fillers) result = [ filler_h_or_e(remain_fillers[np.random.randint(0, len_remain_fillers)], item) for item in num_fulfill_content ] if is_less_than_16: random.shuffle(result) return result[:less_slice] return result
[docs] def make_two_bit_str_unlimit( bitlen: int, backend: PostProcessingBackendLabel = DEFAULT_PROCESS_BACKEND, ) -> list[str]: """Make a list of bit strings with length of `num`. Args: bitlen (int): bit string length. num (Optional[int]): The number of bit strings. backend (PostProcessingBackendLabel): The backend to use. Returns: list[str]: The list of bit strings. """ if bitlen > 32: raise ValueError("bitlen should be less than 32 for safety reason.") if backend == "Rust": if RUST_AVAILABLE: return make_two_bit_str_unlimit_rust_source(bitlen) raise PostProcessingRustUnavailableWarning( "Rust is not available, using python to calculate make_two_bit_str." ) return make_two_bit_str_32_py(bitlen)
# pylint: disable=unnecessary-direct-lambda-call makeTwoBitStrOneLiner: Callable[[int, list[str]], list[str]] = lambda bitlen, bits=[""]: ( (lambda bits: [*["0" + item for item in bits], *["1" + item for item in bits]])( makeTwoBitStrOneLiner(bitlen - 1, bits) ) if bitlen > 0 else bits ) """Make a list of bit strings with length of `num`. But it's an ONE LINE code. Args: bitlen (int): bit string length. bits (list[str], optional): The input for recurrsion. Defaults to ['']. Returns: list[str]: The list of bit strings. """ # pylint: enable=unnecessary-direct-lambda-call
[docs] def make_two_bit_str( bitlen: int, num: Optional[int] = None, backend: PostProcessingBackendLabel = DEFAULT_PROCESS_BACKEND, ) -> list[str]: """Make a list of bit strings with length of `num`. Args: num (int): bit string length. backend (PostProcessingBackendLabel): The backend to use. Returns: list[str]: The list of bit strings. """ if backend == "Rust": if RUST_AVAILABLE: return make_two_bit_str_32_rust_source(bitlen, num) raise PostProcessingRustUnavailableWarning( "Rust is not available, using python to calculate make_two_bit_str." ) return make_two_bit_str_32_py(bitlen, num)
[docs] def make_dummy_case( n_a: int, shot_per_case: int, bitstring_num: Optional[int] = None, backend: PostProcessingBackendLabel = DEFAULT_PROCESS_BACKEND, ) -> dict[str, int]: """Make a dummy case for the experiment. Args: n_a (int): Number of qubits in subsystem A. shot_per_case (int): Number of shots per case. bitstring_num (Optional[int]): Maximum number of bits. backend (PostProcessingBackendLabel): The backend to use. Returns: dict[str, int]: The dummy case. """ if backend == "Rust": if RUST_AVAILABLE: return make_dummy_case_32_rust_source(n_a, shot_per_case, bitstring_num) raise PostProcessingRustUnavailableWarning( "Rust is not available, using python to calculate make_dummy_case." ) bitstring_cases = make_two_bit_str(n_a, bitstring_num, backend) return dict.fromkeys(bitstring_cases, shot_per_case)