1use crate::DeviceResult;
7use quantrs2_core::qubit::QubitId;
8use scirs2_core::random::prelude::*;
9use std::collections::HashMap;
10
11#[derive(Debug, Clone)]
13pub struct ParametricCircuitConfig {
14 pub num_qubits: usize,
16 pub depth: usize,
18 pub ansatz: AnsatzType,
20 pub parameter_map: HashMap<String, usize>,
22}
23
24#[derive(Debug, Clone)]
26pub enum AnsatzType {
27 HardwareEfficient,
29 QAOA,
31 RealAmplitudes,
33 Custom(String),
35}
36
37impl Default for ParametricCircuitConfig {
38 fn default() -> Self {
39 Self {
40 num_qubits: 4,
41 depth: 3,
42 ansatz: AnsatzType::HardwareEfficient,
43 parameter_map: HashMap::new(),
44 }
45 }
46}
47
48#[derive(Debug, Clone)]
50pub struct ParametricCircuit {
51 pub config: ParametricCircuitConfig,
53 pub parameters: Vec<f64>,
55 pub bounds: Vec<(f64, f64)>,
57 pub structure: CircuitStructure,
59}
60
61#[derive(Debug, Clone)]
63pub struct CircuitStructure {
64 pub gates: Vec<ParametricGate>,
66 pub connectivity: Vec<(usize, usize)>,
68 pub estimated_depth: usize,
70}
71
72#[derive(Debug, Clone)]
74pub struct ParametricGate {
75 pub gate_type: GateType,
77 pub qubits: Vec<usize>,
79 pub parameter_indices: Vec<usize>,
81 pub metadata: std::collections::HashMap<String, String>,
83}
84
85#[derive(Debug, Clone, PartialEq, Eq)]
87pub enum GateType {
88 RX,
90 RY,
92 RZ,
94 CNOT,
96 CZ,
98 H,
100 X,
102 Y,
104 Z,
106 Custom(String),
108}
109
110impl ParametricCircuit {
111 pub fn new(config: ParametricCircuitConfig) -> Self {
113 let (num_params, structure) = Self::generate_circuit_structure(&config);
114
115 Self {
116 config,
117 parameters: vec![0.0; num_params],
118 bounds: vec![(-std::f64::consts::PI, std::f64::consts::PI); num_params],
119 structure,
120 }
121 }
122
123 fn generate_circuit_structure(config: &ParametricCircuitConfig) -> (usize, CircuitStructure) {
125 match &config.ansatz {
126 AnsatzType::HardwareEfficient => Self::generate_hardware_efficient(config),
127 AnsatzType::QAOA => Self::generate_qaoa(config),
128 AnsatzType::RealAmplitudes => Self::generate_real_amplitudes(config),
129 AnsatzType::Custom(name) => Self::generate_custom(config, name),
130 }
131 }
132
133 fn generate_hardware_efficient(config: &ParametricCircuitConfig) -> (usize, CircuitStructure) {
135 let mut gates = Vec::new();
136 let mut connectivity = Vec::new();
137 let mut param_count = 0;
138
139 for layer in 0..config.depth {
140 for qubit in 0..config.num_qubits {
142 gates.push(ParametricGate {
144 gate_type: GateType::RY,
145 qubits: vec![qubit],
146 parameter_indices: vec![param_count],
147 metadata: std::iter::once(("layer".to_string(), layer.to_string())).collect(),
148 });
149 param_count += 1;
150
151 gates.push(ParametricGate {
153 gate_type: GateType::RZ,
154 qubits: vec![qubit],
155 parameter_indices: vec![param_count],
156 metadata: std::iter::once(("layer".to_string(), layer.to_string())).collect(),
157 });
158 param_count += 1;
159 }
160
161 for qubit in 0..config.num_qubits {
163 let target = (qubit + 1) % config.num_qubits;
164
165 gates.push(ParametricGate {
166 gate_type: GateType::CNOT,
167 qubits: vec![qubit, target],
168 parameter_indices: vec![], metadata: std::iter::once(("layer".to_string(), layer.to_string())).collect(),
170 });
171
172 connectivity.push((qubit, target));
173 }
174 }
175
176 let structure = CircuitStructure {
177 gates,
178 connectivity,
179 estimated_depth: config.depth * 3, };
181
182 (param_count, structure)
183 }
184
185 fn generate_qaoa(config: &ParametricCircuitConfig) -> (usize, CircuitStructure) {
187 let mut gates = Vec::new();
188 let mut connectivity = Vec::new();
189 let param_count = 2 * config.depth; for qubit in 0..config.num_qubits {
193 gates.push(ParametricGate {
194 gate_type: GateType::H,
195 qubits: vec![qubit],
196 parameter_indices: vec![],
197 metadata: std::iter::once(("layer".to_string(), "initial".to_string())).collect(),
198 });
199 }
200
201 for layer in 0..config.depth {
203 let gamma_idx = layer * 2;
204 let beta_idx = layer * 2 + 1;
205
206 for qubit in 0..config.num_qubits {
208 let neighbor = (qubit + 1) % config.num_qubits;
209
210 gates.push(ParametricGate {
212 gate_type: GateType::CNOT,
213 qubits: vec![qubit, neighbor],
214 parameter_indices: vec![],
215 metadata: [
216 ("layer".to_string(), layer.to_string()),
217 ("type".to_string(), "problem".to_string()),
218 ]
219 .into_iter()
220 .collect(),
221 });
222
223 gates.push(ParametricGate {
224 gate_type: GateType::RZ,
225 qubits: vec![neighbor],
226 parameter_indices: vec![gamma_idx],
227 metadata: [
228 ("layer".to_string(), layer.to_string()),
229 ("type".to_string(), "problem".to_string()),
230 ]
231 .into_iter()
232 .collect(),
233 });
234
235 gates.push(ParametricGate {
236 gate_type: GateType::CNOT,
237 qubits: vec![qubit, neighbor],
238 parameter_indices: vec![],
239 metadata: [
240 ("layer".to_string(), layer.to_string()),
241 ("type".to_string(), "problem".to_string()),
242 ]
243 .into_iter()
244 .collect(),
245 });
246
247 connectivity.push((qubit, neighbor));
248 }
249
250 for qubit in 0..config.num_qubits {
252 gates.push(ParametricGate {
253 gate_type: GateType::RX,
254 qubits: vec![qubit],
255 parameter_indices: vec![beta_idx],
256 metadata: [
257 ("layer".to_string(), layer.to_string()),
258 ("type".to_string(), "mixer".to_string()),
259 ]
260 .into_iter()
261 .collect(),
262 });
263 }
264 }
265
266 let structure = CircuitStructure {
267 gates,
268 connectivity,
269 estimated_depth: config.num_qubits
270 + config.depth * (3 * config.num_qubits + config.num_qubits), };
272
273 (param_count, structure)
274 }
275
276 fn generate_real_amplitudes(config: &ParametricCircuitConfig) -> (usize, CircuitStructure) {
278 let mut gates = Vec::new();
279 let mut connectivity = Vec::new();
280 let mut param_count = 0;
281
282 for layer in 0..config.depth {
283 for qubit in 0..config.num_qubits {
285 gates.push(ParametricGate {
286 gate_type: GateType::RY,
287 qubits: vec![qubit],
288 parameter_indices: vec![param_count],
289 metadata: std::iter::once(("layer".to_string(), layer.to_string())).collect(),
290 });
291 param_count += 1;
292 }
293
294 for qubit in 0..(config.num_qubits - 1) {
296 gates.push(ParametricGate {
297 gate_type: GateType::CNOT,
298 qubits: vec![qubit, qubit + 1],
299 parameter_indices: vec![],
300 metadata: std::iter::once(("layer".to_string(), layer.to_string())).collect(),
301 });
302 connectivity.push((qubit, qubit + 1));
303 }
304 }
305
306 for qubit in 0..config.num_qubits {
308 gates.push(ParametricGate {
309 gate_type: GateType::RY,
310 qubits: vec![qubit],
311 parameter_indices: vec![param_count],
312 metadata: std::iter::once(("layer".to_string(), "final".to_string())).collect(),
313 });
314 param_count += 1;
315 }
316
317 let structure = CircuitStructure {
318 gates,
319 connectivity,
320 estimated_depth: config.depth * 2 + 1, };
322
323 (param_count, structure)
324 }
325
326 const fn generate_custom(
328 _config: &ParametricCircuitConfig,
329 _name: &str,
330 ) -> (usize, CircuitStructure) {
331 let structure = CircuitStructure {
333 gates: Vec::new(),
334 connectivity: Vec::new(),
335 estimated_depth: 1,
336 };
337 (0, structure)
338 }
339
340 pub fn set_parameters(&mut self, params: Vec<f64>) -> DeviceResult<()> {
342 if params.len() != self.parameters.len() {
343 return Err(crate::DeviceError::InvalidInput(format!(
344 "Parameter count mismatch: expected {}, got {}",
345 self.parameters.len(),
346 params.len()
347 )));
348 }
349 self.parameters = params;
350 Ok(())
351 }
352
353 pub fn parameter_count(&self) -> usize {
355 self.parameters.len()
356 }
357
358 pub const fn circuit_depth(&self) -> usize {
360 self.structure.estimated_depth
361 }
362
363 pub fn required_connectivity(&self) -> &[(usize, usize)] {
365 &self.structure.connectivity
366 }
367
368 pub fn gates(&self) -> &[ParametricGate] {
370 &self.structure.gates
371 }
372
373 pub fn random_parameters(&self) -> Vec<f64> {
375 use scirs2_core::random::prelude::*;
376 let mut rng = thread_rng();
377
378 self.bounds
379 .iter()
380 .map(|(min, max)| rng.gen_range(*min..*max))
381 .collect()
382 }
383
384 pub fn set_bounds(&mut self, bounds: Vec<(f64, f64)>) -> DeviceResult<()> {
386 if bounds.len() != self.parameters.len() {
387 return Err(crate::DeviceError::InvalidInput(
388 "Bounds count mismatch".to_string(),
389 ));
390 }
391 self.bounds = bounds;
392 Ok(())
393 }
394
395 pub fn validate_parameters(&self) -> DeviceResult<()> {
397 for (i, (¶m, &(min, max))) in self.parameters.iter().zip(self.bounds.iter()).enumerate()
398 {
399 if param < min || param > max {
400 return Err(crate::DeviceError::InvalidInput(format!(
401 "Parameter {i} ({param}) out of bounds [{min}, {max}]"
402 )));
403 }
404 }
405 Ok(())
406 }
407}