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