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