quantrs2_sim/
optimized_simple.rs1use scirs2_core::Complex64;
7
8use crate::utils::flip_bit;
9
10pub struct OptimizedStateVector {
12 state: Vec<Complex64>,
14 num_qubits: usize,
16}
17
18impl OptimizedStateVector {
19 pub fn new(num_qubits: usize) -> Self {
21 let dim = 1 << num_qubits;
22 let mut state = vec![Complex64::new(0.0, 0.0); dim];
23 state[0] = Complex64::new(1.0, 0.0); Self { state, num_qubits }
26 }
27
28 pub fn state(&self) -> &[Complex64] {
30 &self.state
31 }
32
33 pub fn state_mut(&mut self) -> &mut [Complex64] {
35 &mut self.state
36 }
37
38 pub const fn num_qubits(&self) -> usize {
40 self.num_qubits
41 }
42
43 pub const fn dimension(&self) -> usize {
45 1 << self.num_qubits
46 }
47
48 pub fn apply_single_qubit_gate(&mut self, matrix: &[Complex64], target: usize) {
55 assert!(
56 (target < self.num_qubits),
57 "Target qubit index out of range"
58 );
59
60 let dim = self.state.len();
61 let mut new_state = vec![Complex64::new(0.0, 0.0); dim];
62
63 for i in 0..dim {
65 let bit_val = (i >> target) & 1;
66
67 if bit_val == 0 {
69 let paired_idx = flip_bit(i, target);
70
71 let a0 = self.state[i]; let a1 = self.state[paired_idx]; new_state[i] = matrix[0] * a0 + matrix[1] * a1;
80 new_state[paired_idx] = matrix[2] * a0 + matrix[3] * a1;
81 }
82 }
83
84 self.state = new_state;
85 }
86
87 pub fn apply_cnot(&mut self, control: usize, target: usize) {
94 assert!(
95 !(control >= self.num_qubits || target >= self.num_qubits),
96 "Qubit indices out of range"
97 );
98
99 assert!(
100 (control != target),
101 "Control and target qubits must be different"
102 );
103
104 let dim = self.state.len();
105 let mut new_state = vec![Complex64::new(0.0, 0.0); dim];
106
107 for (i, val) in new_state.iter_mut().enumerate().take(dim) {
109 let control_bit = (i >> control) & 1;
110
111 if control_bit == 0 {
112 *val = self.state[i];
114 } else {
115 let flipped_idx = flip_bit(i, target);
117 *val = self.state[flipped_idx];
118 }
119 }
120
121 self.state = new_state;
122 }
123
124 pub fn apply_two_qubit_gate(&mut self, matrix: &[Complex64], qubit1: usize, qubit2: usize) {
132 assert!(
133 !(qubit1 >= self.num_qubits || qubit2 >= self.num_qubits),
134 "Qubit indices out of range"
135 );
136
137 assert!((qubit1 != qubit2), "Qubit indices must be different");
138
139 let dim = self.state.len();
140 let mut new_state = vec![Complex64::new(0.0, 0.0); dim];
141
142 for (i, val) in new_state.iter_mut().enumerate().take(dim) {
144 let bit1 = (i >> qubit1) & 1;
146 let bit2 = (i >> qubit2) & 1;
147 let subspace_idx = (bit1 << 1) | bit2;
148
149 let bits00 = i & !(1 << qubit1) & !(1 << qubit2);
151 let bits01 = bits00 | (1 << qubit2);
152 let bits10 = bits00 | (1 << qubit1);
153 let bits11 = bits10 | (1 << qubit2);
154
155 *val = matrix[subspace_idx * 4] * self.state[bits00]
157 + matrix[subspace_idx * 4 + 1] * self.state[bits01]
158 + matrix[subspace_idx * 4 + 2] * self.state[bits10]
159 + matrix[subspace_idx * 4 + 3] * self.state[bits11];
160 }
161
162 self.state = new_state;
163 }
164
165 pub fn probability(&self, bit_string: &[u8]) -> f64 {
167 assert!(
168 (bit_string.len() == self.num_qubits),
169 "Bit string length must match number of qubits"
170 );
171
172 let mut idx = 0;
174 for (i, &bit) in bit_string.iter().enumerate() {
175 if bit != 0 {
176 idx |= 1 << i;
177 }
178 }
179
180 self.state[idx].norm_sqr()
182 }
183
184 pub fn probabilities(&self) -> Vec<f64> {
186 self.state.iter().map(|a| a.norm_sqr()).collect()
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193 use std::f64::consts::FRAC_1_SQRT_2;
194
195 #[test]
196 fn test_optimized_state_vector_init() {
197 let sv = OptimizedStateVector::new(2);
198 assert_eq!(sv.num_qubits(), 2);
199 assert_eq!(sv.dimension(), 4);
200
201 assert_eq!(sv.state()[0], Complex64::new(1.0, 0.0));
203 assert_eq!(sv.state()[1], Complex64::new(0.0, 0.0));
204 assert_eq!(sv.state()[2], Complex64::new(0.0, 0.0));
205 assert_eq!(sv.state()[3], Complex64::new(0.0, 0.0));
206 }
207
208 #[test]
209 fn test_hadamard_gate() {
210 let h_matrix = [
212 Complex64::new(FRAC_1_SQRT_2, 0.0),
213 Complex64::new(FRAC_1_SQRT_2, 0.0),
214 Complex64::new(FRAC_1_SQRT_2, 0.0),
215 Complex64::new(-FRAC_1_SQRT_2, 0.0),
216 ];
217
218 let mut sv = OptimizedStateVector::new(2);
220 println!("Initial state: {:?}", sv.state());
221 sv.apply_single_qubit_gate(&h_matrix, 1); println!("After H on qubit 1: {:?}", sv.state());
225
226 assert_eq!(sv.state()[0], Complex64::new(FRAC_1_SQRT_2, 0.0));
228 assert_eq!(sv.state()[1], Complex64::new(0.0, 0.0));
229 assert_eq!(sv.state()[2], Complex64::new(FRAC_1_SQRT_2, 0.0));
230 assert_eq!(sv.state()[3], Complex64::new(0.0, 0.0));
231
232 sv.apply_single_qubit_gate(&h_matrix, 0);
234
235 println!("After both H gates: {:?}", sv.state());
237
238 assert!((sv.state()[0] - Complex64::new(0.5, 0.0)).norm() < 1e-10);
245 assert!((sv.state()[1] - Complex64::new(0.5, 0.0)).norm() < 1e-10);
246 assert!((sv.state()[2] - Complex64::new(0.5, 0.0)).norm() < 1e-10);
247 assert!((sv.state()[3] - Complex64::new(0.5, 0.0)).norm() < 1e-10);
248 }
249
250 #[test]
251 fn test_cnot_gate() {
252 let mut sv = OptimizedStateVector::new(2);
254
255 let h_matrix = [
257 Complex64::new(FRAC_1_SQRT_2, 0.0),
258 Complex64::new(FRAC_1_SQRT_2, 0.0),
259 Complex64::new(FRAC_1_SQRT_2, 0.0),
260 Complex64::new(-FRAC_1_SQRT_2, 0.0),
261 ];
262 sv.apply_single_qubit_gate(&h_matrix, 0);
263
264 sv.apply_cnot(0, 1);
266
267 assert_eq!(sv.state()[0], Complex64::new(FRAC_1_SQRT_2, 0.0));
269 assert_eq!(sv.state()[1], Complex64::new(0.0, 0.0));
270 assert_eq!(sv.state()[2], Complex64::new(0.0, 0.0));
271 assert_eq!(sv.state()[3], Complex64::new(FRAC_1_SQRT_2, 0.0));
272 }
273}