1#![allow(clippy::needless_range_loop)]
8
9use scirs2_core::Complex64;
10use std::fmt::Debug;
11
12use quantrs2_core::error::QuantRS2Result;
13use quantrs2_core::qubit::QubitId;
14
15#[derive(Debug, Clone)]
17pub enum NoiseChannelType {
18 BitFlip(BitFlipChannel),
19 PhaseFlip(PhaseFlipChannel),
20 Depolarizing(DepolarizingChannel),
21 AmplitudeDamping(AmplitudeDampingChannel),
22 PhaseDamping(PhaseDampingChannel),
23}
24
25impl NoiseChannelType {
26 pub fn name(&self) -> &'static str {
28 match self {
29 Self::BitFlip(ch) => ch.name(),
30 Self::PhaseFlip(ch) => ch.name(),
31 Self::Depolarizing(ch) => ch.name(),
32 Self::AmplitudeDamping(ch) => ch.name(),
33 Self::PhaseDamping(ch) => ch.name(),
34 }
35 }
36
37 pub fn normalize_state(state: &mut [Complex64]) {
39 let mut norm_squared = 0.0;
41 for amp in state.iter() {
42 norm_squared += amp.norm_sqr();
43 }
44
45 if (norm_squared - 1.0).abs() > 1e-10 {
47 let norm = norm_squared.sqrt();
48 for amp in state.iter_mut() {
49 *amp /= Complex64::new(norm, 0.0);
50 }
51 }
52 }
53
54 pub fn qubits(&self) -> Vec<QubitId> {
56 match self {
57 Self::BitFlip(ch) => ch.qubits(),
58 Self::PhaseFlip(ch) => ch.qubits(),
59 Self::Depolarizing(ch) => ch.qubits(),
60 Self::AmplitudeDamping(ch) => ch.qubits(),
61 Self::PhaseDamping(ch) => ch.qubits(),
62 }
63 }
64
65 pub fn apply_to_statevector(&self, state: &mut [Complex64]) -> QuantRS2Result<()> {
67 match self {
68 Self::BitFlip(ch) => ch.apply_to_statevector(state),
69 Self::PhaseFlip(ch) => ch.apply_to_statevector(state),
70 Self::Depolarizing(ch) => ch.apply_to_statevector(state),
71 Self::AmplitudeDamping(ch) => ch.apply_to_statevector(state),
72 Self::PhaseDamping(ch) => ch.apply_to_statevector(state),
73 }
74 }
75
76 pub fn probability(&self) -> f64 {
78 match self {
79 Self::BitFlip(ch) => ch.probability(),
80 Self::PhaseFlip(ch) => ch.probability(),
81 Self::Depolarizing(ch) => ch.probability(),
82 Self::AmplitudeDamping(ch) => ch.probability(),
83 Self::PhaseDamping(ch) => ch.probability(),
84 }
85 }
86}
87
88pub trait NoiseChannel: Debug + Clone {
90 fn name(&self) -> &'static str;
92
93 fn qubits(&self) -> Vec<QubitId>;
95
96 fn apply_to_statevector(&self, state: &mut [Complex64]) -> QuantRS2Result<()>;
98
99 fn kraus_operators(&self) -> Vec<Vec<Complex64>>;
101
102 fn probability(&self) -> f64;
104}
105
106#[derive(Debug, Clone)]
108pub struct BitFlipChannel {
109 pub target: QubitId,
111
112 pub probability: f64,
114}
115
116impl NoiseChannel for BitFlipChannel {
117 fn name(&self) -> &'static str {
118 "BitFlip"
119 }
120
121 fn qubits(&self) -> Vec<QubitId> {
122 vec![self.target]
123 }
124
125 fn apply_to_statevector(&self, state: &mut [Complex64]) -> QuantRS2Result<()> {
126 let target_idx = self.target.id() as usize;
127 let dim = state.len();
128
129 if fastrand::f64() < self.probability {
131 let state_copy = state.to_vec();
133
134 for i in 0..dim {
136 let flipped_i = i ^ (1 << target_idx);
137 state[i] = state_copy[flipped_i];
138 }
139 }
140
141 Ok(())
142 }
143
144 fn kraus_operators(&self) -> Vec<Vec<Complex64>> {
145 let p = self.probability;
148 let sqrt_1_minus_p = (1.0 - p).sqrt();
149 let sqrt_p = p.sqrt();
150
151 let k0 = vec![
153 Complex64::new(sqrt_1_minus_p, 0.0),
154 Complex64::new(0.0, 0.0),
155 Complex64::new(0.0, 0.0),
156 Complex64::new(sqrt_1_minus_p, 0.0),
157 ];
158
159 let k1 = vec![
161 Complex64::new(0.0, 0.0),
162 Complex64::new(sqrt_p, 0.0),
163 Complex64::new(sqrt_p, 0.0),
164 Complex64::new(0.0, 0.0),
165 ];
166
167 vec![k0, k1]
168 }
169
170 fn probability(&self) -> f64 {
171 self.probability
172 }
173}
174
175#[derive(Debug, Clone)]
177pub struct PhaseFlipChannel {
178 pub target: QubitId,
180
181 pub probability: f64,
183}
184
185impl NoiseChannel for PhaseFlipChannel {
186 fn name(&self) -> &'static str {
187 "PhaseFlip"
188 }
189
190 fn qubits(&self) -> Vec<QubitId> {
191 vec![self.target]
192 }
193
194 fn apply_to_statevector(&self, state: &mut [Complex64]) -> QuantRS2Result<()> {
195 let target_idx = self.target.id() as usize;
196 let dim = state.len();
197
198 if fastrand::f64() < self.probability {
200 for i in 0..dim {
202 if (i >> target_idx) & 1 == 1 {
203 state[i] = -state[i];
205 }
206 }
207 }
208
209 Ok(())
210 }
211
212 fn kraus_operators(&self) -> Vec<Vec<Complex64>> {
213 let p = self.probability;
216 let sqrt_1_minus_p = (1.0 - p).sqrt();
217 let sqrt_p = p.sqrt();
218
219 let k0 = vec![
221 Complex64::new(sqrt_1_minus_p, 0.0),
222 Complex64::new(0.0, 0.0),
223 Complex64::new(0.0, 0.0),
224 Complex64::new(sqrt_1_minus_p, 0.0),
225 ];
226
227 let k1 = vec![
229 Complex64::new(sqrt_p, 0.0),
230 Complex64::new(0.0, 0.0),
231 Complex64::new(0.0, 0.0),
232 Complex64::new(-sqrt_p, 0.0),
233 ];
234
235 vec![k0, k1]
236 }
237
238 fn probability(&self) -> f64 {
239 self.probability
240 }
241}
242
243#[derive(Debug, Clone)]
245pub struct DepolarizingChannel {
246 pub target: QubitId,
248
249 pub probability: f64,
251}
252
253impl NoiseChannel for DepolarizingChannel {
254 fn name(&self) -> &'static str {
255 "Depolarizing"
256 }
257
258 fn qubits(&self) -> Vec<QubitId> {
259 vec![self.target]
260 }
261
262 fn apply_to_statevector(&self, state: &mut [Complex64]) -> QuantRS2Result<()> {
263 let target_idx = self.target.id() as usize;
264 let dim = state.len();
265
266 if fastrand::f64() < self.probability {
268 let error_type = fastrand::u32(..) % 3;
270
271 let state_copy = state.to_vec();
273
274 match error_type {
275 0 => {
276 for i in 0..dim {
278 let flipped_i = i ^ (1 << target_idx);
279 state[i] = state_copy[flipped_i];
280 }
281 }
282 1 => {
283 for i in 0..dim {
285 let flipped_i = i ^ (1 << target_idx);
286 let phase = if (i >> target_idx) & 1 == 1 {
287 -1.0
288 } else {
289 1.0
290 };
291 state[i] = state_copy[flipped_i] * Complex64::new(0.0, phase);
292 }
293 }
294 2 => {
295 for i in 0..dim {
297 if (i >> target_idx) & 1 == 1 {
298 state[i] = -state_copy[i];
299 } else {
300 state[i] = state_copy[i];
301 }
302 }
303 }
304 _ => unreachable!(),
305 }
306 }
307
308 Ok(())
309 }
310
311 fn kraus_operators(&self) -> Vec<Vec<Complex64>> {
312 let p = self.probability;
318 let sqrt_1_minus_3p_4 = (1.0 - 3.0 * p / 4.0).sqrt();
319 let sqrt_p_4 = (p / 4.0).sqrt();
320
321 let k0 = vec![
323 Complex64::new(sqrt_1_minus_3p_4, 0.0),
324 Complex64::new(0.0, 0.0),
325 Complex64::new(0.0, 0.0),
326 Complex64::new(sqrt_1_minus_3p_4, 0.0),
327 ];
328
329 let k1 = vec![
331 Complex64::new(0.0, 0.0),
332 Complex64::new(sqrt_p_4, 0.0),
333 Complex64::new(sqrt_p_4, 0.0),
334 Complex64::new(0.0, 0.0),
335 ];
336
337 let k2 = vec![
339 Complex64::new(0.0, 0.0),
340 Complex64::new(0.0, -sqrt_p_4),
341 Complex64::new(0.0, sqrt_p_4),
342 Complex64::new(0.0, 0.0),
343 ];
344
345 let k3 = vec![
347 Complex64::new(sqrt_p_4, 0.0),
348 Complex64::new(0.0, 0.0),
349 Complex64::new(0.0, 0.0),
350 Complex64::new(-sqrt_p_4, 0.0),
351 ];
352
353 vec![k0, k1, k2, k3]
354 }
355
356 fn probability(&self) -> f64 {
357 self.probability
358 }
359}
360
361#[derive(Debug, Clone)]
363pub struct AmplitudeDampingChannel {
364 pub target: QubitId,
366
367 pub gamma: f64,
369}
370
371impl NoiseChannel for AmplitudeDampingChannel {
372 fn name(&self) -> &'static str {
373 "AmplitudeDamping"
374 }
375
376 fn qubits(&self) -> Vec<QubitId> {
377 vec![self.target]
378 }
379
380 fn apply_to_statevector(&self, state: &mut [Complex64]) -> QuantRS2Result<()> {
381 let target_idx = self.target.id() as usize;
382 let dim = state.len();
383
384 let state_copy = state.to_vec();
386
387 for i in 0..dim {
389 if (i >> target_idx) & 1 == 1 {
390 let base_idx = i & !(1 << target_idx); if fastrand::f64() < self.gamma {
395 state[base_idx] += state_copy[i];
397 state[i] = Complex64::new(0.0, 0.0);
398 } else {
399 state[i] = state_copy[i] * Complex64::new((1.0 - self.gamma).sqrt(), 0.0);
401 }
402 }
403 }
404
405 Ok(())
406 }
407
408 fn kraus_operators(&self) -> Vec<Vec<Complex64>> {
409 let gamma = self.gamma;
413 let sqrt_1_minus_gamma = (1.0 - gamma).sqrt();
414 let sqrt_gamma = gamma.sqrt();
415
416 let k0 = vec![
418 Complex64::new(1.0, 0.0),
419 Complex64::new(0.0, 0.0),
420 Complex64::new(0.0, 0.0),
421 Complex64::new(sqrt_1_minus_gamma, 0.0),
422 ];
423
424 let k1 = vec![
426 Complex64::new(0.0, 0.0),
427 Complex64::new(sqrt_gamma, 0.0),
428 Complex64::new(0.0, 0.0),
429 Complex64::new(0.0, 0.0),
430 ];
431
432 vec![k0, k1]
433 }
434
435 fn probability(&self) -> f64 {
436 self.gamma
437 }
438}
439
440#[derive(Debug, Clone)]
442pub struct PhaseDampingChannel {
443 pub target: QubitId,
445
446 pub lambda: f64,
448}
449
450impl NoiseChannel for PhaseDampingChannel {
451 fn name(&self) -> &'static str {
452 "PhaseDamping"
453 }
454
455 fn qubits(&self) -> Vec<QubitId> {
456 vec![self.target]
457 }
458
459 fn apply_to_statevector(&self, state: &mut [Complex64]) -> QuantRS2Result<()> {
460 let target_idx = self.target.id() as usize;
461 let dim = state.len();
462
463 for i in 0..dim {
465 if (i >> target_idx) & 1 == 1 {
466 if fastrand::f64() < self.lambda {
469 let phase = 2.0 * std::f64::consts::PI * fastrand::f64();
471 state[i] *= Complex64::new(phase.cos(), phase.sin());
472 }
473 }
474 }
475
476 Ok(())
477 }
478
479 fn kraus_operators(&self) -> Vec<Vec<Complex64>> {
480 let lambda = self.lambda;
484 let sqrt_1_minus_lambda = (1.0 - lambda).sqrt();
485 let sqrt_lambda = lambda.sqrt();
486
487 let k0 = vec![
489 Complex64::new(1.0, 0.0),
490 Complex64::new(0.0, 0.0),
491 Complex64::new(0.0, 0.0),
492 Complex64::new(sqrt_1_minus_lambda, 0.0),
493 ];
494
495 let k1 = vec![
497 Complex64::new(0.0, 0.0),
498 Complex64::new(0.0, 0.0),
499 Complex64::new(0.0, 0.0),
500 Complex64::new(sqrt_lambda, 0.0),
501 ];
502
503 vec![k0, k1]
504 }
505
506 fn probability(&self) -> f64 {
507 self.lambda
508 }
509}
510
511#[derive(Debug, Clone)]
513pub struct NoiseModel {
514 pub channels: Vec<NoiseChannelType>,
516
517 pub per_gate: bool,
519}
520
521impl NoiseModel {
522 pub fn new(per_gate: bool) -> Self {
524 Self {
525 channels: Vec::new(),
526 per_gate,
527 }
528 }
529
530 pub fn add_bit_flip(&mut self, channel: BitFlipChannel) -> &mut Self {
532 self.channels.push(NoiseChannelType::BitFlip(channel));
533 self
534 }
535
536 pub fn add_phase_flip(&mut self, channel: PhaseFlipChannel) -> &mut Self {
538 self.channels.push(NoiseChannelType::PhaseFlip(channel));
539 self
540 }
541
542 pub fn add_depolarizing(&mut self, channel: DepolarizingChannel) -> &mut Self {
544 self.channels.push(NoiseChannelType::Depolarizing(channel));
545 self
546 }
547
548 pub fn add_amplitude_damping(&mut self, channel: AmplitudeDampingChannel) -> &mut Self {
550 self.channels
551 .push(NoiseChannelType::AmplitudeDamping(channel));
552 self
553 }
554
555 pub fn add_phase_damping(&mut self, channel: PhaseDampingChannel) -> &mut Self {
557 self.channels.push(NoiseChannelType::PhaseDamping(channel));
558 self
559 }
560
561 pub fn apply_to_statevector(&self, state: &mut [Complex64]) -> QuantRS2Result<()> {
563 for channel in &self.channels {
564 channel.apply_to_statevector(state)?;
565 }
566
567 NoiseChannelType::normalize_state(state);
569
570 Ok(())
571 }
572
573 pub fn num_channels(&self) -> usize {
575 self.channels.len()
576 }
577}
578
579impl Default for NoiseModel {
580 fn default() -> Self {
581 Self::new(true)
582 }
583}
584
585pub struct NoiseModelBuilder {
587 model: NoiseModel,
588}
589
590impl NoiseModelBuilder {
591 pub fn new(per_gate: bool) -> Self {
593 Self {
594 model: NoiseModel::new(per_gate),
595 }
596 }
597
598 pub fn with_depolarizing_noise(mut self, qubits: &[QubitId], probability: f64) -> Self {
600 for &qubit in qubits {
601 self.model.add_depolarizing(DepolarizingChannel {
602 target: qubit,
603 probability,
604 });
605 }
606 self
607 }
608
609 pub fn with_bit_flip_noise(mut self, qubits: &[QubitId], probability: f64) -> Self {
611 for &qubit in qubits {
612 self.model.add_bit_flip(BitFlipChannel {
613 target: qubit,
614 probability,
615 });
616 }
617 self
618 }
619
620 pub fn with_phase_flip_noise(mut self, qubits: &[QubitId], probability: f64) -> Self {
622 for &qubit in qubits {
623 self.model.add_phase_flip(PhaseFlipChannel {
624 target: qubit,
625 probability,
626 });
627 }
628 self
629 }
630
631 pub fn with_amplitude_damping(mut self, qubits: &[QubitId], gamma: f64) -> Self {
633 for &qubit in qubits {
634 self.model.add_amplitude_damping(AmplitudeDampingChannel {
635 target: qubit,
636 gamma,
637 });
638 }
639 self
640 }
641
642 pub fn with_phase_damping(mut self, qubits: &[QubitId], lambda: f64) -> Self {
644 for &qubit in qubits {
645 self.model.add_phase_damping(PhaseDampingChannel {
646 target: qubit,
647 lambda,
648 });
649 }
650 self
651 }
652
653 pub fn build(self) -> NoiseModel {
655 self.model
656 }
657}