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().expect("Allocations lock poisoned") += 1;
49
50 let current_usage = size * 16;
51 let mut peak = self
52 .peak_memory_usage
53 .lock()
54 .expect("Peak memory usage lock poisoned");
55 if current_usage > *peak {
56 *peak = current_usage;
57 }
58
59 self.state_vector_pool
60 .lock()
61 .expect("State vector pool lock poisoned")
62 .acquire_vec(size)
63 }
64
65 pub fn release_state_vector(&self, buffer: Vec<Complex64>) {
67 let size = buffer.len();
68 metrics::track_deallocation("QuantumStateVector", size * 16, 0);
69 *self
70 .deallocations
71 .lock()
72 .expect("Deallocations lock poisoned") += 1;
73
74 self.state_vector_pool
75 .lock()
76 .expect("State vector pool lock poisoned")
77 .release_vec(buffer);
78 }
79
80 pub fn acquire_probability_buffer(&self, size: usize) -> Vec<f64> {
82 metrics::track_allocation("ProbabilityBuffer", size * 8, 0); *self.allocations.lock().expect("Allocations lock poisoned") += 1;
84
85 self.probability_pool
86 .lock()
87 .expect("Probability pool lock poisoned")
88 .acquire_vec(size)
89 }
90
91 pub fn release_probability_buffer(&self, buffer: Vec<f64>) {
93 let size = buffer.len();
94 metrics::track_deallocation("ProbabilityBuffer", size * 8, 0);
95 *self
96 .deallocations
97 .lock()
98 .expect("Deallocations lock poisoned") += 1;
99
100 self.probability_pool
101 .lock()
102 .expect("Probability pool lock poisoned")
103 .release_vec(buffer);
104 }
105
106 pub fn get_stats(&self) -> MemoryUsageStats {
108 let allocations = *self.allocations.lock().expect("Allocations lock poisoned");
109 let deallocations = *self
110 .deallocations
111 .lock()
112 .expect("Deallocations lock poisoned");
113 MemoryUsageStats {
114 total_allocations: allocations,
115 total_deallocations: deallocations,
116 peak_memory_usage_bytes: *self
117 .peak_memory_usage
118 .lock()
119 .expect("Peak memory usage lock poisoned"),
120 active_buffers: allocations.saturating_sub(deallocations),
121 }
122 }
123}
124
125#[derive(Debug, Clone)]
127pub struct MemoryUsageStats {
128 pub total_allocations: u64,
129 pub total_deallocations: u64,
130 pub peak_memory_usage_bytes: usize,
131 pub active_buffers: u64,
132}
133
134pub struct StateVectorManager {
136 state: Option<Vec<Complex64>>,
138 num_qubits: usize,
140 pool: Arc<QuantumBufferPool>,
142 use_chunked_processing: bool,
144}
145
146impl StateVectorManager {
147 pub const fn new(num_qubits: usize, pool: Arc<QuantumBufferPool>) -> Self {
149 let use_chunked_processing = num_qubits > 20; Self {
152 state: None,
153 num_qubits,
154 pool,
155 use_chunked_processing,
156 }
157 }
158
159 pub fn initialize_zero_state(&mut self) -> QuantRS2Result<()> {
161 let size = 1 << self.num_qubits;
162 let mut state = self.pool.acquire_state_vector(size);
163
164 state.fill(Complex64::new(0.0, 0.0));
166 state[0] = Complex64::new(1.0, 0.0);
167
168 self.state = Some(state);
169 Ok(())
170 }
171
172 pub fn apply_single_qubit_gate(
174 &mut self,
175 gate_matrix: &[Complex64; 4],
176 qubit_idx: usize,
177 ) -> QuantRS2Result<()> {
178 let use_chunked = self.use_chunked_processing;
179 let pool = self.pool.clone();
180
181 let state = self.state.as_mut().ok_or_else(|| {
182 crate::error::QuantRS2Error::InvalidInput("State not initialized".to_string())
183 })?;
184
185 if use_chunked {
186 Self::apply_single_qubit_gate_chunked_impl(&pool, state, gate_matrix, qubit_idx)
187 } else {
188 Self::apply_single_qubit_gate_direct_impl(&pool, state, gate_matrix, qubit_idx)
189 }
190 }
191
192 fn apply_single_qubit_gate_direct_impl(
194 pool: &QuantumBufferPool,
195 state: &mut [Complex64],
196 gate_matrix: &[Complex64; 4],
197 qubit_idx: usize,
198 ) -> QuantRS2Result<()> {
199 let size = state.len();
200 let target_bit = 1 << qubit_idx;
201
202 let mut temp_buffer = pool.acquire_state_vector(size);
204 temp_buffer.copy_from_slice(state);
205
206 for i in 0..size {
208 if i & target_bit == 0 {
209 let j = i | target_bit;
210 let amp_0 = temp_buffer[i];
211 let amp_1 = temp_buffer[j];
212
213 state[i] = gate_matrix[0] * amp_0 + gate_matrix[1] * amp_1;
214 state[j] = gate_matrix[2] * amp_0 + gate_matrix[3] * amp_1;
215 }
216 }
217
218 pool.release_state_vector(temp_buffer);
219 Ok(())
220 }
221
222 fn apply_single_qubit_gate_chunked_impl(
224 pool: &QuantumBufferPool,
225 state: &mut [Complex64],
226 gate_matrix: &[Complex64; 4],
227 qubit_idx: usize,
228 ) -> QuantRS2Result<()> {
229 let chunk_size = 1 << 18; let target_bit = 1 << qubit_idx;
231
232 let mut temp_state = pool.acquire_state_vector(state.len());
234 temp_state.copy_from_slice(state);
235
236 for i in 0..state.len() {
238 if i & target_bit == 0 {
239 let j = i | target_bit;
240 if j < state.len() {
241 let amp_0 = temp_state[i];
242 let amp_1 = temp_state[j];
243
244 state[i] = gate_matrix[0] * amp_0 + gate_matrix[1] * amp_1;
245 state[j] = gate_matrix[2] * amp_0 + gate_matrix[3] * amp_1;
246 }
247 }
248 }
249
250 pool.release_state_vector(temp_state);
251
252 Ok(())
253 }
254
255 pub fn get_probabilities(&self) -> QuantRS2Result<Vec<f64>> {
257 let state = self.state.as_ref().ok_or_else(|| {
258 crate::error::QuantRS2Error::InvalidInput("State not initialized".to_string())
259 })?;
260
261 let mut probabilities = self.pool.acquire_probability_buffer(state.len());
262
263 for (i, &litude) in state.iter().enumerate() {
265 probabilities[i] = amplitude.norm_sqr();
266 }
267
268 Ok(probabilities)
269 }
270
271 pub fn finalize(mut self) {
273 if let Some(state) = self.state.take() {
274 self.pool.release_state_vector(state);
275 }
276 }
277}
278
279static GLOBAL_QUANTUM_POOL: OnceLock<QuantumBufferPool> = OnceLock::new();
281
282pub fn global_quantum_buffer_pool() -> &'static QuantumBufferPool {
284 GLOBAL_QUANTUM_POOL.get_or_init(QuantumBufferPool::new)
285}
286
287pub fn initialize_buffer_pools() {
289 let _pool = global_quantum_buffer_pool();
291}
292
293pub fn optimized_state_vector_allocation(num_qubits: usize) -> StateVectorManager {
295 let pool = Arc::new(QuantumBufferPool::new());
296 StateVectorManager::new(num_qubits, pool)
297}
298
299pub fn get_memory_usage_stats() -> MemoryUsageStats {
301 global_quantum_buffer_pool().get_stats()
302}
303
304#[cfg(test)]
305mod tests {
306 use super::*;
307
308 #[test]
309 #[ignore] fn test_buffer_pool_basic_functionality() {
311 let pool = QuantumBufferPool::new();
312
313 let buffer = pool.acquire_state_vector(100);
315 assert_eq!(buffer.len(), 100);
316
317 let stats_before = pool.get_stats();
318 pool.release_state_vector(buffer);
319 let stats_after = pool.get_stats();
320
321 assert_eq!(
322 stats_after.total_allocations,
323 stats_before.total_allocations
324 );
325 assert_eq!(
326 stats_after.total_deallocations,
327 stats_before.total_deallocations + 1
328 );
329 }
330
331 #[test]
332 fn test_state_vector_manager() {
333 let pool = Arc::new(QuantumBufferPool::new());
334 let mut manager = StateVectorManager::new(2, pool); manager
338 .initialize_zero_state()
339 .expect("Failed to initialize zero state");
340
341 let h_gate = [
343 Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0),
344 Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0),
345 Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0),
346 Complex64::new(-1.0 / 2.0_f64.sqrt(), 0.0),
347 ];
348
349 manager
350 .apply_single_qubit_gate(&h_gate, 0)
351 .expect("Failed to apply Hadamard gate");
352
353 let probabilities = manager
355 .get_probabilities()
356 .expect("Failed to get probabilities");
357 assert_eq!(probabilities.len(), 4);
358
359 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();
366 }
367
368 #[test]
369 fn test_chunked_processing_threshold() {
370 let pool = Arc::new(QuantumBufferPool::new());
371
372 let small_manager = StateVectorManager::new(10, pool.clone());
374 assert!(!small_manager.use_chunked_processing);
375
376 let large_manager = StateVectorManager::new(25, pool);
378 assert!(large_manager.use_chunked_processing);
379 }
380}