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(¤t_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(¤t_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}