quantrs2_core/optimizations/
memory_optimization.rs1use crate::error::QuantRS2Result;
7use scirs2_core::memory::{metrics, BufferPool, ChunkProcessor2D};
8use scirs2_core::ndarray::{Array1, Array2, ArrayViewMut1};
9use scirs2_core::Complex64;
10use std::sync::{Arc, Mutex, OnceLock};
11
12pub struct QuantumBufferPool {
14 state_vector_pool: Arc<Mutex<BufferPool<Complex64>>>,
16 probability_pool: Arc<Mutex<BufferPool<f64>>>,
18 temp_buffer_pool: Arc<Mutex<BufferPool<Complex64>>>,
20 allocations: Arc<Mutex<u64>>,
22 deallocations: Arc<Mutex<u64>>,
23 peak_memory_usage: Arc<Mutex<usize>>,
24}
25
26impl Default for QuantumBufferPool {
27 fn default() -> Self {
28 Self::new()
29 }
30}
31
32impl QuantumBufferPool {
33 pub fn new() -> Self {
35 Self {
36 state_vector_pool: Arc::new(Mutex::new(BufferPool::new())),
37 probability_pool: Arc::new(Mutex::new(BufferPool::new())),
38 temp_buffer_pool: Arc::new(Mutex::new(BufferPool::new())),
39 allocations: Arc::new(Mutex::new(0)),
40 deallocations: Arc::new(Mutex::new(0)),
41 peak_memory_usage: Arc::new(Mutex::new(0)),
42 }
43 }
44
45 pub fn acquire_state_vector(&self, size: usize) -> Vec<Complex64> {
47 metrics::track_allocation("QuantumStateVector", size * 16, 0); *self.allocations.lock().unwrap() += 1;
49
50 let current_usage = size * 16;
51 let mut peak = self.peak_memory_usage.lock().unwrap();
52 if current_usage > *peak {
53 *peak = current_usage;
54 }
55
56 self.state_vector_pool.lock().unwrap().acquire_vec(size)
57 }
58
59 pub fn release_state_vector(&self, buffer: Vec<Complex64>) {
61 let size = buffer.len();
62 metrics::track_deallocation("QuantumStateVector", size * 16, 0);
63 *self.deallocations.lock().unwrap() += 1;
64
65 self.state_vector_pool.lock().unwrap().release_vec(buffer);
66 }
67
68 pub fn acquire_probability_buffer(&self, size: usize) -> Vec<f64> {
70 metrics::track_allocation("ProbabilityBuffer", size * 8, 0); *self.allocations.lock().unwrap() += 1;
72
73 self.probability_pool.lock().unwrap().acquire_vec(size)
74 }
75
76 pub fn release_probability_buffer(&self, buffer: Vec<f64>) {
78 let size = buffer.len();
79 metrics::track_deallocation("ProbabilityBuffer", size * 8, 0);
80 *self.deallocations.lock().unwrap() += 1;
81
82 self.probability_pool.lock().unwrap().release_vec(buffer);
83 }
84
85 pub fn get_stats(&self) -> MemoryUsageStats {
87 MemoryUsageStats {
88 total_allocations: *self.allocations.lock().unwrap(),
89 total_deallocations: *self.deallocations.lock().unwrap(),
90 peak_memory_usage_bytes: *self.peak_memory_usage.lock().unwrap(),
91 active_buffers: self
92 .allocations
93 .lock()
94 .unwrap()
95 .saturating_sub(*self.deallocations.lock().unwrap()),
96 }
97 }
98}
99
100#[derive(Debug, Clone)]
102pub struct MemoryUsageStats {
103 pub total_allocations: u64,
104 pub total_deallocations: u64,
105 pub peak_memory_usage_bytes: usize,
106 pub active_buffers: u64,
107}
108
109pub struct StateVectorManager {
111 state: Option<Vec<Complex64>>,
113 num_qubits: usize,
115 pool: Arc<QuantumBufferPool>,
117 use_chunked_processing: bool,
119}
120
121impl StateVectorManager {
122 pub fn new(num_qubits: usize, pool: Arc<QuantumBufferPool>) -> Self {
124 let use_chunked_processing = num_qubits > 20; Self {
127 state: None,
128 num_qubits,
129 pool,
130 use_chunked_processing,
131 }
132 }
133
134 pub fn initialize_zero_state(&mut self) -> QuantRS2Result<()> {
136 let size = 1 << self.num_qubits;
137 let mut state = self.pool.acquire_state_vector(size);
138
139 state.fill(Complex64::new(0.0, 0.0));
141 state[0] = Complex64::new(1.0, 0.0);
142
143 self.state = Some(state);
144 Ok(())
145 }
146
147 pub fn apply_single_qubit_gate(
149 &mut self,
150 gate_matrix: &[Complex64; 4],
151 qubit_idx: usize,
152 ) -> QuantRS2Result<()> {
153 let use_chunked = self.use_chunked_processing;
154 let pool = self.pool.clone();
155
156 let state = self.state.as_mut().ok_or_else(|| {
157 crate::error::QuantRS2Error::InvalidInput("State not initialized".to_string())
158 })?;
159
160 if use_chunked {
161 Self::apply_single_qubit_gate_chunked_impl(&pool, state, gate_matrix, qubit_idx)
162 } else {
163 Self::apply_single_qubit_gate_direct_impl(&pool, state, gate_matrix, qubit_idx)
164 }
165 }
166
167 fn apply_single_qubit_gate_direct_impl(
169 pool: &QuantumBufferPool,
170 state: &mut [Complex64],
171 gate_matrix: &[Complex64; 4],
172 qubit_idx: usize,
173 ) -> QuantRS2Result<()> {
174 let size = state.len();
175 let target_bit = 1 << qubit_idx;
176
177 let mut temp_buffer = pool.acquire_state_vector(size);
179 temp_buffer.copy_from_slice(state);
180
181 for i in 0..size {
183 if i & target_bit == 0 {
184 let j = i | target_bit;
185 let amp_0 = temp_buffer[i];
186 let amp_1 = temp_buffer[j];
187
188 state[i] = gate_matrix[0] * amp_0 + gate_matrix[1] * amp_1;
189 state[j] = gate_matrix[2] * amp_0 + gate_matrix[3] * amp_1;
190 }
191 }
192
193 pool.release_state_vector(temp_buffer);
194 Ok(())
195 }
196
197 fn apply_single_qubit_gate_chunked_impl(
199 pool: &QuantumBufferPool,
200 state: &mut [Complex64],
201 gate_matrix: &[Complex64; 4],
202 qubit_idx: usize,
203 ) -> QuantRS2Result<()> {
204 let chunk_size = 1 << 18; let target_bit = 1 << qubit_idx;
206
207 let mut temp_state = pool.acquire_state_vector(state.len());
209 temp_state.copy_from_slice(state);
210
211 for i in 0..state.len() {
213 if i & target_bit == 0 {
214 let j = i | target_bit;
215 if j < state.len() {
216 let amp_0 = temp_state[i];
217 let amp_1 = temp_state[j];
218
219 state[i] = gate_matrix[0] * amp_0 + gate_matrix[1] * amp_1;
220 state[j] = gate_matrix[2] * amp_0 + gate_matrix[3] * amp_1;
221 }
222 }
223 }
224
225 pool.release_state_vector(temp_state);
226
227 Ok(())
228 }
229
230 pub fn get_probabilities(&self) -> QuantRS2Result<Vec<f64>> {
232 let state = self.state.as_ref().ok_or_else(|| {
233 crate::error::QuantRS2Error::InvalidInput("State not initialized".to_string())
234 })?;
235
236 let mut probabilities = self.pool.acquire_probability_buffer(state.len());
237
238 for (i, &litude) in state.iter().enumerate() {
240 probabilities[i] = amplitude.norm_sqr();
241 }
242
243 Ok(probabilities)
244 }
245
246 pub fn finalize(mut self) {
248 if let Some(state) = self.state.take() {
249 self.pool.release_state_vector(state);
250 }
251 }
252}
253
254static GLOBAL_QUANTUM_POOL: OnceLock<QuantumBufferPool> = OnceLock::new();
256
257pub fn global_quantum_buffer_pool() -> &'static QuantumBufferPool {
259 GLOBAL_QUANTUM_POOL.get_or_init(QuantumBufferPool::new)
260}
261
262pub fn initialize_buffer_pools() {
264 let _pool = global_quantum_buffer_pool();
266}
267
268pub fn optimized_state_vector_allocation(num_qubits: usize) -> StateVectorManager {
270 let pool = Arc::new(QuantumBufferPool::new());
271 StateVectorManager::new(num_qubits, pool)
272}
273
274pub fn get_memory_usage_stats() -> MemoryUsageStats {
276 global_quantum_buffer_pool().get_stats()
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282
283 #[test]
284 #[ignore] fn test_buffer_pool_basic_functionality() {
286 let pool = QuantumBufferPool::new();
287
288 let buffer = pool.acquire_state_vector(100);
290 assert_eq!(buffer.len(), 100);
291
292 let stats_before = pool.get_stats();
293 pool.release_state_vector(buffer);
294 let stats_after = pool.get_stats();
295
296 assert_eq!(
297 stats_after.total_allocations,
298 stats_before.total_allocations
299 );
300 assert_eq!(
301 stats_after.total_deallocations,
302 stats_before.total_deallocations + 1
303 );
304 }
305
306 #[test]
307 fn test_state_vector_manager() {
308 let pool = Arc::new(QuantumBufferPool::new());
309 let mut manager = StateVectorManager::new(2, pool); manager.initialize_zero_state().unwrap();
313
314 let h_gate = [
316 Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0),
317 Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0),
318 Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0),
319 Complex64::new(-1.0 / 2.0_f64.sqrt(), 0.0),
320 ];
321
322 manager.apply_single_qubit_gate(&h_gate, 0).unwrap();
323
324 let probabilities = manager.get_probabilities().unwrap();
326 assert_eq!(probabilities.len(), 4);
327
328 assert!((probabilities[0] - 0.5).abs() < 1e-10); assert!((probabilities[1] - 0.5).abs() < 1e-10); assert!((probabilities[2] - 0.0).abs() < 1e-10); assert!((probabilities[3] - 0.0).abs() < 1e-10); manager.finalize();
335 }
336
337 #[test]
338 fn test_chunked_processing_threshold() {
339 let pool = Arc::new(QuantumBufferPool::new());
340
341 let small_manager = StateVectorManager::new(10, pool.clone());
343 assert!(!small_manager.use_chunked_processing);
344
345 let large_manager = StateVectorManager::new(25, pool);
347 assert!(large_manager.use_chunked_processing);
348 }
349}