quant_iron/circuit.rs
1use crate::{
2 compiler::{compilable::CompilableCircuit, qasm::QasmCircuit},
3 components::{
4 gate::Gate,
5 measurement::MeasurementBasis,
6 operator::Operator,
7 parametric::{
8 parameter::Parameter,
9 parametric_gate::{
10 ParametricMatchgate, ParametricP, ParametricRx, ParametricRy, ParametricRz,
11 ParametricRyPhase,
12 },
13 },
14 state::State,
15 },
16 errors::{CompilerError, Error},
17 subroutine::Subroutine,
18};
19
20use std::fs;
21use std::io::Write;
22use std::path::Path;
23
24use num_complex::Complex;
25
26/// Represents a quantum circuit as a vector of gates.
27///
28/// # Fields
29///
30/// * `gates` - A vector of gates in the circuit.
31/// * `num_qubits` - The number of qubits in the circuit.
32#[derive(Debug)]
33pub struct Circuit {
34 /// A vector of gates in the circuit.
35 pub gates: Vec<Gate>,
36 /// The number of qubits in the circuit.
37 pub num_qubits: usize,
38}
39
40impl Circuit {
41 // Helper function to validate gate qubits
42 fn _validate_gate_qubits(gate: &Gate, circuit_num_qubits: usize) -> Result<(), Error> {
43 // Check if the gate's target qubits are within the circuit's qubit range
44 for &qubit in gate.get_target_qubits() {
45 if qubit >= circuit_num_qubits {
46 return Err(Error::InvalidQubitIndex(qubit, circuit_num_qubits));
47 }
48 }
49
50 // Check if the gate's control qubits are within the circuit's qubit range
51 if let Some(control_qubits) = gate.get_control_qubits() {
52 for &qubit in control_qubits {
53 if qubit >= circuit_num_qubits {
54 return Err(Error::InvalidQubitIndex(qubit, circuit_num_qubits));
55 }
56 }
57 }
58 Ok(())
59 }
60
61 /// Creates a new circuit with the specified number of qubits.
62 ///
63 /// # Arguments
64 ///
65 /// * `num_qubits` - The number of qubits in the circuit.
66 ///
67 /// # Returns
68 ///
69 /// * `Circuit` - A new instance of the Circuit struct.
70 pub fn new(num_qubits: usize) -> Self {
71 Circuit {
72 gates: Vec::new(),
73 num_qubits,
74 }
75 }
76
77 /// Creates a new circuit with the specified gates and number of qubits.
78 ///
79 /// # Arguments
80 ///
81 /// * `gates` - A vector of gates in the circuit.
82 /// * `num_qubits` - The number of qubits in the circuit.
83 ///
84 /// # Returns
85 ///
86 /// * `Result<Circuit, Error>` - A new instance of the Circuit struct or an error if the circuit cannot be created.
87 pub fn with_gates(gates: Vec<Gate>, num_qubits: usize) -> Result<Circuit, Error> {
88 for gate in &gates {
89 Self::_validate_gate_qubits(gate, num_qubits)?;
90 }
91
92 Ok(Circuit { gates, num_qubits })
93 }
94
95 /// Adds a gate to the circuit.
96 ///
97 /// # Arguments
98 ///
99 /// * `gate` - The gate to be added to the circuit.
100 ///
101 /// # Returns
102 ///
103 /// * `Result<(), Error>` - An empty result if the gate is added successfully, or an error if the gate cannot be added.
104 pub fn add_gate(&mut self, gate: Gate) -> Result<(), Error> {
105 Self::_validate_gate_qubits(&gate, self.num_qubits)?;
106 self.gates.push(gate);
107 Ok(())
108 }
109
110 /// Adds multiple gates to the circuit.
111 ///
112 /// # Arguments
113 ///
114 /// * `gates` - A vector of gates to be added to the circuit.
115 ///
116 /// # Returns
117 ///
118 /// * `Result<(), Error>` - An empty result if the gates are added successfully, or an error if any gate cannot be added.
119 pub fn add_gates(&mut self, gates: Vec<Gate>) -> Result<(), Error> {
120 for gate in &gates {
121 Self::_validate_gate_qubits(gate, self.num_qubits)?;
122 }
123 self.gates.extend(gates);
124 Ok(())
125 }
126
127 /// Gets the number of qubits in the circuit.
128 ///
129 /// # Returns
130 ///
131 /// * `usize` - The number of qubits in the circuit.
132 pub fn get_num_qubits(&self) -> usize {
133 self.num_qubits
134 }
135
136 /// Gets the gates in the circuit.
137 ///
138 /// # Returns
139 ///
140 /// * `&Vec<Gate>` - A reference to the vector of gates in the circuit.
141 pub fn get_gates(&self) -> &Vec<Gate> {
142 &self.gates
143 }
144
145 /// Executes the circuit with the given initial state, and returns the final state.
146 ///
147 /// # Arguments
148 ///
149 /// * `initial_state` - The initial state of the qubits in the circuit.
150 ///
151 /// # Returns
152 ///
153 /// * `Result<State, Error>` - The final state of the qubits after executing the circuit.
154 ///
155 /// # Errors
156 ///
157 /// * Returns an error if the number of qubits in the initial state does not match the number of qubits in the circuit.
158 /// * Returns an error if the circuit cannot be executed due to invalid gate operations.
159 pub fn execute(&self, initial_state: &State) -> Result<State, Error> {
160 if initial_state.num_qubits() != self.num_qubits {
161 return Err(Error::InvalidNumberOfQubits(initial_state.num_qubits()));
162 }
163
164 let mut current_state = initial_state.clone();
165
166 for gate in &self.gates {
167 current_state = gate.apply(¤t_state)?;
168 }
169
170 Ok(current_state)
171 }
172
173 /// Executes the circuit with the given initial state, and returns all the intermediate states and the final state.
174 ///
175 /// # Arguments
176 ///
177 /// * `initial_state` - The initial state of the qubits in the circuit.
178 ///
179 /// # Returns
180 ///
181 /// * `Result<Vec<State>, Error>` - A vector of intermediate states and the final state after executing the circuit.
182 ///
183 /// # Errors
184 ///
185 /// * Returns an error if the number of qubits in the initial state does not match the number of qubits in the circuit.
186 /// * Returns an error if the circuit cannot be executed due to invalid gate operations.
187 pub fn trace_execution(&self, initial_state: &State) -> Result<Vec<State>, Error> {
188 if initial_state.num_qubits() != self.num_qubits {
189 return Err(Error::InvalidNumberOfQubits(initial_state.num_qubits()));
190 }
191
192 let mut current_state = initial_state.clone();
193 let mut states = vec![current_state.clone()];
194
195 for gate in &self.gates {
196 current_state = gate.apply(¤t_state)?;
197 states.push(current_state.clone());
198 }
199
200 Ok(states)
201 }
202
203 /// Converts a parametric circuit into a circuit with concrete gates.
204 pub(crate) fn to_concrete_circuit(&self) -> Self {
205 let concrete_gates = self.gates.iter().flat_map(|g| {
206 match g {
207 Gate::Parametric(p_gate, targets, controls) => {
208 p_gate.to_concrete_gates(targets, controls)
209 }
210 _ => vec![g.clone()],
211 }
212 }).collect();
213
214 Circuit {
215 gates: concrete_gates,
216 num_qubits: self.num_qubits,
217 }
218 }
219
220 /// Converts the circuit to its internal QASM circuit if the circuit is compilable, and return an error if it is not, or if the conversion fails.
221 pub(crate) fn to_qasm_circuit(&self) -> Result<QasmCircuit, CompilerError> {
222 let concrete_circuit = self.to_concrete_circuit();
223 let compilable_circuit = CompilableCircuit::try_from(&concrete_circuit)?;
224 let qasm_instructions =
225 compilable_circuit
226 .to_ir()
227 .iter()
228 .try_fold(Vec::new(), |mut acc, instr| {
229 acc.extend(instr.to_qasm()?);
230 Ok(acc)
231 })?;
232
233 Ok(QasmCircuit::new(
234 qasm_instructions,
235 compilable_circuit.num_qubits,
236 ))
237 }
238
239 /// Converts the circuit to its OpenQASM 3.0 (Quantum Assembly 3.0) representation.
240 pub fn to_qasm(&self, to_dir: Option<impl AsRef<Path>>) -> Result<String, CompilerError> {
241 let qasm_circuit: QasmCircuit = self.to_qasm_circuit()?;
242 let qasm_string = qasm_circuit.to_qasm_string();
243
244 if let Some(path) = to_dir {
245 let dir_path = path.as_ref();
246
247 if !dir_path.is_dir() {
248 return Err(CompilerError::IOError(format!(
249 "Provided path is not a directory: {}",
250 dir_path.display()
251 )));
252 }
253
254 let output_path = dir_path.join("circuit.qasm");
255
256 let mut file = fs::File::create(&output_path).map_err(|e| {
257 CompilerError::IOError(format!(
258 "Error creating file '{}': {}",
259 output_path.display(),
260 e
261 ))
262 })?;
263
264 file.write_all(qasm_string.as_bytes()).map_err(|e| {
265 CompilerError::IOError(format!(
266 "Error writing to file '{}': {}",
267 output_path.display(),
268 e
269 ))
270 })?;
271 }
272
273 Ok(qasm_string)
274 }
275}
276
277/// A builder for creating a quantum circuit.
278///
279/// # Fields
280///
281/// * `gates` - A vector of gates in the circuit.
282///
283/// * `num_qubits` - The number of qubits in the circuit.
284pub struct CircuitBuilder {
285 /// A vector of gates in the circuit builder.
286 /// A temporary vector to hold gates before building the circuit.
287 pub gates: Vec<Gate>,
288 /// The number of qubits in the circuit builder.
289 pub num_qubits: usize,
290}
291
292impl CircuitBuilder {
293 /// Creates a new circuit builder with the specified number of qubits.
294 ///
295 /// # Arguments
296 ///
297 /// * `num_qubits` - The number of qubits in the circuit builder.
298 ///
299 /// # Returns
300 ///
301 /// * `CircuitBuilder` - A new instance of the CircuitBuilder struct.
302 pub fn new(num_qubits: usize) -> Self {
303 CircuitBuilder {
304 gates: Vec::new(),
305 num_qubits,
306 }
307 }
308
309 /// Adds a gate to the circuit builder.
310 ///
311 /// # Arguments
312 ///
313 /// * `gate` - The gate to be added to the circuit builder.
314 pub fn add_gate(&mut self, gate: Gate) -> &mut Self {
315 self.gates.push(gate);
316 self
317 }
318
319 /// Adds multiple gates to the circuit builder.
320 ///
321 /// # Arguments
322 ///
323 /// * `gates` - A vector of gates to be added to the circuit builder.
324 pub fn add_gates(&mut self, gates: Vec<Gate>) -> &mut Self {
325 self.gates.extend(gates);
326 self
327 }
328
329 /// Builds the circuit from the gates in the circuit builder.
330 /// The builder's internal gate list is not cleared, allowing the builder to be reused.
331 /// If this is the final circuit, use `build_final` instead.
332 ///
333 /// # Returns
334 ///
335 /// * `Result<Circuit, Error>` - A new instance of the Circuit struct or an error if the circuit cannot be built.
336 pub fn build(&mut self) -> Result<Circuit, Error> {
337 let gates_cloned = self.gates.clone();
338 Circuit::with_gates(gates_cloned, self.num_qubits)
339 }
340
341 /// Builds the circuit from the gates in the circuit builder.
342 /// The builder's internal gate list is cleared, allowing the builder to be reused.
343 /// If this is an intermediate circuit, use `build` instead to retain the gates for further modifications.
344 ///
345 /// # Returns
346 ///
347 /// * `Result<Circuit, Error>` - A new instance of the Circuit struct or an error if the circuit cannot be built.
348 pub fn build_final(&mut self) -> Result<Circuit, Error> {
349 let gates = std::mem::take(&mut self.gates);
350 Circuit::with_gates(gates, self.num_qubits)
351 }
352
353 /// Builds a subroutine from the gates in the circuit builder.
354 /// The builder's internal gate list is cleared, allowing the builder to be reused.
355 ///
356 /// # Returns
357 ///
358 /// * `Subroutine` - A new instance of the Subroutine struct.
359 pub fn build_subroutine(&mut self) -> Subroutine {
360 let gates = std::mem::take(&mut self.gates);
361 Subroutine::with_gates(gates, self.num_qubits)
362 }
363
364 /// Adds a subroutine to the circuit builder.
365 ///
366 /// # Arguments
367 ///
368 /// * `subroutine` - The subroutine to be added to the circuit builder.
369 pub fn add_subroutine(&mut self, subroutine: Subroutine) -> &mut Self {
370 self.gates.extend(subroutine.gates);
371 self
372 }
373
374 // -- SINGLE QUBIT GATES --
375
376 /// Adds a Hadamard gate to the circuit builder.
377 ///
378 /// # Arguments
379 ///
380 /// * `qubit` - The index of the qubit to which the Hadamard gate will be applied.
381 pub fn h_gate(&mut self, qubit: usize) -> &mut Self {
382 let gate: Gate = Gate::h_gate(qubit);
383 self.add_gate(gate);
384 self
385 }
386
387 /// Adds multiple Hadamard gates to the circuit builder.
388 ///
389 /// # Arguments
390 ///
391 /// * `qubits` - A vector of indices of the qubits to which the Hadamard gates will be applied.
392 pub fn h_gates(&mut self, qubits: Vec<usize>) -> &mut Self {
393 let gates: Vec<Gate> = Gate::h_multi_gate(qubits);
394 self.add_gates(gates);
395 self
396 }
397
398 /// Adds controlled Hadamard gates to the circuit builder.
399 ///
400 /// # Arguments
401 ///
402 /// * `target_qubits` - A vector of indices of the target qubits.
403 /// * `control_qubits` - A vector of indices of the control qubits.
404 pub fn ch_gates(&mut self, target_qubits: Vec<usize>, control_qubits: Vec<usize>) -> &mut Self {
405 let gates: Vec<Gate> = Gate::h_controlled_gates(target_qubits, control_qubits);
406 self.add_gates(gates);
407 self
408 }
409
410 /// Adds a Pauli-X gate to the circuit builder.
411 ///
412 /// # Arguments
413 ///
414 /// * `qubit` - The index of the qubit to which the Pauli-X gate will be applied.
415 pub fn x_gate(&mut self, qubit: usize) -> &mut Self {
416 let gate: Gate = Gate::x_gate(qubit);
417 self.add_gate(gate);
418 self
419 }
420
421 /// Adds multiple Pauli-X gates to the circuit builder.
422 ///
423 /// # Arguments
424 ///
425 /// * `qubits` - A vector of indices of the qubits to which the Pauli-X gates will be applied.
426 pub fn x_gates(&mut self, qubits: Vec<usize>) -> &mut Self {
427 let gates: Vec<Gate> = Gate::x_multi_gate(qubits);
428 self.add_gates(gates);
429 self
430 }
431
432 /// Adds controlled Pauli-X gates to the circuit builder.
433 ///
434 /// # Arguments
435 ///
436 /// * `target_qubits` - A vector of indices of the target qubits.
437 /// * `control_qubits` - A vector of indices of the control qubits.
438 pub fn cx_gates(&mut self, target_qubits: Vec<usize>, control_qubits: Vec<usize>) -> &mut Self {
439 let gates: Vec<Gate> = Gate::x_controlled_gates(target_qubits, control_qubits);
440 self.add_gates(gates);
441 self
442 }
443
444 /// Adds a Pauli-Y gate to the circuit builder.
445 ///
446 /// # Arguments
447 ///
448 /// * `qubit` - The index of the qubit to which the Pauli-Y gate will be applied.
449 pub fn y_gate(&mut self, qubit: usize) -> &mut Self {
450 let gate: Gate = Gate::y_gate(qubit);
451 self.add_gate(gate);
452 self
453 }
454
455 /// Adds multiple Pauli-Y gates to the circuit builder.
456 ///
457 /// # Arguments
458 ///
459 /// * `qubits` - A vector of indices of the qubits to which the Pauli-Y gates will be applied.
460 pub fn y_gates(&mut self, qubits: Vec<usize>) -> &mut Self {
461 let gates: Vec<Gate> = Gate::y_multi_gate(qubits);
462 self.add_gates(gates);
463 self
464 }
465
466 /// Adds controlled Pauli-Y gates to the circuit builder.
467 ///
468 /// # Arguments
469 ///
470 /// * `target_qubits` - A vector of indices of the target qubits.
471 /// * `control_qubits` - A vector of indices of the control qubits.
472 pub fn cy_gates(&mut self, target_qubits: Vec<usize>, control_qubits: Vec<usize>) -> &mut Self {
473 let gates: Vec<Gate> = Gate::y_controlled_gates(target_qubits, control_qubits);
474 self.add_gates(gates);
475 self
476 }
477
478 /// Adds a Pauli-Z gate to the circuit builder.
479 ///
480 /// # Arguments
481 ///
482 /// * `qubit` - The index of the qubit to which the Pauli-Z gate will be applied.
483 pub fn z_gate(&mut self, qubit: usize) -> &mut Self {
484 let gate: Gate = Gate::z_gate(qubit);
485 self.add_gate(gate);
486 self
487 }
488
489 /// Adds multiple Pauli-Z gates to the circuit builder.
490 ///
491 /// # Arguments
492 ///
493 /// * `qubits` - A vector of indices of the qubits to which the Pauli-Z gates will be applied.
494 pub fn z_gates(&mut self, qubits: Vec<usize>) -> &mut Self {
495 let gates: Vec<Gate> = Gate::z_multi_gate(qubits);
496 self.add_gates(gates);
497 self
498 }
499
500 /// Adds controlled Pauli-Z gates to the circuit builder.
501 ///
502 /// # Arguments
503 ///
504 /// * `target_qubits` - A vector of indices of the target qubits.
505 /// * `control_qubits` - A vector of indices of the control qubits.
506 pub fn cz_gates(&mut self, target_qubits: Vec<usize>, control_qubits: Vec<usize>) -> &mut Self {
507 let gates: Vec<Gate> = Gate::z_controlled_gates(target_qubits, control_qubits);
508 self.add_gates(gates);
509 self
510 }
511
512 /// Adds an Identity gate to the circuit builder.
513 ///
514 /// # Arguments
515 ///
516 /// * `qubit` - The index of the qubit to which the Identity gate will be applied.
517 pub fn id_gate(&mut self, qubit: usize) -> &mut Self {
518 let gate: Gate = Gate::i_gate(qubit);
519 self.add_gate(gate);
520 self
521 }
522
523 /// Adds multiple Identity gates to the circuit builder.
524 ///
525 /// # Arguments
526 ///
527 /// * `qubits` - A vector of indices of the qubits to which the Identity gates will be applied.
528 pub fn id_gates(&mut self, qubits: Vec<usize>) -> &mut Self {
529 let gates: Vec<Gate> = Gate::i_multi_gate(qubits);
530 self.add_gates(gates);
531 self
532 }
533
534 /// Adds controlled Identity gates to the circuit builder.
535 ///
536 /// # Arguments
537 ///
538 /// * `target_qubits` - A vector of indices of the target qubits.
539 /// * `control_qubits` - A vector of indices of the control qubits.
540 pub fn ci_gates(&mut self, target_qubits: Vec<usize>, control_qubits: Vec<usize>) -> &mut Self {
541 let gates: Vec<Gate> = Gate::i_controlled_gates(target_qubits, control_qubits);
542 self.add_gates(gates);
543 self
544 }
545
546 /// Adds a Phase S gate to the circuit builder.
547 ///
548 /// # Arguments
549 ///
550 /// * `qubit` - The index of the qubit to which the Phase S gate will be applied.
551 pub fn s_gate(&mut self, qubit: usize) -> &mut Self {
552 let gate: Gate = Gate::s_gate(qubit);
553 self.add_gate(gate);
554 self
555 }
556
557 /// Adds multiple Phase S gates to the circuit builder.
558 ///
559 /// # Arguments
560 ///
561 /// * `qubits` - A vector of indices of the qubits to which the Phase S gates will be applied.
562 pub fn s_gates(&mut self, qubits: Vec<usize>) -> &mut Self {
563 let gates: Vec<Gate> = Gate::s_multi_gate(qubits);
564 self.add_gates(gates);
565 self
566 }
567
568 /// Adds controlled Phase S gates to the circuit builder.
569 ///
570 /// # Arguments
571 ///
572 /// * `target_qubits` - A vector of indices of the target qubits.
573 /// * `control_qubits` - A vector of indices of the control qubits.
574 pub fn cs_gates(&mut self, target_qubits: Vec<usize>, control_qubits: Vec<usize>) -> &mut Self {
575 let gates: Vec<Gate> = Gate::s_controlled_gates(target_qubits, control_qubits);
576 self.add_gates(gates);
577 self
578 }
579
580 /// Adds a Phase S Dagger gate to the circuit builder.
581 ///
582 /// # Arguments
583 ///
584 /// * `qubit` - The index of the qubit to which the Phase S Dagger gate will be applied.
585 pub fn sdag_gate(&mut self, qubit: usize) -> &mut Self {
586 let gate: Gate = Gate::s_dag_gate(qubit);
587 self.add_gate(gate);
588 self
589 }
590
591 /// Adds multiple Phase S Dagger gates to the circuit builder.
592 ///
593 /// # Arguments
594 ///
595 /// * `qubits` - A vector of indices of the qubits to which the Phase S Dagger gates will be applied.
596 pub fn sdag_gates(&mut self, qubits: Vec<usize>) -> &mut Self {
597 let gates: Vec<Gate> = Gate::s_dag_multi_gate(qubits);
598 self.add_gates(gates);
599 self
600 }
601
602 /// Adds controlled Phase S Dagger gates to the circuit builder.
603 ///
604 /// # Arguments
605 ///
606 /// * `target_qubits` - A vector of indices of the target qubits.
607 /// * `control_qubits` - A vector of indices of the control qubits.
608 pub fn csdag_gates(
609 &mut self,
610 target_qubits: Vec<usize>,
611 control_qubits: Vec<usize>,
612 ) -> &mut Self {
613 let gates: Vec<Gate> = Gate::s_dag_controlled_gates(target_qubits, control_qubits);
614 self.add_gates(gates);
615 self
616 }
617
618 /// Adds a Phase T gate to the circuit builder.
619 ///
620 /// # Arguments
621 ///
622 /// * `qubit` - The index of the qubit to which the Phase T gate will be applied.
623 pub fn t_gate(&mut self, qubit: usize) -> &mut Self {
624 let gate: Gate = Gate::t_gate(qubit);
625 self.add_gate(gate);
626 self
627 }
628
629 /// Adds multiple Phase T gates to the circuit builder.
630 ///
631 /// # Arguments
632 ///
633 /// * `qubits` - A vector of indices of the qubits to which the Phase T gates will be applied.
634 pub fn t_gates(&mut self, qubits: Vec<usize>) -> &mut Self {
635 let gates: Vec<Gate> = Gate::t_multi_gate(qubits);
636 self.add_gates(gates);
637 self
638 }
639
640 /// Adds controlled Phase T gates to the circuit builder.
641 ///
642 /// # Arguments
643 ///
644 /// * `target_qubits` - A vector of indices of the target qubits.
645 /// * `control_qubits` - A vector of indices of the control qubits.
646 pub fn ct_gates(&mut self, target_qubits: Vec<usize>, control_qubits: Vec<usize>) -> &mut Self {
647 let gates: Vec<Gate> = Gate::t_controlled_gates(target_qubits, control_qubits);
648 self.add_gates(gates);
649 self
650 }
651
652 /// Adds a Phase T Dagger gate to the circuit builder.
653 ///
654 /// # Arguments
655 ///
656 /// * `qubit` - The index of the qubit to which the Phase T Dagger gate will be applied.
657 pub fn tdag_gate(&mut self, qubit: usize) -> &mut Self {
658 let gate: Gate = Gate::t_dag_gate(qubit);
659 self.add_gate(gate);
660 self
661 }
662
663 /// Adds multiple Phase T Dagger gates to the circuit builder.
664 ///
665 /// # Arguments
666 ///
667 /// * `qubits` - A vector of indices of the qubits to which the Phase T Dagger gates will be applied.
668 pub fn tdag_gates(&mut self, qubits: Vec<usize>) -> &mut Self {
669 let gates: Vec<Gate> = Gate::t_dag_multi_gate(qubits);
670 self.add_gates(gates);
671 self
672 }
673
674 /// Adds controlled Phase T Dagger gates to the circuit builder.
675 ///
676 /// # Arguments
677 ///
678 /// * `target_qubits` - A vector of indices of the target qubits.
679 /// * `control_qubits` - A vector of indices of the control qubits.
680 pub fn ctdag_gates(
681 &mut self,
682 target_qubits: Vec<usize>,
683 control_qubits: Vec<usize>,
684 ) -> &mut Self {
685 let gates: Vec<Gate> = Gate::t_dag_controlled_gates(target_qubits, control_qubits);
686 self.add_gates(gates);
687 self
688 }
689
690 /// Adds a Phase Shift gate to the circuit builder.
691 ///
692 /// # Arguments
693 ///
694 /// * `qubit` - The index of the qubit to which the Phase Shift gate will be applied.
695 /// * `angle` - The phase shift angle in radians.
696 pub fn p_gate(&mut self, qubit: usize, angle: f64) -> &mut Self {
697 let gate: Gate = Gate::p_gate(qubit, angle);
698 self.add_gate(gate);
699 self
700 }
701
702 /// Adds multiple Phase Shift gates to the circuit builder.
703 ///
704 /// # Arguments
705 ///
706 /// * `qubits` - A vector of indices of the qubits to which the Phase Shift gates will be applied.
707 /// * `angle` - The phase shift angle in radians for all gates.
708 pub fn p_gates(&mut self, qubits: Vec<usize>, angle: f64) -> &mut Self {
709 let gates: Vec<Gate> = Gate::p_multi_gate(qubits, angle);
710 self.add_gates(gates);
711 self
712 }
713
714 /// Adds controlled Phase Shift gates to the circuit builder.
715 ///
716 /// # Arguments
717 ///
718 /// * `target_qubits` - A vector of indices of the target qubits.
719 /// * `control_qubits` - A vector of indices of the control qubits.
720 /// * `angle` - The phase shift angle in radians for all gates.
721 pub fn cp_gates(
722 &mut self,
723 target_qubits: Vec<usize>,
724 control_qubits: Vec<usize>,
725 angle: f64,
726 ) -> &mut Self {
727 let gates: Vec<Gate> = Gate::p_controlled_gates(target_qubits, control_qubits, angle);
728 self.add_gates(gates);
729 self
730 }
731
732 /// Adds a Rotate X gate to the circuit builder.
733 ///
734 /// # Arguments
735 ///
736 /// * `qubit` - The index of the qubit to which the Rotate X gate will be applied.
737 /// * `angle` - The rotation angle in radians.
738 pub fn rx_gate(&mut self, qubit: usize, angle: f64) -> &mut Self {
739 let gate: Gate = Gate::rx_gate(qubit, angle);
740 self.add_gate(gate);
741 self
742 }
743
744 /// Adds multiple Rotate X gates to the circuit builder.
745 ///
746 /// # Arguments
747 ///
748 /// * `qubits` - A vector of indices of the qubits to which the Rotate X gates will be applied.
749 /// * `angle` - The rotation angle in radians for all gates.
750 pub fn rx_gates(&mut self, qubits: Vec<usize>, angle: f64) -> &mut Self {
751 let gates: Vec<Gate> = Gate::rx_multi_gate(qubits, angle);
752 self.add_gates(gates);
753 self
754 }
755
756 /// Adds controlled Rotate X gates to the circuit builder.
757 ///
758 /// # Arguments
759 ///
760 /// * `target_qubits` - A vector of indices of the target qubits.
761 /// * `control_qubits` - A vector of indices of the control qubits.
762 /// * `angle` - The rotation angle in radians for all gates.
763 pub fn crx_gates(
764 &mut self,
765 target_qubits: Vec<usize>,
766 control_qubits: Vec<usize>,
767 angle: f64,
768 ) -> &mut Self {
769 let gates: Vec<Gate> = Gate::rx_controlled_gates(target_qubits, control_qubits, angle);
770 self.add_gates(gates);
771 self
772 }
773
774 /// Adds a Rotate Y gate to the circuit builder.
775 ///
776 /// # Arguments
777 ///
778 /// * `qubit` - The index of the qubit to which the Rotate Y gate will be applied.
779 /// * `angle` - The rotation angle in radians.
780 pub fn ry_gate(&mut self, qubit: usize, angle: f64) -> &mut Self {
781 let gate: Gate = Gate::ry_gate(qubit, angle);
782 self.add_gate(gate);
783 self
784 }
785
786 /// Adds multiple Rotate Y gates to the circuit builder.
787 ///
788 /// # Arguments
789 ///
790 /// * `qubits` - A vector of indices of the qubits to which the Rotate Y gates will be applied.
791 /// * `angle` - The rotation angle in radians for all gates.
792 pub fn ry_gates(&mut self, qubits: Vec<usize>, angle: f64) -> &mut Self {
793 let gates: Vec<Gate> = Gate::ry_multi_gate(qubits, angle);
794 self.add_gates(gates);
795 self
796 }
797
798 /// Adds controlled Rotate Y gates to the circuit builder.
799 ///
800 /// # Arguments
801 ///
802 /// * `target_qubits` - A vector of indices of the target qubits.
803 /// * `control_qubits` - A vector of indices of the control qubits.
804 /// * `angle` - The rotation angle in radians for all gates.
805 pub fn cry_gates(
806 &mut self,
807 target_qubits: Vec<usize>,
808 control_qubits: Vec<usize>,
809 angle: f64,
810 ) -> &mut Self {
811 let gates: Vec<Gate> = Gate::ry_controlled_gates(target_qubits, control_qubits, angle);
812 self.add_gates(gates);
813 self
814 }
815
816 /// Adds a Rotate Z gate to the circuit builder.
817 ///
818 /// # Arguments
819 ///
820 /// * `qubit` - The index of the qubit to which the Rotate Z gate will be applied.
821 /// * `angle` - The rotation angle in radians.
822 pub fn rz_gate(&mut self, qubit: usize, angle: f64) -> &mut Self {
823 let gate: Gate = Gate::rz_gate(qubit, angle);
824 self.add_gate(gate);
825 self
826 }
827
828 /// Adds multiple Rotate Z gates to the circuit builder.
829 ///
830 /// # Arguments
831 ///
832 /// * `qubits` - A vector of indices of the qubits to which the Rotate Z gates will be applied.
833 /// * `angle` - The rotation angle in radians for all gates.
834 pub fn rz_gates(&mut self, qubits: Vec<usize>, angle: f64) -> &mut Self {
835 let gates: Vec<Gate> = Gate::rz_multi_gate(qubits, angle);
836 self.add_gates(gates);
837 self
838 }
839
840 /// Adds controlled Rotate Z gates to the circuit builder.
841 ///
842 /// # Arguments
843 ///
844 /// * `target_qubits` - A vector of indices of the target qubits.
845 /// * `control_qubits` - A vector of indices of the control qubits.
846 /// * `angle` - The rotation angle in radians for all gates.
847 pub fn crz_gates(
848 &mut self,
849 target_qubits: Vec<usize>,
850 control_qubits: Vec<usize>,
851 angle: f64,
852 ) -> &mut Self {
853 let gates: Vec<Gate> = Gate::rz_controlled_gates(target_qubits, control_qubits, angle);
854 self.add_gates(gates);
855 self
856 }
857
858 /// Adds an arbitrary unitary operator gate to the circuit builder.
859 ///
860 /// # Arguments
861 ///
862 /// * `qubit` - The index of the qubit to which the operator will be applied.
863 ///
864 /// * `unitary` - Matrix representing the unitary operator.
865 ///
866 /// # Warning
867 ///
868 /// This method is fallible due to the potential for invalid unitary matrices.
869 /// If the unitary matrix is not valid, it will return an error.
870 /// Therefore, the `Result` must be handled appropriately before chaining further operations.
871 pub fn unitary_gate(
872 &mut self,
873 qubit: usize,
874 unitary: [[Complex<f64>; 2]; 2],
875 ) -> Result<&mut Self, Error> {
876 let gate: Gate = Gate::unitary2_gate(qubit, unitary)?;
877 self.add_gate(gate);
878 Ok(self)
879 }
880
881 /// Adds multiple arbitrary unitary operator gates to the circuit builder.
882 ///
883 /// # Arguments
884 ///
885 /// * `qubits` - A vector of indices of the qubits to which the operator will be applied.
886 ///
887 /// * `unitary` - Matrix representing the unitary operator.
888 ///
889 /// # Warning
890 ///
891 /// This method is fallible due to the potential for invalid unitary matrices.
892 /// If the unitary matrix is not valid, it will return an error.
893 /// Therefore, the `Result` must be handled appropriately before chaining further operations.
894 pub fn unitary_gates(
895 &mut self,
896 qubits: Vec<usize>,
897 unitary: [[Complex<f64>; 2]; 2],
898 ) -> Result<&mut Self, Error> {
899 let gates: Vec<Gate> = Gate::unitary2_multi_gate(qubits, unitary)?;
900 self.add_gates(gates);
901 Ok(self)
902 }
903
904 /// Adds controlled arbitrary unitary operator gates to the circuit builder.
905 ///
906 /// # Arguments
907 ///
908 /// * `target_qubits` - A vector of indices of the target qubits.
909 ///
910 /// * `control_qubits` - A vector of indices of the control qubits.
911 ///
912 /// * `unitary` - Matrix representing the unitary operator.
913 ///
914 /// # Warning
915 ///
916 /// This method is fallible due to the potential for invalid unitary matrices.
917 /// If the unitary matrix is not valid, it will return an error.
918 /// Therefore, the `Result` must be handled appropriately before chaining further operations.
919 pub fn cunitary_gates(
920 &mut self,
921 target_qubits: Vec<usize>,
922 control_qubits: Vec<usize>,
923 unitary: [[Complex<f64>; 2]; 2],
924 ) -> Result<&mut Self, Error> {
925 let gates = Gate::unitary2_controlled_gates(target_qubits, control_qubits, unitary)?;
926 self.add_gates(gates);
927 Ok(self)
928 }
929
930 /// Creates and adds a new Unitary2 operator gate from a rotation angle theta and phase shift angle phi.
931 ///
932 /// This operator can be decomposed into a rotation around the Y axis followed by a phase shift.
933 /// The enclosed unitary matrix is guaranteed to be unitary.
934 ///
935 /// Special cases include:
936 ///
937 /// * U(theta, 0) = RY(theta)
938 /// * U(0, phi) = PhaseShift(phi)
939 /// * U(Pi/2, Pi) = Hadamard
940 /// * U(Pi, Pi) = Pauli-X
941 ///
942 /// # Arguments
943 ///
944 /// * `qubit` - The index of the qubit to which the operator will be applied.
945 ///
946 /// * `theta` - The rotation angle in radians.
947 ///
948 /// * `phi` - The phase shift angle in radians.
949 pub fn ry_phase_gate(&mut self, qubit: usize, theta: f64, phi: f64) -> &mut Self {
950 let gate: Gate = Gate::ry_phase_gate(qubit, theta, phi);
951 self.add_gate(gate);
952 self
953 }
954
955 /// Creates and adds multiple new Unitary2 operator gates from a rotation angle theta and phase shift angle phi.
956 ///
957 /// This operator can be decomposed into a rotation around the Y axis followed by a phase shift.
958 /// The enclosed unitary matrix is guaranteed to be unitary.
959 ///
960 /// Special cases include:
961 /// * U(theta, 0) = RY(theta)
962 /// * U(0, phi) = PhaseShift(phi)
963 /// * U(Pi/2, Pi) = Hadamard
964 /// * U(Pi, Pi) = Pauli-X
965 ///
966 /// # Arguments
967 /// * `qubits` - A vector of indices of the qubits to which the operator will be applied.
968 /// * `theta` - The rotation angle in radians for all gates.
969 /// * `phi` - The phase shift angle in radians for all gates.
970 pub fn ry_phase_gates(&mut self, qubits: Vec<usize>, theta: f64, phi: f64) -> &mut Self {
971 let gates: Vec<Gate> = Gate::ry_phase_multi_gate(qubits, theta, phi);
972 self.add_gates(gates);
973 self
974 }
975
976 /// Creates and adds controlled Unitary2 operator gates from a rotation angle theta and phase shift angle phi.
977 ///
978 /// This operator can be decomposed into a rotation around the Y axis followed by a phase shift.
979 /// The enclosed unitary matrix is guaranteed to be unitary.
980 ///
981 /// Special cases include:
982 /// * U(theta, 0) = RY(theta)
983 /// * U(0, phi) = PhaseShift(phi)
984 /// * U(Pi/2, Pi) = Hadamard
985 /// * U(Pi, Pi) = Pauli-X
986 ///
987 /// # Arguments
988 ///
989 /// * `target_qubits` - A vector of indices of the target qubits.
990 ///
991 /// * `control_qubits` - A vector of indices of the control qubits.
992 ///
993 /// * `theta` - The rotation angle in radians for all gates.
994 ///
995 /// * `phi` - The phase shift angle in radians for all gates.
996 pub fn cry_phase_gates(
997 &mut self,
998 target_qubits: Vec<usize>,
999 control_qubits: Vec<usize>,
1000 theta: f64,
1001 phi: f64,
1002 ) -> &mut Self {
1003 let gates: Vec<Gate> =
1004 Gate::ry_phase_controlled_gates(target_qubits, control_qubits, theta, phi);
1005 self.add_gates(gates);
1006 self
1007 }
1008
1009 // -- MULTI-QUBIT GATES --
1010
1011 /// Adds a CNOT gate to the circuit builder.
1012 ///
1013 /// # Arguments
1014 ///
1015 /// * `target_qubit` - The index of the target qubit.
1016 /// * `control_qubit` - The index of the control qubit.
1017 pub fn cnot_gate(&mut self, target_qubit: usize, control_qubit: usize) -> &mut Self {
1018 let gate: Gate = Gate::cnot_gate(target_qubit, control_qubit);
1019 self.add_gate(gate);
1020 self
1021 }
1022
1023 /// Adds a SWAP gate to the circuit builder.
1024 ///
1025 /// # Arguments
1026 ///
1027 /// * `qubit1` - The index of the first qubit to swap.
1028 /// * `qubit2` - The index of the second qubit to swap.
1029 pub fn swap_gate(&mut self, qubit1: usize, qubit2: usize) -> &mut Self {
1030 let gate: Gate = Gate::swap_gate(qubit1, qubit2);
1031 self.add_gate(gate);
1032 self
1033 }
1034
1035 /// Adds a controlled SWAP gate to the circuit builder.
1036 ///
1037 /// # Arguments
1038 ///
1039 /// * `target_qubit1` - The index of the first qubit to swap.
1040 /// * `target_qubit2` - The index of the second qubit to swap.
1041 /// * `control_qubits` - A vector of indices of the control qubits.
1042 pub fn cswap_gate(
1043 &mut self,
1044 target_qubit1: usize,
1045 target_qubit2: usize,
1046 control_qubits: Vec<usize>,
1047 ) -> &mut Self {
1048 let gate: Gate = Gate::Operator(
1049 Box::new(crate::components::operator::SWAP),
1050 vec![target_qubit1, target_qubit2],
1051 control_qubits,
1052 );
1053 self.add_gate(gate);
1054 self
1055 }
1056
1057 /// Adds a Toffoli (CCNOT) gate to the circuit builder.
1058 ///
1059 /// # Arguments
1060 ///
1061 /// * `target_qubit` - The index of the target qubit.
1062 /// * `control_qubit1` - The index of the first control qubit.
1063 /// * `control_qubit2` - The index of the second control qubit.
1064 pub fn toffoli_gate(
1065 &mut self,
1066 control_qubit1: usize,
1067 control_qubit2: usize,
1068 target_qubit: usize,
1069 ) -> &mut Self {
1070 let gate: Gate = Gate::toffoli_gate(target_qubit, vec![control_qubit1, control_qubit2]);
1071 self.add_gate(gate);
1072 self
1073 }
1074
1075 /// Adds a Matchgate to the circuit builder.
1076 ///
1077 /// # Arguments
1078 ///
1079 /// * `target_qubit` - The index of the first target qubit. The second target qubit is assumed to be the next qubit.
1080 /// * `theta` - The angle of rotation in radians.
1081 /// * `phi1` - The first phase shift in radians.
1082 /// * `phi2` - The second phase shift in radians.
1083 ///
1084 /// # Warning
1085 ///
1086 /// This gate is not yet compilable to OpenQASM, since it requires advanced decomposition techniques.
1087 pub fn matchgate(
1088 &mut self,
1089 target_qubit: usize,
1090 theta: f64,
1091 phi1: f64,
1092 phi2: f64,
1093 ) -> &mut Self {
1094 let gate: Gate = Gate::matchgate(target_qubit, theta, phi1, phi2);
1095 self.add_gate(gate);
1096 self
1097 }
1098
1099 /// Adds a controlled Matchgate to the circuit builder.
1100 ///
1101 /// # Arguments
1102 ///
1103 /// * `target_qubit` - The index of the first target qubit. The second target qubit is assumed to be the next qubit.
1104 /// * `control_qubits` - A vector of indices of the control qubits.
1105 /// * `theta` - The angle of rotation in radians.
1106 /// * `phi1` - The first phase shift in radians.
1107 /// * `phi2` - The second phase shift in radians.
1108 ///
1109 /// # Warning
1110 ///
1111 /// This gate is not yet compilable to OpenQASM, since it requires advanced decomposition techniques.
1112 pub fn cmatchgate(
1113 &mut self,
1114 target_qubit: usize,
1115 control_qubits: Vec<usize>,
1116 theta: f64,
1117 phi1: f64,
1118 phi2: f64,
1119 ) -> &mut Self {
1120 let gate: Gate =
1121 Gate::controlled_matchgate(target_qubit, control_qubits, theta, phi1, phi2);
1122 self.add_gate(gate);
1123 self
1124 }
1125
1126 /// Adds a custom operator gate to the circuit builder.
1127 ///
1128 /// # Arguments
1129 ///
1130 /// * `operator` - The operator to be added to the circuit builder.
1131 /// * `target_qubits` - A vector of indices of the target qubits.
1132 /// * `control_qubits` - An vector of indices of the control qubits.
1133 pub fn add_operator_gate(
1134 &mut self,
1135 operator: Box<dyn Operator>,
1136 target_qubits: Vec<usize>,
1137 control_qubits: Vec<usize>,
1138 ) -> &mut Self {
1139 let gate: Gate = Gate::Operator(operator, target_qubits, control_qubits);
1140 self.add_gate(gate);
1141 self
1142 }
1143
1144 // -- PARAMETRIC GATES --
1145
1146 /// Adds a parametric Ry phase gate to the circuit builder.
1147 ///
1148 /// # Arguments
1149 ///
1150 /// * `target_index` - The index of the target qubit.
1151 /// * `parameter` - The parameter of size 2 to be used in the gate.
1152 pub fn parametric_ry_phase_gate(&mut self, target_index: usize, parameter: Parameter<2>) -> &mut Self {
1153 let p_gate = ParametricRyPhase { parameter };
1154 let gate = Gate::Parametric(Box::new(p_gate), vec![target_index], vec![]);
1155 self.add_gate(gate);
1156 self
1157 }
1158
1159 /// Adds multiple parametric Ry phase gates to the circuit builder, each with its own parameter.
1160 ///
1161 /// # Arguments
1162 ///
1163 /// * `target_indices` - A vector of indices of the target qubits.
1164 /// * `parameters` - A vector of parameters of size 2 to be used in the gates.
1165 ///
1166 /// # Warning
1167 ///
1168 /// This method is fallible due to the potential for a mismatch in the number of parameters.
1169 /// If the number of parameters is not equal to the number of target indices, it will return an error.
1170 /// Therefore, the `Result` must be handled appropriately before chaining further operations.
1171 pub fn parametric_ry_phase_gates(&mut self, target_indices: Vec<usize>, parameters: Vec<Parameter<2>>) -> Result<&mut Self, Error> {
1172 if target_indices.len() != parameters.len() {
1173 return Err(Error::MismatchedNumberOfParameters {
1174 expected: target_indices.len(),
1175 actual: parameters.len(),
1176 });
1177 }
1178
1179 for (target_index, parameter) in target_indices.into_iter().zip(parameters.into_iter()) {
1180 self.parametric_ry_phase_gate(target_index, parameter);
1181 }
1182 Ok(self)
1183 }
1184
1185 /// Adds multiple controlled parametric Ry phase gates to the circuit builder, each with its own parameter.
1186 ///
1187 /// # Arguments
1188 ///
1189 /// * `target_indices` - A vector of indices of the target qubits.
1190 /// * `control_indices` - A vector of indices of the control qubits.
1191 /// * `parameters` - A vector of parameters of size 2 to be used in the gates.
1192 ///
1193 /// # Warning
1194 ///
1195 /// This method is fallible due to the potential for a mismatch in the number of parameters.
1196 /// If the number of parameters is not equal to the number of target indices, it will return an error.
1197 /// Therefore, the `Result` must be handled appropriately before chaining further operations.
1198 pub fn parametric_cry_phase_gates(&mut self, target_indices: Vec<usize>, control_indices: Vec<usize>, parameters: Vec<Parameter<2>>) -> Result<&mut Self, Error> {
1199 if target_indices.len() != parameters.len() {
1200 return Err(Error::MismatchedNumberOfParameters {
1201 expected: target_indices.len(),
1202 actual: parameters.len(),
1203 });
1204 }
1205
1206 for (target_index, parameter) in target_indices.into_iter().zip(parameters.into_iter()) {
1207 let p_gate = ParametricRyPhase { parameter: parameter.clone() };
1208 let gate = Gate::Parametric(Box::new(p_gate), vec![target_index], control_indices.clone());
1209 self.add_gate(gate);
1210 }
1211 Ok(self)
1212 }
1213
1214 /// Adds a parametric matchgate to the circuit builder.
1215 ///
1216 /// # Arguments
1217 ///
1218 /// * `target_index` - The index of the target qubit.
1219 /// * `parameter` - The parameter of size 3 to be used in the gate.
1220 pub fn parametric_matchgate(&mut self, target_index: usize, parameter: Parameter<3>) -> &mut Self {
1221 let p_gate = ParametricMatchgate { parameter };
1222 let gate = Gate::Parametric(Box::new(p_gate), vec![target_index], vec![]);
1223 self.add_gate(gate);
1224 self
1225 }
1226
1227 /// Adds a controlled parametric matchgate to the circuit builder.
1228 ///
1229 /// # Arguments
1230 ///
1231 /// * `target_index` - The index of the target qubit.
1232 /// * `control_indices` - A vector of indices of the control qubits.
1233 /// * `parameter` - The parameter of size 3 to be used in the gate.
1234 pub fn parametric_cmatchgate(&mut self, target_index: usize, control_indices: Vec<usize>, parameter: Parameter<3>) -> &mut Self {
1235 let p_gate = ParametricMatchgate { parameter };
1236 let gate = Gate::Parametric(Box::new(p_gate), vec![target_index], control_indices);
1237 self.add_gate(gate);
1238 self
1239 }
1240
1241 /// Adds a parametric Rx gate to the circuit builder.
1242 ///
1243 /// # Arguments
1244 ///
1245 /// * `target_index` - The index of the target qubit.
1246 /// * `parameter` - The parameter of size 1 to be used in the gate.
1247 pub fn parametric_rx_gate(&mut self, target_index: usize, parameter: Parameter<1>) -> &mut Self {
1248 let p_gate = ParametricRx { parameter };
1249 let gate = Gate::Parametric(Box::new(p_gate), vec![target_index], vec![]);
1250 self.add_gate(gate);
1251 self
1252 }
1253
1254 /// Adds multiple parametric Rx gates to the circuit builder, each with its own parameter.
1255 ///
1256 /// # Arguments
1257 ///
1258 /// * `target_indices` - A vector of indices of the target qubits.
1259 /// * `parameters` - A vector of parameters of size 1 to be used in the gates.
1260 ///
1261 /// # Warning
1262 ///
1263 /// This method is fallible due to the potential for a mismatch in the number of parameters.
1264 /// If the number of parameters is not equal to the number of target indices, it will return an error.
1265 /// Therefore, the `Result` must be handled appropriately before chaining further operations.
1266 pub fn parametric_rx_gates(
1267 &mut self,
1268 target_indices: Vec<usize>,
1269 parameters: Vec<Parameter<1>>,
1270 ) -> Result<&mut Self, Error> {
1271 if target_indices.len() != parameters.len() {
1272 return Err(Error::MismatchedNumberOfParameters {
1273 expected: target_indices.len(),
1274 actual: parameters.len(),
1275 });
1276 }
1277
1278 for (target_index, parameter) in target_indices.into_iter().zip(parameters.into_iter()) {
1279 self.parametric_rx_gate(target_index, parameter);
1280 }
1281 Ok(self)
1282 }
1283
1284 /// Adds multiple controlled parametric Rx gates to the circuit builder, each with its own parameter.
1285 ///
1286 /// # Arguments
1287 ///
1288 /// * `target_indices` - A vector of indices of the target qubits.
1289 /// * `control_indices` - A vector of indices of the control qubits.
1290 /// * `parameters` - A vector of parameters of size 1 to be used in the gates.
1291 ///
1292 /// # Warning
1293 ///
1294 /// This method is fallible due to the potential for a mismatch in the number of parameters.
1295 /// If the number of parameters is not equal to the number of target indices, it will return an error.
1296 /// Therefore, the `Result` must be handled appropriately before chaining further operations.
1297 pub fn parametric_crx_gates(
1298 &mut self,
1299 target_indices: Vec<usize>,
1300 control_indices: Vec<usize>,
1301 parameters: Vec<Parameter<1>>,
1302 ) -> Result<&mut Self, Error> {
1303 if target_indices.len() != parameters.len() {
1304 return Err(Error::MismatchedNumberOfParameters {
1305 expected: target_indices.len(),
1306 actual: parameters.len(),
1307 });
1308 }
1309
1310 for (target_index, parameter) in target_indices.into_iter().zip(parameters.into_iter()) {
1311 let p_gate = ParametricRx {
1312 parameter: parameter.clone(),
1313 };
1314 let gate =
1315 Gate::Parametric(Box::new(p_gate), vec![target_index], control_indices.clone());
1316 self.add_gate(gate);
1317 }
1318 Ok(self)
1319 }
1320
1321 /// Adds a parametric Ry gate to the circuit builder.
1322 ///
1323 /// # Arguments
1324 ///
1325 /// * `target_index` - The index of the target qubit.
1326 /// * `parameter` - The parameter of size 1 to be used in the gate.
1327 pub fn parametric_ry_gate(&mut self, target_index: usize, parameter: Parameter<1>) -> &mut Self {
1328 let p_gate = ParametricRy { parameter };
1329 let gate = Gate::Parametric(Box::new(p_gate), vec![target_index], vec![]);
1330 self.add_gate(gate);
1331 self
1332 }
1333
1334 /// Adds multiple parametric Ry gates to the circuit builder, each with its own parameter.
1335 ///
1336 /// # Arguments
1337 ///
1338 /// * `target_indices` - A vector of indices of the target qubits.
1339 /// * `parameters` - A vector of parameters of size 1 to be used in the gates.
1340 ///
1341 /// # Warning
1342 ///
1343 /// This method is fallible due to the potential for a mismatch in the number of parameters.
1344 /// If the number of parameters is not equal to the number of target indices, it will return an error.
1345 /// Therefore, the `Result` must be handled appropriately before chaining further operations.
1346 pub fn parametric_ry_gates(
1347 &mut self,
1348 target_indices: Vec<usize>,
1349 parameters: Vec<Parameter<1>>,
1350 ) -> Result<&mut Self, Error> {
1351 if target_indices.len() != parameters.len() {
1352 return Err(Error::MismatchedNumberOfParameters {
1353 expected: target_indices.len(),
1354 actual: parameters.len(),
1355 });
1356 }
1357
1358 for (target_index, parameter) in target_indices.into_iter().zip(parameters.into_iter()) {
1359 self.parametric_ry_gate(target_index, parameter);
1360 }
1361 Ok(self)
1362 }
1363
1364 /// Adds multiple controlled parametric Ry gates to the circuit builder, each with its own parameter.
1365 ///
1366 /// # Arguments
1367 ///
1368 /// * `target_indices` - A vector of indices of the target qubits.
1369 /// * `control_indices` - A vector of indices of the control qubits.
1370 /// * `parameters` - A vector of parameters of size 1 to be used in the gates.
1371 ///
1372 /// # Warning
1373 ///
1374 /// This method is fallible due to the potential for a mismatch in the number of parameters.
1375 /// If the number of parameters is not equal to the number of target indices, it will return an error.
1376 /// Therefore, the `Result` must be handled appropriately before chaining further operations.
1377 pub fn parametric_cry_gates(
1378 &mut self,
1379 target_indices: Vec<usize>,
1380 control_indices: Vec<usize>,
1381 parameters: Vec<Parameter<1>>,
1382 ) -> Result<&mut Self, Error> {
1383 if target_indices.len() != parameters.len() {
1384 return Err(Error::MismatchedNumberOfParameters {
1385 expected: target_indices.len(),
1386 actual: parameters.len(),
1387 });
1388 }
1389
1390 for (target_index, parameter) in target_indices.into_iter().zip(parameters.into_iter()) {
1391 let p_gate = ParametricRy {
1392 parameter: parameter.clone(),
1393 };
1394 let gate =
1395 Gate::Parametric(Box::new(p_gate), vec![target_index], control_indices.clone());
1396 self.add_gate(gate);
1397 }
1398 Ok(self)
1399 }
1400
1401 /// Adds a parametric Rz gate to the circuit builder.
1402 ///
1403 /// # Arguments
1404 ///
1405 /// * `target_index` - The index of the target qubit.
1406 /// * `parameter` - The parameter of size 1 to be used in the gate.
1407 pub fn parametric_rz_gate(&mut self, target_index: usize, parameter: Parameter<1>) -> &mut Self {
1408 let p_gate = ParametricRz { parameter };
1409 let gate = Gate::Parametric(Box::new(p_gate), vec![target_index], vec![]);
1410 self.add_gate(gate);
1411 self
1412 }
1413
1414 /// Adds multiple parametric Rz gates to the circuit builder, each with its own parameter.
1415 ///
1416 /// # Arguments
1417 ///
1418 /// * `target_indices` - A vector of indices of the target qubits.
1419 /// * `parameters` - A vector of parameters of size 1 to be used in the gates.
1420 ///
1421 /// # Warning
1422 ///
1423 /// This method is fallible due to the potential for a mismatch in the number of parameters.
1424 /// If the number of parameters is not equal to the number of target indices, it will return an error.
1425 /// Therefore, the `Result` must be handled appropriately before chaining further operations.
1426 pub fn parametric_rz_gates(
1427 &mut self,
1428 target_indices: Vec<usize>,
1429 parameters: Vec<Parameter<1>>,
1430 ) -> Result<&mut Self, Error> {
1431 if target_indices.len() != parameters.len() {
1432 return Err(Error::MismatchedNumberOfParameters {
1433 expected: target_indices.len(),
1434 actual: parameters.len(),
1435 });
1436 }
1437
1438 for (target_index, parameter) in target_indices.into_iter().zip(parameters.into_iter()) {
1439 self.parametric_rz_gate(target_index, parameter);
1440 }
1441 Ok(self)
1442 }
1443
1444 /// Adds multiple controlled parametric Rz gates to the circuit builder, each with its own parameter.
1445 ///
1446 /// # Arguments
1447 ///
1448 /// * `target_indices` - A vector of indices of the target qubits.
1449 /// * `control_indices` - A vector of indices of the control qubits.
1450 /// * `parameters` - A vector of parameters of size 1 to be used in the gates.
1451 ///
1452 /// # Warning
1453 ///
1454 /// This method is fallible due to the potential for a mismatch in the number of parameters.
1455 /// If the number of parameters is not equal to the number of target indices, it will return an error.
1456 /// Therefore, the `Result` must be handled appropriately before chaining further operations.
1457 pub fn parametric_crz_gates(
1458 &mut self,
1459 target_indices: Vec<usize>,
1460 control_indices: Vec<usize>,
1461 parameters: Vec<Parameter<1>>,
1462 ) -> Result<&mut Self, Error> {
1463 if target_indices.len() != parameters.len() {
1464 return Err(Error::MismatchedNumberOfParameters {
1465 expected: target_indices.len(),
1466 actual: parameters.len(),
1467 });
1468 }
1469
1470 for (target_index, parameter) in target_indices.into_iter().zip(parameters.into_iter()) {
1471 let p_gate = ParametricRz {
1472 parameter: parameter.clone(),
1473 };
1474 let gate =
1475 Gate::Parametric(Box::new(p_gate), vec![target_index], control_indices.clone());
1476 self.add_gate(gate);
1477 }
1478 Ok(self)
1479 }
1480
1481 /// Adds a parametric P gate to the circuit builder.
1482 ///
1483 /// # Arguments
1484 ///
1485 /// * `target_index` - The index of the target qubit.
1486 /// * `parameter` - The parameter of size 1 to be used in the gate.
1487 pub fn parametric_p_gate(&mut self, target_index: usize, parameter: Parameter<1>) -> &mut Self {
1488 let p_gate = ParametricP { parameter };
1489 let gate = Gate::Parametric(Box::new(p_gate), vec![target_index], vec![]);
1490 self.add_gate(gate);
1491 self
1492 }
1493
1494 /// Adds multiple parametric P gates to the circuit builder, each with its own parameter.
1495 ///
1496 /// # Arguments
1497 ///
1498 /// * `target_indices` - A vector of indices of the target qubits.
1499 /// * `parameters` - A vector of parameters of size 1 to be used in the gates.
1500 ///
1501 /// # Warning
1502 ///
1503 /// This method is fallible due to the potential for a mismatch in the number of parameters.
1504 /// If the number of parameters is not equal to the number of target indices, it will return an error.
1505 /// Therefore, the `Result` must be handled appropriately before chaining further operations.
1506 pub fn parametric_p_gates(
1507 &mut self,
1508 target_indices: Vec<usize>,
1509 parameters: Vec<Parameter<1>>,
1510 ) -> Result<&mut Self, Error> {
1511 if target_indices.len() != parameters.len() {
1512 return Err(Error::MismatchedNumberOfParameters {
1513 expected: target_indices.len(),
1514 actual: parameters.len(),
1515 });
1516 }
1517
1518 for (target_index, parameter) in target_indices.into_iter().zip(parameters.into_iter()) {
1519 self.parametric_p_gate(target_index, parameter);
1520 }
1521 Ok(self)
1522 }
1523
1524 /// Adds multiple controlled parametric P gates to the circuit builder, each with its own parameter.
1525 ///
1526 /// # Arguments
1527 ///
1528 /// * `target_indices` - A vector of indices of the target qubits.
1529 /// * `control_indices` - A vector of indices of the control qubits.
1530 /// * `parameters` - A vector of parameters of size 1 to be used in the gates.
1531 ///
1532 /// # Warning
1533 ///
1534 /// This method is fallible due to the potential for a mismatch in the number of parameters.
1535 /// If the number of parameters is not equal to the number of target indices, it will return an error.
1536 /// Therefore, the `Result` must be handled appropriately before chaining further operations.
1537 pub fn parametric_cp_gates(
1538 &mut self,
1539 target_indices: Vec<usize>,
1540 control_indices: Vec<usize>,
1541 parameters: Vec<Parameter<1>>,
1542 ) -> Result<&mut Self, Error> {
1543 if target_indices.len() != parameters.len() {
1544 return Err(Error::MismatchedNumberOfParameters {
1545 expected: target_indices.len(),
1546 actual: parameters.len(),
1547 });
1548 }
1549
1550 for (target_index, parameter) in target_indices.into_iter().zip(parameters.into_iter()) {
1551 let p_gate = ParametricP {
1552 parameter: parameter.clone(),
1553 };
1554 let gate =
1555 Gate::Parametric(Box::new(p_gate), vec![target_index], control_indices.clone());
1556 self.add_gate(gate);
1557 }
1558 Ok(self)
1559 }
1560
1561 // -- MEASUREMENT GATES --
1562
1563 /// Adds a measurement gate to the circuit builder.
1564 ///
1565 /// # Arguments
1566 ///
1567 /// * `basis` - The measurement basis (e.g., computational).
1568 ///
1569 /// * `qubits` - A vector of indices of the qubits to be measured.
1570 pub fn measure_gate(&mut self, basis: MeasurementBasis, qubits: Vec<usize>) -> &mut Self {
1571 let gate: Gate = Gate::Measurement(basis, qubits);
1572 self.add_gate(gate);
1573 self
1574 }
1575}