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