microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.29.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

source/compiler/qsc_eval/src/backend/noise_tests.rs

564lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use crate::{
5 backend::{Backend, SparseSim},
6 noise::PauliNoise,
7 state::{fmt_complex, format_state_id},
8 val,
9};
10use expect_test::{Expect, expect};
11use num_bigint::BigUint;
12use num_complex::Complex;
13use qdk_simulators::noise_config::{NoiseConfig, NoiseTable, encode_pauli};
14use std::fmt::Write;
15
16#[test]
17fn pauli_noise() {
18 let noise = PauliNoise::from_probabilities(0.0, 0.0, 0.0);
19 assert!(
20 noise
21 .expect("noiseless Pauli noise should be constructable.")
22 .is_noiseless(),
23 "Expected noiseless noise."
24 );
25 let noise = PauliNoise::from_probabilities(1e-5, 0.0, 0.0);
26 assert!(
27 !noise
28 .expect("bit flip noise with probability 1e-5 should be constructable.")
29 .is_noiseless(),
30 "Expected noise to be noisy."
31 );
32 let noise = PauliNoise::from_probabilities(1.0, 0.0, 0.0);
33 assert!(
34 !noise
35 .expect("bit flip noise with probability 1 should be constructable.")
36 .is_noiseless(),
37 "Expected noise to be noisy."
38 );
39 let noise = PauliNoise::from_probabilities(0.01, 0.01, 0.01)
40 .expect("depolarizing noise with probability 0.01 should be constructable..");
41 assert!(!noise.is_noiseless(), "Expected noise to be noisy.");
42 assert!(
43 0.0 <= noise.distribution[0]
44 && noise.distribution[0] <= noise.distribution[1]
45 && noise.distribution[1] <= noise.distribution[2]
46 && noise.distribution[2] <= 1.1,
47 "Expected non-decreasing noise distribution."
48 );
49 let _ = PauliNoise::from_probabilities(-1e-10, 0.1, 0.1)
50 .expect_err("pauli noise with probabilities -1e-10, 0.1, 0.1 should result in error.");
51 let _ = PauliNoise::from_probabilities(1.0 + -1e-10, 0.1, 0.1)
52 .expect_err("pauli noise with probabilities 1.0+1e-10, 0.1, 0.1 should result in error.");
53 let _ = PauliNoise::from_probabilities(0.3, 0.4, 0.5)
54 .expect_err("pauli noise with probabilities 0.3, 0.4, 0.5 should result in error.");
55}
56
57#[test]
58fn noisy_simulator() {
59 let sim = SparseSim::new();
60 assert!(sim.is_noiseless(), "Expected noiseless simulator.");
61
62 let noise = PauliNoise::from_probabilities(0.0, 0.0, 0.0)
63 .expect("noiseless Pauli noise should be constructable.");
64 let sim = SparseSim::new_with_noise(&noise);
65 assert!(sim.is_noiseless(), "Expected noiseless simulator.");
66
67 let noise = PauliNoise::from_probabilities(1e-10, 0.0, 0.0)
68 .expect("1e-10, 0.0, 0.0 Pauli noise should be constructable.");
69 let sim = SparseSim::new_with_noise(&noise);
70 assert!(!sim.is_noiseless(), "Expected noisy simulator.");
71
72 let noise = PauliNoise::from_probabilities(0.0, 0.0, 1e-10)
73 .expect("0.0, 0.0, 1e-10 Pauli noise should be constructable.");
74 let sim = SparseSim::new_with_noise(&noise);
75 assert!(!sim.is_noiseless(), "Expected noisy simulator.");
76}
77
78#[test]
79fn noiseless_gate() {
80 let noise = PauliNoise::from_probabilities(0.0, 0.0, 0.0)
81 .expect("noiseless Pauli noise should be constructable.");
82 let mut sim = SparseSim::new_with_noise(&noise);
83 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
84 for _ in 0..100 {
85 let _ = sim.x(q);
86 let res1 = sim
87 .m(q)
88 .expect("sparse simulator is infinite")
89 .unwrap_bool();
90 assert!(res1, "Expected True without noise.");
91 let _ = sim.x(q);
92 let res2 = sim
93 .m(q)
94 .expect("sparse simulator is infinite")
95 .unwrap_bool();
96 assert!(!res2, "Expected False without noise.");
97 }
98 assert!(
99 sim.qubit_release(q).expect("sparse simulator is infinite"),
100 "Expected correct qubit state on release."
101 );
102}
103
104#[test]
105fn bitflip_measurement() {
106 let noise = PauliNoise::from_probabilities(1.0, 0.0, 0.0)
107 .expect("bit flip noise with probability 100% should be constructable.");
108 let mut sim = SparseSim::new_with_noise(&noise);
109 assert!(!sim.is_noiseless(), "Expected noisy simulator.");
110 let q = sim.qubit_allocate().expect("sparse simulator is infinite"); // Allocation is noiseless even with noise.
111 for _ in 0..100 {
112 let res1 = sim
113 .m(q)
114 .expect("sparse simulator is infinite")
115 .unwrap_bool();
116 assert!(res1, "Expected True for 100% bit flip noise.");
117 let res2 = sim
118 .m(q)
119 .expect("sparse simulator is infinite")
120 .unwrap_bool();
121 assert!(!res2, "Expected False for 100% bit flip noise.");
122 }
123 assert!(
124 sim.qubit_release(q).expect("sparse simulator is infinite"),
125 "Expected correct qubit state on release."
126 );
127}
128
129#[test]
130fn noisy_measurement() {
131 let noise = PauliNoise::from_probabilities(0.3, 0.0, 0.0)
132 .expect("bit flip noise with probability 100% should be constructable.");
133 let mut sim = SparseSim::new_with_noise(&noise);
134 assert!(!sim.is_noiseless(), "Expected noisy simulator.");
135 sim.set_seed(Some(0));
136 let mut true_count = 0;
137 for _ in 0..1000 {
138 let q = sim.qubit_allocate().expect("sparse simulator is infinite"); // Allocation is noiseless even with noise.
139 // sim.m sometimes applies X before measuring
140 if sim
141 .m(q)
142 .expect("sparse simulator is infinite")
143 .unwrap_bool()
144 {
145 true_count += 1;
146 }
147 sim.qubit_release(q).expect("sparse simulator is infinite");
148 }
149 assert!(
150 true_count > 200 && true_count < 400,
151 "Expected about 30% bit flip noise."
152 );
153}
154
155pub fn state_to_string(input: &(Vec<(BigUint, Complex<f64>)>, usize)) -> String {
156 input
157 .0
158 .iter()
159 .fold(String::new(), |mut output, (id, state)| {
160 let _ = write!(
161 output,
162 "{}: {} ",
163 format_state_id(id, input.1),
164 fmt_complex(state)
165 );
166 output
167 })
168 .clone()
169}
170
171fn check_state(sim: &mut SparseSim, expected: &Expect) {
172 let state = sim
173 .capture_quantum_state()
174 .expect("sparse simulator is infinite");
175 expected.assert_eq(&state_to_string(&state));
176}
177
178#[test]
179fn noisy_via_x() {
180 let noise = PauliNoise::from_probabilities(1.0, 0.0, 0.0)
181 .expect("bit flip noise with probability 100% should be constructable.");
182 let mut sim = SparseSim::new_with_noise(&noise);
183 assert!(!sim.is_noiseless(), "Expected noisy simulator.");
184 let q = sim.qubit_allocate().expect("sparse simulator is infinite"); // Allocation is noiseless even with noise.
185 check_state(&mut sim, &expect!["|0⟩: 1.0000+0.0000𝑖 "]);
186 let _ = sim.x(q); // Followed by X. So, no op.
187 check_state(&mut sim, &expect!["|0⟩: 1.0000+0.0000𝑖 "]);
188 let _ = sim.y(q); // Followed by X.
189 check_state(&mut sim, &expect!["|0⟩: 0.0000+1.0000𝑖 "]);
190 let _ = sim.z(q); // Followed by X.
191 check_state(&mut sim, &expect!["|1⟩: 0.0000+1.0000𝑖 "]);
192}
193
194#[test]
195fn noisy_via_y() {
196 let noise = PauliNoise::from_probabilities(0.0, 1.0, 0.0)
197 .expect("0.0, 1.0, 0.0 Pauli noise should be constructable.");
198 let mut sim = SparseSim::new_with_noise(&noise);
199 assert!(!sim.is_noiseless(), "Expected noisy simulator.");
200 let q = sim.qubit_allocate().expect("sparse simulator is infinite"); // Allocation is noiseless even with noise.
201 check_state(&mut sim, &expect!["|0⟩: 1.0000+0.0000𝑖 "]);
202 let _ = sim.x(q); // Followed by Y.
203 check_state(&mut sim, &expect!["|0⟩: 0.0000−1.0000𝑖 "]);
204 let _ = sim.y(q); // Followed by Y. So, no op.
205 check_state(&mut sim, &expect!["|0⟩: 0.0000−1.0000𝑖 "]);
206 let _ = sim.z(q); // Followed by Y.
207 check_state(&mut sim, &expect!["|1⟩: 1.0000+0.0000𝑖 "]);
208}
209
210#[test]
211fn noisy_via_z() {
212 let noise = PauliNoise::from_probabilities(0.0, 0.0, 1.0)
213 .expect("phase flip noise with probability 100% should be constructable.");
214 let mut sim = SparseSim::new_with_noise(&noise);
215 assert!(!sim.is_noiseless(), "Expected noisy simulator.");
216 let q = sim.qubit_allocate().expect("sparse simulator is infinite"); // Allocation is noiseless even with noise.
217 check_state(&mut sim, &expect!["|0⟩: 1.0000+0.0000𝑖 "]);
218 let _ = sim.x(q); // Followed by Z.
219 check_state(&mut sim, &expect!["|1⟩: −1.0000+0.0000𝑖 "]);
220 let _ = sim.y(q); // Followed by Z.
221 check_state(&mut sim, &expect!["|0⟩: 0.0000+1.0000𝑖 "]);
222 let _ = sim.z(q); // Followed by Z. So, no op.
223 check_state(&mut sim, &expect!["|0⟩: 0.0000+1.0000𝑖 "]);
224}
225
226#[test]
227fn measure_without_loss_returns_value() {
228 let mut sim = SparseSim::new();
229 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
230 let res = sim.m(q).expect("sparse simulator is infinite");
231 assert!(
232 matches!(res, val::Result::Val(_)),
233 "Expected measurement to return a result"
234 );
235}
236
237#[test]
238fn measure_with_loss_returns_loss() {
239 let mut sim = SparseSim::new();
240 sim.set_loss(1.0); // Set loss probability to 100%
241 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
242 let res = sim.m(q).expect("sparse simulator is infinite");
243 assert_eq!(
244 res,
245 val::Result::Loss,
246 "Expected measurement with loss to return None"
247 );
248}
249
250/// Creates a `NoiseConfig` where the given gate's `NoiseTable` has 100% probability
251/// of the specified single-qubit Pauli fault, and all other gates are noiseless.
252fn noise_config_with_single_qubit_fault(
253 set_gate: impl FnOnce(&mut NoiseConfig<f64, f64>, NoiseTable<f64>),
254 pauli: &str,
255) -> NoiseConfig<f64, f64> {
256 let mut config = NoiseConfig::NOISELESS;
257 let table = NoiseTable {
258 qubits: 1,
259 pauli_strings: vec![encode_pauli(pauli)],
260 probabilities: vec![1.0],
261 loss: 0.0,
262 };
263 set_gate(&mut config, table);
264 config
265}
266
267/// Creates a `NoiseConfig` where the given gate's `NoiseTable` has 100% probability
268/// of the specified two-qubit Pauli fault, and all other gates are noiseless.
269fn noise_config_with_two_qubit_fault(
270 set_gate: impl FnOnce(&mut NoiseConfig<f64, f64>, NoiseTable<f64>),
271 pauli: &str,
272) -> NoiseConfig<f64, f64> {
273 let mut config = NoiseConfig::NOISELESS;
274 let table = NoiseTable {
275 qubits: 2,
276 pauli_strings: vec![encode_pauli(pauli)],
277 probabilities: vec![1.0],
278 loss: 0.0,
279 };
280 set_gate(&mut config, table);
281 config
282}
283
284// Tests for single-qubit gates with CumulativeNoiseConfig
285
286#[test]
287fn noise_config_x_gate_with_x_fault() {
288 // X gate followed by 100% X fault = identity (X * X = I)
289 let config = noise_config_with_single_qubit_fault(|c, t| c.x = t, "X");
290 let mut sim = SparseSim::new_with_noise_config(config.into());
291 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
292 let _ = sim.x(q); // X then X fault => |0⟩
293 check_state(&mut sim, &expect!["|0⟩: 1.0000+0.0000𝑖 "]);
294}
295
296#[test]
297fn noise_config_x_gate_with_z_fault() {
298 // X gate followed by 100% Z fault = ZX|0⟩ = Z|1⟩ = -|1⟩
299 let config = noise_config_with_single_qubit_fault(|c, t| c.x = t, "Z");
300 let mut sim = SparseSim::new_with_noise_config(config.into());
301 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
302 let _ = sim.x(q);
303 check_state(&mut sim, &expect!["|1⟩: −1.0000+0.0000𝑖 "]);
304}
305
306#[test]
307fn noise_config_x_gate_with_y_fault() {
308 // X gate followed by 100% Y fault = YX|0⟩ = Y|1⟩ = -i|0⟩
309 let config = noise_config_with_single_qubit_fault(|c, t| c.x = t, "Y");
310 let mut sim = SparseSim::new_with_noise_config(config.into());
311 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
312 let _ = sim.x(q);
313 check_state(&mut sim, &expect!["|0⟩: 0.0000−1.0000𝑖 "]);
314}
315
316#[test]
317fn noise_config_h_gate_with_y_fault() {
318 // H|0⟩ = |+⟩, then Y|+⟩ = i|−⟩
319 let config = noise_config_with_single_qubit_fault(|c, t| c.h = t, "Y");
320 let mut sim = SparseSim::new_with_noise_config(config.into());
321 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
322 let _ = sim.h(q);
323 check_state(
324 &mut sim,
325 &expect!["|0⟩: 0.0000+0.7071𝑖 |1⟩: 0.0000−0.7071𝑖 "],
326 );
327}
328
329#[test]
330fn noise_config_h_gate_with_z_fault() {
331 // H|0⟩ = |+⟩, then Z|+⟩ = |−⟩
332 let config = noise_config_with_single_qubit_fault(|c, t| c.h = t, "Z");
333 let mut sim = SparseSim::new_with_noise_config(config.into());
334 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
335 let _ = sim.h(q);
336 check_state(
337 &mut sim,
338 &expect!["|0⟩: 0.7071+0.0000𝑖 |1⟩: −0.7071+0.0000𝑖 "],
339 );
340}
341
342#[test]
343fn noise_config_y_gate_with_y_fault() {
344 // Y gate followed by 100% Y fault = Y*Y = I
345 let config = noise_config_with_single_qubit_fault(|c, t| c.y = t, "Y");
346 let mut sim = SparseSim::new_with_noise_config(config.into());
347 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
348 let _ = sim.y(q);
349 check_state(&mut sim, &expect!["|0⟩: 1.0000+0.0000𝑖 "]);
350}
351
352#[test]
353fn noise_config_z_gate_with_x_fault() {
354 // Z|0⟩ = |0⟩, then X|0⟩ = |1⟩
355 let config = noise_config_with_single_qubit_fault(|c, t| c.z = t, "X");
356 let mut sim = SparseSim::new_with_noise_config(config.into());
357 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
358 let _ = sim.z(q);
359 check_state(&mut sim, &expect!["|1⟩: 1.0000+0.0000𝑖 "]);
360}
361
362#[test]
363fn noise_config_s_gate_with_x_fault() {
364 // S|0⟩ = |0⟩ (S only adds phase to |1⟩), then X|0⟩ = |1⟩
365 let config = noise_config_with_single_qubit_fault(|c, t| c.s = t, "X");
366 let mut sim = SparseSim::new_with_noise_config(config.into());
367 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
368 let _ = sim.s(q);
369 check_state(&mut sim, &expect!["|1⟩: 1.0000+0.0000𝑖 "]);
370}
371
372#[test]
373fn noise_config_s_gate_with_y_fault() {
374 // S|0⟩ = |0⟩, then Y|0⟩ = i|1⟩
375 let config = noise_config_with_single_qubit_fault(|c, t| c.s = t, "Y");
376 let mut sim = SparseSim::new_with_noise_config(config.into());
377 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
378 let _ = sim.s(q);
379 check_state(&mut sim, &expect!["|1⟩: 0.0000+1.0000𝑖 "]);
380}
381
382#[test]
383fn noise_config_t_gate_with_x_fault() {
384 // T|0⟩ = |0⟩ (T only adds phase to |1⟩), then X|0⟩ = |1⟩
385 let config = noise_config_with_single_qubit_fault(|c, t| c.t = t, "X");
386 let mut sim = SparseSim::new_with_noise_config(config.into());
387 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
388 let _ = sim.t(q);
389 check_state(&mut sim, &expect!["|1⟩: 1.0000+0.0000𝑖 "]);
390}
391
392#[test]
393fn noise_config_sadj_gate_with_y_fault() {
394 // Sadj|0⟩ = |0⟩, then Y|0⟩ = i|1⟩
395 let config = noise_config_with_single_qubit_fault(|c, t| c.s_adj = t, "Y");
396 let mut sim = SparseSim::new_with_noise_config(config.into());
397 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
398 let _ = sim.sadj(q);
399 check_state(&mut sim, &expect!["|1⟩: 0.0000+1.0000𝑖 "]);
400}
401
402#[test]
403fn noise_config_tadj_gate_with_y_fault() {
404 // Tadj|0⟩ = |0⟩, then Y|0⟩ = i|1⟩
405 let config = noise_config_with_single_qubit_fault(|c, t| c.t_adj = t, "Y");
406 let mut sim = SparseSim::new_with_noise_config(config.into());
407 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
408 let _ = sim.tadj(q);
409 check_state(&mut sim, &expect!["|1⟩: 0.0000+1.0000𝑖 "]);
410}
411
412#[test]
413fn noise_config_mz_with_x_fault() {
414 // Measurement with 100% X fault: qubit in |0⟩, X is applied before measurement,
415 // so it measures as True (|1⟩).
416 let config = noise_config_with_single_qubit_fault(|c, t| c.mz = t, "X");
417 let mut sim = SparseSim::new_with_noise_config(config.into());
418 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
419 let res = sim
420 .m(q)
421 .expect("sparse simulator is infinite")
422 .unwrap_bool();
423 assert!(
424 res,
425 "Expected True: X fault flips |0⟩ to |1⟩ before measurement."
426 );
427}
428
429#[test]
430fn noise_config_mz_with_z_fault() {
431 // Measurement with 100% Z fault: Z|0⟩ = |0⟩, so measurement is still False.
432 let config = noise_config_with_single_qubit_fault(|c, t| c.mz = t, "Z");
433 let mut sim = SparseSim::new_with_noise_config(config.into());
434 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
435 let res = sim
436 .m(q)
437 .expect("sparse simulator is infinite")
438 .unwrap_bool();
439 assert!(
440 !res,
441 "Expected False: Z fault on |0⟩ doesn't change measurement outcome."
442 );
443}
444
445// Tests for two-qubit gates with CumulativeNoiseConfig
446
447#[test]
448fn noise_config_cx_gate_with_xi_fault() {
449 // CX(ctl, tgt) on |00⟩ = |00⟩, then XI fault: X on control, I on target => |10⟩
450 let config = noise_config_with_two_qubit_fault(|c, t| c.cx = t, "XI");
451 let mut sim = SparseSim::new_with_noise_config(config.into());
452 let ctl = sim.qubit_allocate().expect("sparse simulator is infinite");
453 let tgt = sim.qubit_allocate().expect("sparse simulator is infinite");
454 let _ = sim.cx(ctl, tgt);
455 check_state(&mut sim, &expect!["|10⟩: 1.0000+0.0000𝑖 "]);
456}
457
458#[test]
459fn noise_config_cx_gate_with_ix_fault() {
460 // CX(ctl, tgt) on |00⟩ = |00⟩, then IX fault: I on control, X on target => |01⟩
461 let config = noise_config_with_two_qubit_fault(|c, t| c.cx = t, "IX");
462 let mut sim = SparseSim::new_with_noise_config(config.into());
463 let ctl = sim.qubit_allocate().expect("sparse simulator is infinite");
464 let tgt = sim.qubit_allocate().expect("sparse simulator is infinite");
465 let _ = sim.cx(ctl, tgt);
466 check_state(&mut sim, &expect!["|01⟩: 1.0000+0.0000𝑖 "]);
467}
468
469#[test]
470fn noise_config_cx_gate_with_xx_fault() {
471 // CX(ctl, tgt) on |00⟩ = |00⟩, then XX fault: X on both => |11⟩
472 let config = noise_config_with_two_qubit_fault(|c, t| c.cx = t, "XX");
473 let mut sim = SparseSim::new_with_noise_config(config.into());
474 let ctl = sim.qubit_allocate().expect("sparse simulator is infinite");
475 let tgt = sim.qubit_allocate().expect("sparse simulator is infinite");
476 let _ = sim.cx(ctl, tgt);
477 check_state(&mut sim, &expect!["|11⟩: 1.0000+0.0000𝑖 "]);
478}
479
480#[test]
481fn noise_config_cz_gate_with_xy_fault() {
482 // CZ on |00⟩ = |00⟩, then XY fault: X on first, Y on second
483 // X|0⟩ = |1⟩, Y|0⟩ = i|1⟩ => |1i1⟩
484 let config = noise_config_with_two_qubit_fault(|c, t| c.cz = t, "XY");
485 let mut sim = SparseSim::new_with_noise_config(config.into());
486 let q0 = sim.qubit_allocate().expect("sparse simulator is infinite");
487 let q1 = sim.qubit_allocate().expect("sparse simulator is infinite");
488 let _ = sim.cz(q0, q1);
489 check_state(&mut sim, &expect!["|11⟩: 0.0000+1.0000𝑖 "]);
490}
491
492#[test]
493fn noise_config_swap_gate_with_xx_fault() {
494 // Prepare |10⟩, SWAP => |01⟩, then XX fault => |10⟩ again
495 let config = noise_config_with_two_qubit_fault(|c, t| c.swap = t, "XX");
496 let mut sim = SparseSim::new_with_noise_config(config.into());
497 let q0 = sim.qubit_allocate().expect("sparse simulator is infinite");
498 let q1 = sim.qubit_allocate().expect("sparse simulator is infinite");
499 let _ = sim.x(q0); // |10⟩ (x gate has no noise configured)
500 let _ = sim.swap(q0, q1); // SWAP => |01⟩, then XX => |10⟩
501 check_state(&mut sim, &expect!["|10⟩: 1.0000+0.0000𝑖 "]);
502}
503
504// Test that noise is only applied to the configured gate, not others
505
506#[test]
507fn noise_config_only_affects_configured_gate() {
508 // Configure X fault only on H gate; X gate should be noiseless.
509 let config = noise_config_with_single_qubit_fault(|c, t| c.h = t, "X");
510 let mut sim = SparseSim::new_with_noise_config(config.into());
511 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
512 // X gate has no noise configured, so X|0⟩ = |1⟩ without any fault
513 let _ = sim.x(q);
514 check_state(&mut sim, &expect!["|1⟩: 1.0000+0.0000𝑖 "]);
515 // Now apply H (which has 100% X fault): H|1⟩ = |−⟩, then X|−⟩ = −|−⟩
516 let _ = sim.h(q);
517 check_state(
518 &mut sim,
519 &expect!["|0⟩: −0.7071+0.0000𝑖 |1⟩: 0.7071+0.0000𝑖 "],
520 );
521}
522
523// Test loss via noise config
524
525#[test]
526fn noise_config_mz_with_loss() {
527 let mut config = NoiseConfig::NOISELESS;
528 config.mz = NoiseTable {
529 qubits: 1,
530 pauli_strings: vec![],
531 probabilities: vec![],
532 loss: 1.0,
533 };
534 let mut sim = SparseSim::new_with_noise_config(config.into());
535 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
536 let res = sim.m(q).expect("sparse simulator is infinite");
537 assert_eq!(
538 res,
539 val::Result::Loss,
540 "Expected measurement with 100% loss to return Loss"
541 );
542}
543
544#[test]
545fn noise_config_gate_loss_causes_measurement_loss() {
546 // Configure 100% loss on X gate. After X, qubit is lost.
547 // Measurement of a lost qubit should return Loss.
548 let mut config = NoiseConfig::NOISELESS;
549 config.x = NoiseTable {
550 qubits: 1,
551 pauli_strings: vec![],
552 probabilities: vec![],
553 loss: 1.0,
554 };
555 let mut sim = SparseSim::new_with_noise_config(config.into());
556 let q = sim.qubit_allocate().expect("sparse simulator is infinite");
557 let _ = sim.x(q);
558 let res = sim.m(q).expect("sparse simulator is infinite");
559 assert_eq!(
560 res,
561 val::Result::Loss,
562 "Expected measurement after gate loss to return Loss"
563 );
564}
565