rustiq_core/structures/
clifford_circuit.rs1use rand::Rng;
2#[derive(Debug, Clone, Copy, PartialEq)]
3pub enum CliffordGate {
4 CNOT(usize, usize),
5 CZ(usize, usize),
6 H(usize),
7 S(usize),
8 Sd(usize),
9 SqrtX(usize),
10 SqrtXd(usize),
11}
12impl CliffordGate {
13 pub fn dagger(&self) -> Self {
14 match self {
15 Self::S(i) => Self::Sd(*i),
16 Self::SqrtX(i) => Self::SqrtXd(*i),
17 Self::Sd(i) => Self::S(*i),
18 Self::SqrtXd(i) => Self::SqrtX(*i),
19 _ => *self,
20 }
21 }
22 pub fn to_vec(&self) -> (String, Vec<usize>) {
23 match self {
24 CliffordGate::CNOT(i, j) => ("CNOT".to_owned(), vec![*i, *j]),
25 CliffordGate::CZ(i, j) => ("CZ".to_owned(), vec![*i, *j]),
26 CliffordGate::H(i) => ("H".to_owned(), vec![*i]),
27 CliffordGate::S(i) => ("S".to_owned(), vec![*i]),
28 CliffordGate::Sd(i) => ("Sd".to_owned(), vec![*i]),
29 CliffordGate::SqrtX(i) => ("SqrtX".to_owned(), vec![*i]),
30 CliffordGate::SqrtXd(i) => ("SqrtXd".to_owned(), vec![*i]),
31 }
32 }
33 pub fn from_vec(gate: &str, qbits: &[usize]) -> Self {
34 match gate {
35 "H" => Self::H(qbits[0]),
36 "S" => Self::S(qbits[0]),
37 "Sd" => Self::Sd(qbits[0]),
38 "SqrtX" => Self::SqrtX(qbits[0]),
39 "SqrtXd" => Self::SqrtXd(qbits[0]),
40 "CX" => Self::CNOT(qbits[0], qbits[1]),
41 "CNOT" => Self::CNOT(qbits[0], qbits[1]),
42 "CZ" => Self::CZ(qbits[0], qbits[1]),
43 _ => panic!("Unknown gate {}", gate),
44 }
45 }
46 pub fn arity(&self) -> usize {
47 match self {
48 CliffordGate::CNOT(_, _) => 2,
49 CliffordGate::CZ(_, _) => 2,
50 _ => 1,
51 }
52 }
53}
54#[derive(Debug, Clone)]
55pub struct CliffordCircuit {
56 pub nqbits: usize,
57 pub gates: Vec<CliffordGate>,
58}
59
60impl CliffordCircuit {
61 pub fn new(nqbits: usize) -> Self {
62 Self {
63 nqbits,
64 gates: Vec::new(),
65 }
66 }
67 pub fn from_vec(gates: Vec<(String, Vec<usize>)>) -> Self {
68 let mut nqbits = 0;
69 for (_, qbits) in gates.iter() {
70 for qbit in qbits {
71 if qbit + 1 > nqbits {
72 nqbits = qbit + 1;
73 }
74 }
75 }
76 Self {
77 nqbits,
78 gates: gates
79 .iter()
80 .map(|(gate, qbits)| CliffordGate::from_vec(gate, qbits))
81 .collect(),
82 }
83 }
84
85 pub fn random(nqubits: usize, ngates: usize) -> Self {
86 let mut rng = rand::thread_rng();
87 let mut circuit = Self::new(nqubits);
88 for _ in 0..ngates {
89 if rng.gen_bool(0.5) {
90 let i = rng.gen_range(0..nqubits);
92 let mut j = rng.gen_range(0..nqubits);
93 while j == i {
94 j = rng.gen_range(0..nqubits);
95 }
96 circuit.gates.push(CliffordGate::CNOT(i, j));
97 continue;
98 }
99 if rng.gen_bool(0.5) {
100 let i = rng.gen_range(0..nqubits);
102 circuit.gates.push(CliffordGate::H(i));
103 continue;
104 }
105 let i = rng.gen_range(0..nqubits);
106 circuit.gates.push(CliffordGate::S(i));
107 }
108 circuit
109 }
110
111 pub fn extend_with(&mut self, other: &CliffordCircuit) {
112 self.gates.extend_from_slice(&other.gates);
113 }
114 pub fn cnot_count(&self) -> usize {
116 self.gates
117 .iter()
118 .filter(|gate| matches!(gate, CliffordGate::CNOT(_, _)))
119 .count()
120 }
121 pub fn entangling_count(&self) -> usize {
123 self.gates
124 .iter()
125 .filter(|gate| matches!(gate, CliffordGate::CNOT(_, _) | CliffordGate::CZ(_, _)))
126 .count()
127 }
128 pub fn cnot_depth(&self) -> usize {
130 let mut depths: Vec<usize> = vec![0; self.nqbits];
131 for gate in self.gates.iter() {
132 if let CliffordGate::CNOT(i, j) = gate {
133 let gate_depth = std::cmp::max(depths[*i], depths[*j]) + 1;
134 depths[*i] = gate_depth;
135 depths[*j] = gate_depth;
136 }
137 }
138 *depths.iter().max().unwrap()
139 }
140 pub fn entangling_depth(&self) -> usize {
142 let mut depths: Vec<usize> = vec![0; self.nqbits];
143 for gate in self.gates.iter() {
144 match gate {
145 CliffordGate::CNOT(i, j) => {
146 let gate_depth = std::cmp::max(depths[*i], depths[*j]) + 1;
147 depths[*i] = gate_depth;
148 depths[*j] = gate_depth;
149 }
150 CliffordGate::CZ(i, j) => {
151 let gate_depth = std::cmp::max(depths[*i], depths[*j]) + 1;
152 depths[*i] = gate_depth;
153 depths[*j] = gate_depth;
154 }
155 _ => {}
156 }
157 }
158 *depths.iter().max().unwrap()
159 }
160 pub fn dagger(&self) -> Self {
162 let new_gates = self.gates.iter().rev().map(|gate| gate.dagger()).collect();
163 Self {
164 nqbits: self.nqbits,
165 gates: new_gates,
166 }
167 }
168}