tnc/builders/
sycamore_circuit.rs1use std::f64::consts::{FRAC_PI_2, FRAC_PI_6};
4
5use rand::{seq::IndexedRandom, Rng};
6use rustc_hash::FxHashMap;
7
8use crate::{
9 builders::{
10 connectivity::{sycamore_a, sycamore_b, sycamore_c, sycamore_d},
11 tensorgeneration::random_sparse_tensor_data_with_rng,
12 },
13 tensornetwork::{tensor::Tensor, tensordata::TensorData},
14};
15
16pub fn sycamore_circuit<R>(qubits: usize, depth: usize, rng: &mut R) -> Tensor
25where
26 R: Rng,
27{
28 let mut rounds = [
29 sycamore_a, sycamore_b, sycamore_c, sycamore_d, sycamore_c, sycamore_d, sycamore_a,
30 sycamore_b,
31 ]
32 .iter()
33 .cycle();
34 let single_qubit_gates = [
35 TensorData::Gate((String::from("sx"), Vec::new(), false)),
36 TensorData::Gate((String::from("sy"), Vec::new(), false)),
37 TensorData::Gate((String::from("sz"), Vec::new(), false)),
38 ];
39 let two_qubit_gate =
40 TensorData::Gate((String::from("fsim"), vec![FRAC_PI_2, FRAC_PI_6], false));
41
42 let mut circuit_tn = Tensor::default();
44 let mut next_edge = qubits;
45 let mut open_edges = FxHashMap::default();
46
47 let mut initial_state = Vec::with_capacity(qubits);
49 for i in 0..qubits {
50 let mut new_state = Tensor::new_from_const(vec![i], 2);
51 new_state.set_tensor_data(random_sparse_tensor_data_with_rng(&[2], Some(1f32), rng));
52 open_edges.insert(i, i);
53 initial_state.push(new_state);
54 }
55 circuit_tn.push_tensors(initial_state);
56
57 let mut intermediate_gates = Vec::new();
58 for _ in 0..depth {
59 for i in 0..qubits {
60 let mut new_tensor = Tensor::new_from_const(vec![open_edges[&i], next_edge], 2);
62 new_tensor.set_tensor_data(single_qubit_gates.choose(rng).unwrap().clone());
63 intermediate_gates.push(new_tensor);
64 open_edges.insert(i, next_edge);
65 next_edge += 1;
66 }
67
68 let layer = rounds.next().unwrap()();
69 for (i, j) in layer {
70 if i > qubits || j > qubits {
71 continue;
72 }
73 let i = i - 1;
74 let j = j - 1;
75 let mut new_tensor = Tensor::new_from_const(
76 vec![open_edges[&i], open_edges[&j], next_edge, next_edge + 1],
77 2,
78 );
79 new_tensor.set_tensor_data(two_qubit_gate.clone());
80 intermediate_gates.push(new_tensor);
81 open_edges.insert(i, next_edge);
82 open_edges.insert(j, next_edge + 1);
83 next_edge += 2;
84 }
85 }
86
87 for i in 0..qubits {
88 let mut new_tensor = Tensor::new_from_const(vec![open_edges[&i], next_edge], 2);
90 new_tensor.set_tensor_data(single_qubit_gates.choose(rng).unwrap().clone());
91 intermediate_gates.push(new_tensor);
92 open_edges.insert(i, next_edge);
93 next_edge += 1;
94 }
95 circuit_tn.push_tensors(intermediate_gates);
96
97 let mut final_state = Vec::with_capacity(qubits);
99 for i in 0..qubits {
100 let mut new_state = Tensor::new_from_const(vec![open_edges[&i]], 2);
101 new_state.set_tensor_data(random_sparse_tensor_data_with_rng(&[2], Some(1f32), rng));
102 final_state.push(new_state);
103 }
104 circuit_tn.push_tensors(final_state);
105
106 circuit_tn
107}
108
109#[cfg(test)]
110mod tests {
111 use itertools::Itertools;
112 use rand::{rngs::StdRng, SeedableRng};
113
114 use super::*;
115
116 #[test]
117 fn small_sycamore() {
118 let mut rng = StdRng::seed_from_u64(42);
119 let tn = sycamore_circuit(3, 3, &mut rng);
120
121 let rank_counts = tn.tensors().iter().counts_by(|t| t.legs().len());
122 assert_eq!(rank_counts.len(), 3);
123 assert_eq!(rank_counts[&1], 6);
125 assert_eq!(rank_counts[&2], 12);
127 assert_eq!(rank_counts[&4], 1);
129 }
130}