classical_shadow
¶
ShadowUnveil - Classical Shadow with The Results of Second Order Renyi Entropy
(qurry.qurrent.classical_shadow
)
References
Note
Predicting many properties of a quantum system from very few measurements -
Huang, Hsin-Yuan and Kueng, Richard and Preskill, John [doi:10.1038/s41567-020-0932-7](
The randomized measurement toolbox -
Elben, Andreas and Flammia, Steven T. and Huang, Hsin-Yuan and Kueng, Richard and Preskill, John and Vermersch, Benoît and Zoller, Peter [doi:10.1038/s42254-022-00535-2](
@article{cite-key,
abstract = {
Predicting the properties of complex,
large-scale quantum systems is essential for developing quantum technologies.
We present an efficient method for constructing an approximate classical
description of a quantum state using very few measurements of the state.
different properties; order
{\$}{\$}{\{}{$\backslash$}mathrm{\{}log{\}}{\}}{$\backslash$},(M){\$}{\$}
measurements suffice to accurately predict M different functions of the state
with high success probability. The number of measurements is independent of
the system size and saturates information-theoretic lower bounds. Moreover,
target properties to predict can be
selected after the measurements are completed.
We support our theoretical findings with extensive numerical experiments.
We apply classical shadows to predict quantum fidelities,
entanglement entropies, two-point correlation functions,
expectation values of local observables and the energy variance of
many-body local Hamiltonians.
The numerical results highlight the advantages of classical shadows relative to
previously known methods.},
author = {Huang, Hsin-Yuan and Kueng, Richard and Preskill, John},
date = {2020/10/01},
date-added = {2024-12-03 15:00:55 +0800},
date-modified = {2024-12-03 15:00:55 +0800},
doi = {10.1038/s41567-020-0932-7},
id = {Huang2020},
isbn = {1745-2481},
journal = {Nature Physics},
number = {10},
pages = {1050--1057},
title = {Predicting many properties of a quantum system from very few measurements},
url = {https://doi.org/10.1038/s41567-020-0932-7},
volume = {16},
year = {2020},
bdsk-url-1 = {https://doi.org/10.1038/s41567-020-0932-7}
}
@article{cite-key,
abstract = {
Programmable quantum simulators and quantum computers are opening unprecedented
opportunities for exploring and exploiting the properties of highly entangled
complex quantum systems. The complexity of large quantum systems is the source
of computational power but also makes them difficult to control precisely or
characterize accurately using measured classical data. We review protocols
for probing the properties of complex many-qubit systems using measurement
schemes that are practical using today's quantum platforms. In these protocols,
a quantum state is repeatedly prepared and measured in a randomly chosen basis;
then a classical computer processes the measurement outcomes to estimate the
desired property. The randomization of the measurement procedure has distinct
advantages. For example, a single data set can be used multiple times to pursue
a variety of applications, and imperfections in the measurements are mapped to
a simplified noise model that can more easily be mitigated.
We discuss a range of cases that have already been realized in quantum devices,
including Hamiltonian simulation tasks, probes of quantum chaos,
measurements of non-local order parameters,
and comparison of quantum states produced in distantly separated
laboratories. By providing a workable method for translating a complex quantum
state into a succinct classical representation that preserves a rich variety of
relevant physical properties, the randomized measurement toolbox strengthens our
ability to grasp and control the quantum world.},
author = {
Elben, Andreas and Flammia, Steven T. and Huang, Hsin-Yuan and Kueng,
Richard and Preskill, John and Vermersch, Beno{\^\i}t and Zoller, Peter},
date = {2023/01/01},
date-added = {2024-12-03 15:06:15 +0800},
date-modified = {2024-12-03 15:06:15 +0800},
doi = {10.1038/s42254-022-00535-2},
id = {Elben2023},
isbn = {2522-5820},
journal = {Nature Reviews Physics},
number = {1},
pages = {9--24},
title = {The randomized measurement toolbox},
url = {https://doi.org/10.1038/s42254-022-00535-2},
volume = {5},
year = {2023},
bdsk-url-1 = {https://doi.org/10.1038/s42254-022-00535-2}
}
arguments
¶
ShadowUnveil - Arguments
(qurry.qurrent.classical_shadow.arguments
)
- class qurry.qurrent.classical_shadow.arguments.ShadowUnveilAnalyzeArgs[source]¶
The input of the analyze method.
- class qurry.qurrent.classical_shadow.arguments.ShadowUnveilArguments(exp_name: str = 'exps', times: int = 100, qubits_measured: list[int] | None = None, registers_mapping: dict[int, int] | None = None, actual_num_qubits: int = 0, unitary_located: list[int] | None = None, random_unitary_seeds: dict[int, dict[int, int]] | None = None)[source]¶
Arguments for the experiment.
- exp_name: str = 'exps'¶
The name of the experiment. Naming this experiment to recognize it when the jobs are pending to IBMQ Service. This name is also used for creating a folder to store the exports. Defaults to ‘experiment’.
- random_unitary_seeds: dict[int, dict[int, int]] | None = None¶
The seeds for all random unitary operator. This argument only takes input as type of dict[int, dict[int, int]]. The first key is the index for the random unitary operator. The second key is the index for the qubit.
If you want to generate the seeds for all random unitary operator, you can use the function generate_random_unitary_seeds in qurry.qurrium.utils.random_unitary.
- registers_mapping: dict[int, int] | None = None¶
The mapping of the classical registers with quantum registers.
The key is the index of the quantum register with the numerical order. The value is the index of the classical register with the numerical order.
- class qurry.qurrent.classical_shadow.arguments.ShadowUnveilMeasureArgs[source]¶
Output arguments for
output()
.- random_unitary_seeds: dict[int, dict[int, int]] | None¶
The seeds for all random unitary operator. This argument only takes input as type of dict[int, dict[int, int]]. The first key is the index for the random unitary operator. The second key is the index for the qubit.
If you want to generate the seeds for all random unitary operator, you can use the function generate_random_unitary_seeds in qurry.qurrium.utils.random_unitary.
- unitary_loc_not_cover_measure: bool¶
Whether the range of the unitary operator is not cover the measure range.
- wave: QuantumCircuit | Hashable | None¶
The key or the circuit to execute.
- class qurry.qurrent.classical_shadow.arguments.ShadowUnveilOutputArgs[source]¶
Output arguments for
output()
.- random_unitary_seeds: dict[int, dict[int, int]] | None¶
The seeds for all random unitary operator. This argument only takes input as type of dict[int, dict[int, int]]. The first key is the index for the random unitary operator. The second key is the index for the qubit.
If you want to generate the seeds for all random unitary operator, you can use the function generate_random_unitary_seeds in qurry.qurrium.utils.random_unitary.
analysis
¶
ShadowUnveil - Analysis
(qurry.qurrent.classical_shadow.analysis
)
- class qurry.qurrent.classical_shadow.analysis.SUAnalysisContent(average_classical_snapshots_rho: dict[int, ndarray[tuple[int, int], dtype[complex128]]], classical_registers_actually: list[int], taking_time: float, mean_of_rho: ndarray[tuple[int, int], dtype[complex128]], purity: float, entropy: float, estimate_of_given_operators: list[ndarray[tuple[int, int], dtype[complex128]]], corresponding_rhos: list[ndarray[tuple[int, ...], dtype[complex128]]], accuracy_prob_comp_delta: float, num_of_estimators_k: int, accuracy_predict_epsilon: float, maximum_shadow_norm: float)[source]¶
The content of the analysis.
- accuracy_predict_epsilon: float¶
The prediction of accuracy, which used the notation \(\epsilon\) and mentioned in Theorem S1 in the supplementary material, the equation (S13) in the supplementary material.
We can calculate the prediction of accuracy \(\epsilon\) from the equation (S13) in the supplementary material, the equation (S13) is as follows, .. math:
N = \frac{34}{\epsilon^2} \max_{1 \leq i \leq M} || O_i - \frac{\text{tr}(O_i)}{2^n} ||_{\text{shadow}}^2
where \(\epsilon\) is the prediction of accuracy, and \(M\) is the number of given operatorsm and \(N\) is the number of classical snapshots. The \(|| O_i - \frac{\text{tr}(O_i)}{2^n} ||_{\text{shadow}}^2\) is maximum shadow norm, which is defined in the supplementary material with value between 0 and 1.
- accuracy_prob_comp_delta: float¶
The probabiltiy complement of accuracy, which used the notation \(\delta\) and mentioned in Theorem S1 in the supplementary material, the equation (S13) in the supplementary material. The probabiltiy of accuracy is \(1 - \delta\).
The number of given operators and the accuracy parameters will be used to decide the number of estimators K from the equation (S13) in the supplementary material.
\[K = 2 \log(2M / \delta)\]where \(\delta\) is the probabiltiy complement of accuracy, and \(M\) is the number of given operators.
But we can see \(K\) will be not the integer value of the result of the equation. So, we will use the ceil value of the result of the equation. And recalculate the probabiltiy complement of accuracy from this new value of \(K\).
- average_classical_snapshots_rho: dict[int, ndarray[tuple[int, int], dtype[complex128]]]¶
The dictionary of Rho M.
- corresponding_rhos: list[ndarray[tuple[int, ...], dtype[complex128]]]¶
The corresponding rho of measurement primitive \(\mathcal{U}\).
- estimate_of_given_operators: list[ndarray[tuple[int, int], dtype[complex128]]]¶
The result of measurement primitive \(\mathcal{U}\).
- maximum_shadow_norm: float¶
The maximum shadow norm, which is defined in the supplementary material with value between 0 and 1. The maximum shadow norm is used to calculate the prediction of accuracy \(\epsilon\) from the equation (S13) in the supplementary material.
We can calculate the prediction of accuracy \(\epsilon\) from the equation (S13) in the supplementary material, the equation (S13) is as follows, .. math:
N = \frac{34}{\epsilon^2} \max_{1 \leq i \leq M} || O_i - \frac{\text{tr}(O_i)}{2^n} ||_{\text{shadow}}^2
where \(\epsilon\) is the prediction of accuracy, and \(M\) is the number of given operatorsm and \(N\) is the number of classical snapshots. The \(|| O_i - \frac{\text{tr}(O_i)}{2^n} ||_{\text{shadow}}^2\) is maximum shadow norm, which is defined in the supplementary material with value between 0 and 1.
Due to maximum shadow norm is complex and it is a norm, we suppose we have the worst case scenario, where the maximum shadow norm is 1 as default. Thus, we can simplify the equation to: .. math:
N = \frac{34}{\epsilon^2}
- num_of_estimators_k: int¶
The number of esitmators, which used the notation K and mentioned in Algorithm 1 in the paper, Theorem S1 in the supplementary material, the equation (S13) in the supplementary material.
We can calculate the number of esitmator K from the equation (S13) in the supplementary material, the equation (S13) is as follows, .. math:
K = 2 \log(2M / \delta)
where \(\delta\) is the probabiltiy complement of accuracy, and \(M\) is the number of given operators.
But we can see \(K\) will be not the integer value of the result of the equation. So, we will use the ceil value of the result of the equation. And recalculate the probabiltiy complement of accuracy from this new value of \(K\).
- class qurry.qurrent.classical_shadow.analysis.SUAnalysisInput(shots: int, num_qubits: int, selected_qubits: list[int], registers_mapping: dict[int, int], bitstring_mapping: dict[int, int] | None, unitary_located: list[int] | None = None)[source]¶
To set the analysis.
- bitstring_mapping: dict[int, int] | None¶
The mapping of the bitstring with the classical registers. When there are mulitple classical registers, the bitstring is the concatenation of the classical registers with space on bitstring. For example, there are three registers with the size of 4, 4, and 6, which the first six bits are for the randomized measurement.
So, the mapping will be like this.
{ 0: 10, # The classical register 0 is mapped to the bitstring on the index 0. 1: 11, # The classical register 0 is mapped to the bitstring on the index 1. 2: 12, # The classical register 0 is mapped to the bitstring on the index 2. 3: 13, # The classical register 0 is mapped to the bitstring on the index 3. 4: 14, # The classical register 0 is mapped to the bitstring on the index 4. 5: 15, # The classical register 0 is mapped to the bitstring on the index 5. }
But, if there is only one classical register, the bitstring will map to the classical register directly.
Will be like this.
- class qurry.qurrent.classical_shadow.analysis.ShadowUnveilAnalysis(*, serial: int, log: dict[str, Any] | None = None, datatime: str | None = None, **other_kwargs)[source]¶
The container for the analysis of :cls:`EntropyRandomizedExperiment`.
- classmethod content_type() Type[SUAnalysisContent] [source]¶
The type of the content for the analysis.
- classmethod deprecated_fields_converts(main: dict[str, Any], side: dict[str, Any]) tuple[dict[str, Any], dict[str, Any]] [source]¶
Convert deprecated fields to new fields.
This method should be implemented in the subclass if there are deprecated fields that need to be converted.
- classmethod input_type() Type[SUAnalysisInput] [source]¶
The type of the input for the analysis.
utils
¶
ShadowUnveil - Utils (qurry.qurrent.classical_shadow.utils
)
- qurry.qurrent.classical_shadow.utils.circuit_method_core(idx: int, target_circuit: QuantumCircuit, target_key: Hashable, exp_name: str, registers_mapping: dict[int, int], single_unitary_um: dict[int, int]) QuantumCircuit [source]¶
Build the circuit for the experiment.
- Parameters:
idx (int) – Index of the quantum circuit.
target_circuit (QuantumCircuit) – Target circuit.
target_key (Hashable) – Target key.
exp_name (str) – Experiment name.
registers_mapping (dict[int, int]) – The mapping of the index of selected qubits to the index of the classical register.
single_unitary_dict (dict[int, Operator]) – The dictionary of the unitary operator.
- Returns:
The circuit for the experiment.
- Return type:
QuantumCircuit
experiment
¶
ShadowUnveil - Experiment (qurry.qurrent.classical_shadow.experiment
)
- class qurry.qurrent.classical_shadow.experiment.OutsideAnalyzeInput[source]¶
The input for the outside analyze.
- class qurry.qurrent.classical_shadow.experiment.ShadowUnveilExperiment(arguments: _A | dict[str, Any], commonparams: Commonparams | dict[str, Any], outfields: dict[str, Any], beforewards: Before | None = None, afterwards: After | None = None, reports: AnalysesContainer | None = None)[source]¶
The instance of experiment.
- property analysis_instance: Type[ShadowUnveilAnalysis]¶
The analysis instance for this experiment.
- analyze(selected_qubits: Iterable[int] | None = None, given_operators: list[ndarray[tuple[int, int], dtype[complex128]]] | None = None, accuracy_prob_comp_delta: float = 0.01, max_shadow_norm: float | None = None, rho_method: Literal['numpy', 'numpy_precomputed'] | str | Literal['numpy_flatten', 'jax_flatten'] = 'numpy_precomputed', trace_method: Literal['trace_of_matmul', 'quick_trace_of_matmul', 'einsum_ij_ji'] | str | Literal['einsum_aij_bji_to_ab_numpy', 'einsum_aij_bji_to_ab_jax'] = 'einsum_aij_bji_to_ab_jax', estimate_trace_method: Literal['einsum_aij_bji_to_ab_numpy', 'einsum_aij_bji_to_ab_jax'] | str = 'einsum_aij_bji_to_ab_jax', counts_used: Iterable[int] | None = None, pbar: tqdm | None = None) ShadowUnveilAnalysis [source]¶
Calculate entangled entropy with more information combined.
- Parameters:
selected_qubits (Optional[Iterable[int]], optional) – The selected qubits. Defaults to None.
given_operators (Optional[list[np.ndarray[tuple[int, int], np.dtype[np.complex128]]]]) – The list of the operators to estimate. Defaults to None.
accuracy_prob_comp_delta (float, optional) – The accuracy probability component delta. Defaults to 0.01.
max_shadow_norm (Optional[float], optional) – The maximum shadow norm. Defaults to None. If it is None, it will be calculated by the largest shadow norm upper bound. If it is not None, it must be a positive float number. It is \(|| O_i - \frac{\text{tr}(O_i)}{2^n} ||_{\text{shadow}}^2\) in equation.
rho_method (RhoMCoreMethod, optional) – The method to use for the calculation. Defaults to “numpy_precomputed”. It can be either “numpy”, “numpy_precomputed”, “jax_flatten”, or “numpy_flatten”. - “numpy”: Use Numpy to calculate the rho_m. - “numpy_precomputed”: Use Numpy to calculate the rho_m with precomputed values. - “numpy_flatten”: Use Numpy to calculate the rho_m with a flattening workflow. Currently, “numpy_precomputed” is the best option for performance.
trace_method (Union[SingleTraceRhoMethod, AllTraceRhoMethod], optional) –
The method to calculate the trace of Rho square. - “trace_of_matmul”:
Use np.trace(np.matmul(rho_m1, rho_m2)) to calculate the each summation item in rho_m_list.
- ”quick_trace_of_matmul” or “einsum_ij_ji”:
Use np.einsum(“ij,ji”, rho_m1, rho_m2) to calculate the each summation item in rho_m_list.
- ”einsum_aij_bji_to_ab_numpy”:
Use np.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
- ”einsum_aij_bji_to_ab_jax”:
Use jnp.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
estimate_trace_method (AllTraceRhoMethod, optional) –
The method to calculate the trace for searching esitmator. - “einsum_aij_bji_to_ab_numpy”:
Use np.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
- ”einsum_aij_bji_to_ab_jax”:
Use jnp.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
counts_used (Optional[Iterable[int]], optional) – The index of the counts used. Defaults to None.
pbar (Optional[tqdm.tqdm], optional) – The progress bar. Defaults to None.
- Returns:
The result of the analysis.
- Return type:
- property arguments_instance: Type[ShadowUnveilArguments]¶
The arguments instance for this experiment.
- classmethod method(targets: list[tuple[Hashable, QuantumCircuit]], arguments: ShadowUnveilArguments, pbar: tqdm | None = None, multiprocess: bool = True) tuple[list[QuantumCircuit], dict[str, Any]] [source]¶
The method to construct circuit.
- Parameters:
targets (list[tuple[Hashable, QuantumCircuit]]) – The circuits of the experiment.
arguments (EntropyMeasureRandomizedArguments) – The arguments of the experiment.
pbar (Optional[tqdm.tqdm], optional) – The progress bar for showing the progress of the experiment. Defaults to None.
multiprocess (bool, optional) – Whether to use multiprocessing. Defaults to True.
- Returns:
The circuits of the experiment and the side products.
- Return type:
- outside_analysis_recover(analysis: ShadowUnveilAnalysis) ShadowUnveilAnalysis [source]¶
Recover the analysis from the outside.
- Parameters:
analysis (ShadowUnveilAnalysis) – The analysis to recover.
- Returns:
The recovered analysis.
- Return type:
- classmethod params_control(targets: list[tuple[Hashable, QuantumCircuit]], exp_name: str = 'exps', times: int = 100, measure: tuple[int, int] | int | list[int] | None = None, unitary_loc: tuple[int, int] | int | list[int] | None = None, unitary_loc_not_cover_measure: bool = False, random_unitary_seeds: dict[int, dict[int, int]] | None = None, **custom_kwargs: Any) tuple[ShadowUnveilArguments, Commonparams, dict[str, Any]] [source]¶
Handling all arguments and initializing a single experiment.
- Parameters:
targets (list[tuple[Hashable, QuantumCircuit]]) – The circuits of the experiment.
exp_name (str, optional) – The name of the experiment. Naming this experiment to recognize it when the jobs are pending to IBMQ Service. This name is also used for creating a folder to store the exports. Defaults to ‘exps’.
times (int, optional) – The number of random unitary operator. Defaults to 100. It will denote as N_U in the experiment name.
measure (Optional[Union[list[int], tuple[int, int], int]], optional) – The measure range. Defaults to None.
unitary_loc (Optional[Union[list[int], tuple[int, int], int]], optional) – The range of the unitary operator. Defaults to None.
unitary_loc_not_cover_measure (bool, optional) – Confirm that not all unitary operator are covered by the measure. If True, then close the warning. Defaults to False.
random_unitary_seeds (Optional[dict[int, dict[int, int]]], optional) –
The seeds for all random unitary operator. This argument only takes input as type of dict[int, dict[int, int]]. The first key is the index for the random unitary operator. The second key is the index for the qubit.
If you want to generate the seeds for all random unitary operator, you can use the function generate_random_unitary_seeds in qurry.qurrium.utils.random_unitary.
custom_kwargs (Any) – The custom parameters.
- Raises:
ValueError – If the number of targets is not one.
TypeError – If times is not an integer.
ValueError – If the range of measure is not in the range of unitary_loc.
- Returns:
The arguments of the experiment, the common parameters, and the custom parameters.
- Return type:
tuple[EntropyMeasureRandomizedArguments, Commonparams, dict[str, Any]]
- classmethod quantities(shots: int | None = None, counts: list[dict[str, int]] | None = None, random_unitary_ids: dict[int, dict[int, Literal[0, 1, 2] | int]] | None = None, selected_classical_registers: Iterable[int] | None = None, given_operators: list[ndarray[tuple[int, int], dtype[complex128]]] | None = None, accuracy_prob_comp_delta: float = 0.01, max_shadow_norm: float | None = None, rho_method: Literal['numpy', 'numpy_precomputed'] | str | Literal['numpy_flatten', 'jax_flatten'] = 'numpy_precomputed', trace_method: Literal['trace_of_matmul', 'quick_trace_of_matmul', 'einsum_ij_ji'] | str | Literal['einsum_aij_bji_to_ab_numpy', 'einsum_aij_bji_to_ab_jax'] = 'einsum_aij_bji_to_ab_jax', estimate_trace_method: Literal['einsum_aij_bji_to_ab_numpy', 'einsum_aij_bji_to_ab_jax'] | str = 'einsum_aij_bji_to_ab_jax', pbar: tqdm | None = None) ClassicalShadowComplex [source]¶
Randomized entangled entropy with complex.
- Parameters:
shots (int) – The number of shots.
random_unitary_ids (dict[int, dict[int, Union[Literal[0, 1, 2], int]]]) – The shadow direction of the unitary operators.
selected_classical_registers (Iterable[int]) – The list of the index of the selected_classical_registers.
given_operators (Optional[list[np.ndarray[tuple[int, int], np.dtype[np.complex128]]]]) – The list of the operators to estimate. Defaults to None.
accuracy_prob_comp_delta (float, optional) – The accuracy probability component delta. Defaults to 0.01.
max_shadow_norm (Optional[float], optional) – The maximum shadow norm. Defaults to None. If it is None, it will be calculated by the largest shadow norm upper bound. If it is not None, it must be a positive float number. It is \(|| O_i - \frac{\text{tr}(O_i)}{2^n} ||_{\text{shadow}}^2\) in equation.
rho_method (RhoMCoreMethod, optional) – The method to use for the calculation. Defaults to “numpy_precomputed”. It can be either “numpy”, “numpy_precomputed”, “jax_flatten”, or “numpy_flatten”. - “numpy”: Use Numpy to calculate the rho_m. - “numpy_precomputed”: Use Numpy to calculate the rho_m with precomputed values. - “numpy_flatten”: Use Numpy to calculate the rho_m with a flattening workflow. Currently, “numpy_precomputed” is the best option for performance.
trace_method (TraceRhoMethod, optional) –
The method to calculate the trace of Rho square. - “trace_of_matmul”:
Use np.trace(np.matmul(rho_m1, rho_m2)) to calculate the each summation item in rho_m_list.
- ”quick_trace_of_matmul” or “einsum_ij_ji”:
Use np.einsum(“ij,ji”, rho_m1, rho_m2) to calculate the each summation item in rho_m_list.
- ”einsum_aij_bji_to_ab_numpy”:
Use np.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
- ”einsum_aij_bji_to_ab_jax”:
Use jnp.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
estimate_trace_method (AllTraceRhoMethod, optional) –
The method to calculate the trace for searching esitmator. - “einsum_aij_bji_to_ab_numpy”:
Use np.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
- ”einsum_aij_bji_to_ab_jax”:
Use jnp.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
pbar (Optional[tqdm.tqdm], optional) – The progress bar. Defaults to None.
- Returns:
The result of the classical shadow.
- Return type:
- qurry.qurrent.classical_shadow.experiment.outside_analyze(exp_id: str, shots: int, counts: list[dict[str, int]], random_unitary_ids: dict[int, dict[int, Literal[0, 1, 2] | int]], selected_classical_registers: Iterable[int], num_qubits: int, selected_qubits: list[int], registers_mapping: dict[int, int], bitstring_mapping: dict[int, int], unitary_located: list[int], given_operators: list[ndarray[tuple[int, int], dtype[complex128]]] | None, accuracy_prob_comp_delta: float, max_shadow_norm: float | None, serial: int, rho_method: Literal['numpy', 'numpy_precomputed'] | str | Literal['numpy_flatten', 'jax_flatten'] = 'numpy_precomputed', trace_method: Literal['trace_of_matmul', 'quick_trace_of_matmul', 'einsum_ij_ji'] | str | Literal['einsum_aij_bji_to_ab_numpy', 'einsum_aij_bji_to_ab_jax'] = 'einsum_aij_bji_to_ab_jax', estimate_trace_method: Literal['einsum_aij_bji_to_ab_numpy', 'einsum_aij_bji_to_ab_jax'] | str = 'einsum_aij_bji_to_ab_jax', counts_used: Iterable[int] | None = None) tuple[str, ShadowUnveilAnalysis] [source]¶
Randomized entangled entropy with complex.
- Parameters:
exp_id (str) – The ID of the experiment.
shots (int) – The number of shots.
random_unitary_ids (dict[int, dict[int, Union[Literal[0, 1, 2], int]]]) – The shadow direction of the unitary operators.
selected_classical_registers (Iterable[int]) – The list of the index of the selected_classical_registers.
num_qubits (int) – The number of qubits.
registers_mapping (dict[int, int]) – The mapping of the index of selected qubits to the index of the classical register.
bitstring_mapping (dict[str, int]) – The mapping of the bitstring to the index of the classical register.
unitary_located (list[int]) – The range of the unitary operator.
given_operators (Optional[list[np.ndarray[tuple[int, int], np.dtype[np.complex128]]]]) – The list of the operators to estimate. Defaults to None.
accuracy_prob_comp_delta (float, optional) – The accuracy probability component delta. Defaults to 0.01.
max_shadow_norm (Optional[float], optional) – The maximum shadow norm. Defaults to None. If it is None, it will be calculated by the largest shadow norm upper bound. If it is not None, it must be a positive float number. It is \(|| O_i - \frac{\text{tr}(O_i)}{2^n} ||_{\text{shadow}}^2\) in equation.
serial (int) – The serial number of the experiment.
rho_method (RhoMCoreMethod, optional) – The method to use for the calculation. Defaults to “numpy_precomputed”. It can be either “numpy”, “numpy_precomputed”, “jax_flatten”, or “numpy_flatten”. - “numpy”: Use Numpy to calculate the rho_m. - “numpy_precomputed”: Use Numpy to calculate the rho_m with precomputed values. - “numpy_flatten”: Use Numpy to calculate the rho_m with a flattening workflow. Currently, “numpy_precomputed” is the best option for performance.
trace_method (TraceRhoMethod, optional) –
The method to calculate the trace of Rho square. - “trace_of_matmul”:
Use np.trace(np.matmul(rho_m1, rho_m2)) to calculate the each summation item in rho_m_list.
- ”quick_trace_of_matmul” or “einsum_ij_ji”:
Use np.einsum(“ij,ji”, rho_m1, rho_m2) to calculate the each summation item in rho_m_list.
- ”einsum_aij_bji_to_ab_numpy”:
Use np.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
- ”einsum_aij_bji_to_ab_jax”:
Use jnp.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
estimate_trace_method (AllTraceRhoMethod, optional) –
The method to calculate the trace for searching esitmator. - “einsum_aij_bji_to_ab_numpy”:
Use np.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
- ”einsum_aij_bji_to_ab_jax”:
Use jnp.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
backend (PostProcessingBackend, optional) – Backend for the process. Defaults to DEFAULT_PROCESS_BACKEND.
counts_used (Optional[Iterable[int]], optional) – The index of the counts used. Defaults to None.
- Returns:
The ID of the experiment and the result of the classical shadow.
- Return type:
- qurry.qurrent.classical_shadow.experiment.outside_analyze_wrapper(all_arguments: OutsideAnalyzeInput) tuple[str, ShadowUnveilAnalysis] [source]¶
Wrapper for the outside analyze.
- Parameters:
all_arguments (OutsideAnalyzeInput) – The arguments for the outside analyze.
- Returns:
The ID of the experiment and the result of the classical shadow.
- Return type:
- qurry.qurrent.classical_shadow.experiment.quantities_input_collecter(current_exps: ShadowUnveilExperiment, selected_qubits: Iterable[int] | None = None, given_operators: list[ndarray[tuple[int, int], dtype[complex128]]] | None = None, accuracy_prob_comp_delta: float = 0.01, max_shadow_norm: float | None = None, rho_method: Literal['numpy', 'numpy_precomputed'] | str | Literal['numpy_flatten', 'jax_flatten'] = 'numpy_precomputed', trace_method: Literal['trace_of_matmul', 'quick_trace_of_matmul', 'einsum_ij_ji'] | str | Literal['einsum_aij_bji_to_ab_numpy', 'einsum_aij_bji_to_ab_jax'] = 'einsum_aij_bji_to_ab_jax', estimate_trace_method: Literal['einsum_aij_bji_to_ab_numpy', 'einsum_aij_bji_to_ab_jax'] | str = 'einsum_aij_bji_to_ab_jax', counts_used: Iterable[int] | None = None) OutsideAnalyzeInput [source]¶
Collect the inputs for the quantities.
- Parameters:
current_exps (ShadowUnveilExperiment) – The current experiment instance.
selected_qubits (Optional[Iterable[int]], optional) – The selected qubits. Defaults to None.
given_operators (Optional[list[np.ndarray[tuple[int, int], np.dtype[np.complex128]]]]) – The list of the operators to estimate. Defaults to None.
accuracy_prob_comp_delta (float, optional) – The accuracy probability component delta. Defaults to 0.01.
max_shadow_norm (Optional[float], optional) – The maximum shadow norm. Defaults to None. If it is None, it will be calculated by the largest shadow norm upper bound. If it is not None, it must be a positive float number. It is \(|| O_i - \frac{\text{tr}(O_i)}{2^n} ||_{\text{shadow}}^2\) in equation.
backend (PostProcessingBackendLabel, optional) – The backend for the process. Defaults to DEFAULT_PROCESS_BACKEND.
rho_method (RhoMCoreMethod, optional) – The method to use for the calculation. Defaults to “numpy_precomputed”. It can be either “numpy”, “numpy_precomputed”, “jax_flatten”, or “numpy_flatten”. - “numpy”: Use Numpy to calculate the rho_m. - “numpy_precomputed”: Use Numpy to calculate the rho_m with precomputed values. - “numpy_flatten”: Use Numpy to calculate the rho_m with a flattening workflow. Currently, “numpy_precomputed” is the best option for performance.
trace_method (Union[SingleTraceRhoMethod, AllTraceRhoMethod], optional) –
The method to calculate the trace of Rho square. - “trace_of_matmul”:
Use np.trace(np.matmul(rho_m1, rho_m2)) to calculate the each summation item in rho_m_list.
- ”quick_trace_of_matmul” or “einsum_ij_ji”:
Use np.einsum(“ij,ji”, rho_m1, rho_m2) to calculate the each summation item in rho_m_list.
- ”einsum_aij_bji_to_ab_numpy”:
Use np.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
- ”einsum_aij_bji_to_ab_jax”:
Use jnp.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
estimate_trace_method (AllTraceRhoMethod, optional) –
The method to calculate the trace for searching esitmator. - “einsum_aij_bji_to_ab_numpy”:
Use np.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
- ”einsum_aij_bji_to_ab_jax”:
Use jnp.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
counts_used (Optional[Iterable[int]], optional) – The index of the counts used. Defaults to None.
- Returns:
The inputs for the quantities.
- Return type:
qurry
¶
ShadowUnveil - Qurrium (qurry.qurrent.classical_shadow.qurry
)
- class qurry.qurrent.classical_shadow.qurry.ShadowUnveil[source]¶
Classical Shadow with The Results of Second Order Renyi Entropy.
References
Note
Predicting many properties of a quantum system from very few measurements -
Huang, Hsin-Yuan and Kueng, Richard and Preskill, John [doi:10.1038/s41567-020-0932-7](
The randomized measurement toolbox -
Elben, Andreas and Flammia, Steven T. and Huang, Hsin-Yuan and Kueng, Richard and Preskill, John and Vermersch, Benoît and Zoller, Peter [doi:10.1038/s42254-022-00535-2](
@article{cite-key, abstract = { Predicting the properties of complex, large-scale quantum systems is essential for developing quantum technologies. We present an efficient method for constructing an approximate classical description of a quantum state using very few measurements of the state. different properties; order {\$}{\$}{\{}{$\backslash$}mathrm{\{}log{\}}{\}}{$\backslash$},(M){\$}{\$} measurements suffice to accurately predict M different functions of the state with high success probability. The number of measurements is independent of the system size and saturates information-theoretic lower bounds. Moreover, target properties to predict can be selected after the measurements are completed. We support our theoretical findings with extensive numerical experiments. We apply classical shadows to predict quantum fidelities, entanglement entropies, two-point correlation functions, expectation values of local observables and the energy variance of many-body local Hamiltonians. The numerical results highlight the advantages of classical shadows relative to previously known methods.}, author = {Huang, Hsin-Yuan and Kueng, Richard and Preskill, John}, date = {2020/10/01}, date-added = {2024-12-03 15:00:55 +0800}, date-modified = {2024-12-03 15:00:55 +0800}, doi = {10.1038/s41567-020-0932-7}, id = {Huang2020}, isbn = {1745-2481}, journal = {Nature Physics}, number = {10}, pages = {1050--1057}, title = {Predicting many properties of a quantum system from very few measurements}, url = {https://doi.org/10.1038/s41567-020-0932-7}, volume = {16}, year = {2020}, bdsk-url-1 = {https://doi.org/10.1038/s41567-020-0932-7} } @article{cite-key, abstract = { Programmable quantum simulators and quantum computers are opening unprecedented opportunities for exploring and exploiting the properties of highly entangled complex quantum systems. The complexity of large quantum systems is the source of computational power but also makes them difficult to control precisely or characterize accurately using measured classical data. We review protocols for probing the properties of complex many-qubit systems using measurement schemes that are practical using today's quantum platforms. In these protocols, a quantum state is repeatedly prepared and measured in a randomly chosen basis; then a classical computer processes the measurement outcomes to estimate the desired property. The randomization of the measurement procedure has distinct advantages. For example, a single data set can be used multiple times to pursue a variety of applications, and imperfections in the measurements are mapped to a simplified noise model that can more easily be mitigated. We discuss a range of cases that have already been realized in quantum devices, including Hamiltonian simulation tasks, probes of quantum chaos, measurements of non-local order parameters, and comparison of quantum states produced in distantly separated laboratories. By providing a workable method for translating a complex quantum state into a succinct classical representation that preserves a rich variety of relevant physical properties, the randomized measurement toolbox strengthens our ability to grasp and control the quantum world.}, author = { Elben, Andreas and Flammia, Steven T. and Huang, Hsin-Yuan and Kueng, Richard and Preskill, John and Vermersch, Beno{\^\i}t and Zoller, Peter}, date = {2023/01/01}, date-added = {2024-12-03 15:06:15 +0800}, date-modified = {2024-12-03 15:06:15 +0800}, doi = {10.1038/s42254-022-00535-2}, id = {Elben2023}, isbn = {2522-5820}, journal = {Nature Reviews Physics}, number = {1}, pages = {9--24}, title = {The randomized measurement toolbox}, url = {https://doi.org/10.1038/s42254-022-00535-2}, volume = {5}, year = {2023}, bdsk-url-1 = {https://doi.org/10.1038/s42254-022-00535-2} }
- property experiment_instance: Type[ShadowUnveilExperiment]¶
The container class responding to this QurryV5 class.
- measure(wave: QuantumCircuit | Hashable | None = None, times: int = 100, measure: tuple[int, int] | int | list[int] | None = None, unitary_loc: tuple[int, int] | int | list[int] | None = None, unitary_loc_not_cover_measure: bool = False, random_unitary_seeds: dict[int, dict[int, int]] | None = None, shots: int = 1024, backend: Backend | None = None, exp_name: str = 'experiment', run_args: BaseRunArgs | dict[str, Any] | None = None, transpile_args: TranspileArgs | None = None, passmanager: str | PassManager | tuple[str, PassManager] | None = None, tags: tuple[str, ...] | None = None, qasm_version: Literal['qasm2', 'qasm3'] = 'qasm3', export: bool = False, save_location: Path | str | None = None, pbar: tqdm | None = None) str [source]¶
Execute the experiment.
- Parameters:
wave (Union[QuantumCircuit, Hashable]) – The key or the circuit to execute.
times (int, optional) – The number of random unitary operator. It will denote as N_U in the experiment name. Defaults to 100.
measure (Optional[Union[list[int], tuple[int, int], int]], optional) – The measure range. Defaults to None.
unitary_loc (Optional[Union[list[int], tuple[int, int], int]], optional) – The range of the unitary operator. Defaults to None.
unitary_loc_not_cover_measure (bool, optional) – Whether the range of the unitary operator is not cover the measure range. Defaults to False.
random_unitary_seeds (Optional[dict[int, dict[int, int]]], optional) –
The seeds for all random unitary operator. This argument only takes input as type of dict[int, dict[int, int]]. The first key is the index for the random unitary operator. The second key is the index for the qubit.
If you want to generate the seeds for all random unitary operator, you can use the function generate_random_unitary_seeds in qurry.qurrium.utils.random_unitary.
shots (int, optional) – Shots of the job. Defaults to 1024.
backend (Optional[Backend], optional) – The quantum backend. Defaults to None.
exp_name (str, optional) – The name of the experiment. Naming this experiment to recognize it when the jobs are pending to IBMQ Service. This name is also used for creating a folder to store the exports. Defaults to ‘exps’.
run_args (RunArgsType, optional) – Arguments for
Backend.run()
. Defaults to None.transpile_args (Optional[TranspileArgs], optional) – Arguments of
transpile()
fromqiskit.compiler.transpiler
. Defaults to None.passmanager (PassManagerType, optional) – The passmanager. Defaults to None.
tags (Optional[tuple[str, ...]], optional) – The tags of the experiment. Defaults to None.
qasm_version (Literal["qasm2", "qasm3"], optional) – The version of OpenQASM. Defaults to “qasm3”.
export (bool, optional) – Whether to export the experiment. Defaults to False.
save_location (Optional[Union[Path, str]], optional) – The location to save the experiment. Defaults to None.
pbar (Optional[tqdm.tqdm], optional) – The progress bar for showing the progress of the experiment. Defaults to None.
- Returns:
The experiment ID.
- Return type:
- measure_to_output(wave: QuantumCircuit | Hashable | None = None, times: int = 100, measure: tuple[int, int] | int | list[int] | None = None, unitary_loc: tuple[int, int] | int | list[int] | None = None, unitary_loc_not_cover_measure: bool = False, random_unitary_seeds: dict[int, dict[int, int]] | None = None, shots: int = 1024, backend: Backend | None = None, exp_name: str = 'experiment', run_args: BaseRunArgs | dict[str, Any] | None = None, transpile_args: TranspileArgs | None = None, passmanager: str | PassManager | tuple[str, PassManager] | None = None, tags: tuple[str, ...] | None = None, qasm_version: Literal['qasm2', 'qasm3'] = 'qasm3', export: bool = False, save_location: Path | str | None = None, pbar: tqdm | None = None) ShadowUnveilOutputArgs [source]¶
Trasnform
measure()
arguments form intooutput()
form.- Parameters:
wave (Union[QuantumCircuit, Hashable]) – The key or the circuit to execute.
times (int, optional) – The number of random unitary operator. It will denote as N_U in the experiment name. Defaults to 100.
measure (Optional[Union[list[int], tuple[int, int], int]], optional) – The measure range. Defaults to None.
unitary_loc (Optional[Union[list[int], tuple[int, int], int]], optional) – The range of the unitary operator. Defaults to None.
unitary_loc_not_cover_measure (bool, optional) – Whether the range of the unitary operator is not cover the measure range. Defaults to False.
random_unitary_seeds (Optional[dict[int, dict[int, int]]], optional) –
The seeds for all random unitary operator. This argument only takes input as type of dict[int, dict[int, int]]. The first key is the index for the random unitary operator. The second key is the index for the qubit.
If you want to generate the seeds for all random unitary operator, you can use the function generate_random_unitary_seeds in qurry.qurrium.utils.random_unitary.
shots (int, optional) – Shots of the job. Defaults to 1024.
backend (Optional[Backend], optional) – The quantum backend. Defaults to None.
exp_name (str, optional) – The name of the experiment. Naming this experiment to recognize it when the jobs are pending to IBMQ Service. This name is also used for creating a folder to store the exports. Defaults to ‘exps’.
run_args (RunArgsType, optional) – Arguments for
Backend.run()
. Defaults to None.transpile_args (Optional[TranspileArgs], optional) – Arguments of
transpile()
fromqiskit.compiler.transpiler
. Defaults to None.passmanager (PassManagerType, optional) – The passmanager. Defaults to None.
tags (Optional[tuple[str, ...]], optional) – The tags of the experiment. Defaults to None.
qasm_version (Literal["qasm2", "qasm3"], optional) – The version of OpenQASM. Defaults to “qasm3”.
export (bool, optional) – Whether to export the experiment. Defaults to False.
save_location (Optional[Union[Path, str]], optional) – The location to save the experiment. Defaults to None.
pbar (Optional[tqdm.tqdm], optional) – The progress bar for showing the progress of the experiment. Defaults to None.
- Returns:
The output arguments.
- Return type:
- multiAnalysis(summoner_id: str, *, analysis_name: str = 'report', no_serialize: bool = False, specific_analysis_args: dict[Hashable, ShadowUnveilAnalyzeArgs | dict[str, Any] | bool] | None = None, skip_write: bool = False, multiprocess_write: bool = False, multiprocess_analysis: bool = False, selected_qubits: list[int] | None = None, rho_method: Literal['numpy', 'numpy_precomputed'] | str | Literal['numpy_flatten', 'jax_flatten'] = 'numpy_precomputed', trace_method: Literal['trace_of_matmul', 'quick_trace_of_matmul', 'einsum_ij_ji'] | str | Literal['einsum_aij_bji_to_ab_numpy', 'einsum_aij_bji_to_ab_jax'] = 'einsum_aij_bji_to_ab_jax', counts_used: Iterable[int] | None = None, **analysis_args) str [source]¶
Run the analysis for multiple experiments.
- Parameters:
summoner_id (str) – The summoner_id of multimanager.
analysis_name (str, optional) – The name of analysis. Defaults to ‘report’.
no_serialize (bool, optional) – Whether to serialize the analysis. Defaults to False.
specific_analysis_args (SpecificAnalsisArgs[ShadowUnveilAnalyzeArgs], optional) – The specific arguments for analysis. Defaults to None.
compress (bool, optional) – Whether to compress the export file. Defaults to False.
skip_write (bool, optional) – Whether to skip the file writing during the analysis. Defaults to False.
multiprocess_write (bool, optional) – Whether use multiprocess for writing. Defaults to False.
multiprocess_analysis (bool, optional) – Whether use multiprocess for analysis. Defaults to False.
selected_qubits (Optional[list[int]], optional) – The selected qubits. Defaults to None.
rho_method (RhoMCoreMethod, optional) – The method to use for the calculation. Defaults to “numpy_precomputed”. It can be either “numpy”, “numpy_precomputed”, “numpy_flatten”. - “numpy”: Use Numpy to calculate the rho_m. - “numpy_precomputed”: Use Numpy to calculate the rho_m with precomputed values. - “numpy_flatten”: Use Numpy to calculate the rho_m with a flattening workflow. Currently, “numpy_precomputed” is the best option for performance.
trace_method (TraceRhoMethod, optional) –
The method to calculate the trace of Rho square. - “trace_of_matmul”:
Use np.trace(np.matmul(rho_m1, rho_m2)) to calculate the trace.
- ”quick_trace_of_matmul” or “einsum_ij_ji”:
Use np.einsum(“ij,ji”, rho_m1, rho_m2) to calculate the trace. Which is the fastest method to calculate the trace. Due to handle all computation in einsum.
- ”einsum_aij_bji_to_ab_numpy”:
Use np.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
- ”einsum_aij_bji_to_ab_jax”:
Use jnp.einsum(“aij,bji->ab”, rho_m_list, rho_m_list) to calculate the trace.
counts_used (Optional[Iterable[int]], optional) – The counts used for the analysis. Defaults to None.
- Returns:
The summoner_id of multimanager.
- Return type:
- short_name = 'qurshady_entropy'¶
The short name of Qurrium.