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 fn num_qubits(&self) -> usize {
40 self.num_qubits
41 }
42
43 pub 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 if target >= self.num_qubits {
56 panic!("Target qubit index out of range");
57 }
58
59 let dim = self.state.len();
60 let mut new_state = vec![Complex64::new(0.0, 0.0); dim];
61
62 for i in 0..dim {
64 let bit_val = (i >> target) & 1;
65
66 if bit_val == 0 {
68 let paired_idx = flip_bit(i, target);
69
70 let a0 = self.state[i]; let a1 = self.state[paired_idx]; new_state[i] = matrix[0] * a0 + matrix[1] * a1;
79 new_state[paired_idx] = matrix[2] * a0 + matrix[3] * a1;
80 }
81 }
82
83 self.state = new_state;
84 }
85
86 pub fn apply_cnot(&mut self, control: usize, target: usize) {
93 if control >= self.num_qubits || target >= self.num_qubits {
94 panic!("Qubit indices out of range");
95 }
96
97 if control == target {
98 panic!("Control and target qubits must be different");
99 }
100
101 let dim = self.state.len();
102 let mut new_state = vec![Complex64::new(0.0, 0.0); dim];
103
104 for (i, val) in new_state.iter_mut().enumerate().take(dim) {
106 let control_bit = (i >> control) & 1;
107
108 if control_bit == 0 {
109 *val = self.state[i];
111 } else {
112 let flipped_idx = flip_bit(i, target);
114 *val = self.state[flipped_idx];
115 }
116 }
117
118 self.state = new_state;
119 }
120
121 pub fn apply_two_qubit_gate(&mut self, matrix: &[Complex64], qubit1: usize, qubit2: usize) {
129 if qubit1 >= self.num_qubits || qubit2 >= self.num_qubits {
130 panic!("Qubit indices out of range");
131 }
132
133 if qubit1 == qubit2 {
134 panic!("Qubit indices must be different");
135 }
136
137 let dim = self.state.len();
138 let mut new_state = vec![Complex64::new(0.0, 0.0); dim];
139
140 for (i, val) in new_state.iter_mut().enumerate().take(dim) {
142 let bit1 = (i >> qubit1) & 1;
144 let bit2 = (i >> qubit2) & 1;
145 let subspace_idx = (bit1 << 1) | bit2;
146
147 let bits00 = i & !(1 << qubit1) & !(1 << qubit2);
149 let bits01 = bits00 | (1 << qubit2);
150 let bits10 = bits00 | (1 << qubit1);
151 let bits11 = bits10 | (1 << qubit2);
152
153 *val = matrix[subspace_idx * 4] * self.state[bits00]
155 + matrix[subspace_idx * 4 + 1] * self.state[bits01]
156 + matrix[subspace_idx * 4 + 2] * self.state[bits10]
157 + matrix[subspace_idx * 4 + 3] * self.state[bits11];
158 }
159
160 self.state = new_state;
161 }
162
163 pub fn probability(&self, bit_string: &[u8]) -> f64 {
165 if bit_string.len() != self.num_qubits {
166 panic!("Bit string length must match number of qubits");
167 }
168
169 let mut idx = 0;
171 for (i, &bit) in bit_string.iter().enumerate() {
172 if bit != 0 {
173 idx |= 1 << i;
174 }
175 }
176
177 self.state[idx].norm_sqr()
179 }
180
181 pub fn probabilities(&self) -> Vec<f64> {
183 self.state.iter().map(|a| a.norm_sqr()).collect()
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 use std::f64::consts::FRAC_1_SQRT_2;
191
192 #[test]
193 fn test_optimized_state_vector_init() {
194 let sv = OptimizedStateVector::new(2);
195 assert_eq!(sv.num_qubits(), 2);
196 assert_eq!(sv.dimension(), 4);
197
198 assert_eq!(sv.state()[0], Complex64::new(1.0, 0.0));
200 assert_eq!(sv.state()[1], Complex64::new(0.0, 0.0));
201 assert_eq!(sv.state()[2], Complex64::new(0.0, 0.0));
202 assert_eq!(sv.state()[3], Complex64::new(0.0, 0.0));
203 }
204
205 #[test]
206 fn test_hadamard_gate() {
207 let h_matrix = [
209 Complex64::new(FRAC_1_SQRT_2, 0.0),
210 Complex64::new(FRAC_1_SQRT_2, 0.0),
211 Complex64::new(FRAC_1_SQRT_2, 0.0),
212 Complex64::new(-FRAC_1_SQRT_2, 0.0),
213 ];
214
215 let mut sv = OptimizedStateVector::new(2);
217 println!("Initial state: {:?}", sv.state());
218 sv.apply_single_qubit_gate(&h_matrix, 1); println!("After H on qubit 1: {:?}", sv.state());
222
223 assert_eq!(sv.state()[0], Complex64::new(FRAC_1_SQRT_2, 0.0));
225 assert_eq!(sv.state()[1], Complex64::new(0.0, 0.0));
226 assert_eq!(sv.state()[2], Complex64::new(FRAC_1_SQRT_2, 0.0));
227 assert_eq!(sv.state()[3], Complex64::new(0.0, 0.0));
228
229 sv.apply_single_qubit_gate(&h_matrix, 0);
231
232 println!("After both H gates: {:?}", sv.state());
234
235 assert!((sv.state()[0] - Complex64::new(0.5, 0.0)).norm() < 1e-10);
242 assert!((sv.state()[1] - Complex64::new(0.5, 0.0)).norm() < 1e-10);
243 assert!((sv.state()[2] - Complex64::new(0.5, 0.0)).norm() < 1e-10);
244 assert!((sv.state()[3] - Complex64::new(0.5, 0.0)).norm() < 1e-10);
245 }
246
247 #[test]
248 fn test_cnot_gate() {
249 let mut sv = OptimizedStateVector::new(2);
251
252 let h_matrix = [
254 Complex64::new(FRAC_1_SQRT_2, 0.0),
255 Complex64::new(FRAC_1_SQRT_2, 0.0),
256 Complex64::new(FRAC_1_SQRT_2, 0.0),
257 Complex64::new(-FRAC_1_SQRT_2, 0.0),
258 ];
259 sv.apply_single_qubit_gate(&h_matrix, 0);
260
261 sv.apply_cnot(0, 1);
263
264 assert_eq!(sv.state()[0], Complex64::new(FRAC_1_SQRT_2, 0.0));
266 assert_eq!(sv.state()[1], Complex64::new(0.0, 0.0));
267 assert_eq!(sv.state()[2], Complex64::new(0.0, 0.0));
268 assert_eq!(sv.state()[3], Complex64::new(FRAC_1_SQRT_2, 0.0));
269 }
270}