1.3 Randomized Measurement with Error Mitigation#

Entanglement Entropy#

This method is based on Probing Rényi entanglement entropy via randomized measurements with deplorizing error mitigation by Simple mitigation of global depolarizing errors in quantum simulations.

randomized_entangled_entropy_mitigated#

Similar to randomized_entangled_entropy introduced in section 3.1.1 a, this function is used to calculate the entropy of a quantum state, but additionally, mitigate the depolarizing error. You can call the function randomized_entangled_entropy_mitigated from qurry.process.randomized_measure. In order to perform the error mitigation, this function requires the measurement outcomes of the all system as the baseline.
If you already have data at hand, you can prepare a namedtuple ExistedAllSystemInfo like the following, which can be imported from qurry.process.randomized_measure :

class ExistedAllSystemInfo(NamedTuple):
    """Existed all system information"""

    source: str
    """The source of all system."""

    purityAllSys: GenericFloatType
    """The purity of the all system."""
    entropyAllSys: GenericFloatType
    """The entropy of the all system."""
    puritySDAllSys: GenericFloatType
    """The standard deviation of the purity of the all system."""
    entropySDAllSys: GenericFloatType
    """The standard deviation of the entropy of the all system."""
    purityCellsAllSys: Union[dict[int, np.float64], dict[int, float]]
    """The purity of each single count."""

    # new added
    num_classical_registers_all_sys: int
    """The number of classical registers of all system."""
    classical_registers_all_sys: Optional[list[int]]
    """The list of the index of the selected classical registers."""
    classical_registers_actually_all_sys: list[int]
    """The list of the index of the selected classical registers which is actually used."""

    # refactored
    taking_time_all_sys: GenericFloatType
    """The calculation time of the all system."""

And assign it into the argument existed_all_system of the function randomized_entangled_entropy_mitigated to save a lot of time on mitigating purities of all partitions.

This function requires only three arguments: shots, counts, and selected_classical_registers. All other arguments are optional.

Note that selected_classical_registers expects a list of bitstring indices, NOT qubit indices, as these are distinct.

The following is the arguments of the function:

def randomized_entangled_entropy_mitigated(
    shots: int,
    counts: list[dict[str, int]],
    selected_classical_registers: Optional[list[int]] = None,
    backend: PostProcessingBackendLabel = DEFAULT_PROCESS_BACKEND,
    existed_all_system: Optional[ExistedAllSystemInfo] = None,
    pbar: Optional[tqdm.tqdm] = None,
) -> EntangledEntropyResultMitigated:
    """Calculate entangled entropy.

    Args:
        shots (int):
            Shots of the counts.
        counts (list[dict[str, int]]):
            Counts from randomized measurement results.
        degree (Optional[Union[tuple[int, int], int]]):
            The range of partition.
        measure (Optional[tuple[int, int]], optional):
            The range that implemented the measuring gate.
            If not specified, then use all qubits.
            This will affect the range of partition
            when you not implement the measuring gate on all qubit.
            Defaults to None.
        backend (PostProcessingBackendLabel, optional):
            Backend for the post-processing.
            Defaults to DEFAULT_PROCESS_BACKEND.
        workers_num (Optional[int], optional):
            Number of multi-processing workers, it will be ignored if backend is Rust.
            if sets to 1, then disable to using multi-processing;
            if not specified, then use the number of all cpu counts by `os.cpu_count()`.
            This only works for Python and Cython backend.
            Defaults to None.
        existed_all_system (Optional[ExistingAllSystemSource], optional):
            Existing all system source.
            If there is known all system result,
            then you can put it here to save a lot of time on calculating all system
            for not matter what partition you are using,
            their all system result is the same.
            All system source should contain
            `purityCellsAllSys`, `bitStringRange`, `measureActually`, `source` for its name.
            This can save a lot of time
            Defaults to None.
        pbar (Optional[tqdm.tqdm], optional):
            The progress bar API, you can use put a :cls:`tqdm` object here.
            This function will update the progress bar description.
            Defaults to None.

    Returns:
        RandomizedEntangledEntropyMitigatedComplex:
            A dictionary contains purity, entropy,
            a list of each overlap, puritySD, degree,
            actual measure range, bitstring range and more.
    """

