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