quil_rs/instruction/
mod.rs

1// Copyright 2021 Rigetti Computing
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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
216/// Write a list of qubits, with each prefixed by a space (including the first)
217fn 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
229/// Write qubits as a Quil parameter list, where all are prefixed with ` `.
230fn 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    /// Apply the provided closure to this instruction, mutating any `Expression`s within.
392    /// Does not affect instructions without `Expression`s within.
393    /// Does not traverse or mutate instructions nested within blocks (such as
394    /// within `DEFCAL`).
395    ///
396    /// # Example
397    ///
398    /// ```rust
399    /// use std::mem::replace;
400    /// use std::str::FromStr;
401    /// use quil_rs::{expression::Expression, Program, quil::Quil};
402    ///
403    ///
404    /// let program = Program::from_str("SHIFT-PHASE 0 \"rf\" 2*2").unwrap();
405    /// let mut instructions = program.to_instructions();
406    /// instructions.iter_mut().for_each(|inst| inst.apply_to_expressions(Expression::simplify));
407    ///
408    /// assert_eq!(instructions[0].to_quil().unwrap(), String::from("SHIFT-PHASE 0 \"rf\" 4"))
409    ///
410    /// ```
411    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    /// Return immutable references to the [`Qubit`]s contained within an instruction
578    #[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    /// Return mutable references to the [`Qubit`]s contained within an instruction
597    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    /// Return the waveform _directly_ invoked by the instruction, if any.
637    ///
638    /// Note: this does not expand calibrations or other instructions which may
639    /// indirectly cause a waveform to be invoked.
640    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    /// Parse a single instruction from an input string. Returns an error if the input fails to parse,
650    /// or if there is input left over after parsing.
651    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    /// Returns true if the instruction is a Quil-T instruction.
662    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    /// Per the Quil-T spec, whether this instruction's timing within the pulse
708    /// program must be precisely controlled so as to begin exactly on the end of
709    /// the latest preceding timed instruction
710    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
805/// Trait signature for a function or closure that returns an optional override for whether
806/// an instruction should be scheduled.
807pub trait GetIsScheduledFnMut: FnMut(&Instruction) -> Option<bool> {}
808impl<F> GetIsScheduledFnMut for F where F: FnMut(&Instruction) -> Option<bool> {}
809
810/// Trait signature for a function or closure that returns an optional override for an
811/// instruction's [`InstructionRole`].
812pub trait GetRoleForInstructionFnMut: FnMut(&Instruction) -> Option<InstructionRole> {}
813impl<F> GetRoleForInstructionFnMut for F where F: FnMut(&Instruction) -> Option<InstructionRole> {}
814
815/// Trait signature for a function or closure that returns an optional override for an
816/// instruction's [`MatchedFrames`].
817pub 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
826/// Trait signature for a function or closure that returns an optional override for an
827/// instruction's [`MemoryAccesses`].
828pub trait GetMemoryAccessesFnMut: FnMut(&Instruction) -> Option<MemoryAccesses> {}
829impl<F> GetMemoryAccessesFnMut for F where F: FnMut(&Instruction) -> Option<MemoryAccesses> {}
830
831/// A struct that allows setting optional overrides for key [`Instruction`] methods.
832///
833/// A common use case for this is to support custom `PRAGMA` instructions, which are treated as
834/// classical style no-ops by default.
835#[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    /// Set an override function for whether an instruction is scheduled.
845    ///
846    /// If the provided function returns `None`, a default will be used.
847    /// See also [`InstructionHandler::is_scheduled`].
848    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    /// Set an override function for determining an instruction's [`InstructionRole`].
857    ///
858    /// If the provided function returns `None`, a default will be used.
859    /// See also [`InstructionHandler::role_for_instruction`].
860    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    /// Set an override function for determining an instruction's [`MatchedFrames`].
869    ///
870    /// If the provided function returns `None`, a default will be used.
871    /// See also [`InstructionHandler::get_matching_frames`].
872    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    /// Set an override function for determining an instruction's [`MemoryAccesses`].
881    ///
882    /// If the provided function returns `None`, a default will be used.
883    /// See also [`InstructionHandler::get_memory_accesses`].
884    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    /// Determine whether the given instruction is scheduled.
893    ///
894    /// This uses the return value of the override function, if set and returns `Some`. If not set
895    /// or the function returns `None`, defaults to the return value of
896    /// [`Instruction::is_scheduled`].
897    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    /// Determine the [`InstructionRole`] for the given instruction.
905    ///
906    /// This uses the return value of the override function, if set and returns `Some`. If not set
907    /// or the function returns `None`, defaults to the return value of
908    /// [`InstructionRole::from`].
909    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    /// Determine the [`MatchedFrames`] for the given instruction.
917    ///
918    /// This uses the return value of the override function, if set and returns `Some`. If not set
919    /// or the function returns `None`, defaults to the return value of
920    /// [`Program::get_frames_for_instruction`].
921    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    /// Determine the [`MemoryAccesses`] for the given instruction.
933    ///
934    /// This uses the return value of the override function, if set and returns `Some`. If not set
935    /// or the function returns `None`, defaults to the return value of
936    /// [`Instruction::get_memory_accesses`].
937    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    /// Like [`Program::into_simplified`], but using custom instruction handling.
950    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            // This test assumes that the default simplification behavior will not assign frames to
1106            // `PRAGMA` instructions. This is verified below.
1107            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}