cqlib_core/circuit/ansatz/
layers.rs1use super::traits::Ansatz;
19use crate::circuit::bit::Qubit;
20use crate::circuit::circuit_impl::Circuit;
21use crate::circuit::error::CircuitError;
22use crate::circuit::gate::StandardGate;
23use crate::circuit::{Instruction, Parameter, ParameterValue};
24
25fn validate_rotation_gate(name: &str, gate: StandardGate) -> Result<(), CircuitError> {
26 if !matches!(
27 gate,
28 StandardGate::RX | StandardGate::RY | StandardGate::RZ | StandardGate::Phase
29 ) {
30 return Err(CircuitError::InvalidOperation(format!(
31 "{name} rotation_gate must be RX, RY, RZ, or Phase, got {gate:?}"
32 )));
33 }
34 Ok(())
35}
36
37fn validate_entanglement_gate(name: &str, gate: StandardGate) -> Result<(), CircuitError> {
38 if !matches!(gate, StandardGate::CX | StandardGate::CY | StandardGate::CZ) {
39 return Err(CircuitError::InvalidOperation(format!(
40 "{name} entanglement_gate must be CX, CY, or CZ, got {gate:?}"
41 )));
42 }
43 Ok(())
44}
45
46fn parameter(prefix: &str, idx: usize) -> Result<ParameterValue, CircuitError> {
47 let param_name = format!("{prefix}_{idx}");
48 Parameter::try_from(param_name.as_str())
49 .map(ParameterValue::Param)
50 .map_err(|_| CircuitError::InvalidParameterValue(idx, f64::NAN))
51}
52
53#[derive(Debug, Clone)]
59pub struct BasicEntanglerLayers {
60 num_qubits: usize,
61 reps: usize,
62 rotation_gate: StandardGate,
63 entanglement_gate: StandardGate,
64}
65
66impl BasicEntanglerLayers {
67 pub fn new(num_qubits: usize) -> Self {
71 Self {
72 num_qubits,
73 reps: 1,
74 rotation_gate: StandardGate::RX,
75 entanglement_gate: StandardGate::CX,
76 }
77 }
78
79 pub fn reps(mut self, reps: usize) -> Self {
81 self.reps = reps;
82 self
83 }
84
85 pub fn rotation_gate(mut self, gate: StandardGate) -> Self {
87 self.rotation_gate = gate;
88 self
89 }
90
91 pub fn entanglement_gate(mut self, gate: StandardGate) -> Self {
93 self.entanglement_gate = gate;
94 self
95 }
96
97 fn entanglement_pairs(&self) -> Vec<(usize, usize)> {
98 if self.num_qubits < 2 {
99 return Vec::new();
100 }
101 let mut pairs: Vec<_> = (0..self.num_qubits - 1).map(|i| (i, i + 1)).collect();
102 if self.num_qubits > 2 {
103 pairs.push((self.num_qubits - 1, 0));
104 }
105 pairs
106 }
107}
108
109impl Ansatz for BasicEntanglerLayers {
110 fn validate(&self) -> Result<(), CircuitError> {
111 if self.num_qubits == 0 {
112 return Err(CircuitError::InvalidOperation(
113 "BasicEntanglerLayers requires at least 1 qubit".to_string(),
114 ));
115 }
116 validate_rotation_gate("BasicEntanglerLayers", self.rotation_gate)?;
117 validate_entanglement_gate("BasicEntanglerLayers", self.entanglement_gate)?;
118 Ok(())
119 }
120
121 fn build_circuit(&self, prefix: &str) -> Result<Circuit, CircuitError> {
122 self.validate()?;
123
124 let mut circuit = Circuit::new(self.num_qubits);
125 let mut param_idx = 0;
126 let pairs = self.entanglement_pairs();
127
128 for _layer in 0..self.reps {
129 for q in 0..self.num_qubits {
130 circuit.append(
131 Instruction::Standard(self.rotation_gate),
132 vec![Qubit::new(q as u32)],
133 vec![parameter(prefix, param_idx)?],
134 None,
135 )?;
136 param_idx += 1;
137 }
138 for (control, target) in &pairs {
139 circuit.append(
140 Instruction::Standard(self.entanglement_gate),
141 vec![Qubit::new(*control as u32), Qubit::new(*target as u32)],
142 vec![],
143 None,
144 )?;
145 }
146 }
147
148 Ok(circuit)
149 }
150
151 fn num_parameters(&self) -> usize {
152 self.reps * self.num_qubits
153 }
154
155 fn num_qubits(&self) -> usize {
156 self.num_qubits
157 }
158}
159
160#[derive(Debug, Clone)]
171pub struct StronglyEntanglingLayers {
172 num_qubits: usize,
173 reps: usize,
174 entanglement_gate: StandardGate,
175 ranges: Option<Vec<usize>>,
176}
177
178impl StronglyEntanglingLayers {
179 pub fn new(num_qubits: usize) -> Self {
185 Self {
186 num_qubits,
187 reps: 1,
188 entanglement_gate: StandardGate::CX,
189 ranges: None,
190 }
191 }
192
193 pub fn reps(mut self, reps: usize) -> Self {
195 self.reps = reps;
196 self
197 }
198
199 pub fn entanglement_gate(mut self, gate: StandardGate) -> Self {
205 self.entanglement_gate = gate;
206 self
207 }
208
209 pub fn ranges(mut self, ranges: Vec<usize>) -> Self {
211 self.ranges = Some(ranges);
212 self
213 }
214
215 fn range_for_layer(&self, layer: usize) -> Option<usize> {
216 if self.num_qubits < 2 {
217 return None;
218 }
219 match &self.ranges {
220 Some(ranges) => Some(ranges[layer % ranges.len()]),
221 None => Some((layer % (self.num_qubits - 1)) + 1),
222 }
223 }
224}
225
226impl Ansatz for StronglyEntanglingLayers {
227 fn validate(&self) -> Result<(), CircuitError> {
228 if self.num_qubits == 0 {
229 return Err(CircuitError::InvalidOperation(
230 "StronglyEntanglingLayers requires at least 1 qubit".to_string(),
231 ));
232 }
233 validate_entanglement_gate("StronglyEntanglingLayers", self.entanglement_gate)?;
234 if self.num_qubits > 1
235 && let Some(ranges) = &self.ranges
236 {
237 if ranges.is_empty() {
238 return Err(CircuitError::InvalidOperation(
239 "StronglyEntanglingLayers ranges must not be empty".to_string(),
240 ));
241 }
242 for &range in ranges {
243 if range == 0 || range >= self.num_qubits {
244 return Err(CircuitError::InvalidOperation(format!(
245 "StronglyEntanglingLayers range must be in 1..{}, got {}",
246 self.num_qubits, range
247 )));
248 }
249 }
250 }
251 Ok(())
252 }
253
254 fn build_circuit(&self, prefix: &str) -> Result<Circuit, CircuitError> {
255 self.validate()?;
256
257 let mut circuit = Circuit::new(self.num_qubits);
258 let mut param_idx = 0;
259
260 for layer in 0..self.reps {
261 for q in 0..self.num_qubits {
262 circuit.u(
263 Qubit::new(q as u32),
264 parameter(prefix, param_idx)?,
265 parameter(prefix, param_idx + 1)?,
266 parameter(prefix, param_idx + 2)?,
267 )?;
268 param_idx += 3;
269 }
270
271 if let Some(range) = self.range_for_layer(layer) {
272 for control in 0..self.num_qubits {
273 let target = (control + range) % self.num_qubits;
274 circuit.append(
275 Instruction::Standard(self.entanglement_gate),
276 vec![Qubit::new(control as u32), Qubit::new(target as u32)],
277 vec![],
278 None,
279 )?;
280 }
281 }
282 }
283
284 Ok(circuit)
285 }
286
287 fn num_parameters(&self) -> usize {
288 self.reps * self.num_qubits * 3
289 }
290
291 fn num_qubits(&self) -> usize {
292 self.num_qubits
293 }
294}
295
296#[cfg(test)]
297#[path = "layers_test.rs"]
298mod layers_test;