1use std::marker::PhantomData;
4
5use itertools::Itertools;
6use num_complex::Complex64;
7use permutation::Permutation;
8
9use crate::{
10 tensornetwork::{
11 tensor::{EdgeIndex, Tensor},
12 tensordata::TensorData,
13 },
14 utils::traits::PermutationToVec,
15};
16
17#[derive(Debug)]
21pub struct QuantumRegister<'a> {
22 base: usize,
23 size: usize,
24 phantom: PhantomData<&'a Circuit>,
25}
26
27impl QuantumRegister<'_> {
28 #[cfg(test)]
31 pub(crate) fn new(size: usize) -> Self {
32 QuantumRegister {
33 base: 0,
34 size,
35 phantom: PhantomData,
36 }
37 }
38
39 pub fn qubit(&self, index: usize) -> Qubit<'_> {
41 assert!(index < self.size);
42 Qubit {
43 index: self.base + index,
44 phantom: PhantomData,
45 }
46 }
47
48 pub fn qubits(&self) -> impl Iterator<Item = Qubit<'_>> {
50 (self.base..self.base + self.size).map(|i| Qubit {
51 index: i,
52 phantom: PhantomData,
53 })
54 }
55
56 #[inline]
58 pub fn len(&self) -> usize {
59 self.size
60 }
61
62 #[inline]
64 pub fn is_empty(&self) -> bool {
65 self.size == 0
66 }
67}
68
69pub struct Qubit<'a> {
71 index: usize,
72 phantom: PhantomData<&'a Circuit>,
73}
74
75#[derive(Debug, Clone)]
77pub struct Permutor {
78 target_leg_order: Vec<EdgeIndex>,
79}
80
81impl Permutor {
82 fn new(target_legs: Vec<EdgeIndex>) -> Self {
83 Self {
84 target_leg_order: target_legs,
85 }
86 }
87
88 pub fn apply(&self, tensor: Tensor) -> Tensor {
90 assert!(tensor.is_leaf());
91 if self.is_identity() {
92 return tensor;
93 }
94
95 let Tensor {
96 mut legs,
97 mut bond_dims,
98 tensordata,
99 ..
100 } = tensor;
101 let mut data = tensordata.into_data();
102
103 let mut perm = Self::permutation_between(&legs, &self.target_leg_order);
105
106 perm.apply_slice_in_place(&mut legs);
108 perm.apply_slice_in_place(&mut bond_dims);
109 data = data.permuted_axes(perm.to_vec());
110
111 Tensor {
112 tensors: vec![],
113 legs,
114 bond_dims,
115 tensordata: TensorData::Matrix(data),
116 }
117 }
118
119 #[inline]
122 pub fn is_identity(&self) -> bool {
123 self.target_leg_order.is_empty()
124 }
125
126 fn permutation_between(given: &[usize], target: &[usize]) -> Permutation {
129 let given_to_sorted = permutation::sort_unstable(given);
130 let target_to_sorted = permutation::sort_unstable(target);
131 &target_to_sorted.inverse() * &given_to_sorted
132 }
133}
134
135#[derive(Debug, Default)]
138pub struct Circuit {
139 open_edges: Vec<EdgeIndex>,
141 next_edge: usize,
143 tensors: Vec<Tensor>,
145}
146
147impl Circuit {
148 fn ket0() -> TensorData {
150 TensorData::new_from_data(&[2], vec![Complex64::ONE, Complex64::ZERO])
151 }
152
153 fn ket1() -> TensorData {
155 TensorData::new_from_data(&[2], vec![Complex64::ZERO, Complex64::ONE])
156 }
157
158 fn z() -> TensorData {
160 TensorData::Gate((String::from("z"), vec![], false))
161 }
162
163 fn new_edge(&mut self) -> usize {
165 let edge = self.next_edge;
166 self.next_edge += 1;
167 edge
168 }
169
170 #[inline]
181 pub fn num_qubits(&self) -> usize {
182 self.open_edges.len()
183 }
184
185 pub fn allocate_register<'a>(&mut self, size: usize) -> QuantumRegister<'a> {
188 let previous_qubits = self.num_qubits();
189
190 self.open_edges.reserve(size);
191 self.tensors.reserve(size);
192 for _ in 0..size {
193 let edge = self.new_edge();
194 self.open_edges.push(edge);
195 let mut ket0 = Tensor::new_from_const(vec![edge], 2);
196 ket0.set_tensor_data(Self::ket0());
197 self.tensors.push(ket0);
198 }
199
200 QuantumRegister {
201 base: previous_qubits,
202 size,
203 phantom: PhantomData,
204 }
205 }
206
207 pub fn append_gate(&mut self, gate: TensorData, indices: &[Qubit]) {
209 assert!(
210 indices.iter().map(|q| q.index).all_unique(),
211 "Qubit arguments must be unique"
212 );
213
214 let old_edges = indices.iter().map(|q| self.open_edges[q.index]);
216 let new_edges = (0..indices.len()).map(|e| e + self.next_edge);
217 let edges = new_edges.chain(old_edges).collect_vec();
218 self.next_edge += indices.len();
219
220 for (q, next_edge) in indices.iter().zip(&edges[..indices.len()]) {
222 self.open_edges[q.index] = *next_edge;
223 }
224
225 let mut new_tensor = Tensor::new_from_const(edges, 2);
227 new_tensor.set_tensor_data(gate);
228
229 self.tensors.push(new_tensor);
231 }
232
233 pub fn into_amplitude_network(mut self, bitstring: &str) -> (Tensor, Permutor) {
247 assert_eq!(bitstring.len(), self.num_qubits());
248
249 self.tensors.reserve(bitstring.len());
251 let mut final_legs = Vec::new();
252 for (c, e) in bitstring.chars().zip(self.open_edges) {
253 let bra = match c {
254 '0' => Self::ket0(),
255 '1' => Self::ket1(),
256 '*' => {
257 final_legs.push(e);
258 continue; }
260 _ => panic!("Only 0, 1 and * are allowed in bitstring"),
261 };
262 let mut tensor = Tensor::new_from_const(vec![e], 2);
263 tensor.set_tensor_data(bra);
264 self.tensors.push(tensor);
265 }
266
267 let out = Tensor::new_composite(self.tensors);
272 let permutor = Permutor::new(final_legs);
273 (out, permutor)
274 }
275
276 #[inline]
282 pub fn into_statevector_network(self) -> (Tensor, Permutor) {
283 let qubits = self.num_qubits();
284 self.into_amplitude_network(&"*".repeat(qubits))
285 }
286
287 fn tensor_adjoint(tensor: &Tensor, leg_offset: usize) -> Tensor {
291 let half = tensor.legs().len() / 2;
293 let legs = tensor.legs()[half..]
294 .iter()
295 .chain(&tensor.legs()[..half])
296 .map(|l| l + leg_offset)
297 .collect();
298 let bond_dims = tensor.bond_dims()[half..]
299 .iter()
300 .chain(&tensor.bond_dims()[..half])
301 .copied()
302 .collect();
303
304 let data = tensor.tensor_data().clone();
306 let data = data.adjoint();
307
308 let mut adjoint = Tensor::new(legs, bond_dims);
309 adjoint.set_tensor_data(data);
310 adjoint
311 }
312
313 pub fn into_expectation_value_network(mut self) -> Tensor {
319 let offset = self.next_edge;
320 self.tensors.reserve(self.tensors.len() + self.num_qubits());
321
322 let mut adjoint_tensors = Vec::with_capacity(self.tensors.len());
324 for tensor in &self.tensors {
325 let adjoint = Self::tensor_adjoint(tensor, offset);
326 adjoint_tensors.push(adjoint);
327 }
328 self.tensors.append(&mut adjoint_tensors);
329
330 for e in self.open_edges {
332 let mut t = Tensor::new_from_const(vec![e, e + offset], 2);
333 t.set_tensor_data(Self::z());
334 self.tensors.push(t);
335 }
336
337 Tensor::new_composite(self.tensors)
338 }
339}
340
341#[cfg(test)]
342mod tests {
343 use super::*;
344
345 use std::f64::consts::{FRAC_1_SQRT_2, FRAC_PI_3, FRAC_PI_4};
346
347 use approx::assert_abs_diff_eq;
348 use num_complex::Complex64;
349
350 use crate::{
351 contractionpath::paths::{
352 cotengrust::{Cotengrust, OptMethod},
353 FindPath,
354 },
355 path,
356 tensornetwork::{
357 contraction::contract_tensor_network, tensor::Tensor, tensordata::TensorData,
358 },
359 };
360
361 fn test_permutation_between(given: &[usize], target: &[usize]) {
362 let perm = Permutor::permutation_between(given, target);
363 assert_eq!(perm.apply_slice(given), target);
364 }
365
366 #[test]
367 fn permutation_between() {
368 test_permutation_between(&[1, 2, 3, 4], &[1, 2, 3, 4]);
369 test_permutation_between(&[1, 2, 3, 4], &[4, 3, 2, 1]);
370 test_permutation_between(&[4, 3, 2, 1], &[1, 2, 3, 4]);
371 test_permutation_between(&[4, 1, 3, 2], &[2, 4, 3, 1]);
372 test_permutation_between(&[5, 1, 4, 3, 2, 6], &[1, 6, 3, 5, 2, 4]);
373 }
374
375 #[test]
376 fn hadamards_amplitude() {
377 let qubits = 5;
378 let mut circuit = Circuit::default();
379 let qr = circuit.allocate_register(qubits);
380 for q in qr.qubits() {
381 circuit.append_gate(TensorData::Gate((String::from("h"), vec![], false)), &[q]);
382 }
383 let (tensor_network, permutor) = circuit.into_amplitude_network("00000");
384 assert!(permutor.is_identity());
385
386 let mut opt = Cotengrust::new(&tensor_network, OptMethod::Greedy);
387 opt.find_path();
388 let path = opt.get_best_replace_path();
389
390 let result = contract_tensor_network(tensor_network, &path);
391
392 let mut tn_ref = Tensor::default();
393 tn_ref.set_tensor_data(TensorData::new_from_data(
394 &[],
395 vec![Complex64::new(FRAC_1_SQRT_2.powi(qubits as i32), 0.0)],
396 ));
397
398 assert_abs_diff_eq!(&result, &tn_ref);
399 }
400
401 #[test]
402 fn rx_expectation_value() {
403 let qubits = 2;
404 let mut circuit = Circuit::default();
405 let qr = circuit.allocate_register(qubits);
406 circuit.append_gate(
407 TensorData::Gate((String::from("rx"), vec![FRAC_PI_4], false)),
408 &[qr.qubit(0)],
409 );
410 circuit.append_gate(
411 TensorData::Gate((String::from("rx"), vec![FRAC_PI_3], false)),
412 &[qr.qubit(1)],
413 );
414 let tensor_network = circuit.into_expectation_value_network();
415
416 let mut opt = Cotengrust::new(&tensor_network, OptMethod::Greedy);
417 opt.find_path();
418 let path = opt.get_best_replace_path();
419
420 let result = contract_tensor_network(tensor_network, &path);
421
422 let mut tn_ref = Tensor::default();
423 tn_ref.set_tensor_data(TensorData::new_from_data(
424 &[],
425 vec![Complex64::new(FRAC_1_SQRT_2 * 0.5, 0.0)],
426 ));
427
428 assert_abs_diff_eq!(&result, &tn_ref);
429 }
430
431 #[test]
432 #[should_panic(expected = "Qubit arguments must be unique")]
433 fn duplicate_qubit_arg() {
434 let mut circuit = Circuit::default();
435 let qr = circuit.allocate_register(2);
436 circuit.append_gate(
437 TensorData::Gate((String::from("cx"), vec![], true)),
438 &[qr.qubit(1), qr.qubit(1)],
439 );
440 }
441
442 #[test]
443 fn dimension_order() {
444 let mut circuit = Circuit::default();
445 let qr = circuit.allocate_register(1);
446 circuit.append_gate(
447 TensorData::new_from_data(
448 &[2, 2],
449 vec![
450 Complex64::new(1.0, 0.0),
451 Complex64::new(2.0, 0.0),
452 Complex64::new(3.0, 0.0),
453 Complex64::new(4.0, 0.0),
454 ],
455 ),
456 &[qr.qubit(0)],
457 );
458 let (tensor_network, permutor) = circuit.into_statevector_network();
459 let result = contract_tensor_network(tensor_network, &path![(0, 1)]);
460 let result = permutor.apply(result);
461 let mut tn_ref = Tensor::new_from_const(vec![1], 2);
462 tn_ref.set_tensor_data(TensorData::new_from_data(
463 &[2],
464 vec![Complex64::new(1.0, 0.0), Complex64::new(3.0, 0.0)],
465 ));
466 assert_abs_diff_eq!(&result, &tn_ref);
467 }
468
469 #[test]
470 fn permute() {
471 let mut tensor = Tensor::new_from_const(vec![0, 1, 2], 2);
472 let data = (0..8).map(|i| Complex64::new(i as f64, 0.0)).collect();
473 tensor.set_tensor_data(TensorData::new_from_data(&[2, 2, 2], data));
474
475 let permutor = Permutor::new(vec![2, 0, 1]);
476 let permuted = permutor.apply(tensor);
477
478 let ref_data = [0, 2, 4, 6, 1, 3, 5, 7]
479 .into_iter()
480 .map(|i| Complex64::new(i as f64, 0.0))
481 .collect();
482 let mut expected = Tensor::new_from_const(vec![2, 0, 1], 2);
483 expected.set_tensor_data(TensorData::new_from_data(&[2, 2, 2], ref_data));
484
485 assert_abs_diff_eq!(&permuted, &expected);
486 }
487}