1use std::{collections::HashSet, fmt, iter, str::FromStr};
16
17use itertools::Itertools as _;
18use nom_locate::LocatedSpan;
19
20#[cfg(feature = "stubs")]
21use pyo3_stub_gen::derive::{gen_stub_pyclass_complex_enum, gen_stub_pymethods};
22
23use crate::{
24 expression::Expression,
25 parser::{lex, parse_instructions},
26 program::{
27 frame::{FrameMatchCondition, FrameMatchConditions},
28 MatchedFrames, MemoryAccesses, MemoryAccessesError,
29 },
30 quil::{write_join_quil, Quil, ToQuilResult},
31 Program,
32};
33
34#[cfg(feature = "python")]
35pub(crate) mod quilpy;
36
37mod calibration;
38mod circuit;
39mod classical;
40mod control_flow;
41mod declaration;
42mod extern_call;
43mod frame;
44mod gate;
45mod gate_sequence;
46mod measurement;
47mod pragma;
48mod qubit;
49mod reset;
50mod timing;
51mod waveform;
52
53pub use self::{
54 calibration::{
55 CalibrationDefinition, CalibrationIdentifier, CalibrationSignature,
56 MeasureCalibrationDefinition, MeasureCalibrationIdentifier,
57 },
58 circuit::CircuitDefinition,
59 classical::{
60 Arithmetic, ArithmeticOperand, ArithmeticOperator, BinaryLogic, BinaryOperand,
61 BinaryOperator, ClassicalOperand, Comparison, ComparisonOperand, ComparisonOperator,
62 Convert, Exchange, Move, UnaryLogic, UnaryOperator,
63 },
64 control_flow::{Jump, JumpUnless, JumpWhen, Label, Target, TargetPlaceholder},
65 declaration::{Declaration, Load, MemoryReference, Offset, ScalarType, Sharing, Store, Vector},
66 extern_call::*,
67 frame::{
68 AttributeValue, Capture, FrameAttributes, FrameDefinition, FrameIdentifier, Pulse,
69 RawCapture, SetFrequency, SetPhase, SetScale, ShiftFrequency, ShiftPhase, SwapPhases,
70 },
71 gate::{
72 Gate, GateDefinition, GateError, GateModifier, GateSpecification, GateType, Matrix,
73 PauliGate, PauliSum, PauliTerm,
74 },
75 gate_sequence::{DefGateSequence, DefGateSequenceError, DefGateSequenceExpansionError},
76 measurement::Measurement,
77 pragma::{Include, Pragma, PragmaArgument, RESERVED_PRAGMA_EXTERN},
78 qubit::{Qubit, QubitPlaceholder},
79 reset::Reset,
80 timing::{Delay, Fence},
81 waveform::{Waveform, WaveformDefinition, WaveformInvocation, WaveformParameters},
82};
83
84pub(crate) use self::gate::GateSignature;
85
86#[derive(Clone, Debug, thiserror::Error, PartialEq, Eq)]
87pub enum ValidationError {
88 #[error(transparent)]
89 GateError(#[from] GateError),
90 #[error(transparent)]
91 DefGateSequenceError(#[from] DefGateSequenceError),
92}
93
94#[derive(Clone, Debug, PartialEq)]
141#[cfg_attr(feature = "stubs", gen_stub_pyclass_complex_enum)]
142#[cfg_attr(
143 feature = "python",
144 pyo3::pyclass(module = "quil.instructions", eq, frozen)
145)]
146pub enum Instruction {
147 Arithmetic(Arithmetic),
148 BinaryLogic(BinaryLogic),
149 CalibrationDefinition(CalibrationDefinition),
150 Call(Call),
151 Capture(Capture),
152 CircuitDefinition(CircuitDefinition),
153 Convert(Convert),
154 Comparison(Comparison),
155 Declaration(Declaration),
156 Delay(Delay),
157 Exchange(Exchange),
158 Fence(Fence),
159 FrameDefinition(FrameDefinition),
160 Gate(Gate),
161 GateDefinition(GateDefinition),
162 Halt(),
168 Include(Include),
169 Jump(Jump),
170 JumpUnless(JumpUnless),
171 JumpWhen(JumpWhen),
172 Label(Label),
173 Load(Load),
174 MeasureCalibrationDefinition(MeasureCalibrationDefinition),
175 Measurement(Measurement),
176 Move(Move),
177 Nop(),
178 Pragma(Pragma),
179 Pulse(Pulse),
180 RawCapture(RawCapture),
181 Reset(Reset),
182 SetFrequency(SetFrequency),
183 SetPhase(SetPhase),
184 SetScale(SetScale),
185 ShiftFrequency(ShiftFrequency),
186 ShiftPhase(ShiftPhase),
187 Store(Store),
188 SwapPhases(SwapPhases),
189 UnaryLogic(UnaryLogic),
190 WaveformDefinition(WaveformDefinition),
191 Wait(),
192}
193
194#[cfg_attr(feature = "stubs", gen_stub_pymethods)]
195#[cfg_attr(feature = "python", pyo3::pymethods)]
196impl Instruction {
197 pub fn is_quil_t(&self) -> bool {
199 match self {
200 Instruction::Capture(_)
201 | Instruction::CalibrationDefinition(_)
202 | Instruction::Delay(_)
203 | Instruction::Fence(_)
204 | Instruction::FrameDefinition(_)
205 | Instruction::MeasureCalibrationDefinition(_)
206 | Instruction::Pulse(_)
207 | Instruction::RawCapture(_)
208 | Instruction::SetFrequency(_)
209 | Instruction::SetPhase(_)
210 | Instruction::SetScale(_)
211 | Instruction::ShiftFrequency(_)
212 | Instruction::ShiftPhase(_)
213 | Instruction::SwapPhases(_)
214 | Instruction::WaveformDefinition(_) => true,
215
216 Instruction::Arithmetic(_)
217 | Instruction::BinaryLogic(_)
218 | Instruction::Call(_)
219 | Instruction::CircuitDefinition(_)
220 | Instruction::Convert(_)
221 | Instruction::Comparison(_)
222 | Instruction::Declaration(_)
223 | Instruction::Exchange(_)
224 | Instruction::Gate(_)
225 | Instruction::GateDefinition(_)
226 | Instruction::Halt()
227 | Instruction::Include(_)
228 | Instruction::Jump(_)
229 | Instruction::JumpUnless(_)
230 | Instruction::JumpWhen(_)
231 | Instruction::Label(_)
232 | Instruction::Load(_)
233 | Instruction::Measurement(_)
234 | Instruction::Move(_)
235 | Instruction::Nop()
236 | Instruction::Pragma(_)
237 | Instruction::Reset(_)
238 | Instruction::Store(_)
239 | Instruction::Wait()
240 | Instruction::UnaryLogic(_) => false,
241 }
242 }
243}
244
245#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
249pub enum InstructionRole {
250 ProgramComposition,
264
265 ClassicalCompute,
267
268 RFControl,
275
276 ControlFlow,
278}
279
280pub fn write_instruction_block<'i, I, Q>(
281 f: &mut impl fmt::Write,
282 fall_back_to_debug: bool,
283 values: I,
284) -> crate::quil::ToQuilResult<()>
285where
286 I: IntoIterator<Item = &'i Q>,
287 Q: Quil + 'i,
288{
289 write_join_quil(f, fall_back_to_debug, values, "\n", "\t")
290}
291
292pub(crate) fn write_join(
293 f: &mut impl fmt::Write,
294 values: &[impl fmt::Display],
295 separator: &str,
296 prefix: &str,
297) -> fmt::Result {
298 let mut iter = values.iter();
299 if let Some(first) = iter.next() {
300 write!(f, "{prefix}{first}")?;
301
302 for value in iter {
303 write!(f, "{separator}{prefix}{value}")?;
304 }
305 }
306 Ok(())
307}
308
309pub fn format_integer_vector(values: &[u64]) -> String {
310 values
311 .iter()
312 .map(|q| format!("{q}"))
313 .collect::<Vec<String>>()
314 .join(" ")
315}
316
317fn write_qubits(
319 f: &mut impl fmt::Write,
320 fall_back_to_debug: bool,
321 qubits: &[Qubit],
322) -> crate::quil::ToQuilResult<()> {
323 for qubit in qubits {
324 write!(f, " ")?;
325 qubit.write(f, fall_back_to_debug)?;
326 }
327 Ok(())
328}
329
330fn write_qubit_parameters(
332 f: &mut impl fmt::Write,
333 fall_back_to_debug: bool,
334 qubits: &[Qubit],
335) -> ToQuilResult<()> {
336 for qubit in qubits.iter() {
337 write!(f, " ")?;
338 qubit.write(f, fall_back_to_debug)?;
339 }
340 Ok(())
341}
342
343fn write_expression_parameter_string(
344 f: &mut impl fmt::Write,
345 fall_back_to_debug: bool,
346 parameters: &[Expression],
347) -> crate::quil::ToQuilResult<()> {
348 if parameters.is_empty() {
349 return Ok(());
350 }
351
352 write!(f, "(")?;
353 write_join_quil(f, fall_back_to_debug, parameters, ", ", "")?;
354 write!(f, ")")?;
355 Ok(())
356}
357
358fn write_parameter_string<T: AsRef<str>>(f: &mut impl fmt::Write, parameters: &[T]) -> fmt::Result {
359 if parameters.is_empty() {
360 return Ok(());
361 }
362
363 write!(f, "(")?;
364 write_join(
365 f,
366 parameters
367 .iter()
368 .map(AsRef::as_ref)
369 .collect::<Vec<_>>()
370 .as_slice(),
371 ", ",
372 "%",
373 )?;
374 write!(f, ")")
375}
376
377impl Quil for Instruction {
378 fn write(
379 &self,
380 f: &mut impl fmt::Write,
381 fall_back_to_debug: bool,
382 ) -> Result<(), crate::quil::ToQuilError> {
383 match self {
384 Instruction::Arithmetic(arithmetic) => arithmetic.write(f, fall_back_to_debug),
385 Instruction::CalibrationDefinition(calibration) => {
386 calibration.write(f, fall_back_to_debug)
387 }
388 Instruction::Call(call) => call.write(f, fall_back_to_debug),
389 Instruction::Capture(capture) => capture.write(f, fall_back_to_debug),
390 Instruction::CircuitDefinition(circuit) => circuit.write(f, fall_back_to_debug),
391 Instruction::Convert(convert) => convert.write(f, fall_back_to_debug),
392 Instruction::Declaration(declaration) => declaration.write(f, fall_back_to_debug),
393 Instruction::Delay(delay) => delay.write(f, fall_back_to_debug),
394 Instruction::Fence(fence) => fence.write(f, fall_back_to_debug),
395 Instruction::FrameDefinition(frame_definition) => {
396 frame_definition.write(f, fall_back_to_debug)
397 }
398 Instruction::Gate(gate) => gate.write(f, fall_back_to_debug),
399 Instruction::GateDefinition(gate_definition) => {
400 gate_definition.write(f, fall_back_to_debug)
401 }
402 Instruction::Include(include) => include.write(f, fall_back_to_debug),
403 Instruction::MeasureCalibrationDefinition(measure_calibration) => {
404 measure_calibration.write(f, fall_back_to_debug)
405 }
406 Instruction::Measurement(measurement) => measurement.write(f, fall_back_to_debug),
407 Instruction::Move(r#move) => r#move.write(f, fall_back_to_debug),
408 Instruction::Exchange(exchange) => exchange.write(f, fall_back_to_debug),
409 Instruction::Load(load) => load.write(f, fall_back_to_debug),
410 Instruction::Store(store) => store.write(f, fall_back_to_debug),
411 Instruction::Pulse(pulse) => pulse.write(f, fall_back_to_debug),
412 Instruction::Pragma(pragma) => pragma.write(f, fall_back_to_debug),
413 Instruction::RawCapture(raw_capture) => raw_capture.write(f, fall_back_to_debug),
414 Instruction::Reset(reset) => reset.write(f, fall_back_to_debug),
415 Instruction::SetFrequency(set_frequency) => set_frequency.write(f, fall_back_to_debug),
416 Instruction::SetPhase(set_phase) => set_phase.write(f, fall_back_to_debug),
417 Instruction::SetScale(set_scale) => set_scale.write(f, fall_back_to_debug),
418 Instruction::ShiftFrequency(shift_frequency) => {
419 shift_frequency.write(f, fall_back_to_debug)
420 }
421 Instruction::ShiftPhase(shift_phase) => shift_phase.write(f, fall_back_to_debug),
422 Instruction::SwapPhases(swap_phases) => swap_phases.write(f, fall_back_to_debug),
423 Instruction::WaveformDefinition(waveform_definition) => {
424 waveform_definition.write(f, fall_back_to_debug)
425 }
426 Instruction::Halt() => write!(f, "HALT").map_err(Into::into),
427 Instruction::Nop() => write!(f, "NOP").map_err(Into::into),
428 Instruction::Wait() => write!(f, "WAIT").map_err(Into::into),
429 Instruction::Jump(jump) => jump.write(f, fall_back_to_debug),
430 Instruction::JumpUnless(jump) => jump.write(f, fall_back_to_debug),
431 Instruction::JumpWhen(jump) => jump.write(f, fall_back_to_debug),
432 Instruction::Label(label) => label.write(f, fall_back_to_debug),
433 Instruction::Comparison(comparison) => comparison.write(f, fall_back_to_debug),
434 Instruction::BinaryLogic(binary_logic) => binary_logic.write(f, fall_back_to_debug),
435 Instruction::UnaryLogic(unary_logic) => unary_logic.write(f, fall_back_to_debug),
436 }
437 }
438}
439
440pub(crate) struct QuotedString<S>(pub(crate) S);
441
442impl<S> fmt::Display for QuotedString<S>
443where
444 S: AsRef<str>,
445{
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 write!(f, "\"")?;
448 for c in self.0.as_ref().chars() {
449 match c {
450 '"' => write!(f, "\\\"")?,
451 '\\' => write!(f, "\\\\")?,
452 c => write!(f, "{c}")?,
453 }
454 }
455 write!(f, "\"")
456 }
457}
458
459#[cfg(test)]
460mod test_instruction_display {
461 use crate::{instruction::PragmaArgument, quil::Quil};
462
463 use super::{Instruction, Pragma};
464
465 #[test]
466 fn pragma() {
467 assert_eq!(
468 Instruction::Pragma(Pragma {
469 name: String::from("INITIAL_REWIRING"),
470 arguments: vec![],
471 data: Some(String::from("PARTIAL")),
472 })
473 .to_quil()
474 .unwrap(),
475 "PRAGMA INITIAL_REWIRING \"PARTIAL\""
476 );
477 assert_eq!(
478 Instruction::Pragma(Pragma {
479 name: String::from("LOAD-MEMORY"),
480 arguments: vec![PragmaArgument::Identifier("q0".to_string())],
481 data: Some(String::from("addr")),
482 })
483 .to_quil()
484 .unwrap(),
485 "PRAGMA LOAD-MEMORY q0 \"addr\""
486 );
487 assert_eq!(
488 Instruction::Pragma(Pragma {
489 name: String::from("PRESERVE_BLOCK"),
490 arguments: vec![],
491 data: None,
492 })
493 .to_quil()
494 .unwrap(),
495 "PRAGMA PRESERVE_BLOCK"
496 );
497 }
498}
499
500impl Instruction {
501 pub fn apply_to_expressions(&mut self, mut closure: impl FnMut(&mut Expression)) {
522 match self {
523 Instruction::CalibrationDefinition(CalibrationDefinition {
524 identifier: CalibrationIdentifier { parameters, .. },
525 ..
526 })
527 | Instruction::Gate(Gate { parameters, .. }) => {
528 parameters.iter_mut().for_each(closure);
529 }
530 Instruction::Capture(Capture { waveform, .. })
531 | Instruction::Pulse(Pulse { waveform, .. }) => {
532 waveform.parameters.values_mut().for_each(closure);
533 }
534 Instruction::Delay(Delay { duration, .. })
535 | Instruction::RawCapture(RawCapture { duration, .. }) => {
536 closure(duration);
537 }
538 Instruction::FrameDefinition(FrameDefinition { attributes, .. }) => {
539 for value in attributes.values_mut() {
540 if let AttributeValue::Expression(expression) = value {
541 closure(expression);
542 }
543 }
544 }
545 Instruction::SetFrequency(SetFrequency {
546 frequency: expression,
547 ..
548 })
549 | Instruction::SetPhase(SetPhase {
550 phase: expression, ..
551 })
552 | Instruction::SetScale(SetScale {
553 scale: expression, ..
554 })
555 | Instruction::ShiftFrequency(ShiftFrequency {
556 frequency: expression,
557 ..
558 })
559 | Instruction::ShiftPhase(ShiftPhase {
560 phase: expression, ..
561 }) => {
562 closure(expression);
563 }
564 Instruction::WaveformDefinition(WaveformDefinition { definition, .. }) => {
565 definition.matrix.iter_mut().for_each(closure);
566 }
567 Instruction::GateDefinition(GateDefinition {
568 specification: GateSpecification::Matrix(matrix),
569 ..
570 }) => {
571 for row in matrix {
572 for cell in row {
573 closure(cell);
574 }
575 }
576 }
577 _ => {}
578 }
579 }
580
581 pub(crate) fn default_frame_match_condition<'a>(
582 &'a self,
583 qubits_available: &'a HashSet<Qubit>,
584 ) -> Option<FrameMatchConditions<'a>> {
585 match self {
586 Instruction::Pulse(Pulse {
587 blocking, frame, ..
588 })
589 | Instruction::Capture(Capture {
590 blocking, frame, ..
591 })
592 | Instruction::RawCapture(RawCapture {
593 blocking, frame, ..
594 }) => Some(FrameMatchConditions {
595 blocked: blocking
596 .then(|| FrameMatchCondition::AnyOfQubits(frame.qubits.iter().collect())),
597 used: Some(FrameMatchCondition::Specific(frame)),
598 }),
599 Instruction::Delay(Delay {
600 frame_names,
601 qubits,
602 ..
603 }) => Some(FrameMatchConditions {
604 used: Some(if frame_names.is_empty() {
605 FrameMatchCondition::ExactQubits(qubits.iter().collect())
606 } else {
607 FrameMatchCondition::And(vec![
608 FrameMatchCondition::ExactQubits(qubits.iter().collect()),
609 FrameMatchCondition::AnyOfNames(
610 frame_names.iter().map(String::as_str).collect(),
611 ),
612 ])
613 }),
614 blocked: None,
615 }),
616 Instruction::Fence(Fence { qubits }) => Some(FrameMatchConditions {
617 used: None,
618 blocked: Some(if qubits.is_empty() {
619 FrameMatchCondition::All
620 } else {
621 FrameMatchCondition::AnyOfQubits(qubits.iter().collect())
622 }),
623 }),
624 Instruction::Reset(Reset { qubit }) => {
625 let qubits = match qubit {
626 Some(qubit) => {
627 let mut set = HashSet::new();
628 set.insert(qubit);
629 set
630 }
631 None => qubits_available.iter().collect(),
632 };
633
634 Some(FrameMatchConditions {
635 used: Some(FrameMatchCondition::ExactQubits(qubits.clone())),
636 blocked: Some(FrameMatchCondition::AnyOfQubits(qubits)),
637 })
638 }
639 Instruction::SetFrequency(SetFrequency { frame, .. })
640 | Instruction::SetPhase(SetPhase { frame, .. })
641 | Instruction::SetScale(SetScale { frame, .. })
642 | Instruction::ShiftFrequency(ShiftFrequency { frame, .. })
643 | Instruction::ShiftPhase(ShiftPhase { frame, .. }) => Some(FrameMatchConditions {
644 used: Some(FrameMatchCondition::Specific(frame)),
645 blocked: None,
646 }),
647 Instruction::SwapPhases(SwapPhases { frame_1, frame_2 }) => {
648 Some(FrameMatchConditions {
649 used: Some(FrameMatchCondition::Or(vec![
650 FrameMatchCondition::Specific(frame_1),
651 FrameMatchCondition::Specific(frame_2),
652 ])),
653 blocked: None,
654 })
655 }
656 Instruction::Arithmetic(_)
657 | Instruction::BinaryLogic(_)
658 | Instruction::CalibrationDefinition(_)
659 | Instruction::Call(_)
660 | Instruction::CircuitDefinition(_)
661 | Instruction::Comparison(_)
662 | Instruction::Convert(_)
663 | Instruction::Declaration(_)
664 | Instruction::Exchange(_)
665 | Instruction::FrameDefinition(_)
666 | Instruction::Gate(_)
667 | Instruction::GateDefinition(_)
668 | Instruction::Halt()
669 | Instruction::Include(_)
670 | Instruction::Jump(_)
671 | Instruction::JumpUnless(_)
672 | Instruction::JumpWhen(_)
673 | Instruction::Label(_)
674 | Instruction::Load(_)
675 | Instruction::MeasureCalibrationDefinition(_)
676 | Instruction::Measurement(_)
677 | Instruction::Move(_)
678 | Instruction::Nop()
679 | Instruction::Pragma(_)
680 | Instruction::Store(_)
681 | Instruction::UnaryLogic(_)
682 | Instruction::WaveformDefinition(_)
683 | Instruction::Wait() => None,
684 }
685 }
686
687 #[allow(dead_code)]
689 pub fn get_qubits(&self) -> Vec<&Qubit> {
690 match self {
691 Instruction::Gate(gate) => gate.qubits.iter().collect(),
692 Instruction::CalibrationDefinition(calibration) => calibration
693 .identifier
694 .qubits
695 .iter()
696 .chain(
697 calibration
698 .instructions
699 .iter()
700 .flat_map(|inst| inst.get_qubits()),
701 )
702 .collect(),
703 Instruction::MeasureCalibrationDefinition(measurement) => {
704 iter::once(&measurement.identifier.qubit)
705 .chain(
706 measurement
707 .instructions
708 .iter()
709 .flat_map(|inst| inst.get_qubits()),
710 )
711 .collect()
712 }
713 Instruction::Measurement(measurement) => vec![&measurement.qubit],
714 Instruction::Reset(reset) => match &reset.qubit {
715 Some(qubit) => vec![qubit],
716 None => vec![],
717 },
718 Instruction::Delay(delay) => delay.qubits.iter().collect(),
719 Instruction::Fence(fence) => fence.qubits.iter().collect(),
720 Instruction::Capture(capture) => capture.frame.qubits.iter().collect(),
721 Instruction::Pulse(pulse) => pulse.frame.qubits.iter().collect(),
722 Instruction::RawCapture(raw_capture) => raw_capture.frame.qubits.iter().collect(),
723 _ => vec![],
724 }
725 }
726
727 pub fn get_qubits_mut(&mut self) -> Vec<&mut Qubit> {
729 match self {
730 Instruction::Gate(gate) => gate.qubits.iter_mut().collect(),
731 Instruction::CalibrationDefinition(calibration) => calibration
732 .identifier
733 .qubits
734 .iter_mut()
735 .chain(
736 calibration
737 .instructions
738 .iter_mut()
739 .flat_map(|inst| inst.get_qubits_mut()),
740 )
741 .collect(),
742 Instruction::MeasureCalibrationDefinition(measurement) => {
743 iter::once(&mut measurement.identifier.qubit)
744 .chain(
745 measurement
746 .instructions
747 .iter_mut()
748 .flat_map(|inst| inst.get_qubits_mut()),
749 )
750 .collect()
751 }
752 Instruction::Measurement(measurement) => vec![&mut measurement.qubit],
753 Instruction::Reset(reset) => match &mut reset.qubit {
754 Some(qubit) => vec![qubit],
755 None => vec![],
756 },
757 Instruction::Delay(delay) => delay.qubits.iter_mut().collect(),
758 Instruction::Fence(fence) => fence.qubits.iter_mut().collect(),
759 Instruction::Capture(capture) => capture.frame.qubits.iter_mut().collect(),
760 Instruction::Pulse(pulse) => pulse.frame.qubits.iter_mut().collect(),
761 Instruction::RawCapture(raw_capture) => raw_capture.frame.qubits.iter_mut().collect(),
762 _ => vec![],
763 }
764 }
765
766 pub(crate) fn get_waveform_invocation(&self) -> Option<&WaveformInvocation> {
771 match self {
772 Instruction::Capture(Capture { waveform, .. }) => Some(waveform),
773 Instruction::Pulse(Pulse { waveform, .. }) => Some(waveform),
774 _ => None,
775 }
776 }
777
778 #[cfg(test)]
781 pub(crate) fn parse_in_test(input: &str) -> Result<Self, String> {
782 use crate::parser::instruction::parse_instruction;
783
784 let input = LocatedSpan::new(input);
785 let lexed = lex(input).map_err(|err| err.to_string())?;
786 let (_, instruction) =
787 nom::combinator::all_consuming(parse_instruction)(&lexed).map_err(|e| e.to_string())?;
788 Ok(instruction)
789 }
790
791 pub(crate) fn resolve_placeholders<TR, QR>(&mut self, target_resolver: TR, qubit_resolver: QR)
792 where
793 TR: Fn(&TargetPlaceholder) -> Option<String>,
794 QR: Fn(&QubitPlaceholder) -> Option<u64>,
795 {
796 match self {
797 Instruction::Label(label) => {
798 label.target.resolve_placeholder(target_resolver);
799 }
800 Instruction::Jump(jump) => {
801 jump.target.resolve_placeholder(target_resolver);
802 }
803 Instruction::JumpWhen(jump_when) => {
804 jump_when.target.resolve_placeholder(target_resolver);
805 }
806 Instruction::JumpUnless(jump_unless) => {
807 jump_unless.target.resolve_placeholder(target_resolver);
808 }
809 other => {
810 for qubit in other.get_qubits_mut() {
811 qubit.resolve_placeholder(&qubit_resolver);
812 }
813 }
814 }
815 }
816}
817
818#[derive(Debug, thiserror::Error)]
819pub enum ParseInstructionError {
820 #[error("Failed to parse instruction: {0}")]
821 Parse(String),
822 #[error("Expected to parse exactly one instruction but got {0}")]
823 ZeroOrMany(usize),
824}
825
826impl FromStr for Instruction {
827 type Err = ParseInstructionError;
828
829 fn from_str(s: &str) -> Result<Self, Self::Err> {
830 let input = LocatedSpan::new(s);
831 let lexed = lex(input).map_err(|e| ParseInstructionError::Parse(e.to_string()))?;
832 let instructions =
833 parse_instructions(&lexed).map_err(|e| ParseInstructionError::Parse(e.to_string()))?;
834 if instructions.1.len() != 1 {
835 return Err(ParseInstructionError::ZeroOrMany(instructions.1.len()));
836 }
837 Ok(instructions.1[0].to_owned())
838 }
839}
840
841pub trait InstructionHandler {
842 #[inline]
849 fn is_scheduled(&self, instruction: &Instruction) -> bool {
850 DefaultHandler.is_scheduled(instruction)
851 }
852
853 #[inline]
855 fn role(&self, instruction: &Instruction) -> InstructionRole {
856 DefaultHandler.role(instruction)
857 }
858
859 #[inline]
877 fn matching_frames<'p>(
878 &self,
879 program: &'p Program,
880 instruction: &Instruction,
881 ) -> Option<MatchedFrames<'p>> {
882 DefaultHandler.matching_frames(program, instruction)
883 }
884
885 #[inline]
900 fn memory_accesses(
901 &self,
902 extern_signature_map: &ExternSignatureMap,
903 instruction: &Instruction,
904 ) -> Result<MemoryAccesses, MemoryAccessesError> {
905 DefaultHandler.memory_accesses(extern_signature_map, instruction)
906 }
907}
908
909#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
911pub struct DefaultHandler;
912
913impl fmt::Display for DefaultHandler {
914 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
915 write!(f, "default instruction handler")
916 }
917}
918
919impl InstructionHandler for DefaultHandler {
920 fn is_scheduled(&self, instruction: &Instruction) -> bool {
921 match instruction {
922 Instruction::Reset(_) => false,
923 Instruction::Wait() => true,
924 _ => self.role(instruction) == InstructionRole::RFControl,
925 }
926 }
927
928 fn role(&self, instruction: &Instruction) -> InstructionRole {
929 match instruction {
930 Instruction::CalibrationDefinition(_)
931 | Instruction::CircuitDefinition(_)
932 | Instruction::Declaration(_)
933 | Instruction::FrameDefinition(_)
934 | Instruction::Gate(_)
935 | Instruction::GateDefinition(_)
936 | Instruction::Include(_)
937 | Instruction::Label(_)
938 | Instruction::MeasureCalibrationDefinition(_)
939 | Instruction::Measurement(_)
940 | Instruction::WaveformDefinition(_) => InstructionRole::ProgramComposition,
941
942 Instruction::Reset(_)
943 | Instruction::Capture(_)
944 | Instruction::Delay(_)
945 | Instruction::Fence(_)
946 | Instruction::Pulse(_)
947 | Instruction::RawCapture(_)
948 | Instruction::SetFrequency(_)
949 | Instruction::SetPhase(_)
950 | Instruction::SetScale(_)
951 | Instruction::ShiftFrequency(_)
952 | Instruction::ShiftPhase(_)
953 | Instruction::SwapPhases(_) => InstructionRole::RFControl,
954
955 Instruction::Arithmetic(_)
956 | Instruction::Call(_)
957 | Instruction::Comparison(_)
958 | Instruction::Convert(_)
959 | Instruction::BinaryLogic(_)
960 | Instruction::UnaryLogic(_)
961 | Instruction::Move(_)
962 | Instruction::Exchange(_)
963 | Instruction::Load(_)
964 | Instruction::Nop()
965 | Instruction::Pragma(_)
966 | Instruction::Store(_) => InstructionRole::ClassicalCompute,
967
968 Instruction::Halt()
969 | Instruction::Jump(_)
970 | Instruction::JumpWhen(_)
971 | Instruction::JumpUnless(_)
972 | Instruction::Wait() => InstructionRole::ControlFlow,
973 }
974 }
975
976 fn matching_frames<'p>(
977 &self,
978 program: &'p Program,
979 instruction: &Instruction,
980 ) -> Option<MatchedFrames<'p>> {
981 instruction
982 .default_frame_match_condition(program.get_used_qubits())
983 .map(|condition| program.frames.filter(condition))
984 }
985
986 fn memory_accesses(
987 &self,
988 extern_signature_map: &ExternSignatureMap,
989 instruction: &Instruction,
990 ) -> Result<MemoryAccesses, MemoryAccessesError> {
991 #[inline]
994 fn none() -> HashSet<String> {
995 HashSet::new()
996 }
997
998 #[inline]
999 fn access(reference: &MemoryReference) -> HashSet<String> {
1000 [reference.name.clone()].into()
1001 }
1002
1003 #[inline]
1004 fn access_dynamic(region: &str) -> HashSet<String> {
1005 [region.to_owned()].into()
1006 }
1007
1008 #[inline]
1009 fn accesses(reference1: &MemoryReference, reference2: &MemoryReference) -> HashSet<String> {
1010 [reference1.name.clone(), reference2.name.clone()].into()
1011 }
1012
1013 #[inline]
1014 fn accesses_dynamic_index(region: &str, index: &MemoryReference) -> HashSet<String> {
1015 [region.to_owned(), index.name.clone()].into()
1016 }
1017
1018 #[inline]
1019 fn access_opt(opt_reference: Option<&MemoryReference>) -> HashSet<String> {
1020 opt_reference.map_or_else(HashSet::new, access)
1021 }
1022
1023 #[inline]
1024 fn access_operand(operand: &impl ClassicalOperand) -> HashSet<String> {
1025 access_opt(operand.memory_reference())
1026 }
1027
1028 #[inline]
1029 fn accesses_with_operand(
1030 reference: &MemoryReference,
1031 operand: &impl ClassicalOperand,
1032 ) -> HashSet<String> {
1033 if let Some(other) = operand.memory_reference() {
1034 accesses(reference, other)
1035 } else {
1036 access(reference)
1037 }
1038 }
1039
1040 fn like_move(
1044 destination: &MemoryReference,
1045 source_accesses: HashSet<String>,
1046 ) -> MemoryAccesses {
1047 MemoryAccesses {
1048 reads: source_accesses,
1049 writes: access(destination),
1050 captures: none(),
1051 }
1052 }
1053
1054 fn binary(destination: &MemoryReference, source: &impl ClassicalOperand) -> MemoryAccesses {
1057 MemoryAccesses {
1058 reads: accesses_with_operand(destination, source),
1059 writes: access(destination),
1060 captures: none(),
1061 }
1062 }
1063
1064 fn read_write(places: HashSet<String>) -> MemoryAccesses {
1066 MemoryAccesses {
1067 reads: places.clone(),
1068 writes: places,
1069 captures: none(),
1070 }
1071 }
1072
1073 fn read_one(place: &MemoryReference) -> MemoryAccesses {
1075 MemoryAccesses {
1076 reads: access(place),
1077 writes: none(),
1078 captures: none(),
1079 }
1080 }
1081
1082 fn read_all<'a>(places: impl IntoIterator<Item = &'a MemoryReference>) -> MemoryAccesses {
1085 MemoryAccesses {
1086 reads: places.into_iter().map(|r| r.name.clone()).collect(),
1087 writes: none(),
1088 captures: none(),
1089 }
1090 }
1091
1092 fn gate_application(Gate { parameters, .. }: &Gate) -> MemoryAccesses {
1094 read_all(parameters.iter().flat_map(Expression::memory_references))
1095 }
1096
1097 Ok(match instruction {
1100 Instruction::Convert(Convert {
1102 destination,
1103 source,
1104 }) => like_move(destination, access(source)),
1105 Instruction::Move(Move {
1106 destination,
1107 source,
1108 }) => like_move(destination, access_operand(source)),
1109 Instruction::BinaryLogic(BinaryLogic {
1110 destination,
1111 source,
1112 operator: _,
1113 }) => binary(destination, source),
1114 Instruction::Arithmetic(Arithmetic {
1115 destination,
1116 source,
1117 ..
1118 }) => binary(destination, source),
1119 Instruction::UnaryLogic(UnaryLogic { operand, .. }) => read_write(access(operand)),
1120 Instruction::Exchange(Exchange { left, right }) => read_write(accesses(left, right)),
1121 Instruction::JumpWhen(JumpWhen {
1122 target: _,
1123 condition,
1124 })
1125 | Instruction::JumpUnless(JumpUnless {
1126 target: _,
1127 condition,
1128 }) => read_one(condition),
1129
1130 Instruction::Comparison(Comparison {
1132 destination,
1133 lhs,
1134 rhs,
1135 operator: _,
1136 }) => MemoryAccesses {
1137 reads: accesses_with_operand(lhs, rhs),
1138 writes: access(destination),
1139 captures: none(),
1140 },
1141
1142 Instruction::Delay(Delay { duration: expr, .. })
1144 | Instruction::SetPhase(SetPhase { phase: expr, .. })
1145 | Instruction::SetScale(SetScale { scale: expr, .. })
1146 | Instruction::ShiftPhase(ShiftPhase { phase: expr, .. })
1147 | Instruction::SetFrequency(SetFrequency {
1148 frequency: expr, ..
1149 })
1150 | Instruction::ShiftFrequency(ShiftFrequency {
1151 frequency: expr, ..
1152 }) => read_all(expr.memory_references()),
1153
1154 Instruction::Pulse(Pulse {
1157 waveform,
1158 blocking: _,
1159 frame: _,
1160 }) => read_all(waveform.memory_references()),
1161 Instruction::Gate(gate) => gate_application(gate),
1162
1163 Instruction::Capture(Capture {
1165 memory_reference,
1166 waveform,
1167 blocking: _,
1168 frame: _,
1169 }) => MemoryAccesses {
1170 reads: waveform
1171 .memory_references()
1172 .map(|r| r.name.clone())
1173 .collect(),
1174 captures: access(memory_reference),
1175 writes: none(),
1176 },
1177 Instruction::Measurement(Measurement { target, .. }) => MemoryAccesses {
1178 captures: access_opt(target.as_ref()),
1179 reads: none(),
1180 writes: none(),
1181 },
1182 Instruction::RawCapture(RawCapture {
1183 duration,
1184 memory_reference,
1185 blocking: _,
1186 frame: _,
1187 }) => MemoryAccesses {
1188 reads: duration
1189 .memory_references()
1190 .map(|r| r.name.clone())
1191 .collect(),
1192 captures: access(memory_reference),
1193 writes: none(),
1194 },
1195
1196 Instruction::Call(call) => call.default_memory_accesses(extern_signature_map)?,
1199
1200 Instruction::CalibrationDefinition(CalibrationDefinition {
1202 identifier:
1203 CalibrationIdentifier {
1204 parameters,
1205 modifiers: _,
1206 name: _,
1207 qubits: _,
1208 },
1209 instructions,
1210 }) => {
1211 let parameter_reads = MemoryAccesses {
1212 reads: parameters
1213 .iter()
1214 .flat_map(Expression::memory_references)
1215 .map(|r| r.name.clone())
1216 .collect(),
1217 writes: none(),
1218 captures: none(),
1219 };
1220 instructions
1221 .iter()
1222 .map(|instr| self.memory_accesses(extern_signature_map, instr))
1223 .fold_ok(parameter_reads, MemoryAccesses::union)?
1224 }
1225
1226 Instruction::GateDefinition(GateDefinition {
1230 specification,
1231 name: _,
1232 parameters: _,
1233 }) => match specification {
1234 GateSpecification::Matrix(matrix) => read_all(
1235 matrix
1236 .iter()
1237 .flat_map(|row| row.iter().flat_map(Expression::memory_references)),
1238 ),
1239 GateSpecification::Permutation(_) | GateSpecification::PauliSum(_) => {
1240 MemoryAccesses::none()
1241 }
1242 GateSpecification::Sequence(DefGateSequence { gates, qubits: _ }) => gates
1243 .iter()
1244 .map(gate_application)
1245 .fold(MemoryAccesses::none(), MemoryAccesses::union),
1246 },
1247 Instruction::CircuitDefinition(CircuitDefinition {
1248 instructions,
1249 name: _,
1250 parameters: _,
1251 qubit_variables: _,
1252 })
1253 | Instruction::MeasureCalibrationDefinition(MeasureCalibrationDefinition {
1254 instructions,
1255 identifier: _,
1256 }) => instructions
1257 .iter()
1258 .map(|instr| self.memory_accesses(extern_signature_map, instr))
1259 .fold_ok(MemoryAccesses::none(), MemoryAccesses::union)?,
1260 Instruction::WaveformDefinition(WaveformDefinition {
1261 definition:
1262 Waveform {
1263 matrix,
1264 parameters: _,
1265 },
1266 name: _,
1267 }) => read_all(matrix.iter().flat_map(Expression::memory_references)),
1268
1269 Instruction::Load(Load {
1273 destination,
1274 source,
1275 offset,
1276 }) => MemoryAccesses {
1277 reads: accesses_dynamic_index(source, offset),
1278 writes: access(destination),
1279 captures: none(),
1280 },
1281 Instruction::Store(Store {
1282 destination,
1283 offset,
1284 source,
1285 }) => MemoryAccesses {
1286 reads: accesses_with_operand(offset, source),
1287 writes: access_dynamic(destination),
1288 captures: none(),
1289 },
1290
1291 Instruction::Declaration(_)
1294 | Instruction::Fence(_)
1295 | Instruction::FrameDefinition(_)
1296 | Instruction::Halt()
1297 | Instruction::Wait()
1298 | Instruction::Include(_)
1299 | Instruction::Jump(_)
1300 | Instruction::Label(_)
1301 | Instruction::Nop()
1302 | Instruction::Pragma(_)
1303 | Instruction::Reset(_)
1304 | Instruction::SwapPhases(_) => MemoryAccesses::none(),
1305 })
1306 }
1307}
1308
1309#[cfg(test)]
1310mod tests {
1311 use rstest::*;
1312 use std::str::FromStr as _;
1313
1314 use crate::{expression::Expression, Program};
1315
1316 use super::MemoryReference;
1317
1318 #[test]
1319 fn apply_to_expressions() {
1320 let mut program = Program::from_str(
1321 "DECLARE ro BIT
1322SET-PHASE 0 \"rf\" pi/2
1323RX(2) 0",
1324 )
1325 .unwrap();
1326 let closure = |expr: &mut Expression| *expr = Expression::Variable(String::from("a"));
1327 program.for_each_body_instruction(|instruction| {
1328 instruction.apply_to_expressions(closure);
1329 });
1330
1331 let expected_program = Program::from_str(
1332 "DECLARE ro BIT
1333SET-PHASE 0 \"rf\" %a
1334RX(%a) 0",
1335 )
1336 .unwrap();
1337
1338 assert_eq!(expected_program, program);
1339 }
1340
1341 #[rstest(input, expected,
1342 case("_", MemoryReference { name: "_".to_string(), index: 0 }),
1343 case("a", MemoryReference { name: "a".to_string(), index: 0 }),
1344 case("a---b", MemoryReference { name: "a---b".to_string(), index: 0 }),
1345 case("_a_b_", MemoryReference { name: "_a_b_".to_string(), index: 0 }),
1346 case("a-2_b-2", MemoryReference { name: "a-2_b-2".to_string(), index: 0 }),
1347 case("_[0]", MemoryReference { name: "_".to_string(), index: 0 }),
1348 case("a[1]", MemoryReference { name: "a".to_string(), index: 1 }),
1349 case("a---b[2]", MemoryReference { name: "a---b".to_string(), index: 2 }),
1350 case("_a_b_[3]", MemoryReference { name: "_a_b_".to_string(), index: 3 }),
1351 case("a-2_b-2[4]", MemoryReference { name: "a-2_b-2".to_string(), index: 4 }),
1352 )]
1353 fn it_parses_memory_reference_from_str(input: &str, expected: MemoryReference) {
1354 assert_eq!(MemoryReference::from_str(input), Ok(expected));
1355 }
1356
1357 #[rstest(
1358 input,
1359 case(""),
1360 case("[0]"),
1361 case("a[-1]"),
1362 case("2a[2]"),
1363 case("-a"),
1364 case("NOT[3]"),
1365 case("a a"),
1366 case("a[5] a[5]"),
1367 case("DECLARE a[6]")
1368 )]
1369 fn it_fails_to_parse_memory_reference_from_str(input: &str) {
1370 assert!(MemoryReference::from_str(input).is_err());
1371 }
1372
1373 mod placeholders {
1374 use std::collections::HashMap;
1375
1376 use crate::instruction::{Label, Qubit, QubitPlaceholder, Target, TargetPlaceholder};
1377
1378 #[allow(clippy::redundant_clone)]
1379 #[test]
1380 fn target() {
1381 let placeholder_1 = TargetPlaceholder::new(String::from("label"));
1382 let placeholder_2 = TargetPlaceholder::new(String::from("label"));
1383 let placeholder_3 = TargetPlaceholder::new(String::from("other"));
1384
1385 assert_eq!(placeholder_1, placeholder_1);
1386 assert_eq!(placeholder_1, placeholder_1.clone());
1387 assert_eq!(placeholder_1.clone(), placeholder_1.clone());
1388 assert_ne!(placeholder_1, placeholder_2);
1389 assert_ne!(placeholder_2, placeholder_3);
1390 assert_ne!(placeholder_1, placeholder_3);
1391 }
1392
1393 #[test]
1394 fn target_resolution() {
1395 let placeholder_1 = TargetPlaceholder::new(String::from("label"));
1396 let placeholder_2 = TargetPlaceholder::new(String::from("label"));
1397
1398 let resolver = HashMap::from([(placeholder_1.clone(), String::from("label_1"))]);
1399
1400 let mut label_1 = Label {
1401 target: Target::Placeholder(placeholder_1),
1402 };
1403 label_1
1404 .target
1405 .resolve_placeholder(|k| resolver.get(k).cloned());
1406 assert_eq!(label_1.target, Target::Fixed(String::from("label_1")));
1407
1408 let mut label_2 = Label {
1409 target: Target::Placeholder(placeholder_2.clone()),
1410 };
1411 label_2
1412 .target
1413 .resolve_placeholder(|k| resolver.get(k).cloned());
1414 assert_eq!(label_2.target, Target::Placeholder(placeholder_2));
1415 }
1416
1417 #[allow(clippy::redundant_clone)]
1418 #[test]
1419 fn qubit() {
1420 let placeholder_1 = QubitPlaceholder::default();
1421 let placeholder_2 = QubitPlaceholder::default();
1422
1423 assert_eq!(placeholder_1, placeholder_1);
1424 assert_eq!(placeholder_1, placeholder_1.clone());
1425 assert_eq!(placeholder_1.clone(), placeholder_1.clone());
1426 assert_ne!(placeholder_1, placeholder_2);
1427 }
1428
1429 #[test]
1430 fn qubit_resolution() {
1431 let placeholder_1 = QubitPlaceholder::default();
1432 let placeholder_2 = QubitPlaceholder::default();
1433
1434 let resolver = HashMap::from([(placeholder_1.clone(), 1)]);
1435
1436 let mut qubit_1 = Qubit::Placeholder(placeholder_1);
1437 qubit_1.resolve_placeholder(|k| resolver.get(k).copied());
1438 assert_eq!(qubit_1, Qubit::Fixed(1));
1439
1440 let mut qubit_2 = Qubit::Placeholder(placeholder_2.clone());
1441 qubit_2.resolve_placeholder(|k| resolver.get(k).copied());
1442 assert_eq!(qubit_2, Qubit::Placeholder(placeholder_2));
1443 }
1444 }
1445
1446 mod instruction_handler {
1447 use super::super::*;
1448
1449 struct CustomFrameHandler;
1450
1451 impl InstructionHandler for CustomFrameHandler {
1452 fn matching_frames<'p>(
1453 &self,
1454 program: &'p Program,
1455 instruction: &Instruction,
1456 ) -> Option<MatchedFrames<'p>> {
1457 if let Instruction::Pragma(_) = instruction {
1458 Some(MatchedFrames {
1459 used: program.frames.get_keys().into_iter().collect(),
1460 blocked: HashSet::new(),
1461 })
1462 } else {
1463 DefaultHandler.matching_frames(program, instruction)
1464 }
1465 }
1466 }
1467
1468 #[test]
1469 fn it_considers_custom_instruction_frames() {
1470 let program = r#"DEFFRAME 0 "rf":
1471 CENTER-FREQUENCY: 3e9
1472
1473PRAGMA USES-ALL-FRAMES
1474"#
1475 .parse::<Program>()
1476 .unwrap();
1477
1478 assert!(program.simplify(&DefaultHandler).unwrap().frames.is_empty());
1481
1482 assert_eq!(
1483 program.simplify(&CustomFrameHandler).unwrap().frames.len(),
1484 1
1485 );
1486 }
1487 }
1488}