1use super::{
6 gate::{Matrix, QuantumGate},
7 hamiltonian::Hamiltonian,
8 qubit::{LogicalQubit, PhysicalQubit, Qubit},
9};
10use crate::mapping::allocation::Mapping;
11use serde::{Deserialize, Serialize};
12use std::hash::Hash;
13
14#[derive(Debug, Clone, Default, Serialize, Deserialize)]
15pub enum Instruction<Q> {
16 Gate {
17 gate: QuantumGate,
18 target: Q,
19 control: Vec<Q>,
20 },
21 #[default]
22 Identity,
23 Measure {
24 qubits: Vec<Q>,
25 index: usize,
26 },
27 Sample {
28 qubits: Vec<Q>,
29 index: usize,
30 shots: usize,
31 },
32 Dump {
33 qubits: Vec<Q>,
34 index: usize,
35 },
36 ExpValue {
37 hamiltonian: Hamiltonian<Q>,
38 index: usize,
39 },
40 U2Gates {
41 gates: Vec<QuantumGate>,
42 qubit: Q,
43 },
44}
45
46impl<Q> Instruction<Q>
47where
48 Q: Qubit + Eq + Hash + Clone + Copy,
49{
50 pub(crate) fn qubits(&self) -> impl Iterator<Item = &Q> {
51 use genawaiter::{rc::gen, yield_};
52 gen!({
53 match self {
54 Instruction::Gate {
55 target, control, ..
56 } => {
57 yield_!(target);
58 for qubit in control {
59 yield_!(qubit);
60 }
61 }
62 Instruction::Measure { qubits, .. }
63 | Instruction::Sample { qubits, .. }
64 | Instruction::Dump { qubits, .. } => {
65 for qubit in qubits {
66 yield_!(qubit);
67 }
68 }
69 Instruction::ExpValue { hamiltonian, .. } => {
70 for qubit in hamiltonian.qubits() {
71 yield_!(qubit);
72 }
73 }
74 _ => {}
75 }
76 })
77 .into_iter()
78 }
79
80 pub(crate) fn is_ctrl_gate(&self) -> bool {
81 match self {
82 Instruction::Gate { control, .. } => !control.is_empty(),
83 _ => false,
84 }
85 }
86 pub(crate) fn affect_one_qubit(&self) -> bool {
87 match self {
88 Instruction::Gate { control, .. } => control.is_empty(),
89 Instruction::Measure { qubits, .. }
90 | Instruction::Sample { qubits, .. }
91 | Instruction::Dump { qubits, .. } => qubits.len() == 1,
92 Instruction::Identity => true,
93 Instruction::ExpValue { hamiltonian, .. } => {
94 let mut qubits = hamiltonian.qubits();
95 qubits.next().is_some() && qubits.next().is_none()
96 }
97 Instruction::U2Gates { .. } => panic!("this instructions is restrict"),
98 }
99 }
100
101 pub(crate) fn one_qubit_gate(&self) -> bool {
102 match self {
103 Instruction::Gate { control, .. } => control.is_empty(),
104 Instruction::Identity => true,
105 _ => false,
106 }
107 }
108
109 pub(crate) fn matrix(&self) -> Matrix {
110 match self {
111 Instruction::Gate { gate, .. } => gate.matrix(),
112 Instruction::Identity => QuantumGate::Phase(0.0.into()).matrix(),
113 _ => panic!("matrix available only for gate instruction"),
114 }
115 }
116
117 pub(crate) fn to_usize_qubit(&self) -> Instruction<usize> {
118 match self {
119 Instruction::Gate {
120 gate,
121 target,
122 control,
123 } => Instruction::Gate {
124 gate: *gate,
125 target: target.index(),
126 control: control.iter().map(|c| c.index()).collect(),
127 },
128 Instruction::Identity => Instruction::Identity,
129 Instruction::Measure { qubits, index } => Instruction::Measure {
130 qubits: qubits.iter().map(|q| q.index()).collect(),
131 index: *index,
132 },
133 Instruction::Sample {
134 qubits,
135 index,
136 shots,
137 } => Instruction::Sample {
138 qubits: qubits.iter().map(|q| q.index()).collect(),
139 index: *index,
140 shots: *shots,
141 },
142 Instruction::Dump { qubits, index } => Instruction::Dump {
143 qubits: qubits.iter().map(|q| q.index()).collect(),
144 index: *index,
145 },
146 Instruction::ExpValue { hamiltonian, index } => Instruction::ExpValue {
147 hamiltonian: hamiltonian.to_usize_qubit(),
148 index: *index,
149 },
150 Instruction::U2Gates { .. } => {
151 panic!("U2Gates instruction should not be present at this point.")
152 }
153 }
154 }
155}
156
157impl Instruction<LogicalQubit> {
158 pub(crate) fn map_qubits(&self, mapping: &Mapping) -> Instruction<PhysicalQubit> {
159 match self {
160 Instruction::Gate {
161 gate,
162 target,
163 control,
164 } => Instruction::Gate {
165 gate: *gate,
166 target: *mapping.get_by_left(target).unwrap(),
167 control: control
168 .iter()
169 .map(|qubit| *mapping.get_by_left(qubit).unwrap())
170 .collect(),
171 },
172 Instruction::Measure { qubits, index } => Instruction::Measure {
173 qubits: qubits
174 .iter()
175 .map(|qubit| *mapping.get_by_left(qubit).unwrap())
176 .collect(),
177 index: *index,
178 },
179 Instruction::Sample {
180 qubits,
181 index,
182 shots,
183 } => Instruction::Sample {
184 qubits: qubits
185 .iter()
186 .map(|qubit| *mapping.get_by_left(qubit).unwrap())
187 .collect(),
188 index: *index,
189 shots: *shots,
190 },
191 Instruction::Dump { qubits, index } => Instruction::Dump {
192 qubits: qubits
193 .iter()
194 .map(|qubit| *mapping.get_by_left(qubit).unwrap())
195 .collect(),
196 index: *index,
197 },
198 Instruction::ExpValue { hamiltonian, index } => Instruction::ExpValue {
199 hamiltonian: hamiltonian.map_qubits(mapping),
200 index: *index,
201 },
202 _ => Default::default(),
203 }
204 }
205
206 pub(crate) fn replace_qubit(&mut self, old: LogicalQubit, new: LogicalQubit) {
207 match self {
208 Instruction::Gate {
209 target, control, ..
210 } => {
211 if *target == old {
212 *target = new;
213 }
214 for qubit in control {
215 if *qubit == old {
216 *qubit = new;
217 break;
218 }
219 }
220 }
221 Instruction::Identity => {}
222 _ => {
223 panic!("Qubit replace should only happens in gate instruction")
224 }
225 }
226 }
227}