1use crate::{
7 error::{QuantRS2Error, QuantRS2Result},
8 gate::GateOp,
9 matrix_ops::{DenseMatrix, QuantumMatrix},
10 qubit::QubitId,
11 register::Register,
12};
13use ndarray::{Array, Array2, Array3, Array4, ArrayD, Axis, IxDyn};
14use num_complex::Complex;
15use rustc_hash::FxHashMap;
16use scirs2_linalg::svd;
17use std::collections::{HashMap, HashSet, VecDeque};
18
19type Complex64 = Complex<f64>;
21
22#[derive(Debug, Clone)]
24pub struct Tensor {
25 pub id: usize,
27 pub data: ArrayD<Complex64>,
29 pub indices: Vec<String>,
31 pub shape: Vec<usize>,
33}
34
35impl Tensor {
36 pub fn new(id: usize, data: ArrayD<Complex64>, indices: Vec<String>) -> Self {
38 let shape = data.shape().to_vec();
39 Self {
40 id,
41 data,
42 indices,
43 shape,
44 }
45 }
46
47 pub fn from_matrix(
49 id: usize,
50 matrix: Array2<Complex64>,
51 in_idx: String,
52 out_idx: String,
53 ) -> Self {
54 let shape = matrix.shape().to_vec();
55 let data = matrix.into_dyn();
56 Self {
57 id,
58 data,
59 indices: vec![in_idx, out_idx],
60 shape,
61 }
62 }
63
64 pub fn qubit_zero(id: usize, idx: String) -> Self {
66 let mut data = Array::zeros(IxDyn(&[2]));
67 data[[0]] = Complex64::new(1.0, 0.0);
68 Self {
69 id,
70 data,
71 indices: vec![idx],
72 shape: vec![2],
73 }
74 }
75
76 pub fn qubit_one(id: usize, idx: String) -> Self {
78 let mut data = Array::zeros(IxDyn(&[2]));
79 data[[1]] = Complex64::new(1.0, 0.0);
80 Self {
81 id,
82 data,
83 indices: vec![idx],
84 shape: vec![2],
85 }
86 }
87
88 pub fn rank(&self) -> usize {
90 self.indices.len()
91 }
92
93 pub fn contract(
95 &self,
96 other: &Tensor,
97 self_idx: &str,
98 other_idx: &str,
99 ) -> QuantRS2Result<Tensor> {
100 let self_pos = self
102 .indices
103 .iter()
104 .position(|s| s == self_idx)
105 .ok_or_else(|| {
106 QuantRS2Error::InvalidInput(format!("Index {} not found in tensor", self_idx))
107 })?;
108 let other_pos = other
109 .indices
110 .iter()
111 .position(|s| s == other_idx)
112 .ok_or_else(|| {
113 QuantRS2Error::InvalidInput(format!("Index {} not found in tensor", other_idx))
114 })?;
115
116 if self.shape[self_pos] != other.shape[other_pos] {
118 return Err(QuantRS2Error::InvalidInput(format!(
119 "Cannot contract indices with different dimensions: {} vs {}",
120 self.shape[self_pos], other.shape[other_pos]
121 )));
122 }
123
124 let contracted = self.contract_indices(&other, self_pos, other_pos)?;
126
127 let mut new_indices = Vec::new();
129 for (i, idx) in self.indices.iter().enumerate() {
130 if i != self_pos {
131 new_indices.push(idx.clone());
132 }
133 }
134 for (i, idx) in other.indices.iter().enumerate() {
135 if i != other_pos {
136 new_indices.push(idx.clone());
137 }
138 }
139
140 Ok(Tensor::new(
141 self.id.max(other.id) + 1,
142 contracted,
143 new_indices,
144 ))
145 }
146
147 fn contract_indices(
149 &self,
150 other: &Tensor,
151 self_idx: usize,
152 other_idx: usize,
153 ) -> QuantRS2Result<ArrayD<Complex64>> {
154 let self_shape = self.data.shape();
156 let other_shape = other.data.shape();
157
158 let mut self_left_dims = 1;
160 let mut self_right_dims = 1;
161 for i in 0..self_idx {
162 self_left_dims *= self_shape[i];
163 }
164 for i in (self_idx + 1)..self_shape.len() {
165 self_right_dims *= self_shape[i];
166 }
167
168 let mut other_left_dims = 1;
169 let mut other_right_dims = 1;
170 for i in 0..other_idx {
171 other_left_dims *= other_shape[i];
172 }
173 for i in (other_idx + 1)..other_shape.len() {
174 other_right_dims *= other_shape[i];
175 }
176
177 let contract_dim = self_shape[self_idx];
178
179 let self_mat = self
181 .data
182 .view()
183 .into_shape((self_left_dims, contract_dim * self_right_dims))
184 .map_err(|e| QuantRS2Error::InvalidInput(format!("Shape error: {}", e)))?
185 .to_owned();
186 let other_mat = other
187 .data
188 .view()
189 .into_shape((other_left_dims * contract_dim, other_right_dims))
190 .map_err(|e| QuantRS2Error::InvalidInput(format!("Shape error: {}", e)))?
191 .to_owned();
192
193 let result_mat: Array2<Complex64> = Array2::zeros((
195 self_left_dims * self_right_dims,
196 other_left_dims * other_right_dims,
197 ));
198
199 let mut result_vec = Vec::new();
201 for i in 0..self_left_dims {
202 for j in 0..self_right_dims {
203 for k in 0..other_left_dims {
204 for l in 0..other_right_dims {
205 let mut sum = Complex64::new(0.0, 0.0);
206 for c in 0..contract_dim {
207 let self_idx =
208 i * contract_dim * self_right_dims + c * self_right_dims + j;
209 let other_idx =
210 k * contract_dim * other_right_dims + c * other_right_dims + l;
211 sum += self_mat[[i, c * self_right_dims + j]]
212 * other_mat[[k * contract_dim + c, l]];
213 }
214 result_vec.push(sum);
215 }
216 }
217 }
218 }
219
220 let mut result_shape = Vec::new();
222 for i in 0..self_idx {
223 result_shape.push(self_shape[i]);
224 }
225 for i in (self_idx + 1)..self_shape.len() {
226 result_shape.push(self_shape[i]);
227 }
228 for i in 0..other_idx {
229 result_shape.push(other_shape[i]);
230 }
231 for i in (other_idx + 1)..other_shape.len() {
232 result_shape.push(other_shape[i]);
233 }
234
235 ArrayD::from_shape_vec(IxDyn(&result_shape), result_vec)
236 .map_err(|e| QuantRS2Error::InvalidInput(format!("Shape error: {}", e)))
237 }
238
239 pub fn svd_decompose(
241 &self,
242 idx: usize,
243 max_rank: Option<usize>,
244 ) -> QuantRS2Result<(Tensor, Tensor)> {
245 if idx >= self.rank() {
246 return Err(QuantRS2Error::InvalidInput(format!(
247 "Index {} out of bounds for tensor with rank {}",
248 idx,
249 self.rank()
250 )));
251 }
252
253 let shape = self.data.shape();
255 let mut left_dim = 1;
256 let mut right_dim = 1;
257
258 for i in 0..=idx {
259 left_dim *= shape[i];
260 }
261 for i in (idx + 1)..shape.len() {
262 right_dim *= shape[i];
263 }
264
265 let matrix = self
267 .data
268 .view()
269 .into_shape((left_dim, right_dim))
270 .map_err(|e| QuantRS2Error::InvalidInput(format!("Shape error: {}", e)))?
271 .to_owned();
272
273 let real_matrix = matrix.mapv(|c| c.re);
275 let (u, s, vt) = svd(&real_matrix.view(), false)
276 .map_err(|e| QuantRS2Error::ComputationError(format!("SVD failed: {:?}", e)))?;
277
278 let rank = if let Some(max_r) = max_rank {
280 max_r.min(s.len())
281 } else {
282 s.len()
283 };
284
285 let u_trunc = u.slice(ndarray::s![.., ..rank]).to_owned();
287 let s_trunc = s.slice(ndarray::s![..rank]).to_owned();
288 let vt_trunc = vt.slice(ndarray::s![..rank, ..]).to_owned();
289
290 let mut s_mat = Array2::zeros((rank, rank));
292 for i in 0..rank {
293 s_mat[[i, i]] = Complex64::new(s_trunc[i].sqrt(), 0.0);
294 }
295
296 let left_data = u_trunc.mapv(|x| Complex64::new(x, 0.0)).dot(&s_mat);
298 let right_data = s_mat.dot(&vt_trunc.mapv(|x| Complex64::new(x, 0.0)));
299
300 let mut left_indices = self.indices[..=idx].to_vec();
302 left_indices.push(format!("bond_{}", self.id));
303
304 let mut right_indices = vec![format!("bond_{}", self.id)];
305 right_indices.extend_from_slice(&self.indices[(idx + 1)..]);
306
307 let left_tensor = Tensor::new(self.id * 2, left_data.into_dyn(), left_indices);
308
309 let right_tensor = Tensor::new(self.id * 2 + 1, right_data.into_dyn(), right_indices);
310
311 Ok((left_tensor, right_tensor))
312 }
313}
314
315#[derive(Debug, Clone, PartialEq, Eq, Hash)]
317pub struct TensorEdge {
318 pub tensor1: usize,
320 pub index1: String,
322 pub tensor2: usize,
324 pub index2: String,
326}
327
328#[derive(Debug)]
330pub struct TensorNetwork {
331 pub tensors: HashMap<usize, Tensor>,
333 pub edges: Vec<TensorEdge>,
335 pub open_indices: HashMap<usize, Vec<String>>,
337 next_id: usize,
339}
340
341impl TensorNetwork {
342 pub fn new() -> Self {
344 Self {
345 tensors: HashMap::new(),
346 edges: Vec::new(),
347 open_indices: HashMap::new(),
348 next_id: 0,
349 }
350 }
351
352 pub fn add_tensor(&mut self, tensor: Tensor) -> usize {
354 let id = tensor.id;
355 self.open_indices.insert(id, tensor.indices.clone());
356 self.tensors.insert(id, tensor);
357 self.next_id = self.next_id.max(id + 1);
358 id
359 }
360
361 pub fn connect(
363 &mut self,
364 tensor1: usize,
365 index1: String,
366 tensor2: usize,
367 index2: String,
368 ) -> QuantRS2Result<()> {
369 if !self.tensors.contains_key(&tensor1) {
371 return Err(QuantRS2Error::InvalidInput(format!(
372 "Tensor {} not found",
373 tensor1
374 )));
375 }
376 if !self.tensors.contains_key(&tensor2) {
377 return Err(QuantRS2Error::InvalidInput(format!(
378 "Tensor {} not found",
379 tensor2
380 )));
381 }
382
383 let t1 = &self.tensors[&tensor1];
385 let t2 = &self.tensors[&tensor2];
386
387 let idx1_pos = t1
388 .indices
389 .iter()
390 .position(|s| s == &index1)
391 .ok_or_else(|| {
392 QuantRS2Error::InvalidInput(format!(
393 "Index {} not found in tensor {}",
394 index1, tensor1
395 ))
396 })?;
397 let idx2_pos = t2
398 .indices
399 .iter()
400 .position(|s| s == &index2)
401 .ok_or_else(|| {
402 QuantRS2Error::InvalidInput(format!(
403 "Index {} not found in tensor {}",
404 index2, tensor2
405 ))
406 })?;
407
408 if t1.shape[idx1_pos] != t2.shape[idx2_pos] {
409 return Err(QuantRS2Error::InvalidInput(format!(
410 "Connected indices must have same dimension: {} vs {}",
411 t1.shape[idx1_pos], t2.shape[idx2_pos]
412 )));
413 }
414
415 self.edges.push(TensorEdge {
417 tensor1,
418 index1: index1.clone(),
419 tensor2,
420 index2: index2.clone(),
421 });
422
423 if let Some(indices) = self.open_indices.get_mut(&tensor1) {
425 indices.retain(|s| s != &index1);
426 }
427 if let Some(indices) = self.open_indices.get_mut(&tensor2) {
428 indices.retain(|s| s != &index2);
429 }
430
431 Ok(())
432 }
433
434 pub fn find_contraction_order(&self) -> Vec<(usize, usize)> {
436 let mut remaining_tensors: HashSet<_> = self.tensors.keys().cloned().collect();
438 let mut order = Vec::new();
439
440 let mut adjacency: HashMap<usize, Vec<usize>> = HashMap::new();
442 for edge in &self.edges {
443 adjacency
444 .entry(edge.tensor1)
445 .or_insert_with(Vec::new)
446 .push(edge.tensor2);
447 adjacency
448 .entry(edge.tensor2)
449 .or_insert_with(Vec::new)
450 .push(edge.tensor1);
451 }
452
453 while remaining_tensors.len() > 1 {
454 let mut best_pair = None;
455 let mut min_cost = usize::MAX;
456
457 for &t1 in &remaining_tensors {
459 if let Some(neighbors) = adjacency.get(&t1) {
460 for &t2 in neighbors {
461 if t2 > t1 && remaining_tensors.contains(&t2) {
462 let cost = self.estimate_contraction_cost(t1, t2);
464 if cost < min_cost {
465 min_cost = cost;
466 best_pair = Some((t1, t2));
467 }
468 }
469 }
470 }
471 }
472
473 if let Some((t1, t2)) = best_pair {
474 order.push((t1, t2));
475 remaining_tensors.remove(&t1);
476 remaining_tensors.remove(&t2);
477
478 let virtual_id = self.next_id + order.len();
480 remaining_tensors.insert(virtual_id);
481
482 let mut virtual_neighbors = HashSet::new();
484 if let Some(n1) = adjacency.get(&t1) {
485 virtual_neighbors.extend(
486 n1.iter()
487 .filter(|&&n| n != t2 && remaining_tensors.contains(&n)),
488 );
489 }
490 if let Some(n2) = adjacency.get(&t2) {
491 virtual_neighbors.extend(
492 n2.iter()
493 .filter(|&&n| n != t1 && remaining_tensors.contains(&n)),
494 );
495 }
496 adjacency.insert(virtual_id, virtual_neighbors.into_iter().collect());
497 } else {
498 break;
499 }
500 }
501
502 order
503 }
504
505 fn estimate_contraction_cost(&self, t1: usize, t2: usize) -> usize {
507 1000 }
511
512 pub fn contract_all(&mut self) -> QuantRS2Result<Tensor> {
514 if self.tensors.is_empty() {
515 return Err(QuantRS2Error::InvalidInput(
516 "Cannot contract empty tensor network".into(),
517 ));
518 }
519
520 if self.tensors.len() == 1 {
521 return Ok(self.tensors.values().next().unwrap().clone());
522 }
523
524 let order = self.find_contraction_order();
526
527 let mut tensor_map = self.tensors.clone();
529 let mut next_id = self.next_id;
530
531 for (t1_id, t2_id) in order {
532 let edge = self
534 .edges
535 .iter()
536 .find(|e| {
537 (e.tensor1 == t1_id && e.tensor2 == t2_id)
538 || (e.tensor1 == t2_id && e.tensor2 == t1_id)
539 })
540 .ok_or_else(|| QuantRS2Error::InvalidInput("Tensors not connected".into()))?;
541
542 let t1 = tensor_map
543 .remove(&t1_id)
544 .ok_or_else(|| QuantRS2Error::InvalidInput("Tensor not found".into()))?;
545 let t2 = tensor_map
546 .remove(&t2_id)
547 .ok_or_else(|| QuantRS2Error::InvalidInput("Tensor not found".into()))?;
548
549 let contracted = if edge.tensor1 == t1_id {
551 t1.contract(&t2, &edge.index1, &edge.index2)?
552 } else {
553 t1.contract(&t2, &edge.index2, &edge.index1)?
554 };
555
556 let mut new_tensor = contracted;
558 new_tensor.id = next_id;
559 tensor_map.insert(next_id, new_tensor);
560 next_id += 1;
561 }
562
563 tensor_map
565 .into_values()
566 .next()
567 .ok_or_else(|| QuantRS2Error::InvalidInput("Contraction failed".into()))
568 }
569
570 pub fn to_mps(&self, max_bond_dim: Option<usize>) -> QuantRS2Result<Vec<Tensor>> {
572 Ok(vec![])
575 }
576
577 pub fn apply_mpo(&mut self, mpo: &[Tensor], qubits: &[usize]) -> QuantRS2Result<()> {
579 Ok(())
581 }
582}
583
584pub struct TensorNetworkBuilder {
586 network: TensorNetwork,
587 qubit_indices: HashMap<usize, String>,
588 current_indices: HashMap<usize, String>,
589}
590
591impl TensorNetworkBuilder {
592 pub fn new(num_qubits: usize) -> Self {
594 let mut network = TensorNetwork::new();
595 let mut qubit_indices = HashMap::new();
596 let mut current_indices = HashMap::new();
597
598 for i in 0..num_qubits {
600 let idx = format!("q{}_0", i);
601 let tensor = Tensor::qubit_zero(i, idx.clone());
602 network.add_tensor(tensor);
603 qubit_indices.insert(i, idx.clone());
604 current_indices.insert(i, idx);
605 }
606
607 Self {
608 network,
609 qubit_indices,
610 current_indices,
611 }
612 }
613
614 pub fn apply_single_qubit_gate(
616 &mut self,
617 gate: &dyn GateOp,
618 qubit: usize,
619 ) -> QuantRS2Result<()> {
620 let matrix_vec = gate.matrix()?;
621 let matrix = Array2::from_shape_vec((2, 2), matrix_vec)
622 .map_err(|e| QuantRS2Error::InvalidInput(format!("Shape error: {}", e)))?;
623
624 let in_idx = self.current_indices[&qubit].clone();
626 let out_idx = format!("q{}_{}", qubit, self.network.next_id);
627 let gate_tensor = Tensor::from_matrix(
628 self.network.next_id,
629 matrix,
630 in_idx.clone(),
631 out_idx.clone(),
632 );
633
634 let gate_id = self.network.add_tensor(gate_tensor);
636
637 if let Some(prev_tensor) = self.find_tensor_with_index(&in_idx) {
639 self.network
640 .connect(prev_tensor, in_idx.clone(), gate_id, in_idx)?;
641 }
642
643 self.current_indices.insert(qubit, out_idx);
645
646 Ok(())
647 }
648
649 pub fn apply_two_qubit_gate(
651 &mut self,
652 gate: &dyn GateOp,
653 qubit1: usize,
654 qubit2: usize,
655 ) -> QuantRS2Result<()> {
656 let matrix_vec = gate.matrix()?;
657 let matrix = Array2::from_shape_vec((4, 4), matrix_vec)
658 .map_err(|e| QuantRS2Error::InvalidInput(format!("Shape error: {}", e)))?;
659
660 let tensor_data = matrix
662 .into_shape((2, 2, 2, 2))
663 .map_err(|e| QuantRS2Error::InvalidInput(format!("Shape error: {}", e)))?
664 .into_dyn();
665
666 let in1_idx = self.current_indices[&qubit1].clone();
668 let in2_idx = self.current_indices[&qubit2].clone();
669 let out1_idx = format!("q{}_{}", qubit1, self.network.next_id);
670 let out2_idx = format!("q{}_{}", qubit2, self.network.next_id);
671
672 let gate_tensor = Tensor::new(
673 self.network.next_id,
674 tensor_data,
675 vec![
676 in1_idx.clone(),
677 in2_idx.clone(),
678 out1_idx.clone(),
679 out2_idx.clone(),
680 ],
681 );
682
683 let gate_id = self.network.add_tensor(gate_tensor);
685
686 if let Some(prev1) = self.find_tensor_with_index(&in1_idx) {
688 self.network
689 .connect(prev1, in1_idx.clone(), gate_id, in1_idx)?;
690 }
691 if let Some(prev2) = self.find_tensor_with_index(&in2_idx) {
692 self.network
693 .connect(prev2, in2_idx.clone(), gate_id, in2_idx)?;
694 }
695
696 self.current_indices.insert(qubit1, out1_idx);
698 self.current_indices.insert(qubit2, out2_idx);
699
700 Ok(())
701 }
702
703 fn find_tensor_with_index(&self, index: &str) -> Option<usize> {
705 for (id, tensor) in &self.network.tensors {
706 if tensor.indices.iter().any(|idx| idx == index) {
707 return Some(*id);
708 }
709 }
710 None
711 }
712
713 pub fn build(self) -> TensorNetwork {
715 self.network
716 }
717
718 pub fn to_statevector(&mut self) -> QuantRS2Result<Vec<Complex64>> {
720 let final_tensor = self.network.contract_all()?;
721 Ok(final_tensor.data.into_raw_vec())
722 }
723}
724
725pub struct TensorNetworkSimulator {
727 max_bond_dim: usize,
729 use_compression: bool,
731 parallel_threshold: usize,
733}
734
735impl TensorNetworkSimulator {
736 pub fn new() -> Self {
738 Self {
739 max_bond_dim: 64,
740 use_compression: true,
741 parallel_threshold: 1000,
742 }
743 }
744
745 pub fn with_max_bond_dim(mut self, dim: usize) -> Self {
747 self.max_bond_dim = dim;
748 self
749 }
750
751 pub fn with_compression(mut self, compress: bool) -> Self {
753 self.use_compression = compress;
754 self
755 }
756
757 pub fn simulate<const N: usize>(
759 &self,
760 gates: &[Box<dyn GateOp>],
761 ) -> QuantRS2Result<Register<N>> {
762 let mut builder = TensorNetworkBuilder::new(N);
763
764 for gate in gates {
766 let qubits = gate.qubits();
767 match qubits.len() {
768 1 => builder.apply_single_qubit_gate(gate.as_ref(), qubits[0].0 as usize)?,
769 2 => builder.apply_two_qubit_gate(
770 gate.as_ref(),
771 qubits[0].0 as usize,
772 qubits[1].0 as usize,
773 )?,
774 _ => {
775 return Err(QuantRS2Error::UnsupportedOperation(format!(
776 "Gates with {} qubits not supported in tensor network",
777 qubits.len()
778 )))
779 }
780 }
781 }
782
783 let amplitudes = builder.to_statevector()?;
785 Register::with_amplitudes(amplitudes)
786 }
787}
788
789pub mod contraction_optimization {
791 use super::*;
792
793 pub struct DynamicProgrammingOptimizer {
795 memo: HashMap<Vec<usize>, (usize, Vec<(usize, usize)>)>,
796 }
797
798 impl DynamicProgrammingOptimizer {
799 pub fn new() -> Self {
800 Self {
801 memo: HashMap::new(),
802 }
803 }
804
805 pub fn optimize(&mut self, network: &TensorNetwork) -> Vec<(usize, usize)> {
807 let tensor_ids: Vec<_> = network.tensors.keys().cloned().collect();
808 self.find_optimal_order(&tensor_ids, network).1
809 }
810
811 fn find_optimal_order(
812 &mut self,
813 tensors: &[usize],
814 network: &TensorNetwork,
815 ) -> (usize, Vec<(usize, usize)>) {
816 if tensors.len() <= 1 {
817 return (0, vec![]);
818 }
819
820 let key = tensors.to_vec();
821 if let Some(result) = self.memo.get(&key) {
822 return result.clone();
823 }
824
825 let mut best_cost = usize::MAX;
826 let mut best_order = vec![];
827
828 for i in 0..tensors.len() {
830 for j in (i + 1)..tensors.len() {
831 if self.are_connected(tensors[i], tensors[j], network) {
833 let cost = network.estimate_contraction_cost(tensors[i], tensors[j]);
834
835 let mut remaining = vec![];
837 for (k, &t) in tensors.iter().enumerate() {
838 if k != i && k != j {
839 remaining.push(t);
840 }
841 }
842 remaining.push(network.next_id + remaining.len()); let (sub_cost, sub_order) = self.find_optimal_order(&remaining, network);
845 let total_cost = cost + sub_cost;
846
847 if total_cost < best_cost {
848 best_cost = total_cost;
849 best_order = vec![(tensors[i], tensors[j])];
850 best_order.extend(sub_order);
851 }
852 }
853 }
854 }
855
856 self.memo.insert(key, (best_cost, best_order.clone()));
857 (best_cost, best_order)
858 }
859
860 fn are_connected(&self, t1: usize, t2: usize, network: &TensorNetwork) -> bool {
861 network.edges.iter().any(|e| {
862 (e.tensor1 == t1 && e.tensor2 == t2) || (e.tensor1 == t2 && e.tensor2 == t1)
863 })
864 }
865 }
866}
867
868#[cfg(test)]
869mod tests {
870 use super::*;
871
872 #[test]
873 fn test_tensor_creation() {
874 let data = ArrayD::zeros(IxDyn(&[2, 2]));
875 let tensor = Tensor::new(0, data, vec!["in".to_string(), "out".to_string()]);
876 assert_eq!(tensor.rank(), 2);
877 assert_eq!(tensor.shape, vec![2, 2]);
878 }
879
880 #[test]
881 fn test_qubit_tensors() {
882 let t0 = Tensor::qubit_zero(0, "q0".to_string());
883 assert_eq!(t0.data[[0]], Complex64::new(1.0, 0.0));
884 assert_eq!(t0.data[[1]], Complex64::new(0.0, 0.0));
885
886 let t1 = Tensor::qubit_one(1, "q1".to_string());
887 assert_eq!(t1.data[[0]], Complex64::new(0.0, 0.0));
888 assert_eq!(t1.data[[1]], Complex64::new(1.0, 0.0));
889 }
890
891 #[test]
892 fn test_tensor_network_builder() {
893 let builder = TensorNetworkBuilder::new(2);
894 assert_eq!(builder.network.tensors.len(), 2);
895 }
896
897 #[test]
898 fn test_network_connection() {
899 let mut network = TensorNetwork::new();
900
901 let t1 = Tensor::qubit_zero(0, "q0".to_string());
902 let t2 = Tensor::qubit_zero(1, "q1".to_string());
903
904 let id1 = network.add_tensor(t1);
905 let id2 = network.add_tensor(t2);
906
907 assert!(network
909 .connect(id1, "bond".to_string(), id2, "bond".to_string())
910 .is_err());
911 }
912}