This function returns a dictionary that contains the entropy, purity, and other relevant information. The return dict contains the following variables:

class EntangledEntropyResultMitigated(EntangledEntropyResult):
    """The return type of the post-processing for entangled entropy with error mitigation."""
    # This TyedDict inherit from EntangledEntropyResult

    # refactored
    all_system_source: Union[str, Literal["independent", "null_counts"]]
    """The name of source of all system.

    - independent: The all system is calculated independently.
    - null_counts: No counts exist.
    """

    purityAllSys: GenericFloatType
    """The purity of the all system."""
    entropyAllSys: GenericFloatType
    """The entropy of the all system."""
    puritySDAllSys: GenericFloatType
    """The standard deviation of the purity of the all system."""
    entropySDAllSys: GenericFloatType
    """The standard deviation of the entropy of the all system."""
    purityCellsAllSys: Union[dict[int, np.float64], dict[int, float]]
    """The purity of each single count."""

    # new added
    num_classical_registers_all_sys: int
    """The number of classical registers of all system."""
    classical_registers_all_sys: Optional[list[int]]
    """The list of the index of the selected classical registers."""
    classical_registers_actually_all_sys: list[int]
    """The list of the index of the selected classical registers which is actually used."""

    # mitigated info
    errorRate: GenericFloatType
    """The error rate of the measurement from depolarizing error migigation calculated."""
    mitigatedPurity: GenericFloatType
    """The mitigated purity."""
    mitigatedEntropy: GenericFloatType
    """The mitigated entropy."""

    # refactored
    taking_time_all_sys: GenericFloatType
    """The calculation time of the all system."""

class EntangledEntropyResult(TypedDict, total=False):
    """The return type of the post-processing for entangled entropy."""

    purity: GenericFloatType
    """The purity of the system."""
    entropy: GenericFloatType
    """The entropy of the system."""
    puritySD: GenericFloatType
    """The standard deviation of the purity."""
    entropySD: GenericFloatType
    """The standard deviation of the entropy."""
    purityCells: Union[dict[int, np.float64], dict[int, float]]
    """The purity of each single count."""
    # new added
    num_classical_registers: int
    """The number of classical registers."""
    classical_registers: Optional[list[int]]
    """The list of the index of the selected classical registers."""
    classical_registers_actually: list[int]
    """The list of the index of the selected classical registers which is actually used."""
    # refactored
    counts_num: int
    """The number of counts."""
    taking_time: GenericFloatType
    """The calculation time."""

Dummy Data#

from qurry.capsule import quickRead

easy_dummy: dict[str, dict[str, int]] = quickRead("../easy-dummy.json")
large_dummy_list = [easy_dummy["0"] for _ in range(100)]

Simple Example#

from qurry.process.randomized_measure import (
    randomized_entangled_entropy_mitigated,
    EntangledEntropyResultMitigated,
    ExistedAllSystemInfo,
)

test_result_1_2_1 = randomized_entangled_entropy_mitigated(
    4096, large_dummy_list, list(range(6))
)
from pprint import pprint

print("| result of randomized_entangled_entropy except for purityCells")
pprint({k: v for k, v in test_result_1_2_1.items() if "purityCells" not in k})
# "purityCells" is too long we skip it here
print()
print("| result of randomized_entangled_entropy[purityCells]")
print(test_result_1_2_1["purityCells"][0])
print(test_result_1_2_1["purityCells"][1])
print()
print("| result of randomized_entangled_entropy[purityCellsAllSys]")
print(test_result_1_2_1["purityCellsAllSys"][0])
print(test_result_1_2_1["purityCellsAllSys"][1])
| result of randomized_entangled_entropy except for purityCells
{'all_system_source': 'independent',
 'classical_registers': [0, 1, 2, 3, 4, 5],
 'classical_registers_actually': [0, 1, 2, 3, 4, 5],
 'classical_registers_actually_all_sys': [0, 1, 2, 3, 4, 5, 6, 7],
 'classical_registers_all_sys': None,
 'counts_num': 100,
 'entropy': np.float64(-0.08786065308638322),
 'entropyAllSys': np.float64(0.9461940705953849),
 'entropySD': np.float64(0.0),
 'entropySDAllSys': np.float64(0.0),
 'errorRate': np.float64(0.2808939301105586),
 'mitigatedEntropy': np.float64(-1.0290289944568636),
 'mitigatedPurity': np.float64(2.0406503299038543),
 'num_classical_registers': 8,
 'num_classical_registers_all_sys': 8,
 'purity': np.float64(1.0627930164337158),
 'purityAllSys': np.float64(0.5189998149871826),
 'puritySD': np.float64(0.0),
 'puritySDAllSys': np.float64(0.0),
 'taking_time': 0.002301569,
 'taking_time_all_sys': 0.009348952}

