expectation_process

Post Processing - Classical Shadow - Expectation Process (qurry.process.classical_shadow.expectation_process)

qurry.process.classical_shadow.expectation_process.accuracy_predict_epsilon_calc(num_classical_snapshot: int, max_shadow_norm: float = 1) float[source]

Calculate 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 operators, 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,

Due to maximum shadow norm is complex, we suppose 1 for it should be under the order of 1. Thus, we can simplify the equation to: .. math:

N = \frac{34}{\epsilon^2}
Parameters:
  • num_classical_snapshot (int) – The number of classical snapshots. It is \(N\) in the equation.

  • max_shadow_norm (float, optional) – The maximum shadow norm. Defaults to 1. It is \(|| O_i - \frac{\text{tr}(O_i)}{2^n} ||_{\text{shadow}}^2\) in equation.

Returns:

The accuracy prediction epsilon.

Return type:

float

qurry.process.classical_shadow.expectation_process.accuracy_prob_comp_delta_calc(num_of_given_operators: int, num_of_esitmators: int) float[source]

Calculate the accuracy probability component delta.

The accuracy probability component delta is calculated by the following equation, .. math:

K = 2 \log(2M / \delta) \Rightarrow \delta = 2M \exp(-K / 2)

where \(K\) is the number of estimators, and \(M\) is the number of given operators.

Parameters:
  • num_of_given_operators (int) – The number of given operators. It is \(M\) in the equation.

  • num_of_esitmators (int) – The number of estimators. It is \(K\) in the equation.

Returns:

The accuracy probability component delta.

Return type:

float

qurry.process.classical_shadow.expectation_process.dim_check(op: ndarray[tuple[int, int], dtype[complex128]]) tuple[int, int][source]

Check the dimension of the operator.

The dimension of the operator is defined as follows, .. math:

\text{dim}(X) = 2^n

where \(X\) is the operator, and \(n\) is the number of qubits.

Parameters:

op (np.ndarray[tuple[int, int], np.dtype[np.complex128]]) – The operator to be checked.

Returns:

The dimension of the operator and the number of qubits.

Return type:

tuple[int, int]

Raises:
  • ValueError – If the shape of the operator is not a square matrix with size 2^n,

  • where n is the number of qubits.

qurry.process.classical_shadow.expectation_process.inverted_quantum_channel(op: ndarray[tuple[int, int], dtype[complex128]]) ndarray[tuple[int, int], dtype[complex128]][source]

Inverted quantum channel.

The inverted quantum channel is defined as follows, .. math:

\mathcal{M}_{n}^{-1}(X) = (2^n + 1)X - \mathbb{I}

where \(\mathcal{M}_{n}^{-1}\) is the inverted quantum channel, which mentioned in the paper before Algorithm 1.

where \(X\) is the operator, and \(n\) is the number of qubits.

Parameters:

op (np.ndarray[tuple[int, int], np.dtype[np.complex128]]) – The operator to be inverted.

Returns:

The inverted operator.

Return type:

np.ndarray[tuple[int, int], np.dtype[np.complex128]]

Raises:
  • ValueError – If the shape of the operator is not a square matrix with size 2^n,

  • where n is the number of qubits.

qurry.process.classical_shadow.expectation_process.largest_shadow_norm_squared_upperbound(op: ndarray[tuple[int, int], dtype[complex128]]) float[source]

Calculate the largest shadow norm upper bound.

The largest shadow norm upper bound is defined as follows, .. math:

|| O ||_{\text{shadow}}^2 \leq 4^n || O ||_{\infty}^2

where \(O\) is the operator, and \(n\) is the number of qubits, which mentioned in the paper at Theorem 1 (informal version).

This is the worst scenario of the shadow norm for its scaling can be reduced to \(3^n || O ||_{\infty}^2\), which is the significantly lower bound than the worst case scenario.

Parameters:

op (np.ndarray[tuple[int, int], np.dtype[np.complex128]]) – The operator to be calculated.

Returns:

The largest shadow norm upper bound.

Return type:

float

qurry.process.classical_shadow.expectation_process.num_of_esitmator_calc(num_classical_snapshot: int, num_of_given_operators: int, accuracy_prob_comp_delta: float = 0.01) tuple[int, float][source]

Calculate the number of estimators.

The number of estimators is calculated by the following equation, .. 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\).

But we will check \(K\) is not less than 1 and larger than \(M\) the number of given operators. If so, we will raise an error.

Parameters:
  • num_classical_snapshot (int) – The number of classical snapshots. It is \(N\) in the equation.

  • num_of_given_operators (int) – The number of given operators. It is \(M\) in the equation.

  • accuracy_prob_comp_delta (float, optional) – The accuracy probability component delta. Defaults to None. It is \(\delta\) in the equation. The probabiltiy of accuracy is \(1 - \delta\). If it is 0, it will raise an error.

