tnc/builders/
sycamore_circuit.rs

1//! Generating a tensor network similar to the Sycamore circuits.
2
3use 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
16/// Creates a new tensor network based on the Sycamore circuit.
17///
18/// The `depth` is the
19/// number of rounds, where one round consists of a layer of single-qubit gates
20/// followed by a layer of two-qubit gates. The start and end states are random
21/// product states.
22///
23/// For more details on the circuit, see <https://arxiv.org/abs/1910.11333>.
24pub 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    // Initialize tensornetwork of size `usize`
43    let mut circuit_tn = Tensor::default();
44    let mut next_edge = qubits;
45    let mut open_edges = FxHashMap::default();
46
47    // set up initial state
48    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            // Placing of random single qubit gate
61            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        // Placing of random single qubit gate
89        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    // set up final state
98    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        // 3 initial state, 3 final state
124        assert_eq!(rank_counts[&1], 6);
125        // 4 * 3 single qubit gates
126        assert_eq!(rank_counts[&2], 12);
127        // 1 two-qubit gate (in round C)
128        assert_eq!(rank_counts[&4], 1);
129    }
130}