microsoft/qdk
Publicmirrored fromhttps://github.com/microsoft/qdkAvailable
source/noisy_simulator/src/tests/noisy_tests.rs
74lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | use crate::{ |
| 5 | NoisySimulator, SquareMatrix, operation::Operation, tests::assert_approx_eq_with_tolerance, |
| 6 | }; |
| 7 | use nalgebra::dmatrix; |
| 8 | use num_complex::Complex; |
| 9 | |
| 10 | use super::noiseless_tests; |
| 11 | |
| 12 | const I: Complex<f64> = Complex::I; |
| 13 | const ZERO: Complex<f64> = Complex::ZERO; |
| 14 | const ONE: Complex<f64> = Complex::ONE; |
| 15 | |
| 16 | fn pauli_identity() -> SquareMatrix { |
| 17 | SquareMatrix::identity(2, 2) |
| 18 | } |
| 19 | |
| 20 | fn pauli_x() -> SquareMatrix { |
| 21 | dmatrix![ZERO, ONE; |
| 22 | ONE, ZERO;] |
| 23 | } |
| 24 | |
| 25 | fn pauli_y() -> SquareMatrix { |
| 26 | dmatrix![ZERO, -I; |
| 27 | I, ZERO;] |
| 28 | } |
| 29 | |
| 30 | fn pauli_z() -> SquareMatrix { |
| 31 | dmatrix![ONE, ZERO; |
| 32 | ZERO, -ONE;] |
| 33 | } |
| 34 | |
| 35 | /// Returns a noisy identity gate. |
| 36 | fn depolarizing_channel(lambda: f64) -> Operation { |
| 37 | // 0 <= 𝜆 <= 1 + 1 / (d^2 - 1) |
| 38 | const LAMBDA_UPPER_BOUND: f64 = 1. + 1. / (4. - 1.); |
| 39 | assert!((0. ..=LAMBDA_UPPER_BOUND).contains(&lambda)); |
| 40 | |
| 41 | let lambda: Complex<f64> = lambda.into(); |
| 42 | |
| 43 | // Define kraus matrices of the depolarizing channel. |
| 44 | let k0 = pauli_identity() * (1. - 3. * lambda / 4.).sqrt(); |
| 45 | let k1 = pauli_x() * (lambda / 4.).sqrt(); |
| 46 | let k2 = pauli_y() * (lambda / 4.).sqrt(); |
| 47 | let k3 = pauli_z() * (lambda / 4.).sqrt(); |
| 48 | |
| 49 | Operation::new(vec![k0, k1, k2, k3]).expect("operation should be valid") |
| 50 | } |
| 51 | |
| 52 | pub fn check_noisy_identity_yields_same_qubit_with_right_probability<NS: NoisySimulator>() { |
| 53 | const SHOTS: u64 = 500_000; |
| 54 | |
| 55 | let depolarizing_channel = depolarizing_channel(0.1); |
| 56 | let mz = noiseless_tests::noiseless_mz(); |
| 57 | |
| 58 | let mut total_outcome: usize = 0; |
| 59 | |
| 60 | // Run `SHOTS` simulations, on average we should measure the wrong outcome, i.e. 1, |
| 61 | // 5% of the times (𝜆 / 2). |
| 62 | for seed in 0..SHOTS { |
| 63 | let mut sim = NS::new_with_seed(1, seed); |
| 64 | sim.apply_operation(&depolarizing_channel, &[0]) |
| 65 | .expect("operation should succeed"); |
| 66 | total_outcome += sim |
| 67 | .sample_instrument(&mz, &[0]) |
| 68 | .expect("operation should succeed"); |
| 69 | } |
| 70 | |
| 71 | #[allow(clippy::cast_precision_loss)] |
| 72 | let expected_outcome: f64 = (total_outcome as f64) / (SHOTS as f64); |
| 73 | assert_approx_eq_with_tolerance(0.05, expected_outcome, 0.001); |
| 74 | } |
| 75 | |