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