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>