| result of randomized_entangled_entropy[purityCells]
1.0627930164337158
1.0627930164337158

| result of randomized_entangled_entropy[purityCellsAllSys]
0.5189998149871826
0.5189998149871826

With Existing All System Data#

test_result_1_2_2 = randomized_entangled_entropy_mitigated(
    4096,
    large_dummy_list,
    list(range(6)),
    existed_all_system=ExistedAllSystemInfo(
        source="from_previous_result:test_result_1_2_1",
        purityAllSys=test_result_1_2_1["purityAllSys"],
        entropyAllSys=test_result_1_2_1["entropyAllSys"],
        puritySDAllSys=test_result_1_2_1["puritySDAllSys"],
        entropySDAllSys=test_result_1_2_1["entropySDAllSys"],
        purityCellsAllSys=test_result_1_2_1["purityCellsAllSys"],
        num_classical_registers_all_sys=test_result_1_2_1[
            "num_classical_registers_all_sys"
        ],
        classical_registers_all_sys=test_result_1_2_1["classical_registers_all_sys"],
        classical_registers_actually_all_sys=test_result_1_2_1[
            "classical_registers_actually_all_sys"
        ],
        taking_time_all_sys=test_result_1_2_1["taking_time_all_sys"],
    ),
)
from pprint import pprint

print("| result of randomized_entangled_entropy except for purityCells")
pprint({k: v for k, v in test_result_1_2_2.items() if "purityCells" not in k})
# "purityCells" is too long we skip it here
print()
print("| result of randomized_entangled_entropy[purityCells]")
print(test_result_1_2_2["purityCells"][0])
print(test_result_1_2_2["purityCells"][1])
print()
print("| result of randomized_entangled_entropy[purityCellsAllSys]")
print(test_result_1_2_2["purityCellsAllSys"][0])
print(test_result_1_2_2["purityCellsAllSys"][1])
print()
print("| You can see takingTimeAllSys is 0 for we use existed_all_system")
print(test_result_1_2_2["taking_time_all_sys"])
| result of randomized_entangled_entropy except for purityCells
{'all_system_source': 'from_previous_result:test_result_1_2_1',
 'classical_registers': [0, 1, 2, 3, 4, 5],
 'classical_registers_actually': [0, 1, 2, 3, 4, 5],
 'classical_registers_actually_all_sys': [0, 1, 2, 3, 4, 5, 6, 7],
 'classical_registers_all_sys': None,
 'counts_num': 100,
 'entropy': np.float64(-0.08786065308638322),
 'entropyAllSys': np.float64(0.9461940705953849),
 'entropySD': np.float64(0.0),
 'entropySDAllSys': np.float64(0.0),
 'errorRate': np.float64(0.2808939301105586),
 'mitigatedEntropy': np.float64(-1.0290289944568636),
 'mitigatedPurity': np.float64(2.0406503299038543),
 'num_classical_registers': 8,
 'num_classical_registers_all_sys': 8,
 'purity': np.float64(1.0627930164337158),
 'purityAllSys': np.float64(0.5189998149871826),
 'puritySD': np.float64(0.0),
 'puritySDAllSys': np.float64(0.0),
 'taking_time': 0.001629802,
 'taking_time_all_sys': 0.009348952}

| result of randomized_entangled_entropy[purityCells]
1.0627930164337158
1.0627930164337158

| result of randomized_entangled_entropy[purityCellsAllSys]
0.5189998149871826
0.5189998149871826

| You can see takingTimeAllSys is 0 for we use existed_all_system
0.009348952