Returns:

The number of estimators and the accuracy probability component delta.

The first element is the number of estimators, and the second element is the accuracy probability component delta.

Return type:

tuple[int, float]

qurry.process.classical_shadow.expectation_process.prediction_algorithm(classical_snapshots_rho: dict[int, ndarray[tuple[int, int], dtype[complex128]]], given_operators: list[ndarray[tuple[int, int], dtype[complex128]]], accuracy_prob_comp_delta: float = 0.01, max_shadow_norm: float | None = None, trace_method: Literal['einsum_aij_bji_to_ab_numpy', 'einsum_aij_bji_to_ab_jax'] | str = 'einsum_aij_bji_to_ab_jax') tuple[list[complex128], list[ndarray[tuple[int, int], dtype[complex128]]], float, int, float, float, float, float][source]

Calculate the prediction of accuracy and the number of estimators.

Parameters:
  • classical_snapshots_rho (dict[int, np.ndarray[tuple[int, int], np.dtype[np.complex128]]]) – The classical snapshots. The key is the index of the classical snapshot, and the value is the classical snapshot.

  • given_operators (list[np.ndarray[tuple[int, int], np.dtype[np.complex128]]]) – The list of the operators to estimate.

  • 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.

  • 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.

Returns:

tuple[

list[np.complex128], list[np.ndarray[tuple[int, int], np.dtype[np.complex128]]], float, int, float, float, float, float

]:
  • estimate_of_given_operators: list[np.complex128]

    The esitmation values of measurement primitive \(\mathcal{U}\).

  • corresponding_rhos: list[np.ndarray[tuple[int, int], np.dtype[np.complex128]]]

    The corresponding rho of measurement primitive \(\mathcal{U}\).

  • actual_accuracy_prob_comp_delta: float

    The actual accuracy probability component delta,

  • num_of_estimators: int

    The number of esitmators

  • accuracy_predict_epsilon: float

    The prediction of accuracy

  • max_shadow_norm: float

    The maximum shadow norm

  • epsilon_upperbound: float

    The upper bound of the prediction of accuracy epsilon

  • shadow_norm_upperbound: float

    The upper bound of the shadow norm

Raises:

qurry.process.classical_shadow.expectation_process.traceless(op: ndarray[tuple[int, int], dtype[complex128]]) ndarray[tuple[int, int], dtype[complex128]][source]

Make the operator traceless.

The traceless operator is defined as follows, .. math:

\text{traceless}(O) = O - \frac{\text{tr}(O)}{2^n} \mathbb{I}

where \(O\) is the operator, and \(n\) is the number of qubits, which mentioned in the supplementary material Lemma S1.

Parameters:

op (np.ndarray[tuple[int, int], np.dtype[np.complex128]]) – The operator to be made traceless.

Returns:

The traceless operator.

Return type:

np.ndarray[tuple[int, int], np.dtype[np.complex128]]

qurry.process.classical_shadow.expectation_process.worst_accuracy_predict_epsilon_calc(num_classical_snapshot: int, given_operators: list[ndarray[tuple[int, int], dtype[complex128]]]) tuple[float, float][source]

Calculate the prediction of accuracy in worst scenario, 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 operators, 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,

And we also know the largest upper bound of the shadow norm is .. math:

|| O ||_{\text{shadow}}^2 \leq 4^n || O ||_{\infty}^2

where \(O\) is the any operator, and \(n\) is the number of qubits,

So we set the shadow norm as follows, .. math:

\chi = || O_i - \frac{\text{tr}(O_i)}{2^n} ||_{\text{shadow}} \\
\chi_{\infty} = 4^n || O_i - \frac{\text{tr}(O_i)}{2^n} ||_{\infty}^2 \\
\chi^2 \leq \chi_{\infty}

and we can simplify the equation to: .. math:

N = \frac{34}{\epsilon^2} \max_{1 \leq i \leq M} \chi^2
    \leq \frac{34}{\epsilon^2} \max_{1 \leq i \leq M} \chi_{\infty}^2

Then get: .. math:

\epsilon \leq \sqrt{\frac{34}{N}} \max_{1 \leq i \leq M} \chi_\infty
Parameters:
  • num_classical_snapshot (int) – The number of classical snapshots. It is \(N\) in the equation.

  • given_operators (list[np.ndarray[tuple[int, int], np.dtype[np.complex128]]]) – The list of the operators to estimate.

Returns:

The worst accuracy prediction epsilon and the worst maximum shadow norm.

Return type:

tuple[float, float]