1use crate::{
2 instruction::{
3 write_expression_parameter_string, write_instruction_block, Expression, GateModifier,
4 Instruction, Qubit,
5 },
6 quil::{Quil, INDENT},
7 validation::identifier::{validate_identifier, IdentifierValidationError},
8};
9
10use super::{write_qubit_parameters, Gate};
11
12pub trait CalibrationSignature {
13 type Signature<'a>
14 where
15 Self: 'a;
16
17 fn signature(&self) -> Self::Signature<'_>;
18 fn has_signature(&self, signature: &Self::Signature<'_>) -> bool;
19}
20
21#[derive(Clone, Debug, Default, PartialEq)]
22pub struct Calibration {
23 pub identifier: CalibrationIdentifier,
24 pub instructions: Vec<Instruction>,
25}
26
27impl Calibration {
28 pub fn new(
30 identifier: CalibrationIdentifier,
31 instructions: Vec<Instruction>,
32 ) -> Result<Self, IdentifierValidationError> {
33 Ok(Self {
34 identifier,
35 instructions,
36 })
37 }
38}
39
40impl CalibrationSignature for Calibration {
41 type Signature<'a> = (&'a str, &'a [Expression], &'a [Qubit]);
42
43 fn signature(&self) -> Self::Signature<'_> {
44 self.identifier.signature()
45 }
46
47 fn has_signature(&self, signature: &Self::Signature<'_>) -> bool {
48 self.identifier.has_signature(signature)
49 }
50}
51
52impl Quil for Calibration {
53 fn write(
54 &self,
55 f: &mut impl std::fmt::Write,
56 fall_back_to_debug: bool,
57 ) -> crate::quil::ToQuilResult<()> {
58 self.identifier.write(f, fall_back_to_debug)?;
59 write!(f, ":")?;
60 for instruction in &self.instructions {
61 write!(f, "\n{INDENT}")?;
62 instruction.write(f, fall_back_to_debug)?;
63 }
64 Ok(())
65 }
66}
67
68#[derive(Clone, Debug, Default, PartialEq)]
70pub struct CalibrationIdentifier {
71 pub modifiers: Vec<GateModifier>,
73
74 pub name: String,
76
77 pub parameters: Vec<Expression>,
79
80 pub qubits: Vec<Qubit>,
82}
83
84impl CalibrationIdentifier {
85 pub fn new(
91 name: String,
92 modifiers: Vec<GateModifier>,
93 parameters: Vec<Expression>,
94 qubits: Vec<Qubit>,
95 ) -> Result<Self, IdentifierValidationError> {
96 validate_identifier(name.as_str())?;
97 Ok(Self {
98 modifiers,
99 name,
100 parameters,
101 qubits,
102 })
103 }
104
105 pub fn matches(&self, gate: &Gate) -> bool {
106 if self.name != gate.name
108 || self.modifiers != gate.modifiers
109 || self.parameters.len() != gate.parameters.len()
110 || self.qubits.len() != gate.qubits.len()
111 {
112 return false;
113 }
114
115 let fixed_qubits_match = self
116 .qubits
117 .iter()
118 .enumerate()
119 .all(|(calibration_index, _)| {
120 match (
121 &self.qubits[calibration_index],
122 &gate.qubits[calibration_index],
123 ) {
124 (Qubit::Placeholder(_), _) | (_, Qubit::Placeholder(_)) => false,
126 (Qubit::Fixed(calibration_fixed_qubit), Qubit::Fixed(gate_fixed_qubit)) => {
128 calibration_fixed_qubit == gate_fixed_qubit
129 }
130 (Qubit::Variable(_), _) => true,
132 (Qubit::Fixed(_), _) => false,
134 }
135 });
136 if !fixed_qubits_match {
137 return false;
138 }
139
140 let fixed_parameters_match =
141 self.parameters
142 .iter()
143 .enumerate()
144 .all(|(calibration_index, _)| {
145 let calibration_parameters =
146 self.parameters[calibration_index].clone().into_simplified();
147 let gate_parameters =
148 gate.parameters[calibration_index].clone().into_simplified();
149 match (calibration_parameters, gate_parameters) {
150 (Expression::Variable(_), _) => true,
152 (calib, gate) => calib == gate,
154 }
155 });
156 fixed_parameters_match
157 }
158}
159
160impl CalibrationSignature for CalibrationIdentifier {
161 type Signature<'a> = (&'a str, &'a [Expression], &'a [Qubit]);
162
163 fn signature(&self) -> Self::Signature<'_> {
164 (
165 self.name.as_str(),
166 self.parameters.as_slice(),
167 self.qubits.as_slice(),
168 )
169 }
170
171 fn has_signature(&self, signature: &Self::Signature<'_>) -> bool {
172 let (name, parameters, qubits) = signature;
173 self.name == *name && self.parameters == *parameters && self.qubits == *qubits
174 }
175}
176
177impl Quil for CalibrationIdentifier {
178 fn write(
179 &self,
180 f: &mut impl std::fmt::Write,
181 fall_back_to_debug: bool,
182 ) -> crate::quil::ToQuilResult<()> {
183 write!(f, "DEFCAL {}", self.name)?;
184 write_expression_parameter_string(f, fall_back_to_debug, &self.parameters)?;
185 write_qubit_parameters(f, fall_back_to_debug, &self.qubits)?;
186 Ok(())
187 }
188}
189
190#[derive(Clone, Debug, PartialEq)]
191pub struct MeasureCalibrationDefinition {
192 pub identifier: MeasureCalibrationIdentifier,
193 pub instructions: Vec<Instruction>,
194}
195
196impl MeasureCalibrationDefinition {
197 pub fn new(identifier: MeasureCalibrationIdentifier, instructions: Vec<Instruction>) -> Self {
198 Self {
199 identifier,
200 instructions,
201 }
202 }
203}
204
205impl CalibrationSignature for MeasureCalibrationDefinition {
206 type Signature<'a> = (Option<&'a Qubit>, &'a str);
207
208 fn signature(&self) -> Self::Signature<'_> {
209 self.identifier.signature()
210 }
211
212 fn has_signature(&self, signature: &Self::Signature<'_>) -> bool {
213 self.identifier.has_signature(signature)
214 }
215}
216
217impl Quil for MeasureCalibrationDefinition {
218 fn write(
219 &self,
220 f: &mut impl std::fmt::Write,
221 fall_back_to_debug: bool,
222 ) -> crate::quil::ToQuilResult<()> {
223 self.identifier.write(f, fall_back_to_debug)?;
224 writeln!(f, ":")?;
225
226 write_instruction_block(f, fall_back_to_debug, &self.instructions)?;
227 writeln!(f)?;
228 Ok(())
229 }
230}
231
232#[derive(Clone, Debug, Default, PartialEq)]
234pub struct MeasureCalibrationIdentifier {
235 pub qubit: Option<Qubit>,
237
238 pub parameter: String,
240}
241
242impl MeasureCalibrationIdentifier {
243 pub fn new(qubit: Option<Qubit>, parameter: String) -> Self {
244 Self { qubit, parameter }
245 }
246}
247
248impl CalibrationSignature for MeasureCalibrationIdentifier {
249 type Signature<'a> = (Option<&'a Qubit>, &'a str);
250
251 fn signature(&self) -> Self::Signature<'_> {
252 (self.qubit.as_ref(), self.parameter.as_str())
253 }
254
255 fn has_signature(&self, signature: &Self::Signature<'_>) -> bool {
256 let (qubit, parameter) = signature;
257 self.qubit.as_ref() == *qubit && self.parameter == *parameter
258 }
259}
260
261impl Quil for MeasureCalibrationIdentifier {
262 fn write(
263 &self,
264 f: &mut impl std::fmt::Write,
265 fall_back_to_debug: bool,
266 ) -> crate::quil::ToQuilResult<()> {
267 write!(f, "DEFCAL MEASURE")?;
268 if let Some(qubit) = &self.qubit {
269 write!(f, " ")?;
270 qubit.write(f, fall_back_to_debug)?;
271 }
272 write!(f, " {}", self.parameter,)?;
273 Ok(())
274 }
275}
276
277#[cfg(test)]
278mod test_measure_calibration_definition {
279 use super::MeasureCalibrationDefinition;
280 use crate::expression::Expression;
281 use crate::instruction::calibration::MeasureCalibrationIdentifier;
282 use crate::instruction::{Gate, Instruction, Qubit};
283 use crate::quil::Quil;
284 use insta::assert_snapshot;
285 use rstest::rstest;
286
287 #[rstest]
288 #[case(
289 "With Fixed Qubit",
290 MeasureCalibrationDefinition {
291 identifier: MeasureCalibrationIdentifier {
292 qubit: Some(Qubit::Fixed(0)),
293 parameter: "theta".to_string(),
294 },
295 instructions: vec![Instruction::Gate(Gate {
296 name: "X".to_string(),
297 parameters: vec![Expression::Variable("theta".to_string())],
298 qubits: vec![Qubit::Fixed(0)],
299 modifiers: vec![],
300
301 })]},
302 )]
303 #[case(
304 "With Variable Qubit",
305 MeasureCalibrationDefinition {
306 identifier: MeasureCalibrationIdentifier {
307 qubit: Some(Qubit::Variable("q".to_string())),
308 parameter: "theta".to_string(),
309 },
310 instructions: vec![Instruction::Gate(Gate {
311 name: "X".to_string(),
312 parameters: vec![Expression::Variable("theta".to_string())],
313 qubits: vec![Qubit::Variable("q".to_string())],
314 modifiers: vec![],
315 })]},
316 )]
317 fn test_display(
318 #[case] description: &str,
319 #[case] measure_cal_def: MeasureCalibrationDefinition,
320 ) {
321 insta::with_settings!({
322 snapshot_suffix => description,
323 }, {
324 assert_snapshot!(measure_cal_def.to_quil_or_debug())
325 })
326 }
327}