Integration wit your own progress bar#

from tqdm import tqdm

all_counts_progress_01 = tqdm(
    [
        (4096, large_dummy_list, list(range(6))),
        (4096, large_dummy_list, list(range(2, 8))),
        (4096, large_dummy_list, list(range(7))),
        (4096, large_dummy_list, list(range(0, 7))),
        (4096, large_dummy_list, [0, 1, 2, 6, 7]),
        (4096, large_dummy_list, [3, 4, 5, 6, 7, 0, 1]),
    ],
    bar_format="| {desc} - {elapsed} < {remaining}",
)

test_result_1_2_3 = []
for tmp_shot, tmp_counts, tmp_partition in all_counts_progress_01:
    print(tmp_partition)
    test_result_1_2_3.append(
        randomized_entangled_entropy_mitigated(
            tmp_shot,
            tmp_counts,
            tmp_partition,
            existed_all_system=(
                None
                if len(test_result_1_2_3) == 0
                else ExistedAllSystemInfo(
                    source="from_previous_result:test_result_1_2_1",
                    purityAllSys=test_result_1_2_1["purityAllSys"],
                    entropyAllSys=test_result_1_2_1["entropyAllSys"],
                    puritySDAllSys=test_result_1_2_1["puritySDAllSys"],
                    entropySDAllSys=test_result_1_2_1["entropySDAllSys"],
                    purityCellsAllSys=test_result_1_2_1["purityCellsAllSys"],
                    num_classical_registers_all_sys=test_result_1_2_1[
                        "num_classical_registers_all_sys"
                    ],
                    classical_registers_all_sys=test_result_1_2_1[
                        "classical_registers_all_sys"
                    ],
                    classical_registers_actually_all_sys=test_result_1_2_1[
                        "classical_registers_actually_all_sys"
                    ],
                    taking_time_all_sys=test_result_1_2_1["taking_time_all_sys"],
                )
            ),
            pbar=all_counts_progress_01,
        )
    )
    print(f"| partition: {tmp_partition}")
    print("| - taking_time:", test_result_1_2_3[-1]["taking_time"])
    print("| - taking_time_all_sys:", test_result_1_2_3[-1]["taking_time_all_sys"])
|  - 00:00 < ?
| Calculate selected classical registers: [0, 1, 2, 3, 4, 5]. - 00:00 < ?
| Calculate all system by Rust. - 00:00 < ?                              
| Preparing error mitigation of selected qubits: [0, 1, 2, 3, 4, 5] - 00:00 < ?
| Calculate selected classical registers: [2, 3, 4, 5, 6, 7]. - 00:00 < ?      
| Using existing all system from 'from_previous_result:test_result_1_2_1' - 00:00 < ?
| Preparing error mitigation of selected qubits: [2, 3, 4, 5, 6, 7] - 00:00 < ?      
| Calculate selected classical registers: [0, 1, 2, 3, 4, 5, 6]. - 00:00 < ?   
| Using existing all system from 'from_previous_result:test_result_1_2_1' - 00:00 < ?
| Preparing error mitigation of selected qubits: [0, 1, 2, 3, 4, 5, 6] - 00:00 < ?   
| Calculate selected classical registers: [0, 1, 2, 3, 4, 5, 6]. - 00:00 < ?      
| Using existing all system from 'from_previous_result:test_result_1_2_1' - 00:00 < ?
| Preparing error mitigation of selected qubits: [0, 1, 2, 3, 4, 5, 6] - 00:00 < ?   
| Calculate selected classical registers: [0, 1, 2, 6, 7]. - 00:00 < ?            
| Using existing all system from 'from_previous_result:test_result_1_2_1' - 00:00 < ?
| Preparing error mitigation of selected qubits: [0, 1, 2, 6, 7] - 00:00 < ?         
| Calculate selected classical registers: [3, 4, 5, 6, 7, 0, 1]. - 00:00 < ?
| Using existing all system from 'from_previous_result:test_result_1_2_1' - 00:00 < ?
| Preparing error mitigation of selected qubits: [0, 1, 3, 4, 5, 6, 7] - 00:00 < ?   
| Preparing error mitigation of selected qubits: [0, 1, 3, 4, 5, 6, 7] - 00:00 < 00:00
[0, 1, 2, 3, 4, 5]
| partition: [0, 1, 2, 3, 4, 5]
| - taking_time: 0.001631442
| - taking_time_all_sys: 0.008824854
[2, 3, 4, 5, 6, 7]
| partition: [2, 3, 4, 5, 6, 7]
| - taking_time: 0.001749286
| - taking_time_all_sys: 0.009348952
[0, 1, 2, 3, 4, 5, 6]
| partition: [0, 1, 2, 3, 4, 5, 6]
| - taking_time: 0.00362614
| - taking_time_all_sys: 0.009348952
[0, 1, 2, 3, 4, 5, 6]
| partition: [0, 1, 2, 3, 4, 5, 6]
| - taking_time: 0.003957286
| - taking_time_all_sys: 0.009348952
[0, 1, 2, 6, 7]
| partition: [0, 1, 2, 6, 7]
| - taking_time: 0.000907306
| - taking_time_all_sys: 0.009348952
[3, 4, 5, 6, 7, 0, 1]
| partition: [3, 4, 5, 6, 7, 0, 1]
| - taking_time: 0.003640222
| - taking_time_all_sys: 0.009348952

