1use 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#[derive(Debug, Clone, PartialEq)]
88pub struct ValueControlBody {
89 operations: Vec<ValueOperation>,
90}
91
92impl ValueControlBody {
93 pub fn new(operations: Vec<ValueOperation>) -> Self {
95 Self { operations }
96 }
97
98 pub fn operations(&self) -> &[ValueOperation] {
100 self.operations.as_slice()
101 }
102
103 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 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 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#[derive(Debug, Clone, PartialEq)]
147pub struct ValueSwitchCase {
148 pub value: u128,
150 pub body: ValueControlBody,
152}
153
154impl ValueSwitchCase {
155 pub fn new(value: u128, body: ValueControlBody) -> Self {
157 Self { value, body }
158 }
159}
160
161#[derive(Debug, Clone, PartialEq)]
179pub enum ValueClassicalControlOp {
180 If {
184 condition: ClassicalExpr,
186 then_body: ValueControlBody,
188 else_body: Option<ValueControlBody>,
190 },
191 While {
195 condition: ClassicalExpr,
197 body: ValueControlBody,
199 },
200 For {
205 var: ClassicalVar,
207 start: ClassicalExpr,
209 stop: ClassicalExpr,
211 step: ClassicalExpr,
213 body: ValueControlBody,
215 },
216 Switch {
220 target: ClassicalExpr,
222 cases: Vec<ValueSwitchCase>,
224 default: Option<ValueControlBody>,
226 },
227 Break,
229 Continue,
231}
232
233impl ValueClassicalControlOp {
234 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 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 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 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 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 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 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 pub fn classical_writes(&self) -> Vec<ClassicalVar> {
379 match self {
380 Self::For { var, .. } => vec![*var],
381 _ => Vec::new(),
382 }
383 }
384
385 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 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#[derive(Debug, Clone, PartialEq)]
470pub enum ValueInstruction {
471 Instruction(Instruction),
474 ClassicalControl(ValueClassicalControlOp),
476}
477
478impl ValueInstruction {
479 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 pub fn is_classical_control(&self) -> bool {
495 matches!(self, Self::ClassicalControl(_))
496 }
497
498 pub fn is_instruction(&self) -> bool {
500 matches!(self, Self::Instruction(_))
501 }
502
503 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 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 pub fn is_standard(&self) -> bool {
521 matches!(self, Self::Instruction(instruction) if instruction.is_standard())
522 }
523
524 pub fn is_mcgate(&self) -> bool {
526 matches!(self, Self::Instruction(instruction) if instruction.is_mcgate())
527 }
528
529 pub fn is_unitary(&self) -> bool {
531 matches!(self, Self::Instruction(instruction) if instruction.is_unitary())
532 }
533
534 pub fn is_circuit_gate(&self) -> bool {
536 matches!(self, Self::Instruction(instruction) if instruction.is_circuit_gate())
537 }
538
539 pub fn is_directive(&self) -> bool {
541 matches!(self, Self::Instruction(instruction) if instruction.is_directive())
542 }
543
544 pub fn is_classical_data(&self) -> bool {
546 matches!(self, Self::Instruction(instruction) if instruction.is_classical_data())
547 }
548
549 pub fn is_delay(&self) -> bool {
551 matches!(self, Self::Instruction(instruction) if instruction.is_delay())
552 }
553
554 pub fn standard_gate(&self) -> Option<StandardGate> {
556 self.as_instruction().and_then(Instruction::standard_gate)
557 }
558
559 pub fn directive(&self) -> Option<Directive> {
561 self.as_instruction().and_then(Instruction::directive)
562 }
563
564 pub fn mc_gate(&self) -> Option<&MCGate> {
566 self.as_instruction().and_then(Instruction::mc_gate)
567 }
568
569 pub fn unitary_gate(&self) -> Option<&UnitaryGate> {
571 self.as_instruction().and_then(Instruction::unitary_gate)
572 }
573
574 pub fn circuit_gate(&self) -> Option<&CircuitGate> {
576 self.as_instruction().and_then(Instruction::circuit_gate)
577 }
578
579 pub fn classical_data(&self) -> Option<&ClassicalDataOp> {
581 self.as_instruction().and_then(Instruction::classical_data)
582 }
583
584 pub fn classical_control(&self) -> Option<&ValueClassicalControlOp> {
587 match self {
588 Self::Instruction(_) => None,
589 Self::ClassicalControl(op) => Some(op),
590 }
591 }
592
593 pub fn as_instruction(&self) -> Option<&Instruction> {
595 match self {
596 Self::Instruction(inst) => Some(inst),
597 Self::ClassicalControl(_) => None,
598 }
599 }
600
601 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 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}