1use std::collections::HashSet;
16use std::fmt;
17
18use nom_locate::LocatedSpan;
19
20use crate::expression::Expression;
21use crate::parser::lex;
22use crate::parser::parse_instructions;
23use crate::program::frame::{FrameMatchCondition, FrameMatchConditions};
24use crate::program::ProgramError;
25use crate::program::{MatchedFrames, MemoryAccesses};
26use crate::quil::{write_join_quil, Quil, ToQuilResult};
27use crate::Program;
28
29mod calibration;
30mod circuit;
31mod classical;
32mod control_flow;
33mod declaration;
34mod extern_call;
35mod frame;
36mod gate;
37mod measurement;
38mod pragma;
39mod qubit;
40mod reset;
41mod timing;
42mod waveform;
43
44pub use self::calibration::{
45 Calibration, CalibrationIdentifier, CalibrationSignature, MeasureCalibrationDefinition,
46 MeasureCalibrationIdentifier,
47};
48pub use self::circuit::CircuitDefinition;
49pub use self::classical::{
50 Arithmetic, ArithmeticOperand, ArithmeticOperator, BinaryLogic, BinaryOperand, BinaryOperator,
51 Comparison, ComparisonOperand, ComparisonOperator, Convert, Exchange, Move, UnaryLogic,
52 UnaryOperator,
53};
54pub use self::control_flow::{Jump, JumpUnless, JumpWhen, Label, Target, TargetPlaceholder};
55pub use self::declaration::{
56 Declaration, Load, MemoryReference, Offset, ScalarType, Sharing, Store, Vector,
57};
58pub use self::extern_call::*;
59pub use self::frame::{
60 AttributeValue, Capture, FrameAttributes, FrameDefinition, FrameIdentifier, Pulse, RawCapture,
61 SetFrequency, SetPhase, SetScale, ShiftFrequency, ShiftPhase, SwapPhases,
62};
63pub use self::gate::{
64 Gate, GateDefinition, GateError, GateModifier, GateSpecification, GateType, Matrix, PauliGate,
65 PauliSum, PauliTerm,
66};
67pub use self::measurement::Measurement;
68pub use self::pragma::{Include, Pragma, PragmaArgument, RESERVED_PRAGMA_EXTERN};
69pub use self::qubit::{Qubit, QubitPlaceholder};
70pub use self::reset::Reset;
71pub use self::timing::{Delay, Fence};
72pub use self::waveform::{Waveform, WaveformDefinition, WaveformInvocation, WaveformParameters};
73
74#[derive(Clone, Debug, thiserror::Error, PartialEq, Eq)]
75pub enum ValidationError {
76 #[error(transparent)]
77 GateError(#[from] GateError),
78}
79
80#[derive(Clone, Debug, PartialEq)]
81pub enum Instruction {
82 Arithmetic(Arithmetic),
83 BinaryLogic(BinaryLogic),
84 CalibrationDefinition(Calibration),
85 Call(Call),
86 Capture(Capture),
87 CircuitDefinition(CircuitDefinition),
88 Convert(Convert),
89 Comparison(Comparison),
90 Declaration(Declaration),
91 Delay(Delay),
92 Exchange(Exchange),
93 Fence(Fence),
94 FrameDefinition(FrameDefinition),
95 Gate(Gate),
96 GateDefinition(GateDefinition),
97 Halt,
98 Include(Include),
99 Jump(Jump),
100 JumpUnless(JumpUnless),
101 JumpWhen(JumpWhen),
102 Label(Label),
103 Load(Load),
104 MeasureCalibrationDefinition(MeasureCalibrationDefinition),
105 Measurement(Measurement),
106 Move(Move),
107 Nop,
108 Pragma(Pragma),
109 Pulse(Pulse),
110 RawCapture(RawCapture),
111 Reset(Reset),
112 SetFrequency(SetFrequency),
113 SetPhase(SetPhase),
114 SetScale(SetScale),
115 ShiftFrequency(ShiftFrequency),
116 ShiftPhase(ShiftPhase),
117 Store(Store),
118 SwapPhases(SwapPhases),
119 UnaryLogic(UnaryLogic),
120 WaveformDefinition(WaveformDefinition),
121 Wait,
122}
123
124#[derive(Clone, Copy, Debug)]
125pub enum InstructionRole {
126 ClassicalCompute,
127 ControlFlow,
128 ProgramComposition,
129 RFControl,
130}
131
132impl From<&Instruction> for InstructionRole {
133 fn from(instruction: &Instruction) -> Self {
134 match instruction {
135 Instruction::CalibrationDefinition(_)
136 | Instruction::CircuitDefinition(_)
137 | Instruction::Declaration(_)
138 | Instruction::FrameDefinition(_)
139 | Instruction::Gate(_)
140 | Instruction::GateDefinition(_)
141 | Instruction::Include(_)
142 | Instruction::Label(_)
143 | Instruction::MeasureCalibrationDefinition(_)
144 | Instruction::Measurement(_)
145 | Instruction::WaveformDefinition(_) => InstructionRole::ProgramComposition,
146 Instruction::Reset(_)
147 | Instruction::Capture(_)
148 | Instruction::Delay(_)
149 | Instruction::Fence(_)
150 | Instruction::Pulse(_)
151 | Instruction::RawCapture(_)
152 | Instruction::SetFrequency(_)
153 | Instruction::SetPhase(_)
154 | Instruction::SetScale(_)
155 | Instruction::ShiftFrequency(_)
156 | Instruction::ShiftPhase(_)
157 | Instruction::SwapPhases(_) => InstructionRole::RFControl,
158 Instruction::Arithmetic(_)
159 | Instruction::Call(_)
160 | Instruction::Comparison(_)
161 | Instruction::Convert(_)
162 | Instruction::BinaryLogic(_)
163 | Instruction::UnaryLogic(_)
164 | Instruction::Move(_)
165 | Instruction::Exchange(_)
166 | Instruction::Load(_)
167 | Instruction::Nop
168 | Instruction::Pragma(_)
169 | Instruction::Store(_) => InstructionRole::ClassicalCompute,
170 Instruction::Halt
171 | Instruction::Jump(_)
172 | Instruction::JumpWhen(_)
173 | Instruction::JumpUnless(_)
174 | Instruction::Wait => InstructionRole::ControlFlow,
175 }
176 }
177}
178
179pub fn write_instruction_block<'i, I, Q>(
180 f: &mut impl std::fmt::Write,
181 fall_back_to_debug: bool,
182 values: I,
183) -> crate::quil::ToQuilResult<()>
184where
185 I: IntoIterator<Item = &'i Q>,
186 Q: Quil + 'i,
187{
188 write_join_quil(f, fall_back_to_debug, values, "\n", "\t")
189}
190
191pub(crate) fn write_join(
192 f: &mut impl std::fmt::Write,
193 values: &[impl std::fmt::Display],
194 separator: &str,
195 prefix: &str,
196) -> std::fmt::Result {
197 let mut iter = values.iter();
198 if let Some(first) = iter.next() {
199 write!(f, "{prefix}{first}")?;
200
201 for value in iter {
202 write!(f, "{separator}{prefix}{value}")?;
203 }
204 }
205 Ok(())
206}
207
208pub fn format_integer_vector(values: &[u64]) -> String {
209 values
210 .iter()
211 .map(|q| format!("{q}"))
212 .collect::<Vec<String>>()
213 .join(" ")
214}
215
216fn write_qubits(
218 f: &mut impl std::fmt::Write,
219 fall_back_to_debug: bool,
220 qubits: &[Qubit],
221) -> crate::quil::ToQuilResult<()> {
222 for qubit in qubits {
223 write!(f, " ")?;
224 qubit.write(f, fall_back_to_debug)?;
225 }
226 Ok(())
227}
228
229fn write_qubit_parameters(
231 f: &mut impl std::fmt::Write,
232 fall_back_to_debug: bool,
233 qubits: &[Qubit],
234) -> ToQuilResult<()> {
235 for qubit in qubits.iter() {
236 write!(f, " ")?;
237 qubit.write(f, fall_back_to_debug)?;
238 }
239 Ok(())
240}
241
242fn write_expression_parameter_string(
243 f: &mut impl std::fmt::Write,
244 fall_back_to_debug: bool,
245 parameters: &[Expression],
246) -> crate::quil::ToQuilResult<()> {
247 if parameters.is_empty() {
248 return Ok(());
249 }
250
251 write!(f, "(")?;
252 write_join_quil(f, fall_back_to_debug, parameters, ", ", "")?;
253 write!(f, ")")?;
254 Ok(())
255}
256
257fn write_parameter_string(f: &mut impl std::fmt::Write, parameters: &[String]) -> fmt::Result {
258 if parameters.is_empty() {
259 return Ok(());
260 }
261
262 write!(f, "(")?;
263 write_join(f, parameters, ", ", "%")?;
264 write!(f, ")")
265}
266
267impl Quil for Instruction {
268 fn write(
269 &self,
270 f: &mut impl std::fmt::Write,
271 fall_back_to_debug: bool,
272 ) -> Result<(), crate::quil::ToQuilError> {
273 match self {
274 Instruction::Arithmetic(arithmetic) => arithmetic.write(f, fall_back_to_debug),
275 Instruction::CalibrationDefinition(calibration) => {
276 calibration.write(f, fall_back_to_debug)
277 }
278 Instruction::Call(call) => call.write(f, fall_back_to_debug),
279 Instruction::Capture(capture) => capture.write(f, fall_back_to_debug),
280 Instruction::CircuitDefinition(circuit) => circuit.write(f, fall_back_to_debug),
281 Instruction::Convert(convert) => convert.write(f, fall_back_to_debug),
282 Instruction::Declaration(declaration) => declaration.write(f, fall_back_to_debug),
283 Instruction::Delay(delay) => delay.write(f, fall_back_to_debug),
284 Instruction::Fence(fence) => fence.write(f, fall_back_to_debug),
285 Instruction::FrameDefinition(frame_definition) => {
286 frame_definition.write(f, fall_back_to_debug)
287 }
288 Instruction::Gate(gate) => gate.write(f, fall_back_to_debug),
289 Instruction::GateDefinition(gate_definition) => {
290 gate_definition.write(f, fall_back_to_debug)
291 }
292 Instruction::Include(include) => include.write(f, fall_back_to_debug),
293 Instruction::MeasureCalibrationDefinition(measure_calibration) => {
294 measure_calibration.write(f, fall_back_to_debug)
295 }
296 Instruction::Measurement(measurement) => measurement.write(f, fall_back_to_debug),
297 Instruction::Move(r#move) => r#move.write(f, fall_back_to_debug),
298 Instruction::Exchange(exchange) => exchange.write(f, fall_back_to_debug),
299 Instruction::Load(load) => load.write(f, fall_back_to_debug),
300 Instruction::Store(store) => store.write(f, fall_back_to_debug),
301 Instruction::Pulse(pulse) => pulse.write(f, fall_back_to_debug),
302 Instruction::Pragma(pragma) => pragma.write(f, fall_back_to_debug),
303 Instruction::RawCapture(raw_capture) => raw_capture.write(f, fall_back_to_debug),
304 Instruction::Reset(reset) => reset.write(f, fall_back_to_debug),
305 Instruction::SetFrequency(set_frequency) => set_frequency.write(f, fall_back_to_debug),
306 Instruction::SetPhase(set_phase) => set_phase.write(f, fall_back_to_debug),
307 Instruction::SetScale(set_scale) => set_scale.write(f, fall_back_to_debug),
308 Instruction::ShiftFrequency(shift_frequency) => {
309 shift_frequency.write(f, fall_back_to_debug)
310 }
311 Instruction::ShiftPhase(shift_phase) => shift_phase.write(f, fall_back_to_debug),
312 Instruction::SwapPhases(swap_phases) => swap_phases.write(f, fall_back_to_debug),
313 Instruction::WaveformDefinition(waveform_definition) => {
314 waveform_definition.write(f, fall_back_to_debug)
315 }
316 Instruction::Halt => write!(f, "HALT").map_err(Into::into),
317 Instruction::Nop => write!(f, "NOP").map_err(Into::into),
318 Instruction::Wait => write!(f, "WAIT").map_err(Into::into),
319 Instruction::Jump(jump) => jump.write(f, fall_back_to_debug),
320 Instruction::JumpUnless(jump) => jump.write(f, fall_back_to_debug),
321 Instruction::JumpWhen(jump) => jump.write(f, fall_back_to_debug),
322 Instruction::Label(label) => label.write(f, fall_back_to_debug),
323 Instruction::Comparison(comparison) => comparison.write(f, fall_back_to_debug),
324 Instruction::BinaryLogic(binary_logic) => binary_logic.write(f, fall_back_to_debug),
325 Instruction::UnaryLogic(unary_logic) => unary_logic.write(f, fall_back_to_debug),
326 }
327 }
328}
329
330pub(crate) struct QuotedString<S>(pub(crate) S);
331
332impl<S> fmt::Display for QuotedString<S>
333where
334 S: AsRef<str>,
335{
336 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
337 write!(f, "\"")?;
338 for c in self.0.as_ref().chars() {
339 match c {
340 '"' => write!(f, "\\\"")?,
341 '\\' => write!(f, "\\\\")?,
342 c => write!(f, "{}", c)?,
343 }
344 }
345 write!(f, "\"")
346 }
347}
348
349#[cfg(test)]
350mod test_instruction_display {
351 use crate::{instruction::PragmaArgument, quil::Quil};
352
353 use super::{Instruction, Pragma};
354
355 #[test]
356 fn pragma() {
357 assert_eq!(
358 Instruction::Pragma(Pragma {
359 name: String::from("INITIAL_REWIRING"),
360 arguments: vec![],
361 data: Some(String::from("PARTIAL")),
362 })
363 .to_quil()
364 .unwrap(),
365 "PRAGMA INITIAL_REWIRING \"PARTIAL\""
366 );
367 assert_eq!(
368 Instruction::Pragma(Pragma {
369 name: String::from("LOAD-MEMORY"),
370 arguments: vec![PragmaArgument::Identifier("q0".to_string())],
371 data: Some(String::from("addr")),
372 })
373 .to_quil()
374 .unwrap(),
375 "PRAGMA LOAD-MEMORY q0 \"addr\""
376 );
377 assert_eq!(
378 Instruction::Pragma(Pragma {
379 name: String::from("PRESERVE_BLOCK"),
380 arguments: vec![],
381 data: None,
382 })
383 .to_quil()
384 .unwrap(),
385 "PRAGMA PRESERVE_BLOCK"
386 );
387 }
388}
389
390impl Instruction {
391 pub fn apply_to_expressions(&mut self, mut closure: impl FnMut(&mut Expression)) {
412 match self {
413 Instruction::CalibrationDefinition(Calibration {
414 identifier: CalibrationIdentifier { parameters, .. },
415 ..
416 })
417 | Instruction::Gate(Gate { parameters, .. }) => {
418 parameters.iter_mut().for_each(closure);
419 }
420 Instruction::Capture(Capture { waveform, .. })
421 | Instruction::Pulse(Pulse { waveform, .. }) => {
422 waveform.parameters.values_mut().for_each(closure);
423 }
424 Instruction::Delay(Delay { duration, .. })
425 | Instruction::RawCapture(RawCapture { duration, .. }) => {
426 closure(duration);
427 }
428 Instruction::FrameDefinition(FrameDefinition { attributes, .. }) => {
429 for value in attributes.values_mut() {
430 if let AttributeValue::Expression(expression) = value {
431 closure(expression);
432 }
433 }
434 }
435 Instruction::SetFrequency(SetFrequency {
436 frequency: expression,
437 ..
438 })
439 | Instruction::SetPhase(SetPhase {
440 phase: expression, ..
441 })
442 | Instruction::SetScale(SetScale {
443 scale: expression, ..
444 })
445 | Instruction::ShiftFrequency(ShiftFrequency {
446 frequency: expression,
447 ..
448 })
449 | Instruction::ShiftPhase(ShiftPhase {
450 phase: expression, ..
451 }) => {
452 closure(expression);
453 }
454 Instruction::WaveformDefinition(WaveformDefinition { definition, .. }) => {
455 definition.matrix.iter_mut().for_each(closure);
456 }
457 Instruction::GateDefinition(GateDefinition {
458 specification: GateSpecification::Matrix(matrix),
459 ..
460 }) => {
461 for row in matrix {
462 for cell in row {
463 closure(cell);
464 }
465 }
466 }
467 _ => {}
468 }
469 }
470
471 pub(crate) fn get_frame_match_condition<'a>(
472 &'a self,
473 qubits_available: &'a HashSet<Qubit>,
474 ) -> Option<FrameMatchConditions<'a>> {
475 match self {
476 Instruction::Pulse(Pulse {
477 blocking, frame, ..
478 })
479 | Instruction::Capture(Capture {
480 blocking, frame, ..
481 })
482 | Instruction::RawCapture(RawCapture {
483 blocking, frame, ..
484 }) => Some(FrameMatchConditions {
485 blocked: blocking
486 .then(|| FrameMatchCondition::AnyOfQubits(frame.qubits.iter().collect())),
487 used: Some(FrameMatchCondition::Specific(frame)),
488 }),
489 Instruction::Delay(Delay {
490 frame_names,
491 qubits,
492 ..
493 }) => Some(FrameMatchConditions {
494 used: Some(if frame_names.is_empty() {
495 FrameMatchCondition::ExactQubits(qubits.iter().collect())
496 } else {
497 FrameMatchCondition::And(vec![
498 FrameMatchCondition::ExactQubits(qubits.iter().collect()),
499 FrameMatchCondition::AnyOfNames(
500 frame_names.iter().map(String::as_str).collect(),
501 ),
502 ])
503 }),
504 blocked: None,
505 }),
506 Instruction::Fence(Fence { qubits }) => Some(FrameMatchConditions {
507 used: None,
508 blocked: Some(if qubits.is_empty() {
509 FrameMatchCondition::All
510 } else {
511 FrameMatchCondition::AnyOfQubits(qubits.iter().collect())
512 }),
513 }),
514 Instruction::Reset(Reset { qubit }) => {
515 let qubits = match qubit {
516 Some(qubit) => {
517 let mut set = HashSet::new();
518 set.insert(qubit);
519 set
520 }
521 None => qubits_available.iter().collect(),
522 };
523
524 Some(FrameMatchConditions {
525 used: Some(FrameMatchCondition::ExactQubits(qubits.clone())),
526 blocked: Some(FrameMatchCondition::AnyOfQubits(qubits)),
527 })
528 }
529 Instruction::SetFrequency(SetFrequency { frame, .. })
530 | Instruction::SetPhase(SetPhase { frame, .. })
531 | Instruction::SetScale(SetScale { frame, .. })
532 | Instruction::ShiftFrequency(ShiftFrequency { frame, .. })
533 | Instruction::ShiftPhase(ShiftPhase { frame, .. }) => Some(FrameMatchConditions {
534 used: Some(FrameMatchCondition::Specific(frame)),
535 blocked: None,
536 }),
537 Instruction::SwapPhases(SwapPhases { frame_1, frame_2 }) => {
538 Some(FrameMatchConditions {
539 used: Some(FrameMatchCondition::Or(vec![
540 FrameMatchCondition::Specific(frame_1),
541 FrameMatchCondition::Specific(frame_2),
542 ])),
543 blocked: None,
544 })
545 }
546 Instruction::Arithmetic(_)
547 | Instruction::BinaryLogic(_)
548 | Instruction::CalibrationDefinition(_)
549 | Instruction::Call(_)
550 | Instruction::CircuitDefinition(_)
551 | Instruction::Comparison(_)
552 | Instruction::Convert(_)
553 | Instruction::Declaration(_)
554 | Instruction::Exchange(_)
555 | Instruction::FrameDefinition(_)
556 | Instruction::Gate(_)
557 | Instruction::GateDefinition(_)
558 | Instruction::Halt
559 | Instruction::Include(_)
560 | Instruction::Jump(_)
561 | Instruction::JumpUnless(_)
562 | Instruction::JumpWhen(_)
563 | Instruction::Label(_)
564 | Instruction::Load(_)
565 | Instruction::MeasureCalibrationDefinition(_)
566 | Instruction::Measurement(_)
567 | Instruction::Move(_)
568 | Instruction::Nop
569 | Instruction::Pragma(_)
570 | Instruction::Store(_)
571 | Instruction::UnaryLogic(_)
572 | Instruction::WaveformDefinition(_)
573 | Instruction::Wait => None,
574 }
575 }
576
577 #[allow(dead_code)]
579 pub fn get_qubits(&self) -> Vec<&Qubit> {
580 match self {
581 Instruction::Gate(gate) => gate.qubits.iter().collect(),
582 Instruction::Measurement(measurement) => vec![&measurement.qubit],
583 Instruction::Reset(reset) => match &reset.qubit {
584 Some(qubit) => vec![qubit],
585 None => vec![],
586 },
587 Instruction::Delay(delay) => delay.qubits.iter().collect(),
588 Instruction::Fence(fence) => fence.qubits.iter().collect(),
589 Instruction::Capture(capture) => capture.frame.qubits.iter().collect(),
590 Instruction::Pulse(pulse) => pulse.frame.qubits.iter().collect(),
591 Instruction::RawCapture(raw_capture) => raw_capture.frame.qubits.iter().collect(),
592 _ => vec![],
593 }
594 }
595
596 pub fn get_qubits_mut(&mut self) -> Vec<&mut Qubit> {
598 match self {
599 Instruction::Gate(gate) => gate.qubits.iter_mut().collect(),
600 Instruction::CalibrationDefinition(calibration) => calibration
601 .identifier
602 .qubits
603 .iter_mut()
604 .chain(
605 calibration
606 .instructions
607 .iter_mut()
608 .flat_map(|inst| inst.get_qubits_mut()),
609 )
610 .collect(),
611 Instruction::MeasureCalibrationDefinition(measurement) => measurement
612 .identifier
613 .qubit
614 .iter_mut()
615 .chain(
616 measurement
617 .instructions
618 .iter_mut()
619 .flat_map(|inst| inst.get_qubits_mut()),
620 )
621 .collect(),
622 Instruction::Measurement(measurement) => vec![&mut measurement.qubit],
623 Instruction::Reset(reset) => match &mut reset.qubit {
624 Some(qubit) => vec![qubit],
625 None => vec![],
626 },
627 Instruction::Delay(delay) => delay.qubits.iter_mut().collect(),
628 Instruction::Fence(fence) => fence.qubits.iter_mut().collect(),
629 Instruction::Capture(capture) => capture.frame.qubits.iter_mut().collect(),
630 Instruction::Pulse(pulse) => pulse.frame.qubits.iter_mut().collect(),
631 Instruction::RawCapture(raw_capture) => raw_capture.frame.qubits.iter_mut().collect(),
632 _ => vec![],
633 }
634 }
635
636 pub(crate) fn get_waveform_invocation(&self) -> Option<&WaveformInvocation> {
641 match self {
642 Instruction::Capture(Capture { waveform, .. }) => Some(waveform),
643 Instruction::Pulse(Pulse { waveform, .. }) => Some(waveform),
644 _ => None,
645 }
646 }
647
648 #[cfg(test)]
649 pub(crate) fn parse(input: &str) -> Result<Self, String> {
652 use crate::parser::instruction::parse_instruction;
653
654 let input = LocatedSpan::new(input);
655 let lexed = lex(input).map_err(|err| err.to_string())?;
656 let (_, instruction) =
657 nom::combinator::all_consuming(parse_instruction)(&lexed).map_err(|e| e.to_string())?;
658 Ok(instruction)
659 }
660
661 pub fn is_quil_t(&self) -> bool {
663 match self {
664 Instruction::Capture(_)
665 | Instruction::CalibrationDefinition(_)
666 | Instruction::Delay(_)
667 | Instruction::Fence(_)
668 | Instruction::FrameDefinition(_)
669 | Instruction::MeasureCalibrationDefinition(_)
670 | Instruction::Pulse(_)
671 | Instruction::RawCapture(_)
672 | Instruction::SetFrequency(_)
673 | Instruction::SetPhase(_)
674 | Instruction::SetScale(_)
675 | Instruction::ShiftFrequency(_)
676 | Instruction::ShiftPhase(_)
677 | Instruction::SwapPhases(_)
678 | Instruction::WaveformDefinition(_) => true,
679 Instruction::Arithmetic(_)
680 | Instruction::BinaryLogic(_)
681 | Instruction::Call(_)
682 | Instruction::CircuitDefinition(_)
683 | Instruction::Convert(_)
684 | Instruction::Comparison(_)
685 | Instruction::Declaration(_)
686 | Instruction::Exchange(_)
687 | Instruction::Gate(_)
688 | Instruction::GateDefinition(_)
689 | Instruction::Halt
690 | Instruction::Include(_)
691 | Instruction::Jump(_)
692 | Instruction::JumpUnless(_)
693 | Instruction::JumpWhen(_)
694 | Instruction::Label(_)
695 | Instruction::Load(_)
696 | Instruction::Measurement(_)
697 | Instruction::Move(_)
698 | Instruction::Nop
699 | Instruction::Pragma(_)
700 | Instruction::Reset(_)
701 | Instruction::Store(_)
702 | Instruction::Wait
703 | Instruction::UnaryLogic(_) => false,
704 }
705 }
706
707 pub fn is_scheduled(&self) -> bool {
711 match self {
712 Instruction::Capture(_)
713 | Instruction::Delay(_)
714 | Instruction::Fence(_)
715 | Instruction::Pulse(_)
716 | Instruction::RawCapture(_)
717 | Instruction::SetFrequency(_)
718 | Instruction::SetPhase(_)
719 | Instruction::SetScale(_)
720 | Instruction::ShiftFrequency(_)
721 | Instruction::ShiftPhase(_)
722 | Instruction::SwapPhases(_)
723 | Instruction::Wait => true,
724 Instruction::Arithmetic(_)
725 | Instruction::BinaryLogic(_)
726 | Instruction::CalibrationDefinition(_)
727 | Instruction::Call(_)
728 | Instruction::CircuitDefinition(_)
729 | Instruction::Convert(_)
730 | Instruction::Comparison(_)
731 | Instruction::Declaration(_)
732 | Instruction::Exchange(_)
733 | Instruction::FrameDefinition(_)
734 | Instruction::Gate(_)
735 | Instruction::GateDefinition(_)
736 | Instruction::Halt
737 | Instruction::Include(_)
738 | Instruction::Jump(_)
739 | Instruction::JumpUnless(_)
740 | Instruction::JumpWhen(_)
741 | Instruction::Label(_)
742 | Instruction::Load(_)
743 | Instruction::MeasureCalibrationDefinition(_)
744 | Instruction::Measurement(_)
745 | Instruction::Move(_)
746 | Instruction::Nop
747 | Instruction::Pragma(_)
748 | Instruction::Reset(_)
749 | Instruction::Store(_)
750 | Instruction::UnaryLogic(_)
751 | Instruction::WaveformDefinition(_) => false,
752 }
753 }
754
755 pub(crate) fn resolve_placeholders<TR, QR>(&mut self, target_resolver: TR, qubit_resolver: QR)
756 where
757 TR: Fn(&TargetPlaceholder) -> Option<String>,
758 QR: Fn(&QubitPlaceholder) -> Option<u64>,
759 {
760 match self {
761 Instruction::Label(label) => {
762 label.target.resolve_placeholder(target_resolver);
763 }
764 Instruction::Jump(jump) => {
765 jump.target.resolve_placeholder(target_resolver);
766 }
767 Instruction::JumpWhen(jump_when) => {
768 jump_when.target.resolve_placeholder(target_resolver);
769 }
770 Instruction::JumpUnless(jump_unless) => {
771 jump_unless.target.resolve_placeholder(target_resolver);
772 }
773 other => {
774 for qubit in other.get_qubits_mut() {
775 qubit.resolve_placeholder(&qubit_resolver);
776 }
777 }
778 }
779 }
780}
781
782#[derive(Debug, thiserror::Error)]
783pub enum ParseInstructionError {
784 #[error("Failed to parse instruction: {0}")]
785 Parse(String),
786 #[error("Expected to parse exactly one instruction but got {0}")]
787 ZeroOrMany(usize),
788}
789
790impl std::str::FromStr for Instruction {
791 type Err = ParseInstructionError;
792
793 fn from_str(s: &str) -> Result<Self, Self::Err> {
794 let input = LocatedSpan::new(s);
795 let lexed = lex(input).map_err(|e| ParseInstructionError::Parse(e.to_string()))?;
796 let instructions =
797 parse_instructions(&lexed).map_err(|e| ParseInstructionError::Parse(e.to_string()))?;
798 if instructions.1.len() != 1 {
799 return Err(ParseInstructionError::ZeroOrMany(instructions.1.len()));
800 }
801 Ok(instructions.1[0].to_owned())
802 }
803}
804
805pub trait GetIsScheduledFnMut: FnMut(&Instruction) -> Option<bool> {}
808impl<F> GetIsScheduledFnMut for F where F: FnMut(&Instruction) -> Option<bool> {}
809
810pub trait GetRoleForInstructionFnMut: FnMut(&Instruction) -> Option<InstructionRole> {}
813impl<F> GetRoleForInstructionFnMut for F where F: FnMut(&Instruction) -> Option<InstructionRole> {}
814
815pub trait GetMatchingFramesFnMut:
818 for<'a> FnMut(&'a Instruction, &'a Program) -> Option<Option<MatchedFrames<'a>>>
819{
820}
821impl<F> GetMatchingFramesFnMut for F where
822 F: for<'a> FnMut(&'a Instruction, &'a Program) -> Option<Option<MatchedFrames<'a>>>
823{
824}
825
826pub trait GetMemoryAccessesFnMut: FnMut(&Instruction) -> Option<MemoryAccesses> {}
829impl<F> GetMemoryAccessesFnMut for F where F: FnMut(&Instruction) -> Option<MemoryAccesses> {}
830
831#[derive(Default)]
836pub struct InstructionHandler {
837 get_is_scheduled: Option<Box<dyn GetIsScheduledFnMut>>,
838 get_role_for_instruction: Option<Box<dyn GetRoleForInstructionFnMut>>,
839 get_matching_frames: Option<Box<dyn GetMatchingFramesFnMut>>,
840 get_memory_accesses: Option<Box<dyn GetMemoryAccessesFnMut>>,
841}
842
843impl InstructionHandler {
844 pub fn set_is_scheduled<F>(mut self, f: F) -> Self
849 where
850 F: GetIsScheduledFnMut + 'static,
851 {
852 self.get_is_scheduled = Some(Box::new(f));
853 self
854 }
855
856 pub fn set_role_for_instruction<F>(mut self, f: F) -> Self
861 where
862 F: GetRoleForInstructionFnMut + 'static,
863 {
864 self.get_role_for_instruction = Some(Box::new(f));
865 self
866 }
867
868 pub fn set_matching_frames<F>(mut self, f: F) -> Self
873 where
874 F: GetMatchingFramesFnMut + 'static,
875 {
876 self.get_matching_frames = Some(Box::new(f));
877 self
878 }
879
880 pub fn set_memory_accesses<F>(mut self, f: F) -> Self
885 where
886 F: GetMemoryAccessesFnMut + 'static,
887 {
888 self.get_memory_accesses = Some(Box::new(f));
889 self
890 }
891
892 pub fn is_scheduled(&mut self, instruction: &Instruction) -> bool {
898 self.get_is_scheduled
899 .as_mut()
900 .and_then(|f| f(instruction))
901 .unwrap_or_else(|| instruction.is_scheduled())
902 }
903
904 pub fn role_for_instruction(&mut self, instruction: &Instruction) -> InstructionRole {
910 self.get_role_for_instruction
911 .as_mut()
912 .and_then(|f| f(instruction))
913 .unwrap_or_else(|| InstructionRole::from(instruction))
914 }
915
916 pub fn matching_frames<'a>(
922 &mut self,
923 instruction: &'a Instruction,
924 program: &'a Program,
925 ) -> Option<MatchedFrames<'a>> {
926 self.get_matching_frames
927 .as_mut()
928 .and_then(|f| f(instruction, program))
929 .unwrap_or_else(|| program.get_frames_for_instruction(instruction))
930 }
931
932 pub fn memory_accesses(
938 &mut self,
939 instruction: &Instruction,
940 extern_signature_map: &ExternSignatureMap,
941 ) -> crate::program::MemoryAccessesResult {
942 self.get_memory_accesses
943 .as_mut()
944 .and_then(|f| f(instruction))
945 .map(Ok)
946 .unwrap_or_else(|| instruction.get_memory_accesses(extern_signature_map))
947 }
948
949 pub fn simplify_program(&mut self, program: &Program) -> Result<Program, ProgramError> {
951 program.simplify_with_handler(self)
952 }
953}
954
955#[cfg(test)]
956mod tests {
957 use rstest::*;
958 use std::str::FromStr;
959
960 use crate::{expression::Expression, Program};
961
962 use super::MemoryReference;
963
964 #[test]
965 fn apply_to_expressions() {
966 let mut program = Program::from_str(
967 "DECLARE ro BIT
968SET-PHASE 0 \"rf\" pi/2
969RX(2) 0",
970 )
971 .unwrap();
972 let closure = |expr: &mut Expression| *expr = Expression::Variable(String::from("a"));
973 program.for_each_body_instruction(|instruction| {
974 instruction.apply_to_expressions(closure);
975 });
976
977 let expected_program = Program::from_str(
978 "DECLARE ro BIT
979SET-PHASE 0 \"rf\" %a
980RX(%a) 0",
981 )
982 .unwrap();
983
984 assert_eq!(expected_program, program);
985 }
986
987 #[rstest(input, expected,
988 case("_", MemoryReference { name: "_".to_string(), index: 0 }),
989 case("a", MemoryReference { name: "a".to_string(), index: 0 }),
990 case("a---b", MemoryReference { name: "a---b".to_string(), index: 0 }),
991 case("_a_b_", MemoryReference { name: "_a_b_".to_string(), index: 0 }),
992 case("a-2_b-2", MemoryReference { name: "a-2_b-2".to_string(), index: 0 }),
993 case("_[0]", MemoryReference { name: "_".to_string(), index: 0 }),
994 case("a[1]", MemoryReference { name: "a".to_string(), index: 1 }),
995 case("a---b[2]", MemoryReference { name: "a---b".to_string(), index: 2 }),
996 case("_a_b_[3]", MemoryReference { name: "_a_b_".to_string(), index: 3 }),
997 case("a-2_b-2[4]", MemoryReference { name: "a-2_b-2".to_string(), index: 4 }),
998 )]
999 fn it_parses_memory_reference_from_str(input: &str, expected: MemoryReference) {
1000 assert_eq!(MemoryReference::from_str(input), Ok(expected));
1001 }
1002
1003 #[rstest(
1004 input,
1005 case(""),
1006 case("[0]"),
1007 case("a[-1]"),
1008 case("2a[2]"),
1009 case("-a"),
1010 case("NOT[3]"),
1011 case("a a"),
1012 case("a[5] a[5]"),
1013 case("DECLARE a[6]")
1014 )]
1015 fn it_fails_to_parse_memory_reference_from_str(input: &str) {
1016 assert!(MemoryReference::from_str(input).is_err());
1017 }
1018
1019 mod placeholders {
1020 use std::collections::HashMap;
1021
1022 use crate::instruction::{Label, Qubit, QubitPlaceholder, Target, TargetPlaceholder};
1023
1024 #[allow(clippy::redundant_clone)]
1025 #[test]
1026 fn target() {
1027 let placeholder_1 = TargetPlaceholder::new(String::from("label"));
1028 let placeholder_2 = TargetPlaceholder::new(String::from("label"));
1029 let placeholder_3 = TargetPlaceholder::new(String::from("other"));
1030
1031 assert_eq!(placeholder_1, placeholder_1);
1032 assert_eq!(placeholder_1, placeholder_1.clone());
1033 assert_eq!(placeholder_1.clone(), placeholder_1.clone());
1034 assert_ne!(placeholder_1, placeholder_2);
1035 assert_ne!(placeholder_2, placeholder_3);
1036 assert_ne!(placeholder_1, placeholder_3);
1037 }
1038
1039 #[test]
1040 fn target_resolution() {
1041 let placeholder_1 = TargetPlaceholder::new(String::from("label"));
1042 let placeholder_2 = TargetPlaceholder::new(String::from("label"));
1043
1044 let resolver = HashMap::from([(placeholder_1.clone(), String::from("label_1"))]);
1045
1046 let mut label_1 = Label {
1047 target: Target::Placeholder(placeholder_1),
1048 };
1049 label_1
1050 .target
1051 .resolve_placeholder(|k| resolver.get(k).cloned());
1052 assert_eq!(label_1.target, Target::Fixed(String::from("label_1")));
1053
1054 let mut label_2 = Label {
1055 target: Target::Placeholder(placeholder_2.clone()),
1056 };
1057 label_2
1058 .target
1059 .resolve_placeholder(|k| resolver.get(k).cloned());
1060 assert_eq!(label_2.target, Target::Placeholder(placeholder_2));
1061 }
1062
1063 #[allow(clippy::redundant_clone)]
1064 #[test]
1065 fn qubit() {
1066 let placeholder_1 = QubitPlaceholder::default();
1067 let placeholder_2 = QubitPlaceholder::default();
1068
1069 assert_eq!(placeholder_1, placeholder_1);
1070 assert_eq!(placeholder_1, placeholder_1.clone());
1071 assert_eq!(placeholder_1.clone(), placeholder_1.clone());
1072 assert_ne!(placeholder_1, placeholder_2);
1073 }
1074
1075 #[test]
1076 fn qubit_resolution() {
1077 let placeholder_1 = QubitPlaceholder::default();
1078 let placeholder_2 = QubitPlaceholder::default();
1079
1080 let resolver = HashMap::from([(placeholder_1.clone(), 1)]);
1081
1082 let mut qubit_1 = Qubit::Placeholder(placeholder_1);
1083 qubit_1.resolve_placeholder(|k| resolver.get(k).copied());
1084 assert_eq!(qubit_1, Qubit::Fixed(1));
1085
1086 let mut qubit_2 = Qubit::Placeholder(placeholder_2.clone());
1087 qubit_2.resolve_placeholder(|k| resolver.get(k).copied());
1088 assert_eq!(qubit_2, Qubit::Placeholder(placeholder_2));
1089 }
1090 }
1091
1092 mod instruction_handler {
1093 use super::super::*;
1094
1095 #[test]
1096 fn it_considers_custom_instruction_frames() {
1097 let program = r#"DEFFRAME 0 "rf":
1098 CENTER-FREQUENCY: 3e9
1099
1100PRAGMA USES-ALL-FRAMES
1101"#
1102 .parse::<Program>()
1103 .unwrap();
1104
1105 assert!(program.into_simplified().unwrap().frames.is_empty());
1108
1109 let mut handler =
1110 InstructionHandler::default().set_matching_frames(|instruction, program| {
1111 if let Instruction::Pragma(_) = instruction {
1112 Some(Some(MatchedFrames {
1113 used: program.frames.get_keys().into_iter().collect(),
1114 blocked: HashSet::new(),
1115 }))
1116 } else {
1117 None
1118 }
1119 });
1120
1121 assert_eq!(handler.simplify_program(&program).unwrap().frames.len(), 1);
1122 }
1123 }
1124}