Using Python backend#

It will be slow. Yoy better think twice before using it.

all_counts_progress_02 = tqdm(
    [
        (4096, large_dummy_list, list(range(6))),
        (4096, large_dummy_list, list(range(2, 8))),
        (4096, large_dummy_list, list(range(7))),
        (4096, large_dummy_list, list(range(0, 7))),
        (4096, large_dummy_list, [0, 1, 2, 6, 7]),
        (4096, large_dummy_list, [3, 4, 5, 6, 7, 0, 1]),
    ],
    bar_format="| {desc} - {elapsed} < {remaining}",
)


test_result_1_2_4 = []
for tmp_shot, tmp_counts, tmp_partition in all_counts_progress_02:
    print(tmp_partition)
    test_result_1_2_4.append(
        randomized_entangled_entropy_mitigated(
            tmp_shot,
            tmp_counts,
            tmp_partition,
            existed_all_system=(
                None
                if len(test_result_1_2_3) == 0
                else ExistedAllSystemInfo(
                    source="from_previous_result:test_result_1_2_1",
                    purityAllSys=test_result_1_2_1["purityAllSys"],
                    entropyAllSys=test_result_1_2_1["entropyAllSys"],
                    puritySDAllSys=test_result_1_2_1["puritySDAllSys"],
                    entropySDAllSys=test_result_1_2_1["entropySDAllSys"],
                    purityCellsAllSys=test_result_1_2_1["purityCellsAllSys"],
                    num_classical_registers_all_sys=test_result_1_2_1[
                        "num_classical_registers_all_sys"
                    ],
                    classical_registers_all_sys=test_result_1_2_1[
                        "classical_registers_all_sys"
                    ],
                    classical_registers_actually_all_sys=test_result_1_2_1[
                        "classical_registers_actually_all_sys"
                    ],
                    taking_time_all_sys=test_result_1_2_1["taking_time_all_sys"],
                )
            ),
            pbar=all_counts_progress_02,
            backend="Python",
        )
    )
