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(&current_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(&current_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}