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!("|{i:0num_qubits$b}⟩"))
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 const 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 const 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 const 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)
555 .map_err(|e| SimulatorError::InvalidInput(format!("Failed to serialize data: {e}")))?;
556
557 let mut file = File::create(path)
558 .map_err(|e| SimulatorError::InvalidInput(format!("Failed to create file: {e}")))?;
559
560 file.write_all(json_data.as_bytes())
561 .map_err(|e| SimulatorError::InvalidInput(format!("Failed to write file: {e}")))?;
562
563 Ok(())
564 }
565
566 fn clear(&mut self) {
567 self.data.clear();
568 }
569
570 fn framework(&self) -> VisualizationFramework {
571 VisualizationFramework::JSON
572 }
573}
574
575pub struct ASCIIVisualizationHook {
577 recent_states: VecDeque<Array1<Complex64>>,
579 config: VisualizationConfig,
581}
582
583impl ASCIIVisualizationHook {
584 pub fn new(config: VisualizationConfig) -> Self {
585 Self {
586 recent_states: VecDeque::with_capacity(100),
587 config,
588 }
589 }
590
591 fn state_to_ascii(&self, state: &Array1<Complex64>) -> String {
593 let mut output = String::new();
594 output.push_str("Quantum State Visualization:\n");
595 output.push_str("==========================\n");
596
597 for (i, amplitude) in state.iter().enumerate().take(16) {
598 let magnitude = amplitude.norm();
599 let phase = amplitude.arg();
600
601 let bar_length = (magnitude * 20.0) as usize;
602 let bar = "█".repeat(bar_length) + &"░".repeat(20 - bar_length);
603
604 output.push_str(&format!(
605 "|{:02}⟩: {} {:.4} ∠{:.2}π\n",
606 i,
607 bar,
608 magnitude,
609 phase / std::f64::consts::PI
610 ));
611 }
612
613 if state.len() > 16 {
614 output.push_str(&format!("... ({} more states)\n", state.len() - 16));
615 }
616
617 output
618 }
619}
620
621impl VisualizationHook for ASCIIVisualizationHook {
622 fn process_data(&mut self, data: VisualizationData) -> Result<()> {
623 match data {
624 VisualizationData::StateVector { amplitudes, .. } => {
625 let state = Array1::from_vec(amplitudes);
626
627 if self.config.real_time {
628 println!("{}", self.state_to_ascii(&state));
629 }
630
631 self.recent_states.push_back(state);
632 if self.recent_states.len() > 100 {
633 self.recent_states.pop_front();
634 }
635 }
636 VisualizationData::CircuitDiagram {
637 gates, num_qubits, ..
638 } => {
639 if self.config.real_time {
640 println!(
641 "Circuit Diagram ({} qubits, {} gates):",
642 num_qubits,
643 gates.len()
644 );
645 for gate in gates.iter().take(10) {
646 println!(" {} on qubits {:?}", gate.gate_type, gate.qubits);
647 }
648 if gates.len() > 10 {
649 println!(" ... ({} more gates)", gates.len() - 10);
650 }
651 }
652 }
653 _ => {
654 }
656 }
657
658 Ok(())
659 }
660
661 fn export(&self, path: &str) -> Result<()> {
662 let mut output = String::new();
663 output.push_str("ASCII Visualization Export\n");
664 output.push_str("==========================\n\n");
665
666 for (i, state) in self.recent_states.iter().enumerate() {
667 output.push_str(&format!("State {i}:\n"));
668 output.push_str(&self.state_to_ascii(state));
669 output.push('\n');
670 }
671
672 let mut file = File::create(path)
673 .map_err(|e| SimulatorError::InvalidInput(format!("Failed to create file: {e}")))?;
674
675 file.write_all(output.as_bytes())
676 .map_err(|e| SimulatorError::InvalidInput(format!("Failed to write file: {e}")))?;
677
678 Ok(())
679 }
680
681 fn clear(&mut self) {
682 self.recent_states.clear();
683 }
684
685 fn framework(&self) -> VisualizationFramework {
686 VisualizationFramework::ASCII
687 }
688}
689
690pub fn benchmark_visualization() -> Result<HashMap<String, f64>> {
692 let mut results = HashMap::new();
693
694 let start = std::time::Instant::now();
696 let mut json_hook = JSONVisualizationHook::new(VisualizationConfig::default());
697
698 for i in 0..1000 {
699 let test_state = Array1::from_vec(vec![
700 Complex64::new(0.5, 0.0),
701 Complex64::new(0.5, 0.0),
702 Complex64::new(0.5, 0.0),
703 Complex64::new(0.5, 0.0),
704 ]);
705
706 let data = VisualizationData::StateVector {
707 amplitudes: test_state.to_vec(),
708 basis_labels: vec![
709 "00".to_string(),
710 "01".to_string(),
711 "10".to_string(),
712 "11".to_string(),
713 ],
714 timestamp: i as f64,
715 };
716
717 json_hook.process_data(data)?;
718 }
719
720 let json_time = start.elapsed().as_millis() as f64;
721 results.insert("json_hook_1000_states".to_string(), json_time);
722
723 let start = std::time::Instant::now();
725 let mut ascii_hook = ASCIIVisualizationHook::new(VisualizationConfig {
726 real_time: false,
727 ..Default::default()
728 });
729
730 for i in 0..100 {
731 let test_state = Array1::from_vec(vec![
732 Complex64::new(0.5, 0.0),
733 Complex64::new(0.5, 0.0),
734 Complex64::new(0.5, 0.0),
735 Complex64::new(0.5, 0.0),
736 ]);
737
738 let data = VisualizationData::StateVector {
739 amplitudes: test_state.to_vec(),
740 basis_labels: vec![
741 "00".to_string(),
742 "01".to_string(),
743 "10".to_string(),
744 "11".to_string(),
745 ],
746 timestamp: i as f64,
747 };
748
749 ascii_hook.process_data(data)?;
750 }
751
752 let ascii_time = start.elapsed().as_millis() as f64;
753 results.insert("ascii_hook_100_states".to_string(), ascii_time);
754
755 Ok(results)
756}
757
758#[cfg(test)]
759mod tests {
760 use super::*;
761 use approx::assert_abs_diff_eq;
762
763 #[test]
764 fn test_visualization_manager_creation() {
765 let config = VisualizationConfig::default();
766 let manager = VisualizationManager::new(config);
767 assert_eq!(manager.hooks.len(), 0);
768 }
769
770 #[test]
771 fn test_json_hook() {
772 let mut hook = JSONVisualizationHook::new(VisualizationConfig::default());
773
774 let test_data = VisualizationData::StateVector {
775 amplitudes: vec![Complex64::new(1.0, 0.0), Complex64::new(0.0, 0.0)],
776 basis_labels: vec!["0".to_string(), "1".to_string()],
777 timestamp: 0.0,
778 };
779
780 assert!(hook.process_data(test_data).is_ok());
781 assert_eq!(hook.data.len(), 1);
782 }
783
784 #[test]
785 fn test_ascii_hook() {
786 let mut hook = ASCIIVisualizationHook::new(VisualizationConfig {
787 real_time: false,
788 ..Default::default()
789 });
790
791 let test_data = VisualizationData::StateVector {
792 amplitudes: vec![Complex64::new(0.707, 0.0), Complex64::new(0.707, 0.0)],
793 basis_labels: vec!["0".to_string(), "1".to_string()],
794 timestamp: 0.0,
795 };
796
797 assert!(hook.process_data(test_data).is_ok());
798 assert_eq!(hook.recent_states.len(), 1);
799 }
800
801 #[test]
802 fn test_state_visualization() {
803 let config = VisualizationConfig::default();
804 let mut manager = VisualizationManager::new(config);
805
806 let test_state = Array1::from_vec(vec![
807 Complex64::new(0.5, 0.0),
808 Complex64::new(0.5, 0.0),
809 Complex64::new(0.5, 0.0),
810 Complex64::new(0.5, 0.0),
811 ]);
812
813 assert!(manager.visualize_state(&test_state, None).is_ok());
814 }
815
816 #[test]
817 fn test_circuit_visualization() {
818 let config = VisualizationConfig::default();
819 let mut manager = VisualizationManager::new(config);
820
821 let mut circuit = InterfaceCircuit::new(2, 0);
822 circuit.add_gate(InterfaceGate::new(InterfaceGateType::Hadamard, vec![0]));
823 circuit.add_gate(InterfaceGate::new(InterfaceGateType::CNOT, vec![0, 1]));
824
825 assert!(manager.visualize_circuit(&circuit).is_ok());
826 }
827
828 #[test]
829 fn test_parameter_extraction() {
830 let config = VisualizationConfig::default();
831 let manager = VisualizationManager::new(config);
832
833 let params = manager.extract_gate_parameters(&InterfaceGateType::RX(1.5));
834 assert_eq!(params, vec![1.5]);
835
836 let params = manager.extract_gate_parameters(&InterfaceGateType::U3(1.0, 2.0, 3.0));
837 assert_eq!(params, vec![1.0, 2.0, 3.0]);
838
839 let params = manager.extract_gate_parameters(&InterfaceGateType::Hadamard);
840 assert_eq!(params.len(), 0);
841 }
842
843 #[test]
844 fn test_basis_label_generation() {
845 let config = VisualizationConfig::default();
846 let manager = VisualizationManager::new(config);
847
848 let labels = manager.generate_basis_labels(4);
849 assert_eq!(labels, vec!["|00⟩", "|01⟩", "|10⟩", "|11⟩"]);
850
851 let labels = manager.generate_basis_labels(8);
852 assert_eq!(labels.len(), 8);
853 assert_eq!(labels[0], "|000⟩");
854 assert_eq!(labels[7], "|111⟩");
855 }
856
857 #[test]
858 fn test_entanglement_calculation() {
859 let config = VisualizationConfig::default();
860 let manager = VisualizationManager::new(config);
861
862 let bell_state = Array1::from_vec(vec![
863 Complex64::new(0.707, 0.0),
864 Complex64::new(0.0, 0.0),
865 Complex64::new(0.0, 0.0),
866 Complex64::new(0.707, 0.0),
867 ]);
868
869 let entanglement_matrix = manager
870 .calculate_entanglement_matrix(&bell_state, 2)
871 .unwrap();
872 assert_eq!(entanglement_matrix.shape(), [2, 2]);
873
874 let entropies = manager
875 .calculate_bipartite_entropies(&bell_state, 2)
876 .unwrap();
877 assert_eq!(entropies.len(), 1);
878 }
879}