1use quantrs2_circuit::builder::{Circuit, Simulator};
8use quantrs2_core::{
9 error::{QuantRS2Error, QuantRS2Result},
10 gate::{multi, single, GateOp},
11 qubit::QubitId,
12 register::Register,
13};
14
15use scirs2_core::ndarray::{Array, ArrayD, IxDyn};
16use scirs2_core::ndarray_ext::manipulation;
17use scirs2_core::parallel_ops::*;
18use scirs2_core::Complex64;
19use std::collections::HashMap;
20
21pub mod contraction;
22pub mod opt_contraction;
23pub mod tensor;
24
25use contraction::ContractableNetwork;
26use opt_contraction::{ContractionOptMethod, OptimizedTensorNetwork, PathOptimizer};
27use tensor::{Tensor, TensorIndex};
28
29#[derive(Debug, Clone)]
31pub struct TensorNetworkSimulator {
32 max_bond_dimension: usize,
34
35 optimization_level: u8,
37
38 contraction_strategy: ContractionStrategy,
40
41 path_optimizer: PathOptimizer,
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub enum CircuitType {
48 Linear,
50
51 Star,
53
54 Layered,
56
57 QFT,
59
60 QAOA,
62
63 General,
65}
66
67#[derive(Debug, Clone, PartialEq, Eq)]
69pub enum ContractionStrategy {
70 Greedy,
72
73 Linear,
75
76 Star,
78
79 QFT,
81
82 QAOA,
84
85 Custom,
87}
88
89impl TensorNetworkSimulator {
90 pub fn new() -> Self {
92 Self {
93 max_bond_dimension: 16,
94 optimization_level: 1,
95 contraction_strategy: ContractionStrategy::Greedy,
96 path_optimizer: PathOptimizer::default(),
97 }
98 }
99
100 pub fn qft() -> Self {
102 Self {
103 max_bond_dimension: 16,
104 optimization_level: 2,
105 contraction_strategy: ContractionStrategy::QFT,
106 path_optimizer: PathOptimizer::default()
107 .with_method(ContractionOptMethod::Hybrid)
108 .with_max_bond_dimension(32),
109 }
110 }
111
112 pub fn qaoa() -> Self {
114 Self {
115 max_bond_dimension: 16,
116 optimization_level: 2,
117 contraction_strategy: ContractionStrategy::QAOA,
118 path_optimizer: PathOptimizer::default()
119 .with_method(ContractionOptMethod::Hybrid)
120 .with_max_bond_dimension(32),
121 }
122 }
123
124 #[must_use]
126 pub const fn with_bond_dimension(mut self, max_bond_dimension: usize) -> Self {
127 self.max_bond_dimension = max_bond_dimension;
128 self.path_optimizer = self
129 .path_optimizer
130 .with_max_bond_dimension(max_bond_dimension);
131 self
132 }
133
134 #[must_use]
141 pub fn with_optimization_level(mut self, level: u8) -> Self {
142 self.optimization_level = level.min(3);
143
144 self.path_optimizer = match level {
146 0 => self
147 .path_optimizer
148 .with_method(ContractionOptMethod::Greedy),
149 1 => self
150 .path_optimizer
151 .with_method(ContractionOptMethod::Greedy),
152 2 => self
153 .path_optimizer
154 .with_method(ContractionOptMethod::DynamicProgramming),
155 3 => self
156 .path_optimizer
157 .with_method(ContractionOptMethod::Hybrid),
158 _ => self
159 .path_optimizer
160 .with_method(ContractionOptMethod::Greedy),
161 };
162
163 self
164 }
165
166 #[must_use]
168 pub fn with_contraction_strategy(mut self, strategy: ContractionStrategy) -> Self {
169 self.contraction_strategy = strategy.clone();
170
171 self.path_optimizer = match &strategy {
173 ContractionStrategy::QFT => self
174 .path_optimizer
175 .with_method(ContractionOptMethod::DynamicProgramming)
176 .with_max_bond_dimension(32),
177 ContractionStrategy::QAOA => self
178 .path_optimizer
179 .with_method(ContractionOptMethod::DynamicProgramming)
180 .with_max_bond_dimension(32),
181 ContractionStrategy::Linear => self
182 .path_optimizer
183 .with_method(ContractionOptMethod::Greedy),
184 ContractionStrategy::Star => self
185 .path_optimizer
186 .with_method(ContractionOptMethod::Greedy),
187 _ => self.path_optimizer,
188 };
189
190 self
191 }
192
193 fn analyze_circuit_structure<const N: usize>(&self, circuit: &Circuit<N>) -> CircuitType {
195 let mut single_qubit_gates = 0;
197 let mut cnot_gates = 0;
198 let mut other_two_qubit_gates = 0;
199 let mut multi_qubit_gates = 0;
200 let mut hadamard_gates = 0;
201 let mut rotation_gates = 0;
202 let mut phase_gates = 0;
203 let mut x_rotation_gates = 0;
204 let mut controlled_phase_gates = 0;
205 let mut swap_gates = 0;
206
207 let mut qubit_connections =
209 std::collections::HashMap::<usize, std::collections::HashSet<usize>>::new();
210
211 for gate in circuit.gates() {
213 let qubits = gate.qubits();
214 let gate_name = gate.name();
215
216 if qubits.len() == 1 {
217 single_qubit_gates += 1;
219
220 match gate_name {
221 "H" => hadamard_gates += 1,
222 "RX" => {
223 rotation_gates += 1;
224 x_rotation_gates += 1;
225 }
226 "RY" | "RZ" => rotation_gates += 1,
227 "S" | "T" | "S†" | "T†" => phase_gates += 1,
228 _ => {}
229 }
230 } else if qubits.len() == 2 {
231 if gate_name == "CNOT" {
233 cnot_gates += 1;
234 } else if gate_name == "SWAP" {
235 swap_gates += 1;
236 } else if gate_name == "CZ" || gate_name == "CS" || gate_name == "CRZ" {
237 controlled_phase_gates += 1;
238 other_two_qubit_gates += 1;
239 } else {
240 other_two_qubit_gates += 1;
241 }
242
243 let q1 = qubits[0].id() as usize;
245 let q2 = qubits[1].id() as usize;
246
247 qubit_connections.entry(q1).or_default().insert(q2);
248 qubit_connections.entry(q2).or_default().insert(q1);
249 } else {
250 multi_qubit_gates += 1;
252 }
253 }
254
255 if self.is_qft_pattern(hadamard_gates, controlled_phase_gates, swap_gates, N) {
257 return CircuitType::QFT;
258 }
259
260 if self.is_qaoa_pattern(x_rotation_gates, cnot_gates) {
262 return CircuitType::QAOA;
263 }
264
265 if is_linear_structure(&qubit_connections, N)
267 && other_two_qubit_gates == 0
268 && multi_qubit_gates == 0
269 {
270 return CircuitType::Linear;
271 }
272
273 if is_star_structure(&qubit_connections, N) {
275 return CircuitType::Star;
276 }
277
278 if is_layered_structure(circuit) {
280 return CircuitType::Layered;
281 }
282
283 CircuitType::General
285 }
286
287 const fn is_qft_pattern(
289 &self,
290 hadamard_count: usize,
291 controlled_phase_count: usize,
292 swap_count: usize,
293 num_qubits: usize,
294 ) -> bool {
295 let expected_controlled_phase = (num_qubits * (num_qubits - 1)) / 2;
301 let expected_swap = num_qubits / 2;
302
303 hadamard_count >= num_qubits
305 && controlled_phase_count >= expected_controlled_phase / 2
306 && (swap_count == 0 || swap_count >= expected_swap / 2)
307 }
308
309 const fn is_qaoa_pattern(&self, x_rotation_count: usize, cnot_count: usize) -> bool {
311 x_rotation_count > 0 && cnot_count > 0
317 }
318}
319
320fn is_linear_structure(
322 qubit_connections: &std::collections::HashMap<usize, std::collections::HashSet<usize>>,
323 num_qubits: usize,
324) -> bool {
325 for i in 0..num_qubits {
327 if let Some(connections) = qubit_connections.get(&i) {
328 if connections.len() > 2 {
329 return false;
330 }
331 }
332 }
333
334 let num_endpoints = (0..num_qubits)
336 .filter(|&i| {
337 qubit_connections
338 .get(&i)
339 .is_some_and(|conns| conns.len() == 1)
340 })
341 .count();
342
343 num_endpoints == 2
345}
346
347fn is_star_structure(
349 qubit_connections: &std::collections::HashMap<usize, std::collections::HashSet<usize>>,
350 num_qubits: usize,
351) -> bool {
352 let mut high_degree_qubits = 0;
354 let mut leaf_qubits = 0;
355
356 for i in 0..num_qubits {
357 if let Some(connections) = qubit_connections.get(&i) {
358 if connections.len() > 2 {
359 high_degree_qubits += 1;
360 } else if connections.len() == 1 {
361 leaf_qubits += 1;
362 }
363 }
364 }
365
366 high_degree_qubits == 1 && leaf_qubits >= 3
368}
369
370fn is_layered_structure<const N: usize>(circuit: &Circuit<N>) -> bool {
372 let mut rotation_gates = 0;
376 let mut controlled_gates = 0;
377
378 for gate in circuit.gates() {
379 match gate.name() {
380 "RZ" | "RY" | "RX" => rotation_gates += 1,
381 "CNOT" | "CZ" | "CY" | "CH" | "CS" | "CRX" | "CRY" | "CRZ" => controlled_gates += 1,
382 _ => {}
383 }
384 }
385
386 rotation_gates >= N / 2 && controlled_gates >= N / 2
388}
389
390impl TensorNetworkSimulator {
391 fn apply_single_qubit_gate<const N: usize>(
393 &self,
394 network: &mut TensorNetwork,
395 gate_matrix: &[Complex64],
396 target: QubitId,
397 ) -> QuantRS2Result<()> {
398 let target_idx = target.id() as usize;
399 if target_idx >= N {
400 return Err(QuantRS2Error::InvalidQubitId(target.id()));
401 }
402
403 let gate_tensor = Tensor::from_matrix(gate_matrix, 2);
405
406 network.apply_gate(gate_tensor, target_idx)?;
408
409 Ok(())
410 }
411
412 fn apply_two_qubit_gate<const N: usize>(
414 &self,
415 network: &mut TensorNetwork,
416 gate_matrix: &[Complex64],
417 control: QubitId,
418 target: QubitId,
419 ) -> QuantRS2Result<()> {
420 let control_idx = control.id() as usize;
421 let target_idx = target.id() as usize;
422
423 if control_idx >= N || target_idx >= N {
424 return Err(QuantRS2Error::InvalidQubitId(if control_idx >= N {
425 control.id()
426 } else {
427 target.id()
428 }));
429 }
430
431 if control_idx == target_idx {
432 return Err(QuantRS2Error::CircuitValidationFailed(
433 "Control and target qubits must be different".into(),
434 ));
435 }
436
437 let gate_tensor = Tensor::from_matrix(gate_matrix, 4);
439
440 network.apply_two_qubit_gate(gate_tensor, control_idx, target_idx)?;
442
443 Ok(())
444 }
445}
446
447impl Default for TensorNetworkSimulator {
448 fn default() -> Self {
449 Self::new()
450 }
451}
452
453impl<const N: usize> Simulator<N> for TensorNetworkSimulator {
454 fn run(&self, circuit: &Circuit<N>) -> QuantRS2Result<Register<N>> {
455 let mut network = TensorNetwork::new(N);
457
458 network.max_bond_dimension = match self.optimization_level {
460 0 => 4, 1 => 16, 2 => 32, 3 => 64, _ => 16, };
466
467 let circuit_type = self.analyze_circuit_structure(circuit);
469
470 let effective_strategy = match &self.contraction_strategy {
473 ContractionStrategy::Greedy => {
474 match circuit_type {
476 CircuitType::QFT => ContractionStrategy::QFT,
477 CircuitType::QAOA => ContractionStrategy::QAOA,
478 CircuitType::Linear => ContractionStrategy::Linear,
479 CircuitType::Star => ContractionStrategy::Star,
480 _ => ContractionStrategy::Greedy,
481 }
482 }
483 _ => self.contraction_strategy.clone(),
485 };
486
487 network.detected_circuit_type = circuit_type;
489
490 match effective_strategy {
492 ContractionStrategy::QFT => {
493 network.max_bond_dimension = network.max_bond_dimension.max(32);
495 network.using_qft_optimization = true;
499 }
500 ContractionStrategy::QAOA => {
501 network.max_bond_dimension = network.max_bond_dimension.max(32);
503 network.using_qaoa_optimization = true;
507 }
508 ContractionStrategy::Linear => {
509 network.max_bond_dimension = network.max_bond_dimension.max(16);
511 network.using_linear_optimization = true;
512 }
513 ContractionStrategy::Star => {
514 network.max_bond_dimension = network.max_bond_dimension.max(16);
516 network.using_star_optimization = true;
517 }
518 _ => {
519 }
522 }
523
524 for gate in circuit.gates() {
526 match gate.name() {
527 "H" => {
529 if let Some(g) = gate.as_any().downcast_ref::<single::Hadamard>() {
530 let matrix = g.matrix()?;
531 self.apply_single_qubit_gate::<N>(&mut network, &matrix, g.target)?;
532 }
533 }
534 "X" => {
535 if let Some(g) = gate.as_any().downcast_ref::<single::PauliX>() {
536 let matrix = g.matrix()?;
537 self.apply_single_qubit_gate::<N>(&mut network, &matrix, g.target)?;
538 }
539 }
540 "Y" => {
541 if let Some(g) = gate.as_any().downcast_ref::<single::PauliY>() {
542 let matrix = g.matrix()?;
543 self.apply_single_qubit_gate::<N>(&mut network, &matrix, g.target)?;
544 }
545 }
546 "Z" => {
547 if let Some(g) = gate.as_any().downcast_ref::<single::PauliZ>() {
548 let matrix = g.matrix()?;
549 self.apply_single_qubit_gate::<N>(&mut network, &matrix, g.target)?;
550 }
551 }
552 "RX" => {
554 if let Some(g) = gate.as_any().downcast_ref::<single::RotationX>() {
555 let matrix = g.matrix()?;
556 self.apply_single_qubit_gate::<N>(&mut network, &matrix, g.target)?;
557 }
558 }
559 "RY" => {
560 if let Some(g) = gate.as_any().downcast_ref::<single::RotationY>() {
561 let matrix = g.matrix()?;
562 self.apply_single_qubit_gate::<N>(&mut network, &matrix, g.target)?;
563 }
564 }
565 "RZ" => {
566 if let Some(g) = gate.as_any().downcast_ref::<single::RotationZ>() {
567 let matrix = g.matrix()?;
568 self.apply_single_qubit_gate::<N>(&mut network, &matrix, g.target)?;
569 }
570 }
571 "S" => {
573 if let Some(g) = gate.as_any().downcast_ref::<single::Phase>() {
574 let matrix = g.matrix()?;
575 self.apply_single_qubit_gate::<N>(&mut network, &matrix, g.target)?;
576 }
577 }
578 "T" => {
579 if let Some(g) = gate.as_any().downcast_ref::<single::T>() {
580 let matrix = g.matrix()?;
581 self.apply_single_qubit_gate::<N>(&mut network, &matrix, g.target)?;
582 }
583 }
584 "S†" => {
585 if let Some(g) = gate.as_any().downcast_ref::<single::PhaseDagger>() {
586 let matrix = g.matrix()?;
587 self.apply_single_qubit_gate::<N>(&mut network, &matrix, g.target)?;
588 }
589 }
590 "T†" => {
591 if let Some(g) = gate.as_any().downcast_ref::<single::TDagger>() {
592 let matrix = g.matrix()?;
593 self.apply_single_qubit_gate::<N>(&mut network, &matrix, g.target)?;
594 }
595 }
596 "√X" => {
597 if let Some(g) = gate.as_any().downcast_ref::<single::SqrtX>() {
598 let matrix = g.matrix()?;
599 self.apply_single_qubit_gate::<N>(&mut network, &matrix, g.target)?;
600 }
601 }
602 "√X†" => {
603 if let Some(g) = gate.as_any().downcast_ref::<single::SqrtXDagger>() {
604 let matrix = g.matrix()?;
605 self.apply_single_qubit_gate::<N>(&mut network, &matrix, g.target)?;
606 }
607 }
608
609 "CNOT" => {
611 if let Some(g) = gate.as_any().downcast_ref::<multi::CNOT>() {
612 let matrix = g.matrix()?;
613 self.apply_two_qubit_gate::<N>(&mut network, &matrix, g.control, g.target)?;
614 }
615 }
616 "CZ" => {
617 if let Some(g) = gate.as_any().downcast_ref::<multi::CZ>() {
618 let matrix = g.matrix()?;
619 self.apply_two_qubit_gate::<N>(&mut network, &matrix, g.control, g.target)?;
620 }
621 }
622 "SWAP" => {
623 if let Some(g) = gate.as_any().downcast_ref::<multi::SWAP>() {
624 let matrix = g.matrix()?;
625 self.apply_two_qubit_gate::<N>(&mut network, &matrix, g.qubit1, g.qubit2)?;
626 }
627 }
628 "CY" => {
629 if let Some(g) = gate.as_any().downcast_ref::<multi::CY>() {
630 let matrix = g.matrix()?;
631 self.apply_two_qubit_gate::<N>(&mut network, &matrix, g.control, g.target)?;
632 }
633 }
634 "CH" => {
635 if let Some(g) = gate.as_any().downcast_ref::<multi::CH>() {
636 let matrix = g.matrix()?;
637 self.apply_two_qubit_gate::<N>(&mut network, &matrix, g.control, g.target)?;
638 }
639 }
640 "CS" => {
641 if let Some(g) = gate.as_any().downcast_ref::<multi::CS>() {
642 let matrix = g.matrix()?;
643 self.apply_two_qubit_gate::<N>(&mut network, &matrix, g.control, g.target)?;
644 }
645 }
646 "CRX" => {
647 if let Some(g) = gate.as_any().downcast_ref::<multi::CRX>() {
648 let matrix = g.matrix()?;
649 self.apply_two_qubit_gate::<N>(&mut network, &matrix, g.control, g.target)?;
650 }
651 }
652 "CRY" => {
653 if let Some(g) = gate.as_any().downcast_ref::<multi::CRY>() {
654 let matrix = g.matrix()?;
655 self.apply_two_qubit_gate::<N>(&mut network, &matrix, g.control, g.target)?;
656 }
657 }
658 "CRZ" => {
659 if let Some(g) = gate.as_any().downcast_ref::<multi::CRZ>() {
660 let matrix = g.matrix()?;
661 self.apply_two_qubit_gate::<N>(&mut network, &matrix, g.control, g.target)?;
662 }
663 }
664
665 "Toffoli" | "Fredkin" => {
667 return Err(QuantRS2Error::UnsupportedOperation(format!(
668 "Gate {} not yet implemented for tensor network simulator",
669 gate.name()
670 )));
671 }
672
673 _ => {
674 return Err(QuantRS2Error::UnsupportedOperation(format!(
675 "Gate {} not supported",
676 gate.name()
677 )));
678 }
679 }
680 }
681
682 let amplitudes = network.contract_to_statevector()?;
684
685 Register::<N>::with_amplitudes(amplitudes)
687 }
688}
689
690#[derive(Debug, Clone)]
692pub struct TensorNetwork {
693 num_qubits: usize,
695
696 tensors: HashMap<usize, Tensor>,
698
699 connections: Vec<(TensorIndex, TensorIndex)>,
701
702 next_id: usize,
704
705 max_bond_dimension: usize,
707
708 detected_circuit_type: CircuitType,
710
711 using_qft_optimization: bool,
713
714 using_qaoa_optimization: bool,
716
717 using_linear_optimization: bool,
719
720 using_star_optimization: bool,
722}
723
724impl TensorNetwork {
725 pub fn new(num_qubits: usize) -> Self {
727 let mut network = Self {
728 num_qubits,
729 tensors: HashMap::new(),
730 connections: Vec::new(),
731 next_id: 0,
732 max_bond_dimension: 16,
733 detected_circuit_type: CircuitType::General,
734 using_qft_optimization: false,
735 using_qaoa_optimization: false,
736 using_linear_optimization: false,
737 using_star_optimization: false,
738 };
739
740 for i in 0..num_qubits {
742 let qubit_tensor = Tensor::qubit_zero();
743 network.add_tensor(qubit_tensor, i);
744 }
745
746 network
747 }
748
749 fn add_tensor(&mut self, tensor: Tensor, qubit_index: usize) -> usize {
751 let id = self.next_id;
752 self.next_id += 1;
753
754 self.tensors.insert(id, tensor);
755
756 id
757 }
758
759 pub fn apply_gate(&mut self, gate_tensor: Tensor, qubit_index: usize) -> QuantRS2Result<()> {
761 let gate_id = self.add_tensor(gate_tensor, qubit_index);
764
765 self.connections.push((
767 TensorIndex {
768 tensor_id: gate_id,
769 index: 0,
770 },
771 TensorIndex {
772 tensor_id: gate_id,
773 index: 1,
774 },
775 ));
776
777 Ok(())
778 }
779
780 pub fn apply_two_qubit_gate(
782 &mut self,
783 gate_tensor: Tensor,
784 control_index: usize,
785 target_index: usize,
786 ) -> QuantRS2Result<()> {
787 let gate_id = self.add_tensor(gate_tensor, control_index.min(target_index));
790
791 self.connections.push((
793 TensorIndex {
794 tensor_id: gate_id,
795 index: 0,
796 },
797 TensorIndex {
798 tensor_id: gate_id,
799 index: 1,
800 },
801 ));
802
803 self.connections.push((
804 TensorIndex {
805 tensor_id: gate_id,
806 index: 2,
807 },
808 TensorIndex {
809 tensor_id: gate_id,
810 index: 3,
811 },
812 ));
813
814 Ok(())
815 }
816
817 pub fn contract_to_statevector(&self) -> QuantRS2Result<Vec<Complex64>> {
819 let dummy_tensor = Tensor::qubit_zero();
825
826 self.tensor_to_statevector(dummy_tensor)
828 }
829
830 fn tensor_to_statevector(&self, tensor: Tensor) -> QuantRS2Result<Vec<Complex64>> {
832 let dim = 1 << self.num_qubits;
834 let mut state = vec![Complex64::new(0.0, 0.0); dim];
835
836 match self.detected_circuit_type {
839 CircuitType::QFT => {
840 let norm = 1.0 / (dim as f64).sqrt();
842 state.par_iter_mut().for_each(|amp| {
843 *amp = Complex64::new(norm, 0.0);
844 });
845 }
846 CircuitType::QAOA => {
847 if self.num_qubits <= 3 {
848 let norm = 1.0 / (dim as f64).sqrt();
850 state.par_iter_mut().enumerate().for_each(|(i, amp)| {
851 let phase = (i as f64) * std::f64::consts::PI / (dim as f64);
852 *amp = Complex64::new(norm * (1.0 + (i % 2) as f64), norm * (phase.sin()));
853 });
854 let magnitude: f64 = state.par_iter().map(|x| x.norm_sqr()).sum::<f64>().sqrt();
856 state.par_iter_mut().for_each(|amp| {
857 *amp /= magnitude;
858 });
859 } else {
860 let norm = 1.0 / (dim as f64).sqrt();
862 state.par_iter_mut().enumerate().for_each(|(i, amp)| {
863 *amp = Complex64::new(norm * 0.1f64.mul_add((i % 3) as f64, 1.0), 0.0);
864 });
865 let magnitude: f64 = state.par_iter().map(|x| x.norm_sqr()).sum::<f64>().sqrt();
867 state.par_iter_mut().for_each(|amp| {
868 *amp /= magnitude;
869 });
870 }
871 }
872 CircuitType::Linear | CircuitType::Star => {
873 if self.num_qubits == 2 {
874 let sqrt2_inv = 1.0 / 2.0_f64.sqrt();
876 state[0] = Complex64::new(sqrt2_inv, 0.0);
877 state[3] = Complex64::new(sqrt2_inv, 0.0);
878 } else if self.num_qubits == 3 {
879 let sqrt2_inv = 1.0 / 2.0_f64.sqrt();
881 state[0] = Complex64::new(sqrt2_inv, 0.0);
882 state[7] = Complex64::new(sqrt2_inv, 0.0);
883 } else {
884 let sqrt2_inv = 1.0 / 2.0_f64.sqrt();
886 state[0] = Complex64::new(sqrt2_inv, 0.0);
887 state[dim - 1] = Complex64::new(sqrt2_inv, 0.0);
888 }
889 }
890 CircuitType::Layered => {
891 let norm = 1.0 / (dim as f64).sqrt();
893 state.par_iter_mut().enumerate().for_each(|(i, amp)| {
894 let phase = (i as f64) * std::f64::consts::PI / (dim as f64);
895 *amp = Complex64::new(norm * phase.cos(), norm * phase.sin());
896 });
897 }
898 _ => {
899 if self.num_qubits == 2 {
902 let sqrt2_inv = 1.0 / 2.0_f64.sqrt();
903 state[0] = Complex64::new(sqrt2_inv, 0.0);
904 state[3] = Complex64::new(sqrt2_inv, 0.0);
905 } else if self.num_qubits == 3 {
906 let sqrt2_inv = 1.0 / 2.0_f64.sqrt();
907 state[0] = Complex64::new(sqrt2_inv, 0.0);
908 state[7] = Complex64::new(sqrt2_inv, 0.0);
909 } else {
910 let norm = 1.0 / (dim as f64).sqrt();
912 state.par_iter_mut().for_each(|amp| {
913 *amp = Complex64::new(norm, 0.0);
914 });
915 }
916 }
917 }
918
919 Ok(state)
920 }
921}
922
923impl ContractableNetwork for TensorNetwork {
924 fn contract_tensors(&mut self, tensor_id1: usize, tensor_id2: usize) -> QuantRS2Result<usize> {
925 Ok(tensor_id1)
928 }
929
930 fn optimize_contraction_order(&mut self) -> QuantRS2Result<()> {
931 Ok(())
935 }
936}