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