1use scirs2_core::ndarray::{Array1, Array2, ArrayView1};
9use scirs2_core::Complex64;
10use serde::{Deserialize, Serialize};
11use std::collections::{HashMap, VecDeque};
12use std::fs::File;
13use std::io::Write as IoWrite;
14use std::path::Path;
15use std::sync::{Arc, Mutex};
16use std::time::{Duration, SystemTime, UNIX_EPOCH};
17
18use crate::circuit_interfaces::{InterfaceCircuit, InterfaceGate, InterfaceGateType};
19use crate::debugger::{ExecutionSnapshot, PerformanceMetrics};
20use crate::error::{Result, SimulatorError};
21
22use std::fmt::Write;
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
25pub enum VisualizationFramework {
26 Matplotlib,
28 Plotly,
30 D3JS,
32 SVG,
34 ASCII,
36 LaTeX,
38 JSON,
40}
41
42#[derive(Debug, Clone)]
44pub struct VisualizationConfig {
45 pub framework: VisualizationFramework,
47 pub real_time: bool,
49 pub max_data_points: usize,
51 pub export_directory: String,
53 pub color_scheme: ColorScheme,
55 pub interactive: bool,
57 pub plot_dimensions: (usize, usize),
59 pub enable_animation: bool,
61}
62
63impl Default for VisualizationConfig {
64 fn default() -> Self {
65 Self {
66 framework: VisualizationFramework::JSON,
67 real_time: false,
68 max_data_points: 10_000,
69 export_directory: "./visualization_output".to_string(),
70 color_scheme: ColorScheme::Default,
71 interactive: false,
72 plot_dimensions: (800, 600),
73 enable_animation: false,
74 }
75 }
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub enum ColorScheme {
81 Default,
82 Dark,
83 Light,
84 Scientific,
85 Quantum,
86 Accessibility,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
91pub enum VisualizationData {
92 StateVector {
94 amplitudes: Vec<Complex64>,
95 basis_labels: Vec<String>,
96 timestamp: f64,
97 },
98 CircuitDiagram {
100 gates: Vec<GateVisualizationData>,
101 num_qubits: usize,
102 circuit_depth: usize,
103 },
104 PerformanceTimeSeries {
106 timestamps: Vec<f64>,
107 execution_times: Vec<f64>,
108 memory_usage: Vec<f64>,
109 gate_counts: Vec<HashMap<String, usize>>,
110 },
111 EntanglementVisualization {
113 entanglement_matrix: Array2<f64>,
114 qubit_labels: Vec<String>,
115 bipartite_entropies: Vec<f64>,
116 },
117 SyndromePattern {
119 syndrome_data: Vec<Vec<bool>>,
120 error_locations: Vec<usize>,
121 correction_success: bool,
122 timestamp: f64,
123 },
124 OptimizationLandscape {
126 parameter_values: Vec<Vec<f64>>,
127 cost_values: Vec<f64>,
128 gradient_norms: Vec<f64>,
129 parameter_names: Vec<String>,
130 },
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct GateVisualizationData {
136 pub gate_type: String,
137 pub qubits: Vec<usize>,
138 pub parameters: Vec<f64>,
139 pub position: usize,
140 pub execution_time: Option<f64>,
141 pub label: Option<String>,
142}
143
144pub trait VisualizationHook: Send + Sync {
146 fn process_data(&mut self, data: VisualizationData) -> Result<()>;
148
149 fn export(&self, path: &str) -> Result<()>;
151
152 fn clear(&mut self);
154
155 fn framework(&self) -> VisualizationFramework;
157}
158
159pub struct VisualizationManager {
161 config: VisualizationConfig,
163 hooks: Vec<Box<dyn VisualizationHook>>,
165 data_buffer: Arc<Mutex<VecDeque<VisualizationData>>>,
167 performance_history: Arc<Mutex<Vec<PerformanceMetrics>>>,
169 active_visualizations: HashMap<String, Box<dyn VisualizationHook>>,
171}
172
173impl VisualizationManager {
174 #[must_use]
176 pub fn new(config: VisualizationConfig) -> Self {
177 Self {
178 config,
179 hooks: Vec::new(),
180 data_buffer: Arc::new(Mutex::new(VecDeque::with_capacity(1000))),
181 performance_history: Arc::new(Mutex::new(Vec::new())),
182 active_visualizations: HashMap::new(),
183 }
184 }
185
186 pub fn register_hook(&mut self, hook: Box<dyn VisualizationHook>) {
188 self.hooks.push(hook);
189 }
190
191 pub fn visualize_state(
193 &mut self,
194 state: &Array1<Complex64>,
195 label: Option<String>,
196 ) -> Result<()> {
197 let amplitudes = state.to_vec();
198 let basis_labels = self.generate_basis_labels(state.len());
199 let timestamp = SystemTime::now()
200 .duration_since(UNIX_EPOCH)
201 .map_err(|e| SimulatorError::InvalidOperation(format!("System time error: {e}")))?
202 .as_secs_f64();
203
204 let data = VisualizationData::StateVector {
205 amplitudes,
206 basis_labels,
207 timestamp,
208 };
209
210 self.process_visualization_data(data)?;
211 Ok(())
212 }
213
214 pub fn visualize_circuit(&mut self, circuit: &InterfaceCircuit) -> Result<()> {
216 let gates = circuit
217 .gates
218 .iter()
219 .enumerate()
220 .map(|(pos, gate)| GateVisualizationData {
221 gate_type: format!("{:?}", gate.gate_type),
222 qubits: gate.qubits.clone(),
223 parameters: self.extract_gate_parameters(&gate.gate_type),
224 position: pos,
225 execution_time: None,
226 label: gate.label.clone(),
227 })
228 .collect();
229
230 let data = VisualizationData::CircuitDiagram {
231 gates,
232 num_qubits: circuit.num_qubits,
233 circuit_depth: circuit.gates.len(),
234 };
235
236 self.process_visualization_data(data)?;
237 Ok(())
238 }
239
240 pub fn visualize_performance(&mut self, metrics: &PerformanceMetrics) -> Result<()> {
242 {
243 let mut history = self
244 .performance_history
245 .lock()
246 .map_err(|e| SimulatorError::InvalidOperation(format!("Lock poisoned: {e}")))?;
247 history.push(metrics.clone());
248
249 if history.len() > self.config.max_data_points {
251 history.remove(0);
252 }
253 }
254
255 let data = {
257 let history = self
258 .performance_history
259 .lock()
260 .map_err(|e| SimulatorError::InvalidOperation(format!("Lock poisoned: {e}")))?;
261 let timestamps: Vec<f64> = (0..history.len()).map(|i| i as f64).collect();
262 let execution_times: Vec<f64> =
263 history.iter().map(|m| m.total_time.as_secs_f64()).collect();
264 let memory_usage: Vec<f64> = history
265 .iter()
266 .map(|m| m.memory_usage.peak_statevector_memory as f64)
267 .collect();
268 let gate_counts: Vec<HashMap<String, usize>> =
269 history.iter().map(|m| m.gate_counts.clone()).collect();
270
271 VisualizationData::PerformanceTimeSeries {
272 timestamps,
273 execution_times,
274 memory_usage,
275 gate_counts,
276 }
277 };
278
279 self.process_visualization_data(data)?;
280 Ok(())
281 }
282
283 pub fn visualize_entanglement(
285 &mut self,
286 state: &Array1<Complex64>,
287 qubit_labels: Option<Vec<String>>,
288 ) -> Result<()> {
289 let num_qubits = (state.len() as f64).log2().round() as usize;
290 let labels =
291 qubit_labels.unwrap_or_else(|| (0..num_qubits).map(|i| format!("q{i}")).collect());
292
293 let entanglement_matrix = self.calculate_entanglement_matrix(state, num_qubits)?;
295
296 let bipartite_entropies = self.calculate_bipartite_entropies(state, num_qubits)?;
298
299 let data = VisualizationData::EntanglementVisualization {
300 entanglement_matrix,
301 qubit_labels: labels,
302 bipartite_entropies,
303 };
304
305 self.process_visualization_data(data)?;
306 Ok(())
307 }
308
309 pub fn visualize_syndrome_pattern(
311 &mut self,
312 syndrome_data: Vec<Vec<bool>>,
313 error_locations: Vec<usize>,
314 correction_success: bool,
315 ) -> Result<()> {
316 let timestamp = SystemTime::now()
317 .duration_since(UNIX_EPOCH)
318 .map_err(|e| SimulatorError::InvalidOperation(format!("System time error: {e}")))?
319 .as_secs_f64();
320
321 let data = VisualizationData::SyndromePattern {
322 syndrome_data,
323 error_locations,
324 correction_success,
325 timestamp,
326 };
327
328 self.process_visualization_data(data)?;
329 Ok(())
330 }
331
332 pub fn visualize_optimization_landscape(
334 &mut self,
335 parameter_values: Vec<Vec<f64>>,
336 cost_values: Vec<f64>,
337 gradient_norms: Vec<f64>,
338 parameter_names: Vec<String>,
339 ) -> Result<()> {
340 let data = VisualizationData::OptimizationLandscape {
341 parameter_values,
342 cost_values,
343 gradient_norms,
344 parameter_names,
345 };
346
347 self.process_visualization_data(data)?;
348 Ok(())
349 }
350
351 fn process_visualization_data(&mut self, data: VisualizationData) -> Result<()> {
353 if self.config.real_time {
355 let mut buffer = self
356 .data_buffer
357 .lock()
358 .map_err(|e| SimulatorError::InvalidOperation(format!("Lock poisoned: {e}")))?;
359 buffer.push_back(data.clone());
360 if buffer.len() > self.config.max_data_points {
361 buffer.pop_front();
362 }
363 }
364
365 for hook in &mut self.hooks {
367 hook.process_data(data.clone())?;
368 }
369
370 Ok(())
371 }
372
373 pub fn export_all(&self, base_path: &str) -> Result<()> {
375 std::fs::create_dir_all(base_path).map_err(|e| {
376 SimulatorError::InvalidInput(format!("Failed to create export directory: {e}"))
377 })?;
378
379 for (i, hook) in self.hooks.iter().enumerate() {
380 let export_path = format!(
381 "{}/visualization_{}.{}",
382 base_path,
383 i,
384 self.get_file_extension(hook.framework())
385 );
386 hook.export(&export_path)?;
387 }
388
389 Ok(())
390 }
391
392 pub fn clear_all(&mut self) {
394 for hook in &mut self.hooks {
395 hook.clear();
396 }
397
398 if let Ok(mut buffer) = self.data_buffer.lock() {
399 buffer.clear();
400 }
401 if let Ok(mut history) = self.performance_history.lock() {
402 history.clear();
403 }
404 }
405
406 fn generate_basis_labels(&self, state_size: usize) -> Vec<String> {
408 let num_qubits = (state_size as f64).log2().round() as usize;
409 (0..state_size)
410 .map(|i| format!("|{i:0num_qubits$b}⟩"))
411 .collect()
412 }
413
414 fn extract_gate_parameters(&self, gate_type: &InterfaceGateType) -> Vec<f64> {
416 match gate_type {
417 InterfaceGateType::Phase(angle) => vec![*angle],
418 InterfaceGateType::RX(angle) => vec![*angle],
419 InterfaceGateType::RY(angle) => vec![*angle],
420 InterfaceGateType::RZ(angle) => vec![*angle],
421 InterfaceGateType::U1(angle) => vec![*angle],
422 InterfaceGateType::U2(theta, phi) => vec![*theta, *phi],
423 InterfaceGateType::U3(theta, phi, lambda) => vec![*theta, *phi, *lambda],
424 InterfaceGateType::CRX(angle) => vec![*angle],
425 InterfaceGateType::CRY(angle) => vec![*angle],
426 InterfaceGateType::CRZ(angle) => vec![*angle],
427 InterfaceGateType::CPhase(angle) => vec![*angle],
428 _ => Vec::new(),
429 }
430 }
431
432 fn calculate_entanglement_matrix(
434 &self,
435 state: &Array1<Complex64>,
436 num_qubits: usize,
437 ) -> Result<Array2<f64>> {
438 let mut entanglement_matrix = Array2::zeros((num_qubits, num_qubits));
439
440 for i in 0..num_qubits {
442 for j in i..num_qubits {
443 if i == j {
444 entanglement_matrix[[i, j]] = 1.0;
445 } else {
446 let mutual_info = self.calculate_mutual_information(state, i, j, num_qubits)?;
448 entanglement_matrix[[i, j]] = mutual_info;
449 entanglement_matrix[[j, i]] = mutual_info;
450 }
451 }
452 }
453
454 Ok(entanglement_matrix)
455 }
456
457 fn calculate_bipartite_entropies(
459 &self,
460 state: &Array1<Complex64>,
461 num_qubits: usize,
462 ) -> Result<Vec<f64>> {
463 let mut entropies = Vec::new();
464
465 for cut in 1..num_qubits {
466 let entropy = self.calculate_bipartite_entropy(state, cut, num_qubits)?;
467 entropies.push(entropy);
468 }
469
470 Ok(entropies)
471 }
472
473 const fn calculate_mutual_information(
475 &self,
476 _state: &Array1<Complex64>,
477 _qubit_i: usize,
478 _qubit_j: usize,
479 _num_qubits: usize,
480 ) -> Result<f64> {
481 Ok(0.5)
483 }
484
485 fn calculate_bipartite_entropy(
487 &self,
488 state: &Array1<Complex64>,
489 cut: usize,
490 num_qubits: usize,
491 ) -> Result<f64> {
492 let left_size = 1 << cut;
494 let right_size = 1 << (num_qubits - cut);
495
496 let mut reduced_dm = Array2::zeros((left_size, left_size));
498
499 for i in 0..left_size {
500 for j in 0..left_size {
501 let mut trace_val = Complex64::new(0.0, 0.0);
502 for k in 0..right_size {
503 let idx1 = i * right_size + k;
504 let idx2 = j * right_size + k;
505 if idx1 < state.len() && idx2 < state.len() {
506 trace_val += state[idx1] * state[idx2].conj();
507 }
508 }
509 reduced_dm[[i, j]] = trace_val;
510 }
511 }
512
513 let mut entropy = 0.0;
515 for i in 0..left_size {
516 let eigenval = reduced_dm[[i, i]].norm();
517 if eigenval > 1e-10 {
518 entropy -= eigenval * eigenval.ln();
519 }
520 }
521
522 Ok(entropy)
523 }
524
525 const fn get_file_extension(&self, framework: VisualizationFramework) -> &str {
527 match framework {
528 VisualizationFramework::Matplotlib => "py",
529 VisualizationFramework::Plotly => "html",
530 VisualizationFramework::D3JS => "html",
531 VisualizationFramework::SVG => "svg",
532 VisualizationFramework::ASCII => "txt",
533 VisualizationFramework::LaTeX => "tex",
534 VisualizationFramework::JSON => "json",
535 }
536 }
537}
538
539pub struct JSONVisualizationHook {
541 data: Vec<VisualizationData>,
543 config: VisualizationConfig,
545}
546
547impl JSONVisualizationHook {
548 #[must_use]
549 pub const fn new(config: VisualizationConfig) -> Self {
550 Self {
551 data: Vec::new(),
552 config,
553 }
554 }
555}
556
557impl VisualizationHook for JSONVisualizationHook {
558 fn process_data(&mut self, data: VisualizationData) -> Result<()> {
559 self.data.push(data);
560
561 if self.data.len() > self.config.max_data_points {
563 self.data.remove(0);
564 }
565
566 Ok(())
567 }
568
569 fn export(&self, path: &str) -> Result<()> {
570 let json_data = serde_json::to_string_pretty(&self.data)
571 .map_err(|e| SimulatorError::InvalidInput(format!("Failed to serialize data: {e}")))?;
572
573 let mut file = File::create(path)
574 .map_err(|e| SimulatorError::InvalidInput(format!("Failed to create file: {e}")))?;
575
576 file.write_all(json_data.as_bytes())
577 .map_err(|e| SimulatorError::InvalidInput(format!("Failed to write file: {e}")))?;
578
579 Ok(())
580 }
581
582 fn clear(&mut self) {
583 self.data.clear();
584 }
585
586 fn framework(&self) -> VisualizationFramework {
587 VisualizationFramework::JSON
588 }
589}
590
591pub struct ASCIIVisualizationHook {
593 recent_states: VecDeque<Array1<Complex64>>,
595 config: VisualizationConfig,
597}
598
599impl ASCIIVisualizationHook {
600 #[must_use]
601 pub fn new(config: VisualizationConfig) -> Self {
602 Self {
603 recent_states: VecDeque::with_capacity(100),
604 config,
605 }
606 }
607
608 fn state_to_ascii(&self, state: &Array1<Complex64>) -> String {
610 let mut output = String::new();
611 output.push_str("Quantum State Visualization:\n");
612 output.push_str("==========================\n");
613
614 for (i, amplitude) in state.iter().enumerate().take(16) {
615 let magnitude = amplitude.norm();
616 let phase = amplitude.arg();
617
618 let bar_length = (magnitude * 20.0) as usize;
619 let bar = "█".repeat(bar_length) + &"░".repeat(20 - bar_length);
620
621 writeln!(
622 output,
623 "|{:02}⟩: {} {:.4} ∠{:.2}π",
624 i,
625 bar,
626 magnitude,
627 phase / std::f64::consts::PI
628 )
629 .expect("Failed to write to string buffer");
630 }
631
632 if state.len() > 16 {
633 writeln!(output, "... ({} more states)", state.len() - 16)
634 .expect("Failed to write to string buffer");
635 }
636
637 output
638 }
639}
640
641impl VisualizationHook for ASCIIVisualizationHook {
642 fn process_data(&mut self, data: VisualizationData) -> Result<()> {
643 match data {
644 VisualizationData::StateVector { amplitudes, .. } => {
645 let state = Array1::from_vec(amplitudes);
646
647 if self.config.real_time {
648 println!("{}", self.state_to_ascii(&state));
649 }
650
651 self.recent_states.push_back(state);
652 if self.recent_states.len() > 100 {
653 self.recent_states.pop_front();
654 }
655 }
656 VisualizationData::CircuitDiagram {
657 gates, num_qubits, ..
658 } => {
659 if self.config.real_time {
660 println!(
661 "Circuit Diagram ({} qubits, {} gates):",
662 num_qubits,
663 gates.len()
664 );
665 for gate in gates.iter().take(10) {
666 println!(" {} on qubits {:?}", gate.gate_type, gate.qubits);
667 }
668 if gates.len() > 10 {
669 println!(" ... ({} more gates)", gates.len() - 10);
670 }
671 }
672 }
673 _ => {
674 }
676 }
677
678 Ok(())
679 }
680
681 fn export(&self, path: &str) -> Result<()> {
682 let mut output = String::new();
683 output.push_str("ASCII Visualization Export\n");
684 output.push_str("==========================\n\n");
685
686 for (i, state) in self.recent_states.iter().enumerate() {
687 writeln!(output, "State {i}:").expect("Failed to write to string buffer");
688 output.push_str(&self.state_to_ascii(state));
689 output.push('\n');
690 }
691
692 let mut file = File::create(path)
693 .map_err(|e| SimulatorError::InvalidInput(format!("Failed to create file: {e}")))?;
694
695 file.write_all(output.as_bytes())
696 .map_err(|e| SimulatorError::InvalidInput(format!("Failed to write file: {e}")))?;
697
698 Ok(())
699 }
700
701 fn clear(&mut self) {
702 self.recent_states.clear();
703 }
704
705 fn framework(&self) -> VisualizationFramework {
706 VisualizationFramework::ASCII
707 }
708}
709
710pub fn benchmark_visualization() -> Result<HashMap<String, f64>> {
712 let mut results = HashMap::new();
713
714 let start = std::time::Instant::now();
716 let mut json_hook = JSONVisualizationHook::new(VisualizationConfig::default());
717
718 for i in 0..1000 {
719 let test_state = Array1::from_vec(vec![
720 Complex64::new(0.5, 0.0),
721 Complex64::new(0.5, 0.0),
722 Complex64::new(0.5, 0.0),
723 Complex64::new(0.5, 0.0),
724 ]);
725
726 let data = VisualizationData::StateVector {
727 amplitudes: test_state.to_vec(),
728 basis_labels: vec![
729 "00".to_string(),
730 "01".to_string(),
731 "10".to_string(),
732 "11".to_string(),
733 ],
734 timestamp: f64::from(i),
735 };
736
737 json_hook.process_data(data)?;
738 }
739
740 let json_time = start.elapsed().as_millis() as f64;
741 results.insert("json_hook_1000_states".to_string(), json_time);
742
743 let start = std::time::Instant::now();
745 let mut ascii_hook = ASCIIVisualizationHook::new(VisualizationConfig {
746 real_time: false,
747 ..Default::default()
748 });
749
750 for i in 0..100 {
751 let test_state = Array1::from_vec(vec![
752 Complex64::new(0.5, 0.0),
753 Complex64::new(0.5, 0.0),
754 Complex64::new(0.5, 0.0),
755 Complex64::new(0.5, 0.0),
756 ]);
757
758 let data = VisualizationData::StateVector {
759 amplitudes: test_state.to_vec(),
760 basis_labels: vec![
761 "00".to_string(),
762 "01".to_string(),
763 "10".to_string(),
764 "11".to_string(),
765 ],
766 timestamp: f64::from(i),
767 };
768
769 ascii_hook.process_data(data)?;
770 }
771
772 let ascii_time = start.elapsed().as_millis() as f64;
773 results.insert("ascii_hook_100_states".to_string(), ascii_time);
774
775 Ok(results)
776}
777
778#[cfg(test)]
779mod tests {
780 use super::*;
781 use approx::assert_abs_diff_eq;
782
783 #[test]
784 fn test_visualization_manager_creation() {
785 let config = VisualizationConfig::default();
786 let manager = VisualizationManager::new(config);
787 assert_eq!(manager.hooks.len(), 0);
788 }
789
790 #[test]
791 fn test_json_hook() {
792 let mut hook = JSONVisualizationHook::new(VisualizationConfig::default());
793
794 let test_data = VisualizationData::StateVector {
795 amplitudes: vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
796 basis_labels: vec!["0".to_string(), "1".to_string()],
797 timestamp: 0.0,
798 };
799
800 assert!(hook.process_data(test_data).is_ok());
801 assert_eq!(hook.data.len(), 1);
802 }
803
804 #[test]
805 fn test_ascii_hook() {
806 let mut hook = ASCIIVisualizationHook::new(VisualizationConfig {
807 real_time: false,
808 ..Default::default()
809 });
810
811 let test_data = VisualizationData::StateVector {
812 amplitudes: vec![Complex64::new(0.707, 0.0), Complex64::new(0.707, 0.0)],
813 basis_labels: vec!["0".to_string(), "1".to_string()],
814 timestamp: 0.0,
815 };
816
817 assert!(hook.process_data(test_data).is_ok());
818 assert_eq!(hook.recent_states.len(), 1);
819 }
820
821 #[test]
822 fn test_state_visualization() {
823 let config = VisualizationConfig::default();
824 let mut manager = VisualizationManager::new(config);
825
826 let test_state = Array1::from_vec(vec![
827 Complex64::new(0.5, 0.0),
828 Complex64::new(0.5, 0.0),
829 Complex64::new(0.5, 0.0),
830 Complex64::new(0.5, 0.0),
831 ]);
832
833 assert!(manager.visualize_state(&test_state, None).is_ok());
834 }
835
836 #[test]
837 fn test_circuit_visualization() {
838 let config = VisualizationConfig::default();
839 let mut manager = VisualizationManager::new(config);
840
841 let mut circuit = InterfaceCircuit::new(2, 0);
842 circuit.add_gate(InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]));
843 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![0, 1]));
844
845 assert!(manager.visualize_circuit(&circuit).is_ok());
846 }
847
848 #[test]
849 fn test_parameter_extraction() {
850 let config = VisualizationConfig::default();
851 let manager = VisualizationManager::new(config);
852
853 let params = manager.extract_gate_parameters(&InterfaceGateType::RX(1.5));
854 assert_eq!(params, vec![1.5]);
855
856 let params = manager.extract_gate_parameters(&InterfaceGateType::U3(1.0, 2.0, 3.0));
857 assert_eq!(params, vec![1.0, 2.0, 3.0]);
858
859 let params = manager.extract_gate_parameters(&InterfaceGateType::Hadamard);
860 assert_eq!(params.len(), 0);
861 }
862
863 #[test]
864 fn test_basis_label_generation() {
865 let config = VisualizationConfig::default();
866 let manager = VisualizationManager::new(config);
867
868 let labels = manager.generate_basis_labels(4);
869 assert_eq!(labels, vec!["|00⟩", "|01⟩", "|10⟩", "|11⟩"]);
870
871 let labels = manager.generate_basis_labels(8);
872 assert_eq!(labels.len(), 8);
873 assert_eq!(labels[0], "|000⟩");
874 assert_eq!(labels[7], "|111⟩");
875 }
876
877 #[test]
878 fn test_entanglement_calculation() {
879 let config = VisualizationConfig::default();
880 let manager = VisualizationManager::new(config);
881
882 let bell_state = Array1::from_vec(vec![
883 Complex64::new(0.707, 0.0),
884 Complex64::new(0.0, 0.0),
885 Complex64::new(0.0, 0.0),
886 Complex64::new(0.707, 0.0),
887 ]);
888
889 let entanglement_matrix = manager
890 .calculate_entanglement_matrix(&bell_state, 2)
891 .expect("Entanglement calculation should succeed in test");
892 assert_eq!(entanglement_matrix.shape(), [2, 2]);
893
894 let entropies = manager
895 .calculate_bipartite_entropies(&bell_state, 2)
896 .expect("Entropy calculation should succeed in test");
897 assert_eq!(entropies.len(), 1);
898 }
899}