1use itertools::Itertools;
2use rand::distr::Bernoulli;
3use rand::seq::IndexedRandom;
4use rand::Rng;
5use rustc_hash::FxHashMap;
6
7use crate::builders::circuit_builder::Circuit;
8use crate::builders::connectivity::{Connectivity, ConnectivityLayout};
9use crate::builders::tensorgeneration::random_sparse_tensor_data_with_rng;
10use crate::tensornetwork::tensor::Tensor;
11use crate::tensornetwork::tensordata::TensorData;
12use crate::utils::traits::WithCapacity;
13
14macro_rules! fsim {
15 ($a:expr, $b:expr, $c:expr) => {
16 $crate::tensornetwork::tensordata::TensorData::Gate((
17 String::from("fsim"),
18 vec![$a, $b],
19 $c,
20 ))
21 };
22}
23
24pub fn random_circuit<R>(
30 qubits: usize,
31 rounds: usize,
32 single_qubit_probability: f64,
33 two_qubit_probability: f64,
34 rng: &mut R,
35 connectivity: ConnectivityLayout,
36) -> Tensor
37where
38 R: Rng,
39{
40 let single_qubit_gates = [
41 TensorData::Gate((String::from("sx"), Vec::new(), false)),
42 TensorData::Gate((String::from("sy"), Vec::new(), false)),
43 TensorData::Gate((String::from("sz"), Vec::new(), false)),
44 ];
45
46 let single_qubit_die = Bernoulli::new(single_qubit_probability).unwrap();
47 let two_qubit_die = Bernoulli::new(two_qubit_probability).unwrap();
48
49 let connectivity_graph = Connectivity::new(connectivity);
51 let filtered_connectivity = connectivity_graph
52 .connectivity
53 .iter()
54 .filter(|&&(u, v)| u < qubits && v < qubits)
55 .collect_vec();
56
57 let mut circuit = Circuit::default();
59 let qr = circuit.allocate_register(qubits);
60
61 for _ in 1..rounds {
62 for i in 0..qubits {
63 if rng.sample(single_qubit_die) {
65 let gate = single_qubit_gates.choose(rng).unwrap().clone();
66 circuit.append_gate(gate, &[qr.qubit(i)]);
67 }
68 }
69 for (i, j) in &filtered_connectivity {
70 if rng.sample(two_qubit_die) {
72 let gate = fsim!(0.3, 0.2, false);
73 circuit.append_gate(gate, &[qr.qubit(*i), qr.qubit(*j)]);
74 }
75 }
76 }
77
78 circuit.into_amplitude_network(&"0".repeat(qubits)).0
80}
81
82pub fn random_circuit_with_observable<R>(
89 qubits: usize,
90 round: usize,
91 single_qubit_probability: f64,
92 two_qubit_probability: f64,
93 observable_probability: f64,
94 rng: &mut R,
95 connectivity: ConnectivityLayout,
96) -> Tensor
97where
98 R: Rng,
99{
100 let observable_locations = (0..qubits)
101 .filter(|_| rng.random_bool(observable_probability))
102 .collect_vec();
103
104 random_circuit_with_set_observable(
105 qubits,
106 round,
107 single_qubit_probability,
108 two_qubit_probability,
109 &observable_locations,
110 rng,
111 connectivity,
112 )
113}
114
115pub fn random_circuit_with_set_observable<R>(
121 qubits: usize,
122 round: usize,
123 single_qubit_probability: f64,
124 two_qubit_probability: f64,
125 observable_location: &[usize],
126 rng: &mut R,
127 connectivity: ConnectivityLayout,
128) -> Tensor
129where
130 R: Rng,
131{
132 let single_qubit_gates = [
133 (
134 TensorData::Gate((String::from("sx"), Vec::new(), false)),
135 TensorData::Gate((String::from("sx"), Vec::new(), true)),
136 ),
137 (
138 TensorData::Gate((String::from("sy"), Vec::new(), false)),
139 TensorData::Gate((String::from("sx"), Vec::new(), true)),
140 ),
141 (
142 TensorData::Gate((String::from("sz"), Vec::new(), false)),
143 TensorData::Gate((String::from("sx"), Vec::new(), true)),
144 ),
145 ];
146
147 let observables = [
148 TensorData::Gate((String::from("x"), Vec::new(), false)),
149 TensorData::Gate((String::from("y"), Vec::new(), false)),
150 TensorData::Gate((String::from("z"), Vec::new(), false)),
151 ];
152
153 let single_qubit_die = Bernoulli::new(single_qubit_probability).unwrap();
154 let two_qubit_die = Bernoulli::new(two_qubit_probability).unwrap();
155
156 let mut random_tn = Tensor::default();
158
159 let mut open_edges = FxHashMap::with_capacity(qubits);
160
161 let mut next_edge = 0;
162
163 let mut final_state = Vec::with_capacity(observable_location.len());
164 for i in 0..qubits {
165 if observable_location.contains(&i) {
167 open_edges.insert(i, (next_edge, next_edge + 1));
168 next_edge += 2;
169
170 let new_observable = observables.choose(rng).unwrap().clone();
171 let mut new_tensor =
172 Tensor::new_from_const(vec![open_edges[&i].0, open_edges[&i].1], 2);
173 new_tensor.set_tensor_data(new_observable);
174 final_state.push(new_tensor);
175 } else {
176 open_edges.insert(i, (0, 0));
178 }
179 }
180 random_tn.push_tensors(final_state);
181
182 let connectivity_graph = Connectivity::new(connectivity);
184 let filtered_connectivity = connectivity_graph
185 .connectivity
186 .iter()
187 .filter(|&&(u, v)| u < qubits && v < qubits)
188 .collect_vec();
189
190 let mut intermediate_gates = Vec::new();
191 for _ in 1..round {
192 for (i, j) in &filtered_connectivity {
194 if rng.sample(two_qubit_die)
196 && (open_edges[i].0 != open_edges[i].1 || open_edges[j].0 != open_edges[j].1)
197 {
198 let (left_i_index, right_i_index) = if open_edges[i].0 != open_edges[i].1 {
199 (open_edges[i].0, open_edges[i].1)
200 } else {
201 next_edge += 1;
202 (next_edge - 1, next_edge - 1)
203 };
204
205 let (left_j_index, right_j_index) = if open_edges[j].0 != open_edges[j].1 {
206 (open_edges[j].0, open_edges[j].1)
207 } else {
208 next_edge += 1;
209 (next_edge - 1, next_edge - 1)
210 };
211
212 let mut left_new_tensor = Tensor::new_from_const(
213 vec![next_edge, next_edge + 1, left_i_index, left_j_index],
214 2,
215 );
216 left_new_tensor.set_tensor_data(fsim!(0.3, 0.2, false));
217 intermediate_gates.push(left_new_tensor);
218
219 let mut right_new_tensor = Tensor::new_from_const(
220 vec![right_i_index, right_j_index, next_edge + 2, next_edge + 3],
221 2,
222 );
223 right_new_tensor.set_tensor_data(fsim!(0.3, 0.2, true));
224 intermediate_gates.push(right_new_tensor);
225
226 open_edges.insert(*i, (next_edge, next_edge + 2));
227 open_edges.insert(*j, (next_edge + 1, next_edge + 3));
228
229 next_edge += 4;
230 }
231 }
232
233 for i in 0..qubits {
234 let (left_index, right_index) = open_edges[&i];
236 if rng.sample(single_qubit_die) && left_index != right_index {
237 let (left_new_gate, right_new_gate) =
238 single_qubit_gates.choose(rng).unwrap().clone();
239
240 let mut left_new_tensor = Tensor::new_from_const(vec![next_edge, left_index], 2);
241 left_new_tensor.set_tensor_data(left_new_gate);
242 intermediate_gates.push(left_new_tensor);
243
244 let mut right_new_tensor =
245 Tensor::new_from_const(vec![right_index, next_edge + 1], 2);
246 right_new_tensor.set_tensor_data(right_new_gate);
247 intermediate_gates.push(right_new_tensor);
248
249 open_edges.insert(i, (next_edge, next_edge + 1));
250 next_edge += 2;
251 }
252 }
253 }
254 random_tn.push_tensors(intermediate_gates);
255
256 let mut initial_state = Vec::with_capacity(qubits);
258 for i in 0..qubits {
259 let (left_index, right_index) = open_edges[&i];
260 if left_index != right_index {
261 let random_sparse_tensor = random_sparse_tensor_data_with_rng(&[2], Some(1f32), rng);
262
263 let mut left_new_state = Tensor::new_from_const(vec![left_index], 2);
264 left_new_state.set_tensor_data(random_sparse_tensor.clone());
265 initial_state.push(left_new_state);
266
267 let mut right_new_state = Tensor::new_from_const(vec![right_index], 2);
268 right_new_state.set_tensor_data(random_sparse_tensor);
269 initial_state.push(right_new_state);
270 }
271 }
272 random_tn.push_tensors(initial_state);
273
274 random_tn
275}
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280
281 use std::iter::zip;
282
283 use rand::rng;
284
285 use crate::builders::connectivity::ConnectivityLayout;
286 use crate::tensornetwork::tensor::Tensor;
287
288 #[test]
289 fn test_random_circuit_with_observable() {
290 let size = 4;
291 let rounds = 3;
292 let single_qubit_probability = 1f64;
293 let two_qubit_probability = 1f64;
294 let observable_probability = 1f64;
295 let mut rng = rng();
297 let connectivity = ConnectivityLayout::Line(size);
298 let circuit = random_circuit_with_observable(
299 size,
300 rounds,
301 single_qubit_probability,
302 two_qubit_probability,
303 observable_probability,
304 &mut rng,
305 connectivity,
306 );
307 let ref_legs = [
308 Tensor::new_from_const(vec![0, 1], 2),
309 Tensor::new_from_const(vec![2, 3], 2),
310 Tensor::new_from_const(vec![4, 5], 2),
311 Tensor::new_from_const(vec![6, 7], 2),
312 Tensor::new_from_const(vec![8, 9, 0, 2], 2),
313 Tensor::new_from_const(vec![1, 3, 10, 11], 2),
314 Tensor::new_from_const(vec![12, 13, 9, 4], 2),
315 Tensor::new_from_const(vec![11, 5, 14, 15], 2),
316 Tensor::new_from_const(vec![16, 17, 13, 6], 2),
317 Tensor::new_from_const(vec![15, 7, 18, 19], 2),
318 Tensor::new_from_const(vec![20, 8], 2),
319 Tensor::new_from_const(vec![10, 21], 2),
320 Tensor::new_from_const(vec![22, 12], 2),
321 Tensor::new_from_const(vec![14, 23], 2),
322 Tensor::new_from_const(vec![24, 16], 2),
323 Tensor::new_from_const(vec![18, 25], 2),
324 Tensor::new_from_const(vec![26, 17], 2),
325 Tensor::new_from_const(vec![19, 27], 2),
326 Tensor::new_from_const(vec![28, 29, 20, 22], 2),
327 Tensor::new_from_const(vec![21, 23, 30, 31], 2),
328 Tensor::new_from_const(vec![32, 33, 29, 24], 2),
329 Tensor::new_from_const(vec![31, 25, 34, 35], 2),
330 Tensor::new_from_const(vec![36, 37, 33, 26], 2),
331 Tensor::new_from_const(vec![35, 27, 38, 39], 2),
332 Tensor::new_from_const(vec![40, 28], 2),
333 Tensor::new_from_const(vec![30, 41], 2),
334 Tensor::new_from_const(vec![42, 32], 2),
335 Tensor::new_from_const(vec![34, 43], 2),
336 Tensor::new_from_const(vec![44, 36], 2),
337 Tensor::new_from_const(vec![38, 45], 2),
338 Tensor::new_from_const(vec![46, 37], 2),
339 Tensor::new_from_const(vec![39, 47], 2),
340 Tensor::new_from_const(vec![40], 2),
341 Tensor::new_from_const(vec![41], 2),
342 Tensor::new_from_const(vec![42], 2),
343 Tensor::new_from_const(vec![43], 2),
344 Tensor::new_from_const(vec![44], 2),
345 Tensor::new_from_const(vec![45], 2),
346 Tensor::new_from_const(vec![46], 2),
347 Tensor::new_from_const(vec![47], 2),
348 ];
349
350 assert_eq!(circuit.tensors().len(), 40);
351 for (tensor, ref_tensor) in zip(circuit.tensors(), ref_legs) {
352 assert_eq!(tensor.legs(), ref_tensor.legs());
353 assert_eq!(tensor.bond_dims(), ref_tensor.bond_dims());
354 }
355 }
356
357 #[test]
358 fn test_random_circuit_with_set_observable() {
359 let size = 4;
360 let rounds = 3;
361 let single_qubit_probability = 1f64;
362 let two_qubit_probability = 1f64;
363 let observable_location = &[2];
364 let mut rng = rng();
366 let connectivity = ConnectivityLayout::Line(size);
367 let circuit = random_circuit_with_set_observable(
368 size,
369 rounds,
370 single_qubit_probability,
371 two_qubit_probability,
372 observable_location,
373 &mut rng,
374 connectivity,
375 );
376 let ref_legs = [
377 Tensor::new_from_const(vec![0, 1], 2),
378 Tensor::new_from_const(vec![3, 4, 2, 0], 2),
379 Tensor::new_from_const(vec![2, 1, 5, 6], 2),
380 Tensor::new_from_const(vec![8, 9, 4, 7], 2),
381 Tensor::new_from_const(vec![6, 7, 10, 11], 2),
382 Tensor::new_from_const(vec![12, 3], 2),
383 Tensor::new_from_const(vec![5, 13], 2),
384 Tensor::new_from_const(vec![14, 8], 2),
385 Tensor::new_from_const(vec![10, 15], 2),
386 Tensor::new_from_const(vec![16, 9], 2),
387 Tensor::new_from_const(vec![11, 17], 2),
388 Tensor::new_from_const(vec![19, 20, 18, 12], 2),
389 Tensor::new_from_const(vec![18, 13, 21, 22], 2),
390 Tensor::new_from_const(vec![23, 24, 20, 14], 2),
391 Tensor::new_from_const(vec![22, 15, 25, 26], 2),
392 Tensor::new_from_const(vec![27, 28, 24, 16], 2),
393 Tensor::new_from_const(vec![26, 17, 29, 30], 2),
394 Tensor::new_from_const(vec![31, 19], 2),
395 Tensor::new_from_const(vec![21, 32], 2),
396 Tensor::new_from_const(vec![33, 23], 2),
397 Tensor::new_from_const(vec![25, 34], 2),
398 Tensor::new_from_const(vec![35, 27], 2),
399 Tensor::new_from_const(vec![29, 36], 2),
400 Tensor::new_from_const(vec![37, 28], 2),
401 Tensor::new_from_const(vec![30, 38], 2),
402 Tensor::new_from_const(vec![31], 2),
403 Tensor::new_from_const(vec![32], 2),
404 Tensor::new_from_const(vec![33], 2),
405 Tensor::new_from_const(vec![34], 2),
406 Tensor::new_from_const(vec![35], 2),
407 Tensor::new_from_const(vec![36], 2),
408 Tensor::new_from_const(vec![37], 2),
409 Tensor::new_from_const(vec![38], 2),
410 ];
411
412 assert_eq!(circuit.tensors().len(), 33);
413 for (tensor, ref_tensor) in zip(circuit.tensors(), ref_legs) {
414 assert_eq!(tensor.legs(), ref_tensor.legs());
415 assert_eq!(tensor.bond_dims(), ref_tensor.bond_dims());
416 }
417 }
418}