|  - 00:00 < ?
| Calculate selected classical registers: [0, 1, 2, 3, 4, 5]. - 00:00 < ?
[0, 1, 2, 3, 4, 5]
| Using existing all system from 'from_previous_result:test_result_1_2_1' - 00:02 < ?
| Preparing error mitigation of selected qubits: [5, 4, 3, 2, 1, 0] - 00:02 < ?      
| Preparing error mitigation of selected qubits: [5, 4, 3, 2, 1, 0] - 00:02 < 00:12
| Calculate selected classical registers: [2, 3, 4, 5, 6, 7]. - 00:02 < 00:12      
[2, 3, 4, 5, 6, 7]
| Using existing all system from 'from_previous_result:test_result_1_2_1' - 00:05 < 00:12
| Preparing error mitigation of selected qubits: [7, 6, 5, 4, 3, 2] - 00:05 < 00:12      
| Preparing error mitigation of selected qubits: [7, 6, 5, 4, 3, 2] - 00:05 < 00:11
| Calculate selected classical registers: [0, 1, 2, 3, 4, 5, 6]. - 00:05 < 00:11   
[0, 1, 2, 3, 4, 5, 6]
| Using existing all system from 'from_previous_result:test_result_1_2_1' - 00:09 < 00:11
| Preparing error mitigation of selected qubits: [6, 5, 4, 3, 2, 1, 0] - 00:09 < 00:11   
| Preparing error mitigation of selected qubits: [6, 5, 4, 3, 2, 1, 0] - 00:09 < 00:09
| Calculate selected classical registers: [0, 1, 2, 3, 4, 5, 6]. - 00:09 < 00:09      
[0, 1, 2, 3, 4, 5, 6]
| Using existing all system from 'from_previous_result:test_result_1_2_1' - 00:12 < 00:09
| Preparing error mitigation of selected qubits: [6, 5, 4, 3, 2, 1, 0] - 00:12 < 00:09   
| Preparing error mitigation of selected qubits: [6, 5, 4, 3, 2, 1, 0] - 00:12 < 00:06
| Calculate selected classical registers: [0, 1, 2, 6, 7]. - 00:12 < 00:06            
[0, 1, 2, 6, 7]
| Using existing all system from 'from_previous_result:test_result_1_2_1' - 00:15 < 00:06
| Preparing error mitigation of selected qubits: [7, 6, 2, 1, 0] - 00:15 < 00:06         
| Preparing error mitigation of selected qubits: [7, 6, 2, 1, 0] - 00:15 < 00:03
| Calculate selected classical registers: [3, 4, 5, 6, 7, 0, 1]. - 00:15 < 00:03
[3, 4, 5, 6, 7, 0, 1]
| Using existing all system from 'from_previous_result:test_result_1_2_1' - 00:18 < 00:03
| Preparing error mitigation of selected qubits: [7, 6, 5, 4, 3, 1, 0] - 00:18 < 00:03   
| Preparing error mitigation of selected qubits: [7, 6, 5, 4, 3, 1, 0] - 00:18 < 00:00
| Preparing error mitigation of selected qubits: [7, 6, 5, 4, 3, 1, 0] - 00:18 < 00:00

Post-Process Availablities and Version Info#

from qurry.process.status import AVAIBILITY_STATESHEET

AVAIBILITY_STATESHEET
 | Qurrium version: 0.13.0
---------------------------------------------------------------------------
 ### Qurrium Post-Processing
   - Backend Availability ................... Python Cython Rust   JAX   
 - randomized_measure
   - entangled_entropy.entropy_core_2 ....... Yes    Depr.  Yes    No    
   - entangle_entropy.purity_cell_2 ......... Yes    Depr.  Yes    No    
   - entangled_entropy_v1.entropy_core ...... Yes    Depr.  Yes    No    
   - entangle_entropy_v1.purity_cell ........ Yes    Depr.  Yes    No    
   - wavefunction_overlap.echo_core_2 ....... Yes    Depr.  Yes    No    
   - wavefunction_overlap.echo_cell_2 ....... Yes    Depr.  Yes    No    
   - wavefunction_overlap_v1.echo_core ...... Yes    Depr.  Yes    No    
   - wavefunction_overlap_v1.echo_cell ...... Yes    Depr.  Yes    No    
 - hadamard_test
   - purity_echo_core ....................... Yes    No     Yes    No    
 - magnet_square
   - magnsq_core ............................ Yes    No     Yes    No    
 - string_operator
   - strop_core ............................. Yes    No     Yes    No    
 - classical_shadow
   - rho_m_core ............................. Yes    No     No     Yes   
 - utils
   - randomized ............................. Yes    Depr.  Yes    No    
   - counts_process ......................... Yes    No     Yes    No    
   - bit_slice .............................. Yes    No     Yes    No    
   - dummy .................................. Yes    No     Yes    No    
   - test ................................... Yes    No     Yes    No    
---------------------------------------------------------------------------
   + Yes ...... Working normally.
   + Error .... Exception occurred.
   + No ....... Not supported.
   + Depr. .... Deprecated.
---------------------------------------------------------------------------
by <Hoshi>