1use ndarray::{Array1, Array2};
9use num_complex::Complex64;
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12
13use crate::error::{Result, SimulatorError};
14use crate::scirs2_integration::SciRS2Backend;
15
16#[derive(Debug, Clone)]
18pub struct QCAConfig {
19 pub dimensions: Vec<usize>,
21 pub boundary_conditions: BoundaryConditions,
23 pub neighborhood: NeighborhoodType,
25 pub rule_type: QCARuleType,
27 pub evolution_steps: usize,
29 pub parallel_evolution: bool,
31 pub measurement_strategy: MeasurementStrategy,
33}
34
35impl Default for QCAConfig {
36 fn default() -> Self {
37 Self {
38 dimensions: vec![16], boundary_conditions: BoundaryConditions::Periodic,
40 neighborhood: NeighborhoodType::Moore,
41 rule_type: QCARuleType::Partitioned,
42 evolution_steps: 100,
43 parallel_evolution: true,
44 measurement_strategy: MeasurementStrategy::Probabilistic,
45 }
46 }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub enum BoundaryConditions {
52 Periodic,
54 Fixed,
56 Open,
58 Reflective,
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub enum NeighborhoodType {
65 VonNeumann,
67 Moore,
69 Custom,
71 Extended,
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub enum QCARuleType {
78 Partitioned,
80 Global,
82 Sequential,
84 Margolus,
86 Custom,
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
92pub enum MeasurementStrategy {
93 Probabilistic,
95 Deterministic,
97 Partial,
99 Continuous,
101}
102
103pub struct QuantumCellularAutomaton {
105 config: QCAConfig,
107 state: Array1<Complex64>,
109 evolution_rules: Vec<QCARule>,
111 cell_mapping: CellMapping,
113 backend: Option<SciRS2Backend>,
115 evolution_history: Vec<QCASnapshot>,
117 stats: QCAStats,
119}
120
121#[derive(Debug, Clone)]
123pub struct QCARule {
124 pub id: String,
126 pub unitary: Array2<Complex64>,
128 pub affected_cells: Vec<usize>,
130 pub neighborhood_pattern: Vec<(i32, i32, i32)>, pub parameters: HashMap<String, f64>,
134}
135
136#[derive(Debug, Clone)]
138pub struct CellMapping {
139 pub total_cells: usize,
141 pub dimensions: Vec<usize>,
143 pub coord_to_index: HashMap<Vec<usize>, usize>,
145 pub index_to_coord: HashMap<usize, Vec<usize>>,
147 pub neighbors: HashMap<usize, Vec<usize>>,
149}
150
151#[derive(Debug, Clone)]
153pub struct QCASnapshot {
154 pub time_step: usize,
156 pub state: Array1<Complex64>,
158 pub measurements: Option<Vec<f64>>,
160 pub entanglement_entropy: Option<f64>,
162 pub local_observables: HashMap<String, f64>,
164}
165
166#[derive(Debug, Clone, Default, Serialize, Deserialize)]
168pub struct QCAStats {
169 pub evolution_steps: usize,
171 pub total_evolution_time_ms: f64,
173 pub avg_step_time_ms: f64,
175 pub measurements_performed: usize,
177 pub entropy_stats: EntropyStats,
179 pub rule_applications: HashMap<String, usize>,
181}
182
183#[derive(Debug, Clone, Default, Serialize, Deserialize)]
185pub struct EntropyStats {
186 pub max_entropy: f64,
188 pub min_entropy: f64,
190 pub avg_entropy: f64,
192 pub entropy_variance: f64,
194}
195
196impl QuantumCellularAutomaton {
197 pub fn new(config: QCAConfig) -> Result<Self> {
199 let cell_mapping = Self::create_cell_mapping(&config)?;
200 let total_cells = cell_mapping.total_cells;
201
202 let state_size = 1 << total_cells;
204 let mut state = Array1::zeros(state_size);
205 state[0] = Complex64::new(1.0, 0.0);
206
207 let evolution_rules = Self::create_default_rules(&config, &cell_mapping)?;
208
209 Ok(Self {
210 config,
211 state,
212 evolution_rules,
213 cell_mapping,
214 backend: None,
215 evolution_history: Vec::new(),
216 stats: QCAStats::default(),
217 })
218 }
219
220 pub fn with_backend(mut self) -> Result<Self> {
222 self.backend = Some(SciRS2Backend::new());
223 Ok(self)
224 }
225
226 pub fn set_initial_state(&mut self, initial_state: Array1<Complex64>) -> Result<()> {
228 if initial_state.len() != self.state.len() {
229 return Err(SimulatorError::InvalidInput(format!(
230 "Initial state size {} doesn't match expected size {}",
231 initial_state.len(),
232 self.state.len()
233 )));
234 }
235
236 self.state = initial_state;
237 self.evolution_history.clear();
238 self.stats = QCAStats::default();
239
240 Ok(())
241 }
242
243 pub fn add_rule(&mut self, rule: QCARule) -> Result<()> {
245 if !Self::is_unitary(&rule.unitary) {
247 return Err(SimulatorError::InvalidInput(
248 "Rule matrix is not unitary".to_string(),
249 ));
250 }
251
252 self.evolution_rules.push(rule);
253 Ok(())
254 }
255
256 pub fn evolve(&mut self, steps: usize) -> Result<QCAEvolutionResult> {
258 let start_time = std::time::Instant::now();
259
260 for step in 0..steps {
261 let step_start = std::time::Instant::now();
262
263 match self.config.rule_type {
265 QCARuleType::Partitioned => self.evolve_partitioned()?,
266 QCARuleType::Global => self.evolve_global()?,
267 QCARuleType::Sequential => self.evolve_sequential()?,
268 QCARuleType::Margolus => self.evolve_margolus()?,
269 QCARuleType::Custom => self.evolve_custom()?,
270 }
271
272 if step % 10 == 0 || step == steps - 1 {
274 let snapshot = self.take_snapshot(step)?;
275 self.evolution_history.push(snapshot);
276 }
277
278 if let MeasurementStrategy::Continuous = self.config.measurement_strategy {
280 self.apply_weak_measurements()?;
281 }
282
283 let step_time = step_start.elapsed().as_secs_f64() * 1000.0;
284 self.stats.avg_step_time_ms =
285 (self.stats.avg_step_time_ms * self.stats.evolution_steps as f64 + step_time)
286 / (self.stats.evolution_steps + 1) as f64;
287 self.stats.evolution_steps += 1;
288 }
289
290 let total_time = start_time.elapsed().as_secs_f64() * 1000.0;
291 self.stats.total_evolution_time_ms += total_time;
292
293 Ok(QCAEvolutionResult {
294 final_state: self.state.clone(),
295 evolution_history: self.evolution_history.clone(),
296 total_steps: steps,
297 total_time_ms: total_time,
298 final_entropy: self.calculate_entanglement_entropy()?,
299 })
300 }
301
302 fn evolve_partitioned(&mut self) -> Result<()> {
304 match self.config.dimensions.len() {
305 1 => self.evolve_1d_partitioned(),
306 2 => self.evolve_2d_partitioned(),
307 3 => self.evolve_3d_partitioned(),
308 _ => Err(SimulatorError::UnsupportedOperation(
309 "QCA supports only 1D, 2D, and 3D lattices".to_string(),
310 )),
311 }
312 }
313
314 fn evolve_1d_partitioned(&mut self) -> Result<()> {
316 let lattice_size = self.config.dimensions[0];
317
318 let mut partitions = Vec::new();
320 let partition_size = 2; for start in (0..lattice_size).step_by(partition_size) {
323 let end = (start + partition_size).min(lattice_size);
324 partitions.push((start, end));
325 }
326
327 for (start, end) in partitions {
329 for cell in start..end - 1 {
330 let neighbor = match self.config.boundary_conditions {
331 BoundaryConditions::Periodic => (cell + 1) % lattice_size,
332 BoundaryConditions::Fixed | BoundaryConditions::Open => {
333 if cell + 1 < lattice_size {
334 cell + 1
335 } else {
336 continue;
337 }
338 }
339 BoundaryConditions::Reflective => {
340 if cell + 1 < lattice_size {
341 cell + 1
342 } else {
343 lattice_size - 1
344 }
345 }
346 };
347
348 self.apply_two_cell_rule(cell, neighbor)?;
349 }
350 }
351
352 Ok(())
353 }
354
355 fn evolve_2d_partitioned(&mut self) -> Result<()> {
357 let (width, height) = (self.config.dimensions[0], self.config.dimensions[1]);
358
359 for parity in 0..2 {
361 for y in 0..height {
362 for x in (parity..width).step_by(2) {
363 let cell = y * width + x;
364 let neighbors = self.get_neighbors_2d(x, y, width, height);
365
366 if !neighbors.is_empty() {
367 self.apply_neighborhood_rule(cell, &neighbors)?;
368 }
369 }
370 }
371 }
372
373 Ok(())
374 }
375
376 fn evolve_3d_partitioned(&mut self) -> Result<()> {
378 let (width, height, depth) = (
379 self.config.dimensions[0],
380 self.config.dimensions[1],
381 self.config.dimensions[2],
382 );
383
384 for parity in 0..2 {
386 for z in 0..depth {
387 for y in 0..height {
388 for x in (parity..width).step_by(2) {
389 let cell = z * width * height + y * width + x;
390 let neighbors = self.get_neighbors_3d(x, y, z, width, height, depth);
391
392 if !neighbors.is_empty() {
393 self.apply_neighborhood_rule(cell, &neighbors)?;
394 }
395 }
396 }
397 }
398 }
399
400 Ok(())
401 }
402
403 fn evolve_global(&mut self) -> Result<()> {
405 if let Some(global_rule) = self.evolution_rules.first() {
406 let new_state = global_rule.unitary.dot(&self.state);
408 self.state = new_state;
409
410 let rule_id = global_rule.id.clone();
412 *self.stats.rule_applications.entry(rule_id).or_insert(0) += 1;
413 }
414
415 Ok(())
416 }
417
418 fn evolve_sequential(&mut self) -> Result<()> {
420 let total_cells = self.cell_mapping.total_cells;
421 for cell in 0..total_cells {
422 let neighbors = self
423 .cell_mapping
424 .neighbors
425 .get(&cell)
426 .cloned()
427 .unwrap_or_default();
428 if !neighbors.is_empty() {
429 self.apply_neighborhood_rule(cell, &neighbors)?;
430 }
431 }
432 Ok(())
433 }
434
435 fn evolve_margolus(&mut self) -> Result<()> {
437 if self.config.dimensions.len() != 2 {
439 return Err(SimulatorError::UnsupportedOperation(
440 "Margolus QCA only supports 2D lattices".to_string(),
441 ));
442 }
443
444 let (width, height) = (self.config.dimensions[0], self.config.dimensions[1]);
445 let offset = self.stats.evolution_steps % 2; for y in (offset..height - 1).step_by(2) {
448 for x in (offset..width - 1).step_by(2) {
449 let cells = vec![
451 y * width + x,
452 y * width + (x + 1),
453 (y + 1) * width + x,
454 (y + 1) * width + (x + 1),
455 ];
456
457 self.apply_margolus_rule(&cells)?;
458 }
459 }
460
461 Ok(())
462 }
463
464 fn evolve_custom(&mut self) -> Result<()> {
466 for rule in &self.evolution_rules.clone() {
468 if rule.affected_cells.len() == 1 {
469 self.apply_single_cell_rule(rule.affected_cells[0], &rule.unitary)?;
470 } else if rule.affected_cells.len() == 2 {
471 self.apply_two_cell_rule(rule.affected_cells[0], rule.affected_cells[1])?;
472 } else {
473 self.apply_neighborhood_rule(rule.affected_cells[0], &rule.affected_cells[1..])?;
474 }
475
476 *self
478 .stats
479 .rule_applications
480 .entry(rule.id.clone())
481 .or_insert(0) += 1;
482 }
483
484 Ok(())
485 }
486
487 fn apply_two_cell_rule(&mut self, cell1: usize, cell2: usize) -> Result<()> {
489 let rule_data = self
491 .evolution_rules
492 .iter()
493 .find(|r| r.unitary.dim() == (4, 4))
494 .map(|r| (r.unitary.clone(), r.id.clone()))
495 .ok_or_else(|| {
496 SimulatorError::UnsupportedOperation("No two-cell rule available".to_string())
497 })?;
498
499 self.apply_two_qubit_unitary(cell1, cell2, &rule_data.0)?;
501
502 *self.stats.rule_applications.entry(rule_data.1).or_insert(0) += 1;
504
505 Ok(())
506 }
507
508 fn apply_neighborhood_rule(&mut self, center_cell: usize, neighbors: &[usize]) -> Result<()> {
510 for &neighbor in neighbors {
512 self.apply_two_cell_rule(center_cell, neighbor)?;
513 }
514 Ok(())
515 }
516
517 fn apply_margolus_rule(&mut self, cells: &[usize]) -> Result<()> {
519 if cells.len() != 4 {
520 return Err(SimulatorError::InvalidInput(
521 "Margolus rule requires exactly 4 cells".to_string(),
522 ));
523 }
524
525 let rule_unitary = self
527 .evolution_rules
528 .iter()
529 .find(|r| r.unitary.dim() == (16, 16))
530 .map(|r| r.unitary.clone())
531 .unwrap_or_else(Self::create_margolus_rotation_unitary);
532
533 self.apply_four_qubit_unitary(cells, &rule_unitary)?;
535
536 Ok(())
537 }
538
539 fn apply_single_cell_rule(&mut self, cell: usize, unitary: &Array2<Complex64>) -> Result<()> {
541 self.apply_single_qubit_unitary(cell, unitary)
542 }
543
544 fn apply_single_qubit_unitary(
546 &mut self,
547 qubit: usize,
548 unitary: &Array2<Complex64>,
549 ) -> Result<()> {
550 let state_size = self.state.len();
551 let qubit_mask = 1 << qubit;
552
553 let mut new_state = self.state.clone();
554
555 for i in 0..state_size {
556 if i & qubit_mask == 0 {
557 let j = i | qubit_mask;
558 if j < state_size {
559 let amp_0 = self.state[i];
560 let amp_1 = self.state[j];
561
562 new_state[i] = unitary[[0, 0]] * amp_0 + unitary[[0, 1]] * amp_1;
563 new_state[j] = unitary[[1, 0]] * amp_0 + unitary[[1, 1]] * amp_1;
564 }
565 }
566 }
567
568 self.state = new_state;
569 Ok(())
570 }
571
572 fn apply_two_qubit_unitary(
574 &mut self,
575 qubit1: usize,
576 qubit2: usize,
577 unitary: &Array2<Complex64>,
578 ) -> Result<()> {
579 let state_size = self.state.len();
580 let mask1 = 1 << qubit1;
581 let mask2 = 1 << qubit2;
582
583 let mut new_state = self.state.clone();
584
585 for i in 0..state_size {
586 let i00 = i & !(mask1 | mask2);
587 let i01 = i00 | mask2;
588 let i10 = i00 | mask1;
589 let i11 = i00 | mask1 | mask2;
590
591 if i == i00 {
592 let amp_00 = self.state[i00];
593 let amp_01 = self.state[i01];
594 let amp_10 = self.state[i10];
595 let amp_11 = self.state[i11];
596
597 new_state[i00] = unitary[[0, 0]] * amp_00
598 + unitary[[0, 1]] * amp_01
599 + unitary[[0, 2]] * amp_10
600 + unitary[[0, 3]] * amp_11;
601 new_state[i01] = unitary[[1, 0]] * amp_00
602 + unitary[[1, 1]] * amp_01
603 + unitary[[1, 2]] * amp_10
604 + unitary[[1, 3]] * amp_11;
605 new_state[i10] = unitary[[2, 0]] * amp_00
606 + unitary[[2, 1]] * amp_01
607 + unitary[[2, 2]] * amp_10
608 + unitary[[2, 3]] * amp_11;
609 new_state[i11] = unitary[[3, 0]] * amp_00
610 + unitary[[3, 1]] * amp_01
611 + unitary[[3, 2]] * amp_10
612 + unitary[[3, 3]] * amp_11;
613 }
614 }
615
616 self.state = new_state;
617 Ok(())
618 }
619
620 fn apply_four_qubit_unitary(
622 &mut self,
623 qubits: &[usize],
624 unitary: &Array2<Complex64>,
625 ) -> Result<()> {
626 if qubits.len() != 4 {
627 return Err(SimulatorError::InvalidInput(
628 "Four qubits required".to_string(),
629 ));
630 }
631
632 let state_size = self.state.len();
633 let mut new_state = self.state.clone();
634
635 let masks: Vec<usize> = qubits.iter().map(|&q| 1 << q).collect();
637
638 for i in 0..state_size {
639 let base = i & !(masks[0] | masks[1] | masks[2] | masks[3]);
641
642 if i == base {
644 let mut amplitudes = Vec::new();
646 for state_idx in 0..16 {
647 let full_idx = base
648 | (if state_idx & 1 != 0 { masks[0] } else { 0 })
649 | (if state_idx & 2 != 0 { masks[1] } else { 0 })
650 | (if state_idx & 4 != 0 { masks[2] } else { 0 })
651 | (if state_idx & 8 != 0 { masks[3] } else { 0 });
652 amplitudes.push(self.state[full_idx]);
653 }
654
655 for out_state in 0..16 {
657 let mut new_amplitude = Complex64::new(0.0, 0.0);
658 for (in_state, &litude) in amplitudes.iter().enumerate() {
659 new_amplitude += unitary[[out_state, in_state]] * amplitude;
660 }
661
662 let full_idx = base
663 | (if out_state & 1 != 0 { masks[0] } else { 0 })
664 | (if out_state & 2 != 0 { masks[1] } else { 0 })
665 | (if out_state & 4 != 0 { masks[2] } else { 0 })
666 | (if out_state & 8 != 0 { masks[3] } else { 0 });
667 new_state[full_idx] = new_amplitude;
668 }
669 }
670 }
671
672 self.state = new_state;
673 Ok(())
674 }
675
676 fn get_neighbors_2d(&self, x: usize, y: usize, width: usize, height: usize) -> Vec<usize> {
678 let mut neighbors = Vec::new();
679
680 let deltas: &[(i32, i32)] = match self.config.neighborhood {
681 NeighborhoodType::VonNeumann => &[(-1, 0), (1, 0), (0, -1), (0, 1)],
682 NeighborhoodType::Moore => &[
683 (-1, -1),
684 (-1, 0),
685 (-1, 1),
686 (0, -1),
687 (0, 1),
688 (1, -1),
689 (1, 0),
690 (1, 1),
691 ],
692 _ => &[(-1, 0), (1, 0), (0, -1), (0, 1)], };
694
695 for (dx, dy) in deltas {
696 let nx = x as i32 + dx;
697 let ny = y as i32 + dy;
698
699 let (nx, ny) = match self.config.boundary_conditions {
700 BoundaryConditions::Periodic => {
701 let nx = ((nx % width as i32) + width as i32) % width as i32;
702 let ny = ((ny % height as i32) + height as i32) % height as i32;
703 (nx as usize, ny as usize)
704 }
705 BoundaryConditions::Fixed | BoundaryConditions::Open => {
706 if nx >= 0 && nx < width as i32 && ny >= 0 && ny < height as i32 {
707 (nx as usize, ny as usize)
708 } else {
709 continue;
710 }
711 }
712 BoundaryConditions::Reflective => {
713 let nx = if nx < 0 {
714 0
715 } else if nx >= width as i32 {
716 width - 1
717 } else {
718 nx as usize
719 };
720 let ny = if ny < 0 {
721 0
722 } else if ny >= height as i32 {
723 height - 1
724 } else {
725 ny as usize
726 };
727 (nx, ny)
728 }
729 };
730
731 neighbors.push(ny * width + nx);
732 }
733
734 neighbors
735 }
736
737 fn get_neighbors_3d(
739 &self,
740 x: usize,
741 y: usize,
742 z: usize,
743 width: usize,
744 height: usize,
745 depth: usize,
746 ) -> Vec<usize> {
747 let mut neighbors = Vec::new();
748
749 let deltas = [
751 (-1, 0, 0),
752 (1, 0, 0),
753 (0, -1, 0),
754 (0, 1, 0),
755 (0, 0, -1),
756 (0, 0, 1),
757 ];
758
759 for (dx, dy, dz) in deltas {
760 let nx = x as i32 + dx;
761 let ny = y as i32 + dy;
762 let nz = z as i32 + dz;
763
764 let (nx, ny, nz) = match self.config.boundary_conditions {
765 BoundaryConditions::Periodic => {
766 let nx = ((nx % width as i32) + width as i32) % width as i32;
767 let ny = ((ny % height as i32) + height as i32) % height as i32;
768 let nz = ((nz % depth as i32) + depth as i32) % depth as i32;
769 (nx as usize, ny as usize, nz as usize)
770 }
771 BoundaryConditions::Fixed | BoundaryConditions::Open => {
772 if nx >= 0
773 && nx < width as i32
774 && ny >= 0
775 && ny < height as i32
776 && nz >= 0
777 && nz < depth as i32
778 {
779 (nx as usize, ny as usize, nz as usize)
780 } else {
781 continue;
782 }
783 }
784 BoundaryConditions::Reflective => {
785 let nx = if nx < 0 {
786 0
787 } else if nx >= width as i32 {
788 width - 1
789 } else {
790 nx as usize
791 };
792 let ny = if ny < 0 {
793 0
794 } else if ny >= height as i32 {
795 height - 1
796 } else {
797 ny as usize
798 };
799 let nz = if nz < 0 {
800 0
801 } else if nz >= depth as i32 {
802 depth - 1
803 } else {
804 nz as usize
805 };
806 (nx, ny, nz)
807 }
808 };
809
810 neighbors.push(nz * width * height + ny * width + nx);
811 }
812
813 neighbors
814 }
815
816 fn apply_weak_measurements(&mut self) -> Result<()> {
818 let measurement_strength = 0.01; let cells_to_measure = (0..self.cell_mapping.total_cells)
821 .step_by(4)
822 .collect::<Vec<_>>();
823
824 for &cell in &cells_to_measure {
825 let measurement_operator =
827 self.create_weak_measurement_operator(cell, measurement_strength);
828 self.state = measurement_operator.dot(&self.state);
829
830 let norm: f64 = self.state.iter().map(|x| x.norm_sqr()).sum::<f64>().sqrt();
832 if norm > 1e-15 {
833 self.state.mapv_inplace(|x| x / norm);
834 }
835 }
836
837 self.stats.measurements_performed += cells_to_measure.len();
838 Ok(())
839 }
840
841 fn create_weak_measurement_operator(&self, cell: usize, strength: f64) -> Array2<Complex64> {
843 let state_size = self.state.len();
844 let mut operator = Array2::eye(state_size);
845 let cell_mask = 1 << cell;
846
847 for i in 0..state_size {
848 if i & cell_mask != 0 {
849 let factor = Complex64::new((1.0 - strength).sqrt(), 0.0);
851 operator[[i, i]] = factor;
852 }
853 }
854
855 operator
856 }
857
858 fn take_snapshot(&mut self, time_step: usize) -> Result<QCASnapshot> {
860 let entropy = self.calculate_entanglement_entropy()?;
861
862 if self.stats.entropy_stats.max_entropy == 0.0 {
864 self.stats.entropy_stats.max_entropy = entropy;
865 self.stats.entropy_stats.min_entropy = entropy;
866 } else {
867 self.stats.entropy_stats.max_entropy =
868 self.stats.entropy_stats.max_entropy.max(entropy);
869 self.stats.entropy_stats.min_entropy =
870 self.stats.entropy_stats.min_entropy.min(entropy);
871 }
872
873 let snapshot_count = self.evolution_history.len() as f64;
874 self.stats.entropy_stats.avg_entropy =
875 (self.stats.entropy_stats.avg_entropy * snapshot_count + entropy)
876 / (snapshot_count + 1.0);
877
878 Ok(QCASnapshot {
879 time_step,
880 state: self.state.clone(),
881 measurements: None,
882 entanglement_entropy: Some(entropy),
883 local_observables: self.calculate_local_observables()?,
884 })
885 }
886
887 fn calculate_entanglement_entropy(&self) -> Result<f64> {
889 let half_size = self.cell_mapping.total_cells / 2;
891 if half_size == 0 {
892 return Ok(0.0);
893 }
894
895 let reduced_dm = self.compute_reduced_density_matrix(half_size)?;
896 let eigenvalues = self.compute_eigenvalues(&reduced_dm)?;
897
898 let entropy = eigenvalues
899 .iter()
900 .filter(|&&lambda| lambda > 1e-15)
901 .map(|&lambda| -lambda * lambda.ln())
902 .sum();
903
904 Ok(entropy)
905 }
906
907 fn compute_reduced_density_matrix(&self, n_qubits: usize) -> Result<Array2<f64>> {
909 let reduced_size = 1 << n_qubits;
910 let mut reduced_dm = Array2::zeros((reduced_size, reduced_size));
911
912 let total_qubits = self.cell_mapping.total_cells;
913 let env_size = 1 << (total_qubits - n_qubits);
914
915 for i in 0..reduced_size {
916 for j in 0..reduced_size {
917 let mut element = 0.0;
918
919 for k in 0..env_size {
920 let full_i = i | (k << n_qubits);
921 let full_j = j | (k << n_qubits);
922
923 if full_i < self.state.len() && full_j < self.state.len() {
924 element += (self.state[full_i] * self.state[full_j].conj()).re;
925 }
926 }
927
928 reduced_dm[[i, j]] = element;
929 }
930 }
931
932 Ok(reduced_dm)
933 }
934
935 fn compute_eigenvalues(&self, matrix: &Array2<f64>) -> Result<Vec<f64>> {
937 let mut eigenvalues = Vec::new();
939
940 if matrix.dim().0 <= 4 {
942 for i in 0..matrix.dim().0 {
944 eigenvalues.push(matrix[[i, i]]); }
946 } else {
947 for i in 0..matrix.dim().0 {
949 eigenvalues.push(matrix[[i, i]]);
950 }
951 }
952
953 Ok(eigenvalues)
954 }
955
956 fn calculate_local_observables(&self) -> Result<HashMap<String, f64>> {
958 let mut observables = HashMap::new();
959
960 for cell in 0..self.cell_mapping.total_cells {
962 let magnetization = self.calculate_local_magnetization(cell)?;
963 observables.insert(format!("magnetization_{}", cell), magnetization);
964 }
965
966 for cell in 0..self.cell_mapping.total_cells {
968 if let Some(neighbors) = self.cell_mapping.neighbors.get(&cell) {
969 for &neighbor in neighbors {
970 if neighbor > cell {
971 let correlation = self.calculate_correlation(cell, neighbor)?;
973 observables
974 .insert(format!("correlation_{}_{}", cell, neighbor), correlation);
975 }
976 }
977 }
978 }
979
980 Ok(observables)
981 }
982
983 fn calculate_local_magnetization(&self, cell: usize) -> Result<f64> {
985 let cell_mask = 1 << cell;
986 let mut expectation = 0.0;
987
988 for (i, &litude) in self.state.iter().enumerate() {
989 let prob = amplitude.norm_sqr();
990 let z_value = if i & cell_mask != 0 { -1.0 } else { 1.0 };
991 expectation += prob * z_value;
992 }
993
994 Ok(expectation)
995 }
996
997 fn calculate_correlation(&self, cell1: usize, cell2: usize) -> Result<f64> {
999 let mask1 = 1 << cell1;
1000 let mask2 = 1 << cell2;
1001 let mut correlation = 0.0;
1002
1003 for (i, &litude) in self.state.iter().enumerate() {
1004 let prob = amplitude.norm_sqr();
1005 let z1 = if i & mask1 != 0 { -1.0 } else { 1.0 };
1006 let z2 = if i & mask2 != 0 { -1.0 } else { 1.0 };
1007 correlation += prob * z1 * z2;
1008 }
1009
1010 Ok(correlation)
1011 }
1012
1013 pub fn measure_cells(&mut self, cells: &[usize]) -> Result<Vec<bool>> {
1015 let mut results = Vec::new();
1016
1017 for &cell in cells {
1018 let prob_one = self.calculate_measurement_probability(cell)?;
1019 let result = fastrand::f64() < prob_one;
1020 results.push(result);
1021
1022 self.collapse_state_after_measurement(cell, result)?;
1024 }
1025
1026 self.stats.measurements_performed += cells.len();
1027 Ok(results)
1028 }
1029
1030 fn calculate_measurement_probability(&self, cell: usize) -> Result<f64> {
1032 let cell_mask = 1 << cell;
1033 let mut prob_one = 0.0;
1034
1035 for (i, &litude) in self.state.iter().enumerate() {
1036 if i & cell_mask != 0 {
1037 prob_one += amplitude.norm_sqr();
1038 }
1039 }
1040
1041 Ok(prob_one)
1042 }
1043
1044 fn collapse_state_after_measurement(&mut self, cell: usize, result: bool) -> Result<()> {
1046 let cell_mask = 1 << cell;
1047 let mut norm = 0.0;
1048
1049 for (i, amplitude) in self.state.iter_mut().enumerate() {
1051 let cell_value = (i & cell_mask) != 0;
1052 if cell_value != result {
1053 *amplitude = Complex64::new(0.0, 0.0);
1054 } else {
1055 norm += amplitude.norm_sqr();
1056 }
1057 }
1058
1059 if norm > 1e-15 {
1061 let norm_factor = 1.0 / norm.sqrt();
1062 self.state.mapv_inplace(|x| x * norm_factor);
1063 }
1064
1065 Ok(())
1066 }
1067
1068 pub fn get_state(&self) -> &Array1<Complex64> {
1070 &self.state
1071 }
1072
1073 pub fn get_evolution_history(&self) -> &[QCASnapshot] {
1075 &self.evolution_history
1076 }
1077
1078 pub fn get_stats(&self) -> &QCAStats {
1080 &self.stats
1081 }
1082
1083 pub fn reset(&mut self) -> Result<()> {
1085 let state_size = self.state.len();
1086 self.state = Array1::zeros(state_size);
1087 self.state[0] = Complex64::new(1.0, 0.0);
1088 self.evolution_history.clear();
1089 self.stats = QCAStats::default();
1090 Ok(())
1091 }
1092
1093 fn create_cell_mapping(config: &QCAConfig) -> Result<CellMapping> {
1095 let total_cells = config.dimensions.iter().product();
1096 let mut coord_to_index = HashMap::new();
1097 let mut index_to_coord = HashMap::new();
1098 let mut neighbors = HashMap::new();
1099
1100 match config.dimensions.len() {
1101 1 => {
1102 let size = config.dimensions[0];
1103 for i in 0..size {
1104 coord_to_index.insert(vec![i], i);
1105 index_to_coord.insert(i, vec![i]);
1106
1107 let mut cell_neighbors = Vec::new();
1108 match config.boundary_conditions {
1109 BoundaryConditions::Periodic => {
1110 cell_neighbors.push((i + size - 1) % size);
1111 cell_neighbors.push((i + 1) % size);
1112 }
1113 _ => {
1114 if i > 0 {
1115 cell_neighbors.push(i - 1);
1116 }
1117 if i < size - 1 {
1118 cell_neighbors.push(i + 1);
1119 }
1120 }
1121 }
1122 neighbors.insert(i, cell_neighbors);
1123 }
1124 }
1125 2 => {
1126 let (width, height) = (config.dimensions[0], config.dimensions[1]);
1127 for y in 0..height {
1128 for x in 0..width {
1129 let index = y * width + x;
1130 coord_to_index.insert(vec![x, y], index);
1131 index_to_coord.insert(index, vec![x, y]);
1132 neighbors.insert(index, Vec::new());
1134 }
1135 }
1136 }
1137 3 => {
1138 let (width, height, depth) = (
1139 config.dimensions[0],
1140 config.dimensions[1],
1141 config.dimensions[2],
1142 );
1143 for z in 0..depth {
1144 for y in 0..height {
1145 for x in 0..width {
1146 let index = z * width * height + y * width + x;
1147 coord_to_index.insert(vec![x, y, z], index);
1148 index_to_coord.insert(index, vec![x, y, z]);
1149 neighbors.insert(index, Vec::new());
1150 }
1151 }
1152 }
1153 }
1154 _ => {
1155 return Err(SimulatorError::UnsupportedOperation(
1156 "QCA supports only 1D, 2D, and 3D lattices".to_string(),
1157 ))
1158 }
1159 }
1160
1161 Ok(CellMapping {
1162 total_cells,
1163 dimensions: config.dimensions.clone(),
1164 coord_to_index,
1165 index_to_coord,
1166 neighbors,
1167 })
1168 }
1169
1170 fn create_default_rules(
1171 config: &QCAConfig,
1172 cell_mapping: &CellMapping,
1173 ) -> Result<Vec<QCARule>> {
1174 let mut rules = Vec::new();
1175
1176 match config.rule_type {
1177 QCARuleType::Global => {
1178 let state_size = 1 << cell_mapping.total_cells.min(10); let unitary = Self::create_random_unitary(state_size);
1181 rules.push(QCARule {
1182 id: "global_evolution".to_string(),
1183 unitary,
1184 affected_cells: (0..cell_mapping.total_cells).collect(),
1185 neighborhood_pattern: Vec::new(),
1186 parameters: HashMap::new(),
1187 });
1188 }
1189 _ => {
1190 rules.push(QCARule {
1192 id: "two_cell_interaction".to_string(),
1193 unitary: Self::create_cnot_unitary(),
1194 affected_cells: Vec::new(),
1195 neighborhood_pattern: vec![(0, 0, 0), (1, 0, 0)],
1196 parameters: HashMap::new(),
1197 });
1198
1199 rules.push(QCARule {
1200 id: "single_cell_rotation".to_string(),
1201 unitary: Self::create_rotation_unitary(std::f64::consts::PI / 4.0),
1202 affected_cells: Vec::new(),
1203 neighborhood_pattern: vec![(0, 0, 0)],
1204 parameters: HashMap::new(),
1205 });
1206 }
1207 }
1208
1209 Ok(rules)
1210 }
1211
1212 fn create_cnot_unitary() -> Array2<Complex64> {
1213 Array2::from_shape_vec(
1214 (4, 4),
1215 vec![
1216 Complex64::new(1.0, 0.0),
1217 Complex64::new(0.0, 0.0),
1218 Complex64::new(0.0, 0.0),
1219 Complex64::new(0.0, 0.0),
1220 Complex64::new(0.0, 0.0),
1221 Complex64::new(1.0, 0.0),
1222 Complex64::new(0.0, 0.0),
1223 Complex64::new(0.0, 0.0),
1224 Complex64::new(0.0, 0.0),
1225 Complex64::new(0.0, 0.0),
1226 Complex64::new(0.0, 0.0),
1227 Complex64::new(1.0, 0.0),
1228 Complex64::new(0.0, 0.0),
1229 Complex64::new(0.0, 0.0),
1230 Complex64::new(1.0, 0.0),
1231 Complex64::new(0.0, 0.0),
1232 ],
1233 )
1234 .unwrap()
1235 }
1236
1237 fn create_rotation_unitary(angle: f64) -> Array2<Complex64> {
1238 let cos_half = (angle / 2.0).cos();
1239 let sin_half = (angle / 2.0).sin();
1240 Array2::from_shape_vec(
1241 (2, 2),
1242 vec![
1243 Complex64::new(cos_half, 0.0),
1244 Complex64::new(0.0, -sin_half),
1245 Complex64::new(0.0, -sin_half),
1246 Complex64::new(cos_half, 0.0),
1247 ],
1248 )
1249 .unwrap()
1250 }
1251
1252 fn create_margolus_rotation_unitary() -> Array2<Complex64> {
1253 let mut unitary = Array2::zeros((16, 16));
1255
1256 for i in 0..16 {
1258 let a = (i >> 3) & 1;
1260 let b = (i >> 2) & 1;
1261 let c = (i >> 1) & 1;
1262 let d = i & 1;
1263
1264 let rotated = (d << 3) | (a << 2) | (b << 1) | c;
1265 unitary[[rotated, i]] = Complex64::new(1.0, 0.0);
1266 }
1267
1268 unitary
1269 }
1270
1271 fn create_random_unitary(size: usize) -> Array2<Complex64> {
1272 let mut matrix = Array2::zeros((size, size));
1274
1275 for i in 0..size {
1277 for j in 0..size {
1278 matrix[[i, j]] = Complex64::new(fastrand::f64() - 0.5, fastrand::f64() - 0.5);
1279 }
1280 }
1281
1282 for j in 0..size {
1284 let mut norm_sq = 0.0;
1286 for i in 0..size {
1287 norm_sq += matrix[[i, j]].norm_sqr();
1288 }
1289 let norm = norm_sq.sqrt();
1290
1291 if norm > 1e-15 {
1292 for i in 0..size {
1293 matrix[[i, j]] /= norm;
1294 }
1295 }
1296
1297 for k in j + 1..size {
1299 let mut inner_product = Complex64::new(0.0, 0.0);
1300 for i in 0..size {
1301 inner_product += matrix[[i, j]].conj() * matrix[[i, k]];
1302 }
1303
1304 for i in 0..size {
1305 let correction = inner_product * matrix[[i, j]];
1306 matrix[[i, k]] -= correction;
1307 }
1308 }
1309 }
1310
1311 matrix
1312 }
1313
1314 fn is_unitary(matrix: &Array2<Complex64>) -> bool {
1315 let (rows, cols) = matrix.dim();
1316 if rows != cols {
1317 return false;
1318 }
1319
1320 let mut identity_check = Array2::zeros((rows, cols));
1322
1323 for i in 0..rows {
1324 for j in 0..cols {
1325 let mut sum = Complex64::new(0.0, 0.0);
1326 for k in 0..rows {
1327 sum += matrix[[k, i]].conj() * matrix[[k, j]];
1328 }
1329 identity_check[[i, j]] = sum;
1330 }
1331 }
1332
1333 for i in 0..rows {
1335 for j in 0..cols {
1336 let expected = if i == j {
1337 Complex64::new(1.0, 0.0)
1338 } else {
1339 Complex64::new(0.0, 0.0)
1340 };
1341 let diff = (identity_check[[i, j]] - expected).norm();
1342 if diff > 1e-10 {
1343 return false;
1344 }
1345 }
1346 }
1347
1348 true
1349 }
1350}
1351
1352#[derive(Debug, Clone)]
1354pub struct QCAEvolutionResult {
1355 pub final_state: Array1<Complex64>,
1357 pub evolution_history: Vec<QCASnapshot>,
1359 pub total_steps: usize,
1361 pub total_time_ms: f64,
1363 pub final_entropy: f64,
1365}
1366
1367pub struct QCAUtils;
1369
1370impl QCAUtils {
1371 pub fn create_predefined_config(config_type: &str, size: usize) -> QCAConfig {
1373 match config_type {
1374 "game_of_life" => QCAConfig {
1375 dimensions: vec![size, size],
1376 boundary_conditions: BoundaryConditions::Periodic,
1377 neighborhood: NeighborhoodType::Moore,
1378 rule_type: QCARuleType::Partitioned,
1379 evolution_steps: 50,
1380 parallel_evolution: true,
1381 measurement_strategy: MeasurementStrategy::Probabilistic,
1382 },
1383 "elementary_ca" => QCAConfig {
1384 dimensions: vec![size],
1385 boundary_conditions: BoundaryConditions::Periodic,
1386 neighborhood: NeighborhoodType::VonNeumann,
1387 rule_type: QCARuleType::Sequential,
1388 evolution_steps: 100,
1389 parallel_evolution: false,
1390 measurement_strategy: MeasurementStrategy::Deterministic,
1391 },
1392 "margolus_ca" => QCAConfig {
1393 dimensions: vec![size, size],
1394 boundary_conditions: BoundaryConditions::Periodic,
1395 neighborhood: NeighborhoodType::Custom,
1396 rule_type: QCARuleType::Margolus,
1397 evolution_steps: 25,
1398 parallel_evolution: true,
1399 measurement_strategy: MeasurementStrategy::Partial,
1400 },
1401 _ => QCAConfig::default(),
1402 }
1403 }
1404
1405 pub fn create_initial_pattern(pattern_type: &str, dimensions: &[usize]) -> Array1<Complex64> {
1407 let total_cells = dimensions.iter().product::<usize>();
1408 let state_size = 1 << total_cells;
1409 let mut state = Array1::zeros(state_size);
1410
1411 match pattern_type {
1412 "random" => {
1413 for i in 0..state_size {
1415 state[i] = Complex64::new(fastrand::f64() - 0.5, fastrand::f64() - 0.5);
1416 }
1417 let norm: f64 = state.iter().map(|x| x.norm_sqr()).sum::<f64>().sqrt();
1419 state.mapv_inplace(|x| x / norm);
1420 }
1421 "glider" if dimensions.len() == 2 => {
1422 let width = dimensions[0];
1424 let height = dimensions[1];
1425
1426 if width >= 3 && height >= 3 {
1427 let glider_positions = [
1429 width,
1430 2 * width + 1,
1431 2, width + 2,
1433 2 * width + 2,
1434 ];
1435
1436 let mut glider_state = 0;
1437 for &pos in &glider_positions {
1438 if pos < total_cells {
1439 glider_state |= 1 << pos;
1440 }
1441 }
1442
1443 if glider_state < state_size {
1444 state[glider_state] = Complex64::new(1.0, 0.0);
1445 }
1446 }
1447 }
1448 "uniform" => {
1449 let amplitude = 1.0 / (state_size as f64).sqrt();
1451 state.fill(Complex64::new(amplitude, 0.0));
1452 }
1453 _ => {
1454 state[0] = Complex64::new(1.0, 0.0);
1456 }
1457 }
1458
1459 state
1460 }
1461
1462 pub fn benchmark_qca() -> Result<QCABenchmarkResults> {
1464 let mut results = QCABenchmarkResults::default();
1465
1466 let configs = vec![
1467 (
1468 "1d_elementary",
1469 QCAUtils::create_predefined_config("elementary_ca", 8),
1470 ),
1471 (
1472 "2d_game_of_life",
1473 QCAUtils::create_predefined_config("game_of_life", 4),
1474 ),
1475 (
1476 "2d_margolus",
1477 QCAUtils::create_predefined_config("margolus_ca", 4),
1478 ),
1479 ];
1480
1481 for (name, mut config) in configs {
1482 config.evolution_steps = 20; let mut qca = QuantumCellularAutomaton::new(config)?;
1485 let initial_state = QCAUtils::create_initial_pattern("random", &qca.config.dimensions);
1486 qca.set_initial_state(initial_state)?;
1487
1488 let start = std::time::Instant::now();
1489 let _result = qca.evolve(20)?;
1490 let time = start.elapsed().as_secs_f64() * 1000.0;
1491
1492 results.benchmark_times.push((name.to_string(), time));
1493 results
1494 .qca_stats
1495 .insert(name.to_string(), qca.get_stats().clone());
1496 }
1497
1498 Ok(results)
1499 }
1500}
1501
1502#[derive(Debug, Clone, Default)]
1504pub struct QCABenchmarkResults {
1505 pub benchmark_times: Vec<(String, f64)>,
1507 pub qca_stats: HashMap<String, QCAStats>,
1509}
1510
1511#[cfg(test)]
1512mod tests {
1513 use super::*;
1514 use approx::assert_abs_diff_eq;
1515
1516 #[test]
1517 fn test_qca_creation() {
1518 let config = QCAConfig::default();
1519 let qca = QuantumCellularAutomaton::new(config);
1520 assert!(qca.is_ok());
1521 }
1522
1523 #[test]
1524 fn test_qca_1d_evolution() {
1525 let config = QCAConfig {
1526 dimensions: vec![4],
1527 evolution_steps: 5,
1528 ..Default::default()
1529 };
1530
1531 let mut qca = QuantumCellularAutomaton::new(config).unwrap();
1532 let result = qca.evolve(5);
1533 assert!(result.is_ok());
1534
1535 let evolution_result = result.unwrap();
1536 assert_eq!(evolution_result.total_steps, 5);
1537 assert!(evolution_result.total_time_ms > 0.0);
1538 }
1539
1540 #[test]
1541 fn test_qca_2d_evolution() {
1542 let config = QCAConfig {
1543 dimensions: vec![3, 3],
1544 evolution_steps: 3,
1545 rule_type: QCARuleType::Partitioned,
1546 ..Default::default()
1547 };
1548
1549 let mut qca = QuantumCellularAutomaton::new(config).unwrap();
1550 let result = qca.evolve(3);
1551 assert!(result.is_ok());
1552 }
1553
1554 #[test]
1555 fn test_qca_measurement() {
1556 let config = QCAConfig {
1557 dimensions: vec![3],
1558 ..Default::default()
1559 };
1560
1561 let mut qca = QuantumCellularAutomaton::new(config).unwrap();
1562
1563 let results = qca.measure_cells(&[0, 1, 2]);
1565 assert!(results.is_ok());
1566 assert_eq!(results.unwrap().len(), 3);
1567 }
1568
1569 #[test]
1570 fn test_boundary_conditions() {
1571 let configs = vec![
1572 BoundaryConditions::Periodic,
1573 BoundaryConditions::Fixed,
1574 BoundaryConditions::Open,
1575 BoundaryConditions::Reflective,
1576 ];
1577
1578 for boundary in configs {
1579 let config = QCAConfig {
1580 dimensions: vec![4],
1581 boundary_conditions: boundary,
1582 evolution_steps: 2,
1583 ..Default::default()
1584 };
1585
1586 let mut qca = QuantumCellularAutomaton::new(config).unwrap();
1587 let result = qca.evolve(2);
1588 assert!(result.is_ok());
1589 }
1590 }
1591
1592 #[test]
1593 fn test_neighborhood_types() {
1594 let neighborhoods = vec![NeighborhoodType::VonNeumann, NeighborhoodType::Moore];
1595
1596 for neighborhood in neighborhoods {
1597 let config = QCAConfig {
1598 dimensions: vec![3, 3],
1599 neighborhood,
1600 evolution_steps: 2,
1601 ..Default::default()
1602 };
1603
1604 let mut qca = QuantumCellularAutomaton::new(config).unwrap();
1605 let result = qca.evolve(2);
1606 assert!(result.is_ok());
1607 }
1608 }
1609
1610 #[test]
1611 fn test_predefined_configs() {
1612 let config_types = vec!["game_of_life", "elementary_ca", "margolus_ca"];
1613
1614 for config_type in config_types {
1615 let config = QCAUtils::create_predefined_config(config_type, 4);
1616 let qca = QuantumCellularAutomaton::new(config);
1617 assert!(qca.is_ok());
1618 }
1619 }
1620
1621 #[test]
1622 fn test_initial_patterns() {
1623 let dimensions = vec![4, 4];
1624 let patterns = vec!["random", "glider", "uniform"];
1625
1626 for pattern in patterns {
1627 let state = QCAUtils::create_initial_pattern(pattern, &dimensions);
1628 assert_eq!(state.len(), 1 << 16); let norm: f64 = state.iter().map(|x| x.norm_sqr()).sum();
1632 assert_abs_diff_eq!(norm, 1.0, epsilon = 1e-10);
1633 }
1634 }
1635
1636 #[test]
1637 fn test_entanglement_entropy_calculation() {
1638 let config = QCAConfig {
1639 dimensions: vec![4],
1640 ..Default::default()
1641 };
1642
1643 let mut qca = QuantumCellularAutomaton::new(config).unwrap();
1644
1645 let state_size = qca.state.len();
1647 qca.state = Array1::zeros(state_size);
1648 qca.state[0] = Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0); qca.state[15] = Complex64::new(1.0 / 2.0_f64.sqrt(), 0.0); let entropy = qca.calculate_entanglement_entropy().unwrap();
1652 assert!(entropy >= 0.0);
1653 }
1654
1655 #[test]
1656 fn test_local_observables() {
1657 let config = QCAConfig {
1658 dimensions: vec![3],
1659 ..Default::default()
1660 };
1661
1662 let qca = QuantumCellularAutomaton::new(config).unwrap();
1663 let observables = qca.calculate_local_observables().unwrap();
1664
1665 assert!(observables.contains_key("magnetization_0"));
1667 assert!(observables.contains_key("magnetization_1"));
1668 assert!(observables.contains_key("magnetization_2"));
1669 }
1670
1671 #[test]
1672 fn test_unitary_check() {
1673 let cnot = QuantumCellularAutomaton::create_cnot_unitary();
1674 assert!(QuantumCellularAutomaton::is_unitary(&cnot));
1675
1676 let rotation =
1677 QuantumCellularAutomaton::create_rotation_unitary(std::f64::consts::PI / 4.0);
1678 assert!(QuantumCellularAutomaton::is_unitary(&rotation));
1679 }
1680}