Skip to main content

cqlib_core/circuit/
value_instruction.rs

1// This code is part of Cqlib.
2//
3// (C) Copyright China Telecom Quantum Group 2026
4//
5// This code is licensed under the Apache License, Version 2.0. You may
6// obtain a copy of this license in the LICENSE.txt file in the root directory
7// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8//
9// Any modifications or derivative works of this code must retain this
10// copyright notice, and modified files need to carry a notice indicating
11// that they have been altered from the originals.
12
13//! Value-level instruction types for circuit construction.
14//!
15//! This module defines the **construction IR** — operations that have not yet been assigned to a
16//! specific [`Circuit`](crate::circuit::Circuit). Where the storage IR ([`Instruction`],
17//! [`Operation`]) uses interned [`CircuitParam::Index`] references into a circuit's parameter
18//! table, the construction IR uses [`ParameterValue`] and recursive value-level control-flow
19//! bodies.
20//!
21//! # Two IRs, One Conversion Point
22//!
23//! ```text
24//! ValueInstruction tree ──from_operations()──▶ Instruction / Operation tree
25//! ```
26//!
27//! [`Circuit::from_operations`](crate::circuit::Circuit::from_operations) is the sole bridge.
28//! It recursively walks a [`ValueInstruction`] tree, interns every [`ParameterValue`] into the
29//! target circuit, and produces a [`ClassicalControlOp`] with [`ControlBody`] bodies whose
30//! [`CircuitParam::Index`] values are valid within that circuit.
31//!
32//! # Why Separate Types?
33//!
34//! The storage IR [`ControlBody`] wraps `Arc<Vec<Operation>>`. If a [`ValueOperation`] carried
35//! [`Instruction::ClassicalControl`] directly, its nested body would contain
36//! [`CircuitParam::Index`] values with no source parameter table — a silent correctness bug.
37//!
38//! By giving the construction IR its own control-flow types ([`ValueClassicalControlOp`] with
39//! [`ValueControlBody`]), we ensure that every parameter in a construction-time operation tree
40//! is a [`ParameterValue`]. The compiler enforces that indexed parameters never appear in
41//! construction IR.
42
43use crate::circuit::ClassicalControlOp;
44use crate::circuit::ClassicalType;
45use crate::circuit::circuit_param::{CircuitParam, ParameterValue};
46use crate::circuit::classical::{ClassicalValue, ClassicalVar};
47use crate::circuit::classical_expr::ClassicalExpr;
48use crate::circuit::control_flow::{ControlBody, validate_for_types, validate_switch};
49use crate::circuit::error::CircuitError;
50use crate::circuit::gate::directive::Directive;
51use crate::circuit::gate::instruction::Instruction;
52use crate::circuit::gate::standard_gate::StandardGate;
53use crate::circuit::operation::{Operation, ValueOperation};
54use alloc::collections::BTreeSet;
55use std::fmt;
56
57/// A value-level control-flow body.
58///
59/// This is the construction-IR counterpart of [`ControlBody`].
60/// Instead of storing indexed [`Operation`] values, it stores
61/// [`ValueOperation`] values whose parameters are [`ParameterValue`] objects that have not
62/// yet been interned into any circuit.
63///
64/// # Examples
65///
66/// ```
67/// use cqlib_core::circuit::value_instruction::ValueControlBody;
68/// use cqlib_core::circuit::{ValueOperation, Qubit, StandardGate, ParameterValue};
69/// use smallvec::smallvec;
70///
71/// let body = ValueControlBody::new(vec![
72///     ValueOperation::from_standard(
73///         StandardGate::H,
74///         [Qubit::new(0)],
75///         [],
76///     ),
77///     ValueOperation::from_standard(
78///         StandardGate::RX,
79///         [Qubit::new(0)],
80///         [ParameterValue::from("theta")],
81///     ),
82/// ]);
83/// assert_eq!(body.operations().len(), 2);
84/// ```
85#[derive(Debug, Clone, PartialEq)]
86pub struct ValueControlBody {
87    operations: Vec<ValueOperation>,
88}
89
90impl ValueControlBody {
91    /// Creates a body from a sequence of value-level operations.
92    pub fn new(operations: Vec<ValueOperation>) -> Self {
93        Self { operations }
94    }
95
96    /// Returns the body operations.
97    pub fn operations(&self) -> &[ValueOperation] {
98        self.operations.as_slice()
99    }
100
101    /// Returns every qubit used directly or by nested control-flow operations.
102    pub fn used_qubits(&self) -> BTreeSet<crate::circuit::Qubit> {
103        let mut qubits = BTreeSet::new();
104        for operation in &self.operations {
105            qubits.extend(operation.qubits.iter().copied());
106            if let ValueInstruction::ClassicalControl(control) = &operation.instruction {
107                qubits.extend(control.used_qubits());
108            }
109        }
110        qubits
111    }
112
113    /// Returns true if this body directly or recursively contains measurement.
114    pub fn has_measurement(&self) -> bool {
115        self.operations
116            .iter()
117            .any(|operation| match &operation.instruction {
118                ValueInstruction::Instruction(instruction) => instruction.has_measurement(),
119                ValueInstruction::ClassicalControl(control) => control.has_measurement(),
120            })
121    }
122
123    /// Returns true if this body directly or recursively reads `value`.
124    pub fn reads_value(&self, value: ClassicalValue) -> bool {
125        self.operations
126            .iter()
127            .any(|operation| match &operation.instruction {
128                ValueInstruction::Instruction(instruction) => instruction.reads_value(value),
129                ValueInstruction::ClassicalControl(control) => control.reads_value(value),
130            })
131    }
132}
133
134impl From<Vec<ValueOperation>> for ValueControlBody {
135    fn from(operations: Vec<ValueOperation>) -> Self {
136        Self::new(operations)
137    }
138}
139
140/// A single case in a value-level [`SwitchOp`](crate::circuit::SwitchOp)-like construct.
141///
142/// Each case matches an exact unsigned integer value and carries a [`ValueControlBody`]
143/// to execute when the switch target equals that value.
144#[derive(Debug, Clone, PartialEq)]
145pub struct ValueSwitchCase {
146    /// The exact unsigned integer value that triggers this case.
147    pub value: u128,
148    /// The body to execute when the switch target matches `value`.
149    pub body: ValueControlBody,
150}
151
152impl ValueSwitchCase {
153    /// Creates a switch case with the given match value and body.
154    pub fn new(value: u128, body: ValueControlBody) -> Self {
155        Self { value, body }
156    }
157}
158
159/// A value-level classical control-flow operation.
160///
161/// This mirrors [`ClassicalControlOp`] but every
162/// nested body is a [`ValueControlBody`] containing [`ValueOperation`] entries with
163/// [`ParameterValue`] parameters. There are no [`CircuitParam::Index`] values anywhere
164/// in this tree.
165///
166/// # Variants
167///
168/// | Variant | Storage-IR equivalent |
169/// |---|---|
170/// | `If` | [`IfOp`](crate::circuit::IfOp) |
171/// | `While` | [`WhileOp`](crate::circuit::WhileOp) |
172/// | `For` | [`ForOp`](crate::circuit::ForOp) |
173/// | `Switch` | [`SwitchOp`](crate::circuit::SwitchOp) |
174/// | `Break` | [`ClassicalControlOp::Break`](crate::circuit::ClassicalControlOp) |
175/// | `Continue` | [`ClassicalControlOp::Continue`](crate::circuit::ClassicalControlOp) |
176#[derive(Debug, Clone, PartialEq)]
177pub enum ValueClassicalControlOp {
178    /// Execute `then_body` when `condition` is true, optionally `else_body` when false.
179    ///
180    /// `condition` must have type [`ClassicalType::Bool`](crate::circuit::ClassicalType).
181    If {
182        /// Boolean branch condition.
183        condition: ClassicalExpr,
184        /// Body executed when the condition is true.
185        then_body: ValueControlBody,
186        /// Optional body executed when the condition is false.
187        else_body: Option<ValueControlBody>,
188    },
189    /// Repeat `body` while `condition` remains true.
190    ///
191    /// `condition` must have type [`ClassicalType::Bool`](crate::circuit::ClassicalType).
192    While {
193        /// Boolean loop condition.
194        condition: ClassicalExpr,
195        /// Body executed while the condition is true.
196        body: ValueControlBody,
197    },
198    /// Iterate `body` over an unsigned half-open range `[start, stop)` with the given `step`.
199    ///
200    /// `var` must have type [`ClassicalType::UInt`](crate::circuit::ClassicalType).
201    /// `start`, `stop`, and `step` must match `var`'s width.
202    For {
203        /// Mutable unsigned loop variable.
204        var: ClassicalVar,
205        /// Inclusive initial value.
206        start: ClassicalExpr,
207        /// Exclusive upper bound.
208        stop: ClassicalExpr,
209        /// Non-zero iteration increment.
210        step: ClassicalExpr,
211        /// Loop body.
212        body: ValueControlBody,
213    },
214    /// Select one body by matching `target` against exact case values.
215    ///
216    /// `target` must have an unsigned integer type. Cases do not fall through.
217    Switch {
218        /// Unsigned expression matched against case values.
219        target: ClassicalExpr,
220        /// Exact-value cases in source order.
221        cases: Vec<ValueSwitchCase>,
222        /// Optional default body.
223        default: Option<ValueControlBody>,
224    },
225    /// Exit the nearest enclosing loop or switch body.
226    Break,
227    /// Advance to the next iteration of the nearest enclosing loop.
228    Continue,
229}
230
231impl ValueClassicalControlOp {
232    /// Creates a validated `if` operation.
233    ///
234    /// `condition` must have type [`ClassicalType::Bool`].
235    pub fn new_if(
236        condition: ClassicalExpr,
237        then_body: ValueControlBody,
238        else_body: Option<ValueControlBody>,
239    ) -> Result<Self, CircuitError> {
240        if condition.ty() != ClassicalType::Bool {
241            return Err(CircuitError::InvalidOperation(format!(
242                "if condition must be Bool, got {:?}",
243                condition.ty()
244            )));
245        }
246        Ok(Self::If {
247            condition,
248            then_body,
249            else_body,
250        })
251    }
252
253    /// Creates a validated `while` operation.
254    ///
255    /// `condition` must have type [`ClassicalType::Bool`].
256    pub fn new_while(
257        condition: ClassicalExpr,
258        body: ValueControlBody,
259    ) -> Result<Self, CircuitError> {
260        if condition.ty() != ClassicalType::Bool {
261            return Err(CircuitError::InvalidOperation(format!(
262                "while condition must be Bool, got {:?}",
263                condition.ty()
264            )));
265        }
266        Ok(Self::While { condition, body })
267    }
268
269    /// Creates a validated unsigned range `for` operation.
270    ///
271    /// `var` must be a `UInt` and `start`, `stop`, and `step` must match its width.
272    pub fn new_for(
273        var: ClassicalVar,
274        start: ClassicalExpr,
275        stop: ClassicalExpr,
276        step: ClassicalExpr,
277        body: ValueControlBody,
278    ) -> Result<Self, CircuitError> {
279        validate_for_types(var, &start, &stop, &step)?;
280        Ok(Self::For {
281            var,
282            start,
283            stop,
284            step,
285            body,
286        })
287    }
288
289    /// Creates a validated exact-value `switch` operation.
290    ///
291    /// `target` must be a `UInt`; every case value must fit its width and be unique.
292    pub fn new_switch(
293        target: ClassicalExpr,
294        cases: Vec<ValueSwitchCase>,
295        default: Option<ValueControlBody>,
296    ) -> Result<Self, CircuitError> {
297        validate_switch(&target, cases.iter().map(|case| case.value))?;
298        Ok(Self::Switch {
299            target,
300            cases,
301            default,
302        })
303    }
304
305    /// Returns every qubit used by the operation's nested control-flow bodies.
306    pub fn used_qubits(&self) -> BTreeSet<crate::circuit::Qubit> {
307        let mut qubits = BTreeSet::new();
308        match self {
309            Self::If {
310                then_body,
311                else_body,
312                ..
313            } => {
314                qubits.extend(then_body.used_qubits());
315                if let Some(else_body) = else_body {
316                    qubits.extend(else_body.used_qubits());
317                }
318            }
319            Self::While { body, .. } | Self::For { body, .. } => {
320                qubits.extend(body.used_qubits());
321            }
322            Self::Switch { cases, default, .. } => {
323                for case in cases {
324                    qubits.extend(case.body.used_qubits());
325                }
326                if let Some(default) = default {
327                    qubits.extend(default.used_qubits());
328                }
329            }
330            Self::Break | Self::Continue => {}
331        }
332        qubits
333    }
334
335    /// Returns the classical variables read by the controlling expressions.
336    pub fn classical_var_reads(&self) -> Vec<ClassicalVar> {
337        match self {
338            Self::If { condition, .. } | Self::While { condition, .. } => {
339                condition.vars().into_iter().collect()
340            }
341            Self::For {
342                start, stop, step, ..
343            } => {
344                let mut vars: Vec<_> = start.vars().into_iter().collect();
345                vars.extend(stop.vars());
346                vars.extend(step.vars());
347                vars
348            }
349            Self::Switch { target, .. } => target.vars().into_iter().collect(),
350            Self::Break | Self::Continue => Vec::new(),
351        }
352    }
353
354    /// Returns the immutable classical values read by the controlling expressions.
355    pub fn classical_value_reads(&self) -> Vec<crate::circuit::ClassicalValue> {
356        match self {
357            Self::If { condition, .. } | Self::While { condition, .. } => {
358                condition.values().into_iter().collect()
359            }
360            Self::For {
361                start, stop, step, ..
362            } => {
363                let mut vals: Vec<_> = start.values().into_iter().collect();
364                vals.extend(stop.values());
365                vals.extend(step.values());
366                vals
367            }
368            Self::Switch { target, .. } => target.values().into_iter().collect(),
369            Self::Break | Self::Continue => Vec::new(),
370        }
371    }
372
373    /// Returns the classical variables written by this operation.
374    ///
375    /// Currently only [`For`](Self::For) writes its loop variable.
376    pub fn classical_writes(&self) -> Vec<ClassicalVar> {
377        match self {
378            Self::For { var, .. } => vec![*var],
379            _ => Vec::new(),
380        }
381    }
382
383    /// Returns true if this control operation recursively contains measurement.
384    pub fn has_measurement(&self) -> bool {
385        match self {
386            Self::If {
387                then_body,
388                else_body,
389                ..
390            } => {
391                then_body.has_measurement()
392                    || else_body
393                        .as_ref()
394                        .is_some_and(|body| body.has_measurement())
395            }
396            Self::While { body, .. } | Self::For { body, .. } => body.has_measurement(),
397            Self::Switch { cases, default, .. } => {
398                cases.iter().any(|case| case.body.has_measurement())
399                    || default.as_ref().is_some_and(|body| body.has_measurement())
400            }
401            Self::Break | Self::Continue => false,
402        }
403    }
404
405    /// Returns true if this control operation recursively reads `value`.
406    pub fn reads_value(&self, value: ClassicalValue) -> bool {
407        if self.classical_value_reads().contains(&value) {
408            return true;
409        }
410        match self {
411            Self::If {
412                then_body,
413                else_body,
414                ..
415            } => {
416                then_body.reads_value(value)
417                    || else_body
418                        .as_ref()
419                        .is_some_and(|body| body.reads_value(value))
420            }
421            Self::While { body, .. } | Self::For { body, .. } => body.reads_value(value),
422            Self::Switch { cases, default, .. } => {
423                cases.iter().any(|case| case.body.reads_value(value))
424                    || default.as_ref().is_some_and(|body| body.reads_value(value))
425            }
426            Self::Break | Self::Continue => false,
427        }
428    }
429}
430
431impl fmt::Display for ValueClassicalControlOp {
432    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
433        match self {
434            Self::If { .. } => write!(f, "if"),
435            Self::While { .. } => write!(f, "while"),
436            Self::For { .. } => write!(f, "for"),
437            Self::Switch { .. } => write!(f, "switch"),
438            Self::Break => write!(f, "break"),
439            Self::Continue => write!(f, "continue"),
440        }
441    }
442}
443
444/// A value-level instruction for circuit construction.
445///
446/// `ValueInstruction` is the construction-IR counterpart of [`Instruction`]. It has two
447/// families of variants:
448///
449/// - **`Instruction(Instruction)`** — all non-control-flow operations (gates, directives,
450///   classical data). The wrapped [`Instruction`] must not be
451///   [`Instruction::ClassicalControl`]; use [`ValueInstruction::ClassicalControl`] for
452///   control flow.
453/// - **`ClassicalControl(ValueClassicalControlOp)`** — value-level classical control flow
454///   whose bodies recursively contain [`ValueOperation`] entries with [`ParameterValue`]
455///   parameters.
456///
457/// # Conversion to Storage IR
458///
459/// [`Circuit::from_operations`](crate::circuit::Circuit::from_operations) recursively
460/// converts every `ValueInstruction` into an [`Instruction`]:
461///
462/// - `ValueInstruction::Instruction(inst)` → `inst` (pass-through, validated to not be
463///   `ClassicalControl`).
464/// - `ValueInstruction::ClassicalControl(vcc)` → `Instruction::ClassicalControl(cc)`,
465///   where every nested [`ValueControlBody`] is recursively converted to a
466///   [`ControlBody`] with interned parameters.
467#[derive(Debug, Clone, PartialEq)]
468pub enum ValueInstruction {
469    /// A non-control-flow instruction. The wrapped [`Instruction`] must not be
470    /// [`Instruction::ClassicalControl`].
471    Instruction(Instruction),
472    /// A value-level classical control-flow operation.
473    ClassicalControl(ValueClassicalControlOp),
474}
475
476impl ValueInstruction {
477    /// Creates a `ValueInstruction` from a non-control-flow [`Instruction`].
478    ///
479    /// # Panics
480    ///
481    /// Panics in debug builds if `inst` is [`Instruction::ClassicalControl`]. Use
482    /// [`ValueInstruction::ClassicalControl`] for control flow.
483    pub fn from_instruction(inst: Instruction) -> Self {
484        debug_assert!(
485            !matches!(inst, Instruction::ClassicalControl(_)),
486            "Instruction::ClassicalControl must use ValueInstruction::ClassicalControl variant"
487        );
488        Self::Instruction(inst)
489    }
490
491    /// Returns `true` if this is a classical control-flow instruction.
492    pub fn is_classical_control(&self) -> bool {
493        matches!(self, Self::ClassicalControl(_))
494    }
495
496    /// Returns `true` if this is a non-control-flow instruction.
497    pub fn is_instruction(&self) -> bool {
498        matches!(self, Self::Instruction(_))
499    }
500
501    /// Returns the human-readable instruction name.
502    pub fn name(&self) -> String {
503        match self {
504            Self::Instruction(instruction) => instruction.name(),
505            Self::ClassicalControl(control) => control.to_string(),
506        }
507    }
508
509    /// Returns a stable category name for this instruction.
510    pub fn instruction_type(&self) -> &'static str {
511        match self {
512            Self::Instruction(instruction) => instruction.instruction_type(),
513            Self::ClassicalControl(_) => "classical_control",
514        }
515    }
516
517    /// Returns `true` if this is a standard-gate instruction.
518    pub fn is_standard(&self) -> bool {
519        matches!(self, Self::Instruction(instruction) if instruction.is_standard())
520    }
521
522    /// Returns `true` if this is a multi-controlled-gate instruction.
523    pub fn is_mcgate(&self) -> bool {
524        matches!(self, Self::Instruction(instruction) if instruction.is_mcgate())
525    }
526
527    /// Returns `true` if this is a user-defined unitary instruction.
528    pub fn is_unitary(&self) -> bool {
529        matches!(self, Self::Instruction(instruction) if instruction.is_unitary())
530    }
531
532    /// Returns `true` if this is a circuit-backed gate instruction.
533    pub fn is_circuit_gate(&self) -> bool {
534        matches!(self, Self::Instruction(instruction) if instruction.is_circuit_gate())
535    }
536
537    /// Returns `true` if this is a non-unitary directive.
538    pub fn is_directive(&self) -> bool {
539        matches!(self, Self::Instruction(instruction) if instruction.is_directive())
540    }
541
542    /// Returns `true` if this is a classical-data instruction.
543    pub fn is_classical_data(&self) -> bool {
544        matches!(self, Self::Instruction(instruction) if instruction.is_classical_data())
545    }
546
547    /// Returns `true` if this is a delay instruction.
548    pub fn is_delay(&self) -> bool {
549        matches!(self, Self::Instruction(instruction) if instruction.is_delay())
550    }
551
552    /// Returns the standard gate when this is a standard-gate instruction.
553    pub fn standard_gate(&self) -> Option<StandardGate> {
554        match self {
555            Self::Instruction(Instruction::Standard(gate)) => Some(*gate),
556            _ => None,
557        }
558    }
559
560    /// Returns the directive when this is a directive instruction.
561    pub fn directive(&self) -> Option<Directive> {
562        match self {
563            Self::Instruction(Instruction::Directive(directive)) => Some(*directive),
564            _ => None,
565        }
566    }
567
568    /// Returns the wrapped storage instruction when this is a non-control-flow value instruction.
569    pub fn as_instruction(&self) -> Option<&Instruction> {
570        match self {
571            Self::Instruction(inst) => Some(inst),
572            Self::ClassicalControl(_) => None,
573        }
574    }
575
576    /// Consumes this value instruction and returns the wrapped storage instruction
577    /// when it is non-control-flow.
578    pub fn into_instruction(self) -> Option<Instruction> {
579        match self {
580            Self::Instruction(inst) => Some(inst),
581            Self::ClassicalControl(_) => None,
582        }
583    }
584}
585
586impl From<Instruction> for ValueInstruction {
587    /// Converts a non-control-flow [`Instruction`] into a `ValueInstruction`.
588    ///
589    /// # Panics
590    ///
591    /// Panics in debug builds if the instruction is [`Instruction::ClassicalControl`].
592    fn from(inst: Instruction) -> Self {
593        Self::from_instruction(inst)
594    }
595}
596
597impl From<ValueClassicalControlOp> for ValueInstruction {
598    fn from(op: ValueClassicalControlOp) -> Self {
599        Self::ClassicalControl(op)
600    }
601}
602
603impl fmt::Display for ValueInstruction {
604    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
605        match self {
606            Self::Instruction(inst) => write!(f, "{}", inst),
607            Self::ClassicalControl(vcc) => write!(f, "{}", vcc),
608        }
609    }
610}
611
612pub fn storage_operation_to_value<F>(
613    operation: Operation,
614    resolve_parameter: &F,
615) -> Result<ValueOperation, CircuitError>
616where
617    F: Fn(&CircuitParam) -> Result<ParameterValue, CircuitError>,
618{
619    fn convert_operation<F>(
620        operation: Operation,
621        resolve_parameter: &F,
622    ) -> Result<ValueOperation, CircuitError>
623    where
624        F: Fn(&CircuitParam) -> Result<ParameterValue, CircuitError>,
625    {
626        let params = operation
627            .params
628            .iter()
629            .map(resolve_parameter)
630            .collect::<Result<_, _>>()?;
631        Ok(ValueOperation {
632            instruction: convert_instruction(operation.instruction, resolve_parameter)?,
633            qubits: operation.qubits,
634            params,
635            label: operation.label,
636        })
637    }
638
639    fn convert_body<F>(
640        body: &ControlBody,
641        resolve_parameter: &F,
642    ) -> Result<ValueControlBody, CircuitError>
643    where
644        F: Fn(&CircuitParam) -> Result<ParameterValue, CircuitError>,
645    {
646        body.operations()
647            .iter()
648            .cloned()
649            .map(|operation| convert_operation(operation, resolve_parameter))
650            .collect::<Result<Vec<_>, _>>()
651            .map(ValueControlBody::new)
652    }
653
654    fn convert_instruction<F>(
655        instruction: Instruction,
656        resolve_parameter: &F,
657    ) -> Result<ValueInstruction, CircuitError>
658    where
659        F: Fn(&CircuitParam) -> Result<ParameterValue, CircuitError>,
660    {
661        let Instruction::ClassicalControl(op) = instruction else {
662            return Ok(ValueInstruction::Instruction(instruction));
663        };
664
665        let op = match op {
666            ClassicalControlOp::If(op) => ValueClassicalControlOp::If {
667                condition: op.condition().clone(),
668                then_body: convert_body(op.then_body(), resolve_parameter)?,
669                else_body: op
670                    .else_body()
671                    .map(|body| convert_body(body, resolve_parameter))
672                    .transpose()?,
673            },
674            ClassicalControlOp::While(op) => ValueClassicalControlOp::While {
675                condition: op.condition().clone(),
676                body: convert_body(op.body(), resolve_parameter)?,
677            },
678            ClassicalControlOp::For(op) => ValueClassicalControlOp::For {
679                var: op.var(),
680                start: op.start().clone(),
681                stop: op.stop().clone(),
682                step: op.step().clone(),
683                body: convert_body(op.body(), resolve_parameter)?,
684            },
685            ClassicalControlOp::Switch(op) => ValueClassicalControlOp::Switch {
686                target: op.target().clone(),
687                cases: op
688                    .cases()
689                    .iter()
690                    .map(|case| {
691                        Ok(ValueSwitchCase::new(
692                            case.value(),
693                            convert_body(case.body(), resolve_parameter)?,
694                        ))
695                    })
696                    .collect::<Result<_, CircuitError>>()?,
697                default: op
698                    .default()
699                    .map(|body| convert_body(body, resolve_parameter))
700                    .transpose()?,
701            },
702            ClassicalControlOp::Break => ValueClassicalControlOp::Break,
703            ClassicalControlOp::Continue => ValueClassicalControlOp::Continue,
704        };
705        Ok(ValueInstruction::ClassicalControl(op))
706    }
707
708    convert_operation(operation, resolve_parameter)
709}
710
711#[cfg(test)]
712mod tests {
713    use super::*;
714    use crate::circuit::ClassicalType;
715    use crate::circuit::bit::Qubit;
716    use crate::circuit::gate::{ClassicalDataOp, Directive, StandardGate};
717    use std::num::NonZeroU32;
718
719    #[test]
720    fn value_control_body_stores_value_operations() {
721        let ops = vec![ValueOperation::from_standard(
722            StandardGate::H,
723            [Qubit::new(0)],
724            [],
725        )];
726        let body = ValueControlBody::new(ops);
727        assert_eq!(body.operations().len(), 1);
728    }
729
730    #[test]
731    fn value_control_body_from_vec() {
732        let ops = vec![
733            ValueOperation::from_standard(StandardGate::X, [Qubit::new(0)], []),
734            ValueOperation::from_standard(StandardGate::Y, [Qubit::new(1)], []),
735        ];
736        let body: ValueControlBody = ops.into();
737        assert_eq!(body.operations().len(), 2);
738    }
739
740    #[test]
741    fn value_instruction_from_gate_instruction() {
742        let vi = ValueInstruction::from_instruction(Instruction::Standard(StandardGate::H));
743        assert!(vi.is_instruction());
744        assert!(!vi.is_classical_control());
745    }
746
747    #[test]
748    fn value_instruction_from_classical_control() {
749        let vcc = ValueClassicalControlOp::Break;
750        let vi = ValueInstruction::from(vcc);
751        assert!(vi.is_classical_control());
752        assert!(!vi.is_instruction());
753    }
754
755    #[test]
756    fn value_instruction_exposes_instruction_queries() {
757        let standard = ValueInstruction::from_instruction(Instruction::Standard(StandardGate::H));
758        assert_eq!(standard.name(), "H");
759        assert_eq!(standard.instruction_type(), "standard");
760        assert!(standard.is_standard());
761        assert_eq!(standard.standard_gate(), Some(StandardGate::H));
762        assert_eq!(standard.directive(), None);
763
764        let directive =
765            ValueInstruction::from_instruction(Instruction::Directive(Directive::Barrier));
766        assert_eq!(directive.name(), "barrier");
767        assert_eq!(directive.to_string(), "barrier");
768        assert_eq!(directive.instruction_type(), "directive");
769        assert!(directive.is_directive());
770        assert_eq!(directive.directive(), Some(Directive::Barrier));
771
772        let value =
773            ClassicalValue::new(crate::circuit::CircuitId::default(), 0, ClassicalType::Bit);
774        let classical_data = ValueInstruction::from_instruction(Instruction::ClassicalData(
775            ClassicalDataOp::MeasureBit { result: value },
776        ));
777        assert_eq!(classical_data.name(), "measure_bit");
778        assert_eq!(classical_data.instruction_type(), "classical_data");
779        assert!(classical_data.is_classical_data());
780
781        let control = ValueInstruction::from(ValueClassicalControlOp::Break);
782        assert_eq!(control.name(), "break");
783        assert_eq!(control.instruction_type(), "classical_control");
784        assert!(control.is_classical_control());
785
786        let delay = ValueInstruction::from_instruction(Instruction::Delay);
787        assert_eq!(delay.name(), "delay");
788        assert_eq!(delay.instruction_type(), "delay");
789        assert!(delay.is_delay());
790    }
791
792    #[test]
793    fn value_classical_control_reads_and_writes() {
794        let var = ClassicalVar::new(
795            crate::circuit::CircuitId::default(),
796            0,
797            ClassicalType::UInt(NonZeroU32::new(8).unwrap()),
798        );
799        let start = ClassicalExpr::var(var);
800        let stop = ClassicalExpr::uint_literal(8, 10).unwrap();
801        let step = ClassicalExpr::uint_literal(8, 1).unwrap();
802        let body = ValueControlBody::new(vec![]);
803
804        let vcc = ValueClassicalControlOp::For {
805            var,
806            start,
807            stop,
808            step,
809            body,
810        };
811
812        assert_eq!(vcc.classical_var_reads().len(), 1);
813        assert_eq!(vcc.classical_writes().len(), 1);
814        assert_eq!(vcc.classical_writes()[0], var);
815    }
816
817    #[test]
818    fn value_body_reports_nested_measurements() {
819        let value =
820            ClassicalValue::new(crate::circuit::CircuitId::default(), 0, ClassicalType::Bit);
821        let nested = ValueControlBody::new(vec![ValueOperation {
822            instruction: ValueInstruction::from_instruction(Instruction::ClassicalData(
823                ClassicalDataOp::MeasureBit { result: value },
824            )),
825            qubits: smallvec::smallvec![Qubit::new(0)],
826            params: smallvec::smallvec![],
827            label: None,
828        }]);
829        let body = ValueControlBody::new(vec![ValueOperation {
830            instruction: ValueInstruction::ClassicalControl(ValueClassicalControlOp::If {
831                condition: ClassicalExpr::bool_literal(true),
832                then_body: nested,
833                else_body: None,
834            }),
835            qubits: smallvec::smallvec![Qubit::new(0)],
836            params: smallvec::smallvec![],
837            label: None,
838        }]);
839
840        assert!(body.has_measurement());
841    }
842
843    #[test]
844    fn value_body_reports_nested_value_reads() {
845        let circuit_id = crate::circuit::CircuitId::default();
846        let value = ClassicalValue::new(circuit_id, 0, ClassicalType::Bit);
847        let target = ClassicalVar::new(circuit_id, 1, ClassicalType::Bit);
848        let nested = ValueControlBody::new(vec![ValueOperation {
849            instruction: ValueInstruction::from_instruction(Instruction::ClassicalData(
850                ClassicalDataOp::Store {
851                    target,
852                    value: value.expr(),
853                },
854            )),
855            qubits: smallvec::smallvec![],
856            params: smallvec::smallvec![],
857            label: None,
858        }]);
859        let control = ValueClassicalControlOp::While {
860            condition: ClassicalExpr::bool_literal(true),
861            body: nested,
862        };
863
864        assert!(control.reads_value(value));
865    }
866
867    #[test]
868    fn value_switch_case_construction() {
869        let body = ValueControlBody::new(vec![]);
870        let case = ValueSwitchCase::new(1, body);
871        assert_eq!(case.value, 1);
872        assert_eq!(case.body.operations().len(), 0);
873    }
874
875    #[test]
876    fn value_instructions_compare_nested_control_flow_structurally() {
877        let make_if = || {
878            ValueInstruction::ClassicalControl(ValueClassicalControlOp::If {
879                condition: ClassicalExpr::bool_literal(true),
880                then_body: ValueControlBody::new(vec![ValueOperation::from_standard(
881                    StandardGate::H,
882                    [Qubit::new(0)],
883                    [],
884                )]),
885                else_body: None,
886            })
887        };
888
889        assert_eq!(make_if(), make_if());
890
891        let different_body = ValueInstruction::ClassicalControl(ValueClassicalControlOp::If {
892            condition: ClassicalExpr::bool_literal(true),
893            then_body: ValueControlBody::new(vec![ValueOperation::from_standard(
894                StandardGate::X,
895                [Qubit::new(0)],
896                [],
897            )]),
898            else_body: None,
899        });
900        assert_ne!(make_if(), different_body);
901
902        let with_else = ValueInstruction::ClassicalControl(ValueClassicalControlOp::If {
903            condition: ClassicalExpr::bool_literal(true),
904            then_body: ValueControlBody::new(vec![ValueOperation::from_standard(
905                StandardGate::H,
906                [Qubit::new(0)],
907                [],
908            )]),
909            else_body: Some(ValueControlBody::new(vec![])),
910        });
911        assert_ne!(make_if(), with_else);
912
913        assert_eq!(
914            ValueInstruction::from_instruction(Instruction::Standard(StandardGate::H)),
915            ValueInstruction::from_instruction(Instruction::Standard(StandardGate::H))
916        );
917        assert_ne!(
918            ValueInstruction::from_instruction(Instruction::Standard(StandardGate::H)),
919            ValueInstruction::from_instruction(Instruction::Standard(StandardGate::X))
920        );
921    }
922}