1use crate::circuit::bit::Qubit;
51use crate::circuit::circuit_classical::ControlScopeKind;
52use crate::circuit::circuit_param::{CircuitParam, ParameterValue};
53use crate::circuit::classical::CircuitId;
54use crate::circuit::classical_expr::{ClassicalExpr, ClassicalExprKind};
55use crate::circuit::error::CircuitError;
56use crate::circuit::gate::circuit_gate::{CircuitGate, FrozenCircuit};
57use crate::circuit::gate::instruction::Instruction;
58use crate::circuit::gate::{Directive, StandardGate, UnitaryGate};
59use crate::circuit::operation::{Operation, ValueOperation};
60use crate::circuit::parameter::Parameter;
61use crate::circuit::value_instruction::{
62 ValueControlBody, ValueInstruction, storage_operation_to_value,
63};
64use crate::circuit::{
65 ClassicalControlOp, ClassicalType, ClassicalValue, ClassicalVar, ControlBody, ForOp, IfOp,
66 SwitchCase, SwitchOp, ValueClassicalControlOp, WhileOp,
67};
68use crate::circuit::{ClassicalDataOp, circuit_to_matrix};
69use indexmap::IndexSet;
70use ndarray::Array2;
71use num_complex::Complex64;
72use smallvec::{SmallVec, smallvec};
73use std::collections::{HashMap, HashSet};
74use std::sync::Arc;
75
76#[derive(Debug)]
89pub struct Circuit {
90 pub(super) circuit_id: CircuitId,
91 pub(super) qubits: IndexSet<Qubit>,
97 pub(super) symbols: IndexSet<String>,
101 pub(super) parameters: IndexSet<Parameter>,
109 pub(super) data: Arc<Vec<Operation>>,
113 pub(super) classical_vars: Vec<ClassicalType>,
119 pub(super) classical_values: Vec<ClassicalType>,
124 pub(super) control_scope_stack: Vec<ControlScopeKind>,
128 pub(super) global_phase: CircuitParam,
134}
135
136impl Clone for Circuit {
137 fn clone(&self) -> Self {
138 let circuit_id = CircuitId::new();
139 if self.classical_vars.is_empty() && self.classical_values.is_empty() {
140 return Self {
141 circuit_id,
142 qubits: self.qubits.clone(),
143 symbols: self.symbols.clone(),
144 parameters: self.parameters.clone(),
145 data: self.data.clone(),
146 classical_vars: Vec::new(),
147 classical_values: Vec::new(),
148 control_scope_stack: self.control_scope_stack.clone(),
149 global_phase: self.global_phase.clone(),
150 };
151 }
152 let var_map = self
153 .classical_vars
154 .iter()
155 .enumerate()
156 .map(|(index, ty)| {
157 (
158 ClassicalVar::new(self.circuit_id, index as u32, *ty),
159 ClassicalVar::new(circuit_id, index as u32, *ty),
160 )
161 })
162 .collect::<HashMap<_, _>>();
163 let value_map = self
164 .classical_values
165 .iter()
166 .enumerate()
167 .map(|(index, ty)| {
168 (
169 ClassicalValue::new(self.circuit_id, index as u32, *ty),
170 ClassicalValue::new(circuit_id, index as u32, *ty),
171 )
172 })
173 .collect::<HashMap<_, _>>();
174 let data = self
175 .data
176 .iter()
177 .map(|operation| {
178 Self::remap_operation(
179 operation,
180 &|qubit| Ok(qubit),
181 &|param| Ok(param.clone()),
182 &var_map,
183 &value_map,
184 )
185 })
186 .collect::<Result<Vec<_>, _>>()
187 .expect("a valid circuit must be cloneable with complete handle mappings");
188
189 Self {
190 circuit_id,
191 qubits: self.qubits.clone(),
192 symbols: self.symbols.clone(),
193 parameters: self.parameters.clone(),
194 data: Arc::new(data),
195 classical_vars: self.classical_vars.clone(),
196 classical_values: self.classical_values.clone(),
197 control_scope_stack: self.control_scope_stack.clone(),
198 global_phase: self.global_phase.clone(),
199 }
200 }
201}
202
203impl PartialEq for Circuit {
205 fn eq(&self, other: &Self) -> bool {
206 if self.qubits != other.qubits
207 || self.symbols != other.symbols
208 || self.parameters.len() != other.parameters.len()
209 || !self
210 .parameters
211 .iter()
212 .all(|parameter| other.parameters.contains(parameter))
213 || self.classical_vars != other.classical_vars
214 || self.classical_values != other.classical_values
215 || self.control_scope_stack != other.control_scope_stack
216 || self.data.len() != other.data.len()
217 {
218 return false;
219 }
220 circuit_params_equal(
221 &self.global_phase,
222 &other.global_phase,
223 &self.parameters,
224 &other.parameters,
225 ) && operations_structurally_equal(
226 self.data.as_slice(),
227 other.data.as_slice(),
228 &self.parameters,
229 &other.parameters,
230 )
231 }
232}
233
234impl Circuit {
235 pub(crate) fn operations_structurally_equal(&self, other: &Self) -> bool {
237 operations_structurally_equal(
238 self.data.as_slice(),
239 other.data.as_slice(),
240 &self.parameters,
241 &other.parameters,
242 )
243 }
244}
245
246fn circuit_params_equal(
247 left: &CircuitParam,
248 right: &CircuitParam,
249 left_parameters: &IndexSet<Parameter>,
250 right_parameters: &IndexSet<Parameter>,
251) -> bool {
252 match (left, right) {
253 (CircuitParam::Fixed(left), CircuitParam::Fixed(right)) => left == right,
254 (CircuitParam::Index(left), CircuitParam::Index(right)) => left_parameters
255 .get_index(*left as usize)
256 .zip(right_parameters.get_index(*right as usize))
257 .is_some_and(|(left, right)| left == right),
258 (CircuitParam::Fixed(value), CircuitParam::Index(index)) => right_parameters
259 .get_index(*index as usize)
260 .is_some_and(|right| Parameter::from(*value) == *right),
261 (CircuitParam::Index(index), CircuitParam::Fixed(value)) => left_parameters
262 .get_index(*index as usize)
263 .is_some_and(|left| *left == Parameter::from(*value)),
264 }
265}
266
267fn classical_var_equal(left: ClassicalVar, right: ClassicalVar) -> bool {
268 left.index() == right.index() && left.ty() == right.ty()
269}
270
271fn classical_value_equal(left: ClassicalValue, right: ClassicalValue) -> bool {
272 left.index() == right.index() && left.ty() == right.ty()
273}
274
275fn classical_expr_equal(left: &ClassicalExpr, right: &ClassicalExpr) -> bool {
276 if left.ty() != right.ty() {
277 return false;
278 }
279 match (left.kind(), right.kind()) {
280 (ClassicalExprKind::Var(left), ClassicalExprKind::Var(right)) => {
281 classical_var_equal(*left, *right)
282 }
283 (ClassicalExprKind::Value(left), ClassicalExprKind::Value(right)) => {
284 classical_value_equal(*left, *right)
285 }
286 (
287 ClassicalExprKind::Unary {
288 op: left_op,
289 expr: left,
290 },
291 ClassicalExprKind::Unary {
292 op: right_op,
293 expr: right,
294 },
295 ) => left_op == right_op && classical_expr_equal(left, right),
296 (
297 ClassicalExprKind::Binary {
298 op: left_op,
299 lhs: left_lhs,
300 rhs: left_rhs,
301 },
302 ClassicalExprKind::Binary {
303 op: right_op,
304 lhs: right_lhs,
305 rhs: right_rhs,
306 },
307 ) => {
308 left_op == right_op
309 && classical_expr_equal(left_lhs, right_lhs)
310 && classical_expr_equal(left_rhs, right_rhs)
311 }
312 (
313 ClassicalExprKind::Compare {
314 op: left_op,
315 lhs: left_lhs,
316 rhs: left_rhs,
317 },
318 ClassicalExprKind::Compare {
319 op: right_op,
320 lhs: right_lhs,
321 rhs: right_rhs,
322 },
323 ) => {
324 left_op == right_op
325 && classical_expr_equal(left_lhs, right_lhs)
326 && classical_expr_equal(left_rhs, right_rhs)
327 }
328 (
329 ClassicalExprKind::Cast {
330 cast: left_cast,
331 expr: left,
332 },
333 ClassicalExprKind::Cast {
334 cast: right_cast,
335 expr: right,
336 },
337 ) => left_cast == right_cast && classical_expr_equal(left, right),
338 (
339 ClassicalExprKind::Select {
340 condition: left_condition,
341 then_expr: left_then,
342 else_expr: left_else,
343 },
344 ClassicalExprKind::Select {
345 condition: right_condition,
346 then_expr: right_then,
347 else_expr: right_else,
348 },
349 ) => {
350 classical_expr_equal(left_condition, right_condition)
351 && classical_expr_equal(left_then, right_then)
352 && classical_expr_equal(left_else, right_else)
353 }
354 (
355 ClassicalExprKind::ExtractBit {
356 value: left,
357 index: left_index,
358 },
359 ClassicalExprKind::ExtractBit {
360 value: right,
361 index: right_index,
362 },
363 ) => left_index == right_index && classical_expr_equal(left, right),
364 (
365 ClassicalExprKind::ExtractBits {
366 value: left,
367 offset: left_offset,
368 width: left_width,
369 },
370 ClassicalExprKind::ExtractBits {
371 value: right,
372 offset: right_offset,
373 width: right_width,
374 },
375 ) => {
376 left_offset == right_offset
377 && left_width == right_width
378 && classical_expr_equal(left, right)
379 }
380 (ClassicalExprKind::Concat { parts: left }, ClassicalExprKind::Concat { parts: right })
381 | (
382 ClassicalExprKind::PackBits { bits: left },
383 ClassicalExprKind::PackBits { bits: right },
384 ) => {
385 left.len() == right.len()
386 && left
387 .iter()
388 .zip(right.iter())
389 .all(|(left, right)| classical_expr_equal(left, right))
390 }
391 (left, right) => left == right,
392 }
393}
394
395fn classical_data_equal(left: &ClassicalDataOp, right: &ClassicalDataOp) -> bool {
396 match (left, right) {
397 (
398 ClassicalDataOp::Store {
399 target: left_target,
400 value: left_value,
401 },
402 ClassicalDataOp::Store {
403 target: right_target,
404 value: right_value,
405 },
406 ) => {
407 classical_var_equal(*left_target, *right_target)
408 && classical_expr_equal(left_value, right_value)
409 }
410 (
411 ClassicalDataOp::MeasureBit { result: left },
412 ClassicalDataOp::MeasureBit { result: right },
413 )
414 | (
415 ClassicalDataOp::MeasureBits { result: left },
416 ClassicalDataOp::MeasureBits { result: right },
417 ) => classical_value_equal(*left, *right),
418 _ => false,
419 }
420}
421
422fn operation_instruction_equal(
423 left: &Instruction,
424 right: &Instruction,
425 left_parameters: &IndexSet<Parameter>,
426 right_parameters: &IndexSet<Parameter>,
427) -> bool {
428 match (left, right) {
429 (Instruction::ClassicalData(left), Instruction::ClassicalData(right)) => {
430 classical_data_equal(left, right)
431 }
432 (Instruction::ClassicalControl(left), Instruction::ClassicalControl(right)) => {
433 classical_control_equal(left, right, left_parameters, right_parameters)
434 }
435 _ => left == right,
436 }
437}
438
439fn control_body_equal(
440 left: &ControlBody,
441 right: &ControlBody,
442 left_parameters: &IndexSet<Parameter>,
443 right_parameters: &IndexSet<Parameter>,
444) -> bool {
445 operations_structurally_equal(
446 left.operations(),
447 right.operations(),
448 left_parameters,
449 right_parameters,
450 )
451}
452
453fn classical_control_equal(
454 left: &ClassicalControlOp,
455 right: &ClassicalControlOp,
456 left_parameters: &IndexSet<Parameter>,
457 right_parameters: &IndexSet<Parameter>,
458) -> bool {
459 match (left, right) {
460 (ClassicalControlOp::If(left), ClassicalControlOp::If(right)) => {
461 classical_expr_equal(left.condition(), right.condition())
462 && control_body_equal(
463 left.then_body(),
464 right.then_body(),
465 left_parameters,
466 right_parameters,
467 )
468 && match (left.else_body(), right.else_body()) {
469 (Some(left), Some(right)) => {
470 control_body_equal(left, right, left_parameters, right_parameters)
471 }
472 (None, None) => true,
473 _ => false,
474 }
475 }
476 (ClassicalControlOp::While(left), ClassicalControlOp::While(right)) => {
477 classical_expr_equal(left.condition(), right.condition())
478 && control_body_equal(left.body(), right.body(), left_parameters, right_parameters)
479 }
480 (ClassicalControlOp::For(left), ClassicalControlOp::For(right)) => {
481 classical_var_equal(left.var(), right.var())
482 && classical_expr_equal(left.start(), right.start())
483 && classical_expr_equal(left.stop(), right.stop())
484 && classical_expr_equal(left.step(), right.step())
485 && control_body_equal(left.body(), right.body(), left_parameters, right_parameters)
486 }
487 (ClassicalControlOp::Switch(left), ClassicalControlOp::Switch(right)) => {
488 classical_expr_equal(left.target(), right.target())
489 && left.cases().len() == right.cases().len()
490 && left.cases().iter().zip(right.cases()).all(|(left, right)| {
491 left.value() == right.value()
492 && control_body_equal(
493 left.body(),
494 right.body(),
495 left_parameters,
496 right_parameters,
497 )
498 })
499 && match (left.default(), right.default()) {
500 (Some(left), Some(right)) => {
501 control_body_equal(left, right, left_parameters, right_parameters)
502 }
503 (None, None) => true,
504 _ => false,
505 }
506 }
507 (ClassicalControlOp::Break, ClassicalControlOp::Break)
508 | (ClassicalControlOp::Continue, ClassicalControlOp::Continue) => true,
509 _ => false,
510 }
511}
512
513fn operations_structurally_equal(
514 left: &[Operation],
515 right: &[Operation],
516 left_parameters: &IndexSet<Parameter>,
517 right_parameters: &IndexSet<Parameter>,
518) -> bool {
519 left.len() == right.len()
520 && left.iter().zip(right).all(|(left, right)| {
521 left.qubits == right.qubits
522 && left.label == right.label
523 && left.params.len() == right.params.len()
524 && left.params.iter().zip(&right.params).all(|(left, right)| {
525 circuit_params_equal(left, right, left_parameters, right_parameters)
526 })
527 && operation_instruction_equal(
528 &left.instruction,
529 &right.instruction,
530 left_parameters,
531 right_parameters,
532 )
533 })
534}
535
536impl From<usize> for Circuit {
537 fn from(num_qubits: usize) -> Self {
538 Circuit::new(num_qubits)
539 }
540}
541
542impl Circuit {
543 pub fn new(num_qubits: usize) -> Self {
560 let qubits = (0..num_qubits).map(|i| Qubit::new(i as u32)).collect();
561
562 Self {
563 circuit_id: CircuitId::new(),
564 qubits,
565 data: Arc::new(Vec::new()),
566 classical_vars: vec![],
567 classical_values: vec![],
568 control_scope_stack: vec![],
569 symbols: IndexSet::default(),
570 parameters: IndexSet::default(),
571 global_phase: CircuitParam::Fixed(0.0),
572 }
573 }
574
575 pub fn from_qubits(qubits: Vec<Qubit>) -> Result<Circuit, CircuitError> {
587 if !Self::check_qubits_unique(&qubits) {
588 return Err(CircuitError::DuplicateQubits);
589 }
590
591 Ok(Self {
592 circuit_id: CircuitId::new(),
593 symbols: IndexSet::new(),
594 qubits: qubits.into_iter().collect(),
595 data: Arc::new(Vec::new()),
596 classical_vars: vec![],
597 classical_values: vec![],
598 control_scope_stack: vec![],
599 parameters: IndexSet::default(),
600 global_phase: CircuitParam::Fixed(0.0),
601 })
602 }
603
604 pub fn from_operations(
620 qubits: Vec<Qubit>,
621 operations: impl IntoIterator<Item = ValueOperation>,
622 classical_vars: Option<Vec<ClassicalType>>,
623 classical_values: Option<Vec<ClassicalType>>,
624 ) -> Result<Self, CircuitError> {
625 let operations = operations.into_iter().collect::<Vec<_>>();
626 let mut circuit = Self::from_qubits(qubits)?;
627 Arc::make_mut(&mut circuit.data).reserve(operations.len());
628 if let Some(circuit_id) = infer_classical_circuit_id(&operations)? {
629 circuit.circuit_id = circuit_id;
630 }
631 circuit.classical_vars = classical_vars.unwrap_or_default();
632 circuit.classical_values = classical_values.unwrap_or_default();
633 for operation in operations {
634 circuit.append_value_operation_deferred_validation(operation)?;
635 }
636 circuit.validate_operation_parameters(circuit.operations())?;
637 circuit.validate()?;
638 Ok(circuit)
639 }
640
641 pub fn append_value_operation(
647 &mut self,
648 operation: ValueOperation,
649 ) -> Result<(), CircuitError> {
650 self.append_value_operation_with_validation(operation, true)
651 }
652
653 fn append_value_operation_deferred_validation(
654 &mut self,
655 operation: ValueOperation,
656 ) -> Result<(), CircuitError> {
657 self.append_value_operation_with_validation(operation, false)
658 }
659
660 fn append_value_operation_with_validation(
661 &mut self,
662 operation: ValueOperation,
663 validate_builder_state: bool,
664 ) -> Result<(), CircuitError> {
665 let ValueOperation {
666 instruction,
667 qubits,
668 params,
669 label,
670 } = operation;
671 let instruction = self.lower_instruction(instruction)?;
672 self.append_owned_with_validation(
673 instruction,
674 qubits,
675 params,
676 label,
677 validate_builder_state,
678 )
679 }
680
681 pub fn add_qubits(&mut self, new_qubits: Vec<Qubit>) -> Result<(), CircuitError> {
692 let mut seen_new = HashSet::with_capacity(new_qubits.len());
693
694 for q in &new_qubits {
695 if self.qubits.contains(q) {
696 return Err(CircuitError::DuplicateQubits);
697 }
698
699 if !seen_new.insert(*q) {
700 return Err(CircuitError::DuplicateQubits);
701 }
702 }
703 self.qubits.extend(new_qubits);
704 Ok(())
705 }
706
707 pub fn add_parameter(&mut self, param: Parameter) -> (usize, bool) {
711 let (index, is_new) = self.parameters.insert_full(param.clone());
712 if is_new {
713 for sym in param.get_symbols() {
714 self.symbols.insert(sym);
715 }
716 }
717 (index, is_new)
718 }
719
720 pub fn resolve_parameter(&self, param: &CircuitParam) -> Result<Parameter, CircuitError> {
733 match param {
734 CircuitParam::Fixed(value) => {
735 if !value.is_finite() {
736 return Err(CircuitError::InvalidParameterValue(0, *value));
737 }
738 Ok(Parameter::from(*value))
739 }
740 CircuitParam::Index(index) => self
741 .parameters
742 .get_index(*index as usize)
743 .cloned()
744 .ok_or(CircuitError::InvalidParameterIndex(*index)),
745 }
746 }
747
748 pub fn parameter_value(&self, param: &CircuitParam) -> Result<ParameterValue, CircuitError> {
759 match param {
760 CircuitParam::Fixed(value) => Ok(ParameterValue::Fixed(*value)),
761 CircuitParam::Index(index) => self
762 .parameters
763 .get_index(*index as usize)
764 .cloned()
765 .map(ParameterValue::Param)
766 .ok_or(CircuitError::InvalidParameterIndex(*index)),
767 }
768 }
769
770 pub fn map_param(&mut self, param: Parameter) -> Result<CircuitParam, CircuitError> {
790 let param = param.canonicalized()?;
791 if param.get_symbols().is_empty() {
792 let value = param.evaluate(&None)?;
793 let value = if value == 0.0 { 0.0 } else { value };
794 Ok(CircuitParam::Fixed(value))
795 } else {
796 let (index, _) = self.add_parameter(param);
797 Ok(CircuitParam::Index(index as u32))
798 }
799 }
800
801 pub fn width(&self) -> usize {
805 self.qubits.len()
806 }
807
808 pub fn num_qubits(&self) -> usize {
810 self.qubits.len()
811 }
812
813 pub fn parameters(&self) -> &IndexSet<Parameter> {
815 &self.parameters
816 }
817
818 pub fn symbols(&self) -> &IndexSet<String> {
825 &self.symbols
826 }
827
828 pub fn used_symbols(&self) -> IndexSet<String> {
835 let referenced_indices = self.referenced_parameter_indices();
836 let mut referenced_symbols = HashSet::new();
837 for index in referenced_indices {
838 if let Some(parameter) = self.parameters.get_index(index as usize) {
839 referenced_symbols.extend(parameter.get_symbols());
840 }
841 }
842
843 self.symbols
844 .iter()
845 .filter(|symbol| referenced_symbols.contains(symbol.as_str()))
846 .cloned()
847 .collect()
848 }
849
850 pub fn uses_symbol(&self, symbol: &str) -> bool {
857 self.referenced_parameter_indices()
858 .into_iter()
859 .any(|index| {
860 self.parameters
861 .get_index(index as usize)
862 .is_some_and(|parameter| parameter.get_symbols().contains(symbol))
863 })
864 }
865
866 fn referenced_parameter_indices(&self) -> HashSet<u32> {
867 let mut indices = HashSet::new();
868 if let CircuitParam::Index(index) = self.global_phase {
869 indices.insert(index);
870 }
871 Self::collect_operation_parameter_indices(self.data.as_slice(), &mut indices);
872 indices
873 }
874
875 fn collect_operation_parameter_indices(operations: &[Operation], indices: &mut HashSet<u32>) {
876 for operation in operations {
877 indices.extend(operation.params.iter().filter_map(|param| match param {
878 CircuitParam::Index(index) => Some(*index),
879 CircuitParam::Fixed(_) => None,
880 }));
881
882 if let Instruction::ClassicalControl(control) = &operation.instruction {
883 match control {
884 ClassicalControlOp::If(op) => {
885 Self::collect_operation_parameter_indices(
886 op.then_body().operations(),
887 indices,
888 );
889 if let Some(body) = op.else_body() {
890 Self::collect_operation_parameter_indices(body.operations(), indices);
891 }
892 }
893 ClassicalControlOp::While(op) => {
894 Self::collect_operation_parameter_indices(op.body().operations(), indices);
895 }
896 ClassicalControlOp::For(op) => {
897 Self::collect_operation_parameter_indices(op.body().operations(), indices);
898 }
899 ClassicalControlOp::Switch(op) => {
900 for case in op.cases() {
901 Self::collect_operation_parameter_indices(
902 case.body().operations(),
903 indices,
904 );
905 }
906 if let Some(body) = op.default() {
907 Self::collect_operation_parameter_indices(body.operations(), indices);
908 }
909 }
910 ClassicalControlOp::Break | ClassicalControlOp::Continue => {}
911 }
912 }
913 }
914 }
915
916 pub fn qubits(&self) -> Vec<Qubit> {
918 self.qubits.iter().cloned().collect()
919 }
920
921 pub(crate) fn contains_qubit(&self, qubit: &Qubit) -> bool {
924 self.qubits.contains(qubit)
925 }
926
927 pub(crate) fn has_same_qubits(&self, other: &Self) -> bool {
930 self.qubits == other.qubits
931 }
932
933 pub fn global_phase(&self) -> Parameter {
935 match self.global_phase {
936 CircuitParam::Index(index) => self.parameters[index as usize].clone(),
937 CircuitParam::Fixed(value) => Parameter::from(value),
938 }
939 }
940
941 pub fn global_phase_param(&self) -> &CircuitParam {
943 &self.global_phase
944 }
945
946 pub fn set_global_phase(&mut self, phase: Parameter) {
948 if let Ok(val) = phase.evaluate(&None) {
950 self.global_phase = CircuitParam::Fixed(val);
951 } else {
952 let (index, is_new) = self.parameters.insert_full(phase.clone());
953 if is_new {
954 for sym in phase.get_symbols() {
955 self.symbols.insert(sym);
956 }
957 }
958 self.global_phase = CircuitParam::Index(index as u32);
959 }
960 }
961
962 pub fn operations(&self) -> &[Operation] {
964 self.data.as_slice()
965 }
966
967 pub fn remove_operation(&mut self, index: usize) -> Result<Operation, CircuitError> {
983 let mut removed = self.remove_operations([index])?;
984 Ok(removed.remove(0))
985 }
986
987 pub fn remove_operations<I>(&mut self, indices: I) -> Result<Vec<Operation>, CircuitError>
1010 where
1011 I: IntoIterator<Item = usize>,
1012 {
1013 let mut indices = indices.into_iter().collect::<Vec<_>>();
1014 indices.sort_unstable();
1015 indices.dedup();
1016
1017 if indices.is_empty() {
1018 return Ok(Vec::new());
1019 }
1020
1021 if let Some(index) = indices
1022 .iter()
1023 .copied()
1024 .find(|&index| index >= self.data.len())
1025 {
1026 return Err(CircuitError::OperationIndexOutOfBounds {
1027 index,
1028 len: self.data.len(),
1029 });
1030 }
1031
1032 let mut removed = Vec::with_capacity(indices.len());
1033 let mut removed_values = Vec::new();
1034 for &index in &indices {
1035 let operation = self.data[index].clone();
1036 Self::collect_defined_classical_values(&operation, &mut removed_values);
1037 removed.push(operation);
1038 }
1039 removed_values.sort_unstable();
1040 removed_values.dedup();
1041
1042 let remove_set = indices.iter().copied().collect::<HashSet<_>>();
1043
1044 for (operation_index, operation) in self.data.iter().enumerate() {
1045 if remove_set.contains(&operation_index) {
1046 continue;
1047 }
1048 for value in &removed_values {
1049 if operation.instruction.reads_value(*value) {
1050 return Err(CircuitError::ClassicalValueStillInUse {
1051 index: value.index(),
1052 context: format!("operation {operation_index}"),
1053 });
1054 }
1055 }
1056 }
1057
1058 let mut candidate_classical_values = self.classical_values.clone();
1059 let candidate_data = if removed_values.is_empty() {
1060 let mut candidate_data = Vec::with_capacity(self.data.len() - indices.len());
1061 for (operation_index, operation) in self.data.iter().cloned().enumerate() {
1062 if !remove_set.contains(&operation_index) {
1063 candidate_data.push(operation);
1064 }
1065 }
1066 candidate_data
1067 } else {
1068 let (compacted_values, value_map) = Self::build_value_compaction_map(
1069 self.circuit_id,
1070 &candidate_classical_values,
1071 &removed_values,
1072 );
1073 candidate_classical_values = compacted_values;
1074
1075 let qubit_mapping = self
1076 .qubits
1077 .iter()
1078 .copied()
1079 .map(|qubit| (qubit, qubit))
1080 .collect::<HashMap<_, _>>();
1081 let param_index_map = (0..self.parameters.len())
1082 .map(|index| CircuitParam::Index(index as u32))
1083 .collect::<Vec<_>>();
1084 let var_map = self
1085 .classical_vars
1086 .iter()
1087 .copied()
1088 .enumerate()
1089 .map(|(var_index, ty)| {
1090 let var = ClassicalVar::new(self.circuit_id, var_index as u32, ty);
1091 (var, var)
1092 })
1093 .collect::<HashMap<_, _>>();
1094
1095 self.data
1096 .iter()
1097 .enumerate()
1098 .filter(|(operation_index, _)| !remove_set.contains(operation_index))
1099 .map(|(_, operation)| {
1100 Self::remap_compose_operation(
1101 operation,
1102 &qubit_mapping,
1103 ¶m_index_map,
1104 &var_map,
1105 &value_map,
1106 )
1107 })
1108 .collect::<Result<Vec<_>, _>>()?
1109 };
1110
1111 let candidate = Self {
1112 circuit_id: self.circuit_id,
1113 qubits: self.qubits.clone(),
1114 symbols: self.symbols.clone(),
1115 parameters: self.parameters.clone(),
1116 data: Arc::new(candidate_data),
1117 classical_vars: self.classical_vars.clone(),
1118 classical_values: candidate_classical_values,
1119 control_scope_stack: self.control_scope_stack.clone(),
1120 global_phase: self.global_phase.clone(),
1121 };
1122 candidate.validate()?;
1123
1124 self.data = candidate.data;
1125 self.classical_values = candidate.classical_values;
1126
1127 Ok(removed)
1128 }
1129
1130 fn collect_defined_classical_values(operation: &Operation, out: &mut Vec<ClassicalValue>) {
1131 let collect_from_body = |body: &ControlBody, out: &mut Vec<ClassicalValue>| {
1132 for operation in body.operations() {
1133 Circuit::collect_defined_classical_values(operation, out);
1134 }
1135 };
1136
1137 match &operation.instruction {
1138 Instruction::ClassicalData(op) => {
1139 if let Some(result) = op.result() {
1140 out.push(result);
1141 }
1142 }
1143 Instruction::ClassicalControl(op) => match op {
1144 ClassicalControlOp::If(op) => {
1145 collect_from_body(op.then_body(), out);
1146 if let Some(body) = op.else_body() {
1147 collect_from_body(body, out);
1148 }
1149 }
1150 ClassicalControlOp::While(op) => collect_from_body(op.body(), out),
1151 ClassicalControlOp::For(op) => collect_from_body(op.body(), out),
1152 ClassicalControlOp::Switch(op) => {
1153 for case in op.cases() {
1154 collect_from_body(case.body(), out);
1155 }
1156 if let Some(body) = op.default() {
1157 collect_from_body(body, out);
1158 }
1159 }
1160 ClassicalControlOp::Break | ClassicalControlOp::Continue => {}
1161 },
1162 _ => {}
1163 }
1164 }
1165
1166 fn build_value_compaction_map(
1167 circuit_id: CircuitId,
1168 values: &[ClassicalType],
1169 removed: &[ClassicalValue],
1170 ) -> (Vec<ClassicalType>, HashMap<ClassicalValue, ClassicalValue>) {
1171 let removed_indices = removed
1172 .iter()
1173 .map(|value| value.index())
1174 .collect::<HashSet<_>>();
1175 let mut compacted = Vec::with_capacity(values.len().saturating_sub(removed_indices.len()));
1176 let mut value_map =
1177 HashMap::with_capacity(values.len().saturating_sub(removed_indices.len()));
1178
1179 for (old_index, ty) in values.iter().copied().enumerate() {
1180 if removed_indices.contains(&(old_index as u32)) {
1181 continue;
1182 }
1183 let new_index = compacted.len() as u32;
1184 compacted.push(ty);
1185 value_map.insert(
1186 ClassicalValue::new(circuit_id, old_index as u32, ty),
1187 ClassicalValue::new(circuit_id, new_index, ty),
1188 );
1189 }
1190
1191 (compacted, value_map)
1192 }
1193
1194 pub fn depth(&self, recurse: bool) -> Result<usize, CircuitError> {
1214 crate::circuit::depth::circuit_depth(
1215 self.qubits.iter().copied(),
1216 self.data.as_slice(),
1217 recurse,
1218 )
1219 }
1220
1221 pub fn classical_vars(&self) -> &[ClassicalType] {
1223 &self.classical_vars
1224 }
1225
1226 pub fn id(&self) -> CircuitId {
1229 self.circuit_id
1230 }
1231
1232 pub fn classical_values(&self) -> &[ClassicalType] {
1234 &self.classical_values
1235 }
1236
1237 pub fn append<Q, P>(
1260 &mut self,
1261 instruction: Instruction,
1262 qubits: Q,
1263 params: P,
1264 label: Option<&str>,
1265 ) -> Result<(), CircuitError>
1266 where
1267 Q: IntoIterator,
1268 Q::Item: Into<Qubit>,
1269 P: IntoIterator<Item = ParameterValue>,
1270 {
1271 self.append_with_validation(instruction, qubits, params, label, true)
1272 }
1273
1274 fn append_with_validation<Q, P>(
1275 &mut self,
1276 instruction: Instruction,
1277 qubits: Q,
1278 params: P,
1279 label: Option<&str>,
1280 validate_builder_state: bool,
1281 ) -> Result<(), CircuitError>
1282 where
1283 Q: IntoIterator,
1284 Q::Item: Into<Qubit>,
1285 P: IntoIterator<Item = ParameterValue>,
1286 {
1287 self.append_owned_with_validation(
1288 instruction,
1289 qubits,
1290 params,
1291 label.map(Into::into),
1292 validate_builder_state,
1293 )
1294 }
1295
1296 fn append_owned_with_validation<Q, P>(
1297 &mut self,
1298 instruction: Instruction,
1299 qubits: Q,
1300 params: P,
1301 label: Option<Box<str>>,
1302 validate_builder_state: bool,
1303 ) -> Result<(), CircuitError>
1304 where
1305 Q: IntoIterator,
1306 Q::Item: Into<Qubit>,
1307 P: IntoIterator<Item = ParameterValue>,
1308 {
1309 let validate_classical_now = validate_builder_state
1310 && matches!(
1311 instruction,
1312 Instruction::ClassicalData(_) | Instruction::ClassicalControl(_)
1313 );
1314 let checkpoint = validate_classical_now.then(|| self.checkpoint());
1315
1316 if let Instruction::ClassicalControl(op) = &instruction {
1317 self.validate_control_op(op)?;
1318 }
1319
1320 let qubits_sv: SmallVec<[Qubit; 3]> = qubits.into_iter().map(|q| q.into()).collect();
1321 let params_sv: SmallVec<[ParameterValue; 1]> = params.into_iter().collect();
1322
1323 if let Some((expected_qubits, expected_params)) = instruction.gate_arity() {
1324 if qubits_sv.len() != expected_qubits {
1325 return Err(CircuitError::QubitCountMismatch {
1326 expected: expected_qubits,
1327 actual: qubits_sv.len(),
1328 });
1329 }
1330 if params_sv.len() != expected_params {
1331 return Err(CircuitError::ParameterCountMismatch {
1332 expected: expected_params,
1333 actual: params_sv.len(),
1334 });
1335 }
1336 }
1337
1338 const INLINE_DUPLICATE_CHECK_LIMIT: usize = 8;
1339 if qubits_sv.len() <= INLINE_DUPLICATE_CHECK_LIMIT {
1340 if qubits_sv
1341 .iter()
1342 .enumerate()
1343 .any(|(index, qubit)| qubits_sv[..index].contains(qubit))
1344 {
1345 return Err(CircuitError::DuplicateQubits);
1346 }
1347 } else {
1348 let mut seen = HashSet::with_capacity(qubits_sv.len());
1349 for &qubit in &qubits_sv {
1350 if !seen.insert(qubit) {
1351 return Err(CircuitError::DuplicateQubits);
1352 }
1353 }
1354 }
1355
1356 for qubit in &qubits_sv {
1357 if !self.qubits.contains(qubit) {
1358 return Err(CircuitError::QubitNotFound(qubit.id()));
1359 }
1360 }
1361 if let Instruction::ClassicalData(op) = &instruction {
1362 self.validate_classical_data_op(op, qubits_sv.len())?;
1363 }
1364
1365 let mut circuit_params = smallvec![];
1366 for (param_index, p) in params_sv.into_iter().enumerate() {
1367 match p {
1368 ParameterValue::Param(param) => {
1369 let (index, is_new) = self.parameters.insert_full(param.clone());
1370 if is_new {
1371 for sym in param.get_symbols() {
1372 self.symbols.insert(sym);
1373 }
1374 }
1375 circuit_params.push(CircuitParam::Index(index as u32));
1376 }
1377 ParameterValue::Fixed(value) => {
1378 if !value.is_finite() {
1379 return Err(CircuitError::InvalidParameterValue(param_index, value));
1380 }
1381 circuit_params.push(CircuitParam::Fixed(value));
1382 }
1383 }
1384 }
1385
1386 Arc::make_mut(&mut self.data).push(Operation {
1387 instruction,
1388 qubits: qubits_sv,
1389 params: circuit_params,
1390 label,
1391 });
1392
1393 if validate_classical_now && let Err(error) = self.validate_builder_state() {
1394 self.rollback_to(checkpoint.expect("classical append must define a checkpoint"));
1395 return Err(error);
1396 }
1397
1398 Ok(())
1399 }
1400
1401 pub fn h(&mut self, qubit: Qubit) -> Result<(), CircuitError> {
1405 self.append(
1406 Instruction::Standard(StandardGate::H),
1407 [qubit],
1408 std::iter::empty(),
1409 None,
1410 )
1411 }
1412
1413 pub fn i(&mut self, qubit: Qubit) -> Result<(), CircuitError> {
1419 self.append(
1420 Instruction::Standard(StandardGate::I),
1421 [qubit],
1422 std::iter::empty(),
1423 None,
1424 )
1425 }
1426
1427 pub fn x(&mut self, qubit: Qubit) -> Result<(), CircuitError> {
1431 self.append(
1432 Instruction::Standard(StandardGate::X),
1433 [qubit],
1434 std::iter::empty(),
1435 None,
1436 )
1437 }
1438
1439 pub fn y(&mut self, qubit: Qubit) -> Result<(), CircuitError> {
1443 self.append(
1444 Instruction::Standard(StandardGate::Y),
1445 [qubit],
1446 std::iter::empty(),
1447 None,
1448 )
1449 }
1450
1451 pub fn z(&mut self, qubit: Qubit) -> Result<(), CircuitError> {
1455 self.append(
1456 Instruction::Standard(StandardGate::Z),
1457 [qubit],
1458 std::iter::empty(),
1459 None,
1460 )
1461 }
1462
1463 pub fn x2p(&mut self, qubit: Qubit) -> Result<(), CircuitError> {
1467 self.append(
1468 Instruction::Standard(StandardGate::X2P),
1469 [qubit],
1470 std::iter::empty(),
1471 None,
1472 )
1473 }
1474
1475 pub fn x2m(&mut self, qubit: Qubit) -> Result<(), CircuitError> {
1479 self.append(
1480 Instruction::Standard(StandardGate::X2M),
1481 [qubit],
1482 std::iter::empty(),
1483 None,
1484 )
1485 }
1486
1487 pub fn y2p(&mut self, qubit: Qubit) -> Result<(), CircuitError> {
1489 self.append(
1490 Instruction::Standard(StandardGate::Y2P),
1491 [qubit],
1492 std::iter::empty(),
1493 None,
1494 )
1495 }
1496
1497 pub fn y2m(&mut self, qubit: Qubit) -> Result<(), CircuitError> {
1499 self.append(
1500 Instruction::Standard(StandardGate::Y2M),
1501 [qubit],
1502 std::iter::empty(),
1503 None,
1504 )
1505 }
1506
1507 pub fn xy(
1511 &mut self,
1512 qubit: Qubit,
1513 theta: impl Into<ParameterValue>,
1514 ) -> Result<(), CircuitError> {
1515 let params: SmallVec<[ParameterValue; 1]> = smallvec![theta.into()];
1516 self.append(
1517 Instruction::Standard(StandardGate::XY),
1518 [qubit],
1519 params,
1520 None,
1521 )
1522 }
1523
1524 pub fn xy2p(
1526 &mut self,
1527 qubit: Qubit,
1528 theta: impl Into<ParameterValue>,
1529 ) -> Result<(), CircuitError> {
1530 let params: SmallVec<[ParameterValue; 1]> = smallvec![theta.into()];
1531 self.append(
1532 Instruction::Standard(StandardGate::XY2P),
1533 [qubit],
1534 params,
1535 None,
1536 )
1537 }
1538
1539 pub fn xy2m(
1541 &mut self,
1542 qubit: Qubit,
1543 theta: impl Into<ParameterValue>,
1544 ) -> Result<(), CircuitError> {
1545 let params: SmallVec<[ParameterValue; 1]> = smallvec![theta.into()];
1546 self.append(
1547 Instruction::Standard(StandardGate::XY2M),
1548 [qubit],
1549 params,
1550 None,
1551 )
1552 }
1553
1554 pub fn s(&mut self, qubit: Qubit) -> Result<(), CircuitError> {
1560 self.append(
1561 Instruction::Standard(StandardGate::S),
1562 [qubit],
1563 std::iter::empty(),
1564 None,
1565 )
1566 }
1567
1568 pub fn sdg(&mut self, qubit: Qubit) -> Result<(), CircuitError> {
1572 self.append(
1573 Instruction::Standard(StandardGate::SDG),
1574 [qubit],
1575 std::iter::empty(),
1576 None,
1577 )
1578 }
1579
1580 pub fn t(&mut self, qubit: Qubit) -> Result<(), CircuitError> {
1584 self.append(
1585 Instruction::Standard(StandardGate::T),
1586 [qubit],
1587 std::iter::empty(),
1588 None,
1589 )
1590 }
1591
1592 pub fn tdg(&mut self, qubit: Qubit) -> Result<(), CircuitError> {
1594 self.append(
1595 Instruction::Standard(StandardGate::TDG),
1596 [qubit],
1597 std::iter::empty(),
1598 None,
1599 )
1600 }
1601
1602 pub fn rx(
1608 &mut self,
1609 qubit: Qubit,
1610 theta: impl Into<ParameterValue>,
1611 ) -> Result<(), CircuitError> {
1612 let params: SmallVec<[ParameterValue; 1]> = smallvec![theta.into()];
1613 self.append(
1614 Instruction::Standard(StandardGate::RX),
1615 [qubit],
1616 params,
1617 None,
1618 )
1619 }
1620
1621 pub fn ry(
1625 &mut self,
1626 qubit: Qubit,
1627 theta: impl Into<ParameterValue>,
1628 ) -> Result<(), CircuitError> {
1629 let params: SmallVec<[ParameterValue; 1]> = smallvec![theta.into()];
1630
1631 self.append(
1632 Instruction::Standard(StandardGate::RY),
1633 [qubit],
1634 params,
1635 None,
1636 )
1637 }
1638
1639 pub fn rz(
1643 &mut self,
1644 qubit: Qubit,
1645 theta: impl Into<ParameterValue>,
1646 ) -> Result<(), CircuitError> {
1647 let params: SmallVec<[ParameterValue; 1]> = smallvec![theta.into()];
1648
1649 self.append(
1650 Instruction::Standard(StandardGate::RZ),
1651 [qubit],
1652 params,
1653 None,
1654 )
1655 }
1656
1657 pub fn phase(
1662 &mut self,
1663 qubit: Qubit,
1664 lambda: impl Into<ParameterValue>,
1665 ) -> Result<(), CircuitError> {
1666 let params: SmallVec<[ParameterValue; 1]> = smallvec![lambda.into()];
1667
1668 self.append(
1669 Instruction::Standard(StandardGate::Phase),
1670 [qubit],
1671 params,
1672 None,
1673 )
1674 }
1675
1676 pub fn u(
1686 &mut self,
1687 qubit: Qubit,
1688 theta: impl Into<ParameterValue>,
1689 phi: impl Into<ParameterValue>,
1690 lambda: impl Into<ParameterValue>,
1691 ) -> Result<(), CircuitError> {
1692 let params: SmallVec<[ParameterValue; 1]> =
1693 smallvec![theta.into(), phi.into(), lambda.into()];
1694
1695 self.append(
1696 Instruction::Standard(StandardGate::U),
1697 [qubit],
1698 params,
1699 None,
1700 )
1701 }
1702
1703 pub fn cx(&mut self, control: Qubit, target: Qubit) -> Result<(), CircuitError> {
1707 self.append(
1708 Instruction::Standard(StandardGate::CX),
1709 [control, target],
1710 std::iter::empty(),
1711 None,
1712 )
1713 }
1714
1715 pub fn cy(&mut self, control: Qubit, target: Qubit) -> Result<(), CircuitError> {
1717 self.append(
1718 Instruction::Standard(StandardGate::CY),
1719 [control, target],
1720 std::iter::empty(),
1721 None,
1722 )
1723 }
1724
1725 pub fn cz(&mut self, control: Qubit, target: Qubit) -> Result<(), CircuitError> {
1729 self.append(
1730 Instruction::Standard(StandardGate::CZ),
1731 [control, target],
1732 std::iter::empty(),
1733 None,
1734 )
1735 }
1736
1737 pub fn swap(&mut self, a: Qubit, b: Qubit) -> Result<(), CircuitError> {
1741 self.append(
1742 Instruction::Standard(StandardGate::SWAP),
1743 [a, b],
1744 std::iter::empty(),
1745 None,
1746 )
1747 }
1748
1749 pub fn rxx(
1753 &mut self,
1754 a: Qubit,
1755 b: Qubit,
1756 theta: impl Into<ParameterValue>,
1757 ) -> Result<(), CircuitError> {
1758 let params: SmallVec<[ParameterValue; 1]> = smallvec![theta.into()];
1759
1760 self.append(
1761 Instruction::Standard(StandardGate::RXX),
1762 [a, b],
1763 params,
1764 None,
1765 )
1766 }
1767
1768 pub fn ryy(
1772 &mut self,
1773 a: Qubit,
1774 b: Qubit,
1775 theta: impl Into<ParameterValue>,
1776 ) -> Result<(), CircuitError> {
1777 let params: SmallVec<[ParameterValue; 1]> = smallvec![theta.into()];
1778
1779 self.append(
1780 Instruction::Standard(StandardGate::RYY),
1781 [a, b],
1782 params,
1783 None,
1784 )
1785 }
1786
1787 pub fn rzz(
1791 &mut self,
1792 a: Qubit,
1793 b: Qubit,
1794 theta: impl Into<ParameterValue>,
1795 ) -> Result<(), CircuitError> {
1796 let params: SmallVec<[ParameterValue; 1]> = smallvec![theta.into()];
1797
1798 self.append(
1799 Instruction::Standard(StandardGate::RZZ),
1800 [a, b],
1801 params,
1802 None,
1803 )
1804 }
1805
1806 pub fn rzx(
1810 &mut self,
1811 a: Qubit,
1812 b: Qubit,
1813 theta: impl Into<ParameterValue>,
1814 ) -> Result<(), CircuitError> {
1815 let params: SmallVec<[ParameterValue; 1]> = smallvec![theta.into()];
1816
1817 self.append(
1818 Instruction::Standard(StandardGate::RZX),
1819 [a, b],
1820 params,
1821 None,
1822 )
1823 }
1824
1825 pub fn crx(
1829 &mut self,
1830 control: Qubit,
1831 target: Qubit,
1832 theta: impl Into<ParameterValue>,
1833 ) -> Result<(), CircuitError> {
1834 let params: SmallVec<[ParameterValue; 1]> = smallvec![theta.into()];
1835
1836 self.append(
1837 Instruction::Standard(StandardGate::CRX),
1838 [control, target],
1839 params,
1840 None,
1841 )
1842 }
1843
1844 pub fn cry(
1846 &mut self,
1847 control: Qubit,
1848 target: Qubit,
1849 theta: impl Into<ParameterValue>,
1850 ) -> Result<(), CircuitError> {
1851 let params: SmallVec<[ParameterValue; 1]> = smallvec![theta.into()];
1852
1853 self.append(
1854 Instruction::Standard(StandardGate::CRY),
1855 [control, target],
1856 params,
1857 None,
1858 )
1859 }
1860
1861 pub fn crz(
1863 &mut self,
1864 control: Qubit,
1865 target: Qubit,
1866 theta: impl Into<ParameterValue>,
1867 ) -> Result<(), CircuitError> {
1868 let params: SmallVec<[ParameterValue; 1]> = smallvec![theta.into()];
1869
1870 self.append(
1871 Instruction::Standard(StandardGate::CRZ),
1872 [control, target],
1873 params,
1874 None,
1875 )
1876 }
1877
1878 pub fn ccx(
1882 &mut self,
1883 control1: Qubit,
1884 control2: Qubit,
1885 target: Qubit,
1886 ) -> Result<(), CircuitError> {
1887 self.append(
1888 Instruction::Standard(StandardGate::CCX),
1889 [control1, control2, target],
1890 std::iter::empty(),
1891 None,
1892 )
1893 }
1894
1895 pub fn fsim(
1910 &mut self,
1911 a: Qubit,
1912 b: Qubit,
1913 theta: impl Into<ParameterValue>,
1914 phi: impl Into<ParameterValue>,
1915 ) -> Result<(), CircuitError> {
1916 let params: SmallVec<[ParameterValue; 1]> = smallvec![theta.into(), phi.into()];
1917
1918 self.append(
1919 Instruction::Standard(StandardGate::FSIM),
1920 [a, b],
1921 params,
1922 None,
1923 )
1924 }
1925
1926 pub fn rxy(
1928 &mut self,
1929 qubit: Qubit,
1930 theta: impl Into<ParameterValue>,
1931 phi: impl Into<ParameterValue>,
1932 ) -> Result<(), CircuitError> {
1933 let params: SmallVec<[ParameterValue; 2]> = smallvec![theta.into(), phi.into()];
1934
1935 self.append(
1936 Instruction::Standard(StandardGate::RXY),
1937 [qubit],
1938 params,
1939 None,
1940 )
1941 }
1942
1943 pub fn barrier(&mut self, qubits: Vec<Qubit>) -> Result<(), CircuitError> {
1952 self.append(
1953 Instruction::Directive(Directive::Barrier),
1954 qubits,
1955 std::iter::empty(),
1956 None,
1957 )
1958 }
1959
1960 pub fn reset(&mut self, qubit: Qubit) -> Result<(), CircuitError> {
1964 self.append(
1965 Instruction::Directive(Directive::Reset),
1966 [qubit],
1967 std::iter::empty(),
1968 None,
1969 )
1970 }
1971
1972 pub fn multi_control<I, C, T, P>(
2001 &mut self,
2002 instruction: I,
2003 controls: C,
2004 targets: T,
2005 params: P,
2006 ) -> Result<(), CircuitError>
2007 where
2008 I: Into<Instruction>,
2009 C: IntoIterator,
2010 C::Item: Into<Qubit>,
2011 T: IntoIterator,
2012 T::Item: Into<Qubit>,
2013 P: IntoIterator<Item = ParameterValue>,
2014 {
2015 let controls_sv: SmallVec<[Qubit; 3]> = controls.into_iter().map(|q| q.into()).collect();
2016 let targets_sv: SmallVec<[Qubit; 1]> = targets.into_iter().map(|q| q.into()).collect();
2017 let num_controls = controls_sv.len();
2018
2019 let inst: Instruction = instruction.into();
2020
2021 let controlled_inst = inst
2022 .control(num_controls)
2023 .ok_or_else(|| CircuitError::InvalidControlOperation(inst.to_string()))?;
2024
2025 let mut all_qubits = controls_sv;
2026 all_qubits.extend(targets_sv);
2027 self.append(controlled_inst, all_qubits, params, None)
2028 }
2029
2030 pub fn unitary(&mut self, gate: UnitaryGate, qubits: Vec<Qubit>) -> Result<(), CircuitError> {
2059 self.unitary_with_params(gate, qubits, std::iter::empty())
2060 }
2061
2062 pub fn unitary_with_params<P>(
2064 &mut self,
2065 gate: UnitaryGate,
2066 qubits: Vec<Qubit>,
2067 params: P,
2068 ) -> Result<(), CircuitError>
2069 where
2070 P: IntoIterator<Item = ParameterValue>,
2071 {
2072 let qubits_sv: SmallVec<[Qubit; 3]> = qubits.into();
2073 let params_vec: Vec<ParameterValue> = params.into_iter().collect();
2074
2075 if qubits_sv.len() != gate.num_qubits() as usize {
2077 return Err(CircuitError::QubitCountMismatch {
2078 expected: gate.num_qubits() as usize,
2079 actual: qubits_sv.len(),
2080 });
2081 }
2082 if params_vec.len() != gate.num_params() as usize {
2083 return Err(CircuitError::ParameterCountMismatch {
2084 expected: gate.num_params() as usize,
2085 actual: params_vec.len(),
2086 });
2087 }
2088
2089 self.append(
2090 Instruction::UnitaryGate(Box::new(gate)),
2091 qubits_sv,
2092 params_vec,
2093 None,
2094 )
2095 }
2096
2097 pub fn delay(
2107 &mut self,
2108 qubit: impl Into<Qubit>,
2109 delay: ParameterValue,
2110 ) -> Result<(), CircuitError> {
2111 self.append(Instruction::Delay, vec![qubit], vec![delay], None)
2112 }
2113
2114 pub fn circuit_gate(
2124 &mut self,
2125 gate: CircuitGate,
2126 qubits: Vec<Qubit>,
2127 params: impl IntoIterator<Item = ParameterValue>,
2128 ) -> Result<(), CircuitError> {
2129 self.append(
2130 Instruction::CircuitGate(Box::new(gate)),
2131 qubits,
2132 params,
2133 None,
2134 )
2135 }
2136
2137 pub fn inverse(&self) -> Result<Circuit, CircuitError> {
2146 let mut new_circuit = Circuit::from_qubits(self.qubits())?;
2147 new_circuit.classical_vars = self.classical_vars.clone();
2148 new_circuit.classical_values = self.classical_values.clone();
2149 Arc::make_mut(&mut new_circuit.data).reserve(self.data.len());
2150 let current_phase_param = self.global_phase();
2152 let new_phase_param = Parameter::from(-1.0) * current_phase_param;
2154
2155 if let Ok(val) = new_phase_param.evaluate(&None) {
2157 new_circuit.global_phase = CircuitParam::Fixed(val);
2158 } else {
2159 let (index, is_new) = new_circuit.parameters.insert_full(new_phase_param.clone());
2160 if is_new {
2161 for sym in new_phase_param.get_symbols() {
2162 new_circuit.symbols.insert(sym);
2163 }
2164 }
2165 new_circuit.global_phase = CircuitParam::Index(index as u32);
2166 }
2167
2168 for op in self.data.iter().rev() {
2170 match &op.instruction {
2172 Instruction::Directive(directive) => match directive {
2173 Directive::Barrier => {
2174 new_circuit.append(
2175 Instruction::Directive(Directive::Barrier),
2176 op.qubits.clone(),
2177 std::iter::empty(),
2178 op.label.as_deref(),
2179 )?;
2180 continue;
2181 }
2182 _ => return Err(CircuitError::IrreversibleOperation),
2183 },
2184 Instruction::ClassicalData(_) | Instruction::ClassicalControl(_) => {
2185 return Err(CircuitError::IrreversibleOperation);
2187 }
2188 _ => {
2189 let params: SmallVec<[Parameter; 3]> = op
2191 .params
2192 .iter()
2193 .map(|p| match p {
2194 CircuitParam::Fixed(val) => Parameter::from(*val),
2195 CircuitParam::Index(idx) => self.parameters[*idx as usize].clone(),
2196 })
2197 .collect();
2198
2199 if let Some((inv_inst, inv_params)) = op.instruction.inverse(¶ms) {
2201 let param_values: SmallVec<[ParameterValue; 3]> =
2203 inv_params.into_iter().map(ParameterValue::from).collect();
2204
2205 new_circuit.append(
2206 inv_inst,
2207 op.qubits.clone(),
2208 param_values,
2209 op.label.as_deref(),
2210 )?;
2211 } else {
2212 return Err(CircuitError::IrreversibleOperation);
2213 }
2214 }
2215 }
2216 }
2217
2218 Ok(new_circuit)
2219 }
2220
2221 pub fn to_gate(self, name: impl Into<String>) -> Result<Instruction, CircuitError> {
2232 let frozen = FrozenCircuit::new(self);
2233 let gate = CircuitGate::new(name, frozen)?;
2234 Ok(Instruction::CircuitGate(Box::new(gate)))
2235 }
2236
2237 fn check_qubits_unique(qubits: &[Qubit]) -> bool {
2238 let mut seen = HashSet::with_capacity(qubits.len());
2239 for q in qubits {
2240 if !seen.insert(q) {
2241 return false;
2242 }
2243 }
2244 true
2245 }
2246
2247 pub fn decompose(&self) -> Result<Circuit, CircuitError> {
2272 let mut new_circuit = Circuit::from_qubits(self.qubits()).unwrap();
2273 new_circuit.classical_vars = self.classical_vars.clone();
2274 new_circuit.classical_values = self.classical_values.clone();
2275 new_circuit.symbols = self.symbols.clone();
2277
2278 match &self.global_phase {
2280 CircuitParam::Fixed(f) => new_circuit.global_phase = CircuitParam::Fixed(*f),
2281 CircuitParam::Index(i) => {
2282 let p = self.parameters[*i as usize].clone();
2283 let (idx, is_new) = new_circuit.parameters.insert_full(p.clone());
2284 if is_new {
2285 for sym in p.get_symbols() {
2286 new_circuit.symbols.insert(sym);
2287 }
2288 }
2289 new_circuit.global_phase = CircuitParam::Index(idx as u32);
2290 }
2291 }
2292
2293 let initial_qubit_map: HashMap<Qubit, Qubit> =
2294 self.qubits.iter().map(|q| (*q, *q)).collect();
2295 let initial_param_map: HashMap<String, Parameter> = HashMap::new();
2296 let var_map = self
2297 .classical_vars
2298 .iter()
2299 .enumerate()
2300 .map(|(index, ty)| {
2301 (
2302 ClassicalVar::new(self.circuit_id, index as u32, *ty),
2303 ClassicalVar::new(new_circuit.circuit_id, index as u32, *ty),
2304 )
2305 })
2306 .collect();
2307 let value_map = self
2308 .classical_values
2309 .iter()
2310 .enumerate()
2311 .map(|(index, ty)| {
2312 (
2313 ClassicalValue::new(self.circuit_id, index as u32, *ty),
2314 ClassicalValue::new(new_circuit.circuit_id, index as u32, *ty),
2315 )
2316 })
2317 .collect();
2318
2319 for op in self.data.iter() {
2320 Self::decompose_recursive(
2321 op,
2322 self,
2323 &initial_qubit_map,
2324 &initial_param_map,
2325 &var_map,
2326 &value_map,
2327 &mut new_circuit,
2328 )?;
2329 }
2330
2331 Ok(new_circuit)
2332 }
2333
2334 fn decompose_recursive(
2335 op: &Operation,
2336 context_circuit: &Circuit,
2337 qubit_map: &HashMap<Qubit, Qubit>,
2338 param_map: &HashMap<String, Parameter>,
2339 var_map: &HashMap<ClassicalVar, ClassicalVar>,
2340 value_map: &HashMap<ClassicalValue, ClassicalValue>,
2341 target_circuit: &mut Circuit,
2342 ) -> Result<(), CircuitError> {
2343 match &op.instruction {
2344 Instruction::CircuitGate(cg) => {
2345 let mut resolved_params = Vec::with_capacity(op.params.len());
2347 for p in &op.params {
2348 let mut param = match p {
2349 CircuitParam::Fixed(v) => Parameter::from(*v),
2350 CircuitParam::Index(idx) => {
2351 context_circuit.parameters[*idx as usize].clone()
2352 }
2353 };
2354
2355 param = Self::apply_param_map(param, param_map);
2358 if param.get_symbols().is_empty() {
2359 param.evaluate(&None)?;
2360 }
2361 resolved_params.push(param);
2362 }
2363
2364 let mut next_param_map = HashMap::new();
2367 for (i, sym) in cg.signature_params().iter().enumerate() {
2368 if i < resolved_params.len() {
2369 next_param_map.insert(sym.clone(), resolved_params[i].clone());
2370 }
2371 }
2372
2373 if cg.circuit.circuit.global_phase_param() != &CircuitParam::Fixed(0.0) {
2376 let phase =
2377 Self::apply_param_map(cg.circuit.circuit.global_phase(), &next_param_map);
2378 if phase.get_symbols().is_empty() {
2379 phase.evaluate(&None)?;
2380 }
2381 let phase = target_circuit.global_phase() + phase;
2382 if phase.get_symbols().is_empty() {
2383 phase.evaluate(&None)?;
2384 }
2385 target_circuit.set_global_phase(phase);
2386 }
2387
2388 let mut next_qubit_map = HashMap::new();
2392 for (i, inner_q) in cg.circuit.circuit.qubits().iter().enumerate() {
2393 if i < op.qubits.len() {
2394 let local_q = op.qubits[i];
2395 let global_q = qubit_map.get(&local_q).unwrap_or(&local_q);
2396 next_qubit_map.insert(*inner_q, *global_q);
2397 }
2398 }
2399
2400 for sub_op in cg.circuit.circuit.data.iter() {
2402 Self::decompose_recursive(
2403 sub_op,
2404 &cg.circuit.circuit,
2405 &next_qubit_map,
2406 &next_param_map,
2407 var_map,
2408 value_map,
2409 target_circuit,
2410 )?;
2411 }
2412 Ok(())
2413 }
2414 Instruction::ClassicalControl(_) => Err(CircuitError::InvalidOperation(
2415 "decomposing circuits with classical control is not yet supported".to_string(),
2416 )),
2417 _ => {
2418 let mapped_qubits: SmallVec<[Qubit; 3]> = op
2421 .qubits
2422 .iter()
2423 .map(|q| *qubit_map.get(q).unwrap_or(q))
2424 .collect();
2425
2426 let mut mapped_params: SmallVec<[ParameterValue; 3]> = smallvec![];
2428 for p in &op.params {
2429 let mut param = match p {
2430 CircuitParam::Fixed(v) => Parameter::from(*v),
2431 CircuitParam::Index(idx) => {
2432 context_circuit.parameters[*idx as usize].clone()
2433 }
2434 };
2435
2436 param = Self::apply_param_map(param, param_map);
2437 if param.get_symbols().is_empty() {
2438 param.evaluate(&None)?;
2439 }
2440
2441 mapped_params.push(ParameterValue::from(param));
2442 }
2443
2444 let instruction = match &op.instruction {
2445 Instruction::ClassicalData(op) => Instruction::ClassicalData(
2446 Self::remap_classical_data_op(op, var_map, value_map)?,
2447 ),
2448 _ => op.instruction.clone(),
2449 };
2450
2451 target_circuit.append(
2452 instruction,
2453 mapped_qubits,
2454 mapped_params,
2455 op.label.as_deref(),
2456 )?;
2457 Ok(())
2458 }
2459 }
2460 }
2461
2462 fn apply_param_map(param: Parameter, map: &HashMap<String, Parameter>) -> Parameter {
2463 param.substitute_many_simultaneous(map)
2464 }
2465
2466 pub fn to_matrix(
2482 &self,
2483 qubits_order: Option<&[usize]>,
2484 ) -> Result<Array2<Complex64>, CircuitError> {
2485 circuit_to_matrix(self, qubits_order)
2486 }
2487
2488 pub fn assign_parameters(
2500 &self,
2501 bindings: &Option<HashMap<&str, f64>>,
2502 ) -> Result<Circuit, CircuitError> {
2503 if self
2504 .data
2505 .iter()
2506 .any(|op| matches!(op.instruction, Instruction::ClassicalControl(_)))
2507 {
2508 return Err(CircuitError::InvalidOperation(
2509 "assigning parameters in circuits with classical control is not yet supported"
2510 .to_string(),
2511 ));
2512 }
2513
2514 let mut new_circuit = Circuit::from_qubits(self.qubits())?;
2515 new_circuit.classical_vars = self.classical_vars.clone();
2516 new_circuit.classical_values = self.classical_values.clone();
2517
2518 let var_map = self
2519 .classical_vars
2520 .iter()
2521 .enumerate()
2522 .map(|(index, ty)| {
2523 (
2524 ClassicalVar::new(self.circuit_id, index as u32, *ty),
2525 ClassicalVar::new(new_circuit.circuit_id, index as u32, *ty),
2526 )
2527 })
2528 .collect();
2529 let value_map = self
2530 .classical_values
2531 .iter()
2532 .enumerate()
2533 .map(|(index, ty)| {
2534 (
2535 ClassicalValue::new(self.circuit_id, index as u32, *ty),
2536 ClassicalValue::new(new_circuit.circuit_id, index as u32, *ty),
2537 )
2538 })
2539 .collect();
2540
2541 let mut index_map: Vec<CircuitParam> = Vec::with_capacity(self.parameters.len());
2543
2544 for param in self.parameters.iter() {
2545 if let Ok(val) = param.evaluate(bindings) {
2546 index_map.push(CircuitParam::Fixed(val));
2547 continue;
2548 }
2549
2550 let mut tp = param.clone();
2551 if let Some(bindings) = bindings {
2552 for (k, v) in bindings.iter() {
2553 tp = tp.replace(k, Parameter::from(*v));
2554 }
2555 let s = tp.simplify();
2556 tp = s.map_err(|e| CircuitError::UnresolvedParameter(format!("{:?}", e)))?;
2557 }
2558
2559 if tp.get_symbols().is_empty() {
2560 index_map.push(CircuitParam::Fixed(tp.evaluate(&None)?));
2561 } else {
2562 let (idx, is_new) = new_circuit.parameters.insert_full(tp.clone());
2564
2565 if is_new {
2567 for sym in tp.get_symbols() {
2568 new_circuit.symbols.insert(sym);
2569 }
2570 }
2571 index_map.push(CircuitParam::Index(idx as u32));
2572 }
2573 }
2574
2575 let new_data = Arc::make_mut(&mut new_circuit.data);
2577 new_data.reserve(self.data.len());
2578 for op in self.data.iter() {
2579 new_data.push(Self::remap_operation(
2580 op,
2581 &|qubit| Ok(qubit),
2582 &|param| match param {
2583 CircuitParam::Index(old_idx) => index_map
2584 .get(*old_idx as usize)
2585 .cloned()
2586 .ok_or(CircuitError::InvalidParameterIndex(*old_idx)),
2587 CircuitParam::Fixed(value) => Ok(CircuitParam::Fixed(*value)),
2588 },
2589 &var_map,
2590 &value_map,
2591 )?);
2592 }
2593
2594 match self.global_phase {
2596 CircuitParam::Index(old_idx) => {
2597 new_circuit.global_phase = index_map
2598 .get(old_idx as usize)
2599 .cloned()
2600 .ok_or(CircuitError::InvalidParameterIndex(old_idx))?;
2601 }
2602 CircuitParam::Fixed(val) => {
2603 new_circuit.global_phase = CircuitParam::Fixed(val);
2604 }
2605 }
2606
2607 Ok(new_circuit)
2608 }
2609
2610 fn remap_compose_operation(
2611 op: &Operation,
2612 qubit_mapping: &HashMap<Qubit, Qubit>,
2613 param_index_map: &[CircuitParam],
2614 var_map: &HashMap<ClassicalVar, ClassicalVar>,
2615 value_map: &HashMap<ClassicalValue, ClassicalValue>,
2616 ) -> Result<Operation, CircuitError> {
2617 Self::remap_operation(
2618 op,
2619 &|qubit| {
2620 qubit_mapping
2621 .get(&qubit)
2622 .copied()
2623 .ok_or(CircuitError::QubitNotFound(qubit.id()))
2624 },
2625 &|param| match param {
2626 CircuitParam::Index(old_idx) => param_index_map
2627 .get(*old_idx as usize)
2628 .cloned()
2629 .ok_or(CircuitError::InvalidParameterIndex(*old_idx)),
2630 CircuitParam::Fixed(value) => Ok(CircuitParam::Fixed(*value)),
2631 },
2632 var_map,
2633 value_map,
2634 )
2635 }
2636
2637 fn remap_operation<QubitMapper, ParamMapper>(
2638 op: &Operation,
2639 map_qubit: &QubitMapper,
2640 map_param: &ParamMapper,
2641 var_map: &HashMap<ClassicalVar, ClassicalVar>,
2642 value_map: &HashMap<ClassicalValue, ClassicalValue>,
2643 ) -> Result<Operation, CircuitError>
2644 where
2645 QubitMapper: Fn(Qubit) -> Result<Qubit, CircuitError>,
2646 ParamMapper: Fn(&CircuitParam) -> Result<CircuitParam, CircuitError>,
2647 {
2648 let qubits = op
2649 .qubits
2650 .iter()
2651 .copied()
2652 .map(map_qubit)
2653 .collect::<Result<_, _>>()?;
2654 let params = op.params.iter().map(map_param).collect::<Result<_, _>>()?;
2655 let instruction = match &op.instruction {
2656 Instruction::ClassicalData(classical_op) => Instruction::ClassicalData(
2657 Self::remap_classical_data_op(classical_op, var_map, value_map)?,
2658 ),
2659 Instruction::ClassicalControl(op) => Instruction::ClassicalControl(
2660 Self::remap_control_op(op, map_qubit, map_param, var_map, value_map)?,
2661 ),
2662 _ => op.instruction.clone(),
2663 };
2664
2665 Ok(Operation {
2666 instruction,
2667 qubits,
2668 params,
2669 label: op.label.clone(),
2670 })
2671 }
2672
2673 fn remap_classical_data_op(
2674 op: &ClassicalDataOp,
2675 var_map: &HashMap<ClassicalVar, ClassicalVar>,
2676 value_map: &HashMap<ClassicalValue, ClassicalValue>,
2677 ) -> Result<ClassicalDataOp, CircuitError> {
2678 match op {
2679 ClassicalDataOp::Store { target, value } => Ok(ClassicalDataOp::Store {
2680 target: var_map.get(target).copied().ok_or_else(|| {
2681 CircuitError::InvalidOperation(format!(
2682 "missing classical variable remap for id {}",
2683 target.id()
2684 ))
2685 })?,
2686 value: value.remap_classical_ids(var_map, value_map)?,
2687 }),
2688 ClassicalDataOp::MeasureBit { result } => Ok(ClassicalDataOp::MeasureBit {
2689 result: value_map.get(result).copied().ok_or_else(|| {
2690 CircuitError::InvalidOperation(format!(
2691 "missing classical value remap for id {}",
2692 result.index()
2693 ))
2694 })?,
2695 }),
2696 ClassicalDataOp::MeasureBits { result } => Ok(ClassicalDataOp::MeasureBits {
2697 result: value_map.get(result).copied().ok_or_else(|| {
2698 CircuitError::InvalidOperation(format!(
2699 "missing classical value remap for id {}",
2700 result.index()
2701 ))
2702 })?,
2703 }),
2704 }
2705 }
2706
2707 fn remap_control_body<QubitMapper, ParamMapper>(
2708 body: &ControlBody,
2709 map_qubit: &QubitMapper,
2710 map_param: &ParamMapper,
2711 var_map: &HashMap<ClassicalVar, ClassicalVar>,
2712 value_map: &HashMap<ClassicalValue, ClassicalValue>,
2713 ) -> Result<ControlBody, CircuitError>
2714 where
2715 QubitMapper: Fn(Qubit) -> Result<Qubit, CircuitError>,
2716 ParamMapper: Fn(&CircuitParam) -> Result<CircuitParam, CircuitError>,
2717 {
2718 body.operations()
2719 .iter()
2720 .map(|op| Self::remap_operation(op, map_qubit, map_param, var_map, value_map))
2721 .collect::<Result<Vec<_>, _>>()
2722 .map(ControlBody::new)
2723 }
2724
2725 fn remap_control_op<QubitMapper, ParamMapper>(
2726 op: &ClassicalControlOp,
2727 map_qubit: &QubitMapper,
2728 map_param: &ParamMapper,
2729 var_map: &HashMap<ClassicalVar, ClassicalVar>,
2730 value_map: &HashMap<ClassicalValue, ClassicalValue>,
2731 ) -> Result<ClassicalControlOp, CircuitError>
2732 where
2733 QubitMapper: Fn(Qubit) -> Result<Qubit, CircuitError>,
2734 ParamMapper: Fn(&CircuitParam) -> Result<CircuitParam, CircuitError>,
2735 {
2736 match op {
2737 ClassicalControlOp::If(op) => {
2738 let condition = op.condition().remap_classical_ids(var_map, value_map)?;
2739 let then_body = Self::remap_control_body(
2740 op.then_body(),
2741 map_qubit,
2742 map_param,
2743 var_map,
2744 value_map,
2745 )?;
2746 let else_body = op
2747 .else_body()
2748 .map(|body| {
2749 Self::remap_control_body(body, map_qubit, map_param, var_map, value_map)
2750 })
2751 .transpose()?;
2752 IfOp::new(condition, then_body, else_body).map(ClassicalControlOp::If)
2753 }
2754 ClassicalControlOp::While(op) => {
2755 let condition = op.condition().remap_classical_ids(var_map, value_map)?;
2756 let body =
2757 Self::remap_control_body(op.body(), map_qubit, map_param, var_map, value_map)?;
2758 WhileOp::new(condition, body).map(ClassicalControlOp::While)
2759 }
2760 ClassicalControlOp::For(op) => {
2761 let var = var_map.get(&op.var()).copied().ok_or_else(|| {
2762 CircuitError::InvalidOperation(format!(
2763 "missing classical variable remap for id {}",
2764 op.var().id()
2765 ))
2766 })?;
2767 let start = op.start().remap_classical_ids(var_map, value_map)?;
2768 let stop = op.stop().remap_classical_ids(var_map, value_map)?;
2769 let step = op.step().remap_classical_ids(var_map, value_map)?;
2770 let body =
2771 Self::remap_control_body(op.body(), map_qubit, map_param, var_map, value_map)?;
2772 ForOp::new(var, start, stop, step, body).map(ClassicalControlOp::For)
2773 }
2774 ClassicalControlOp::Switch(op) => {
2775 let target = op.target().remap_classical_ids(var_map, value_map)?;
2776 let cases = op
2777 .cases()
2778 .iter()
2779 .map(|case| {
2780 Ok(SwitchCase::new(
2781 case.value(),
2782 Self::remap_control_body(
2783 case.body(),
2784 map_qubit,
2785 map_param,
2786 var_map,
2787 value_map,
2788 )?,
2789 ))
2790 })
2791 .collect::<Result<Vec<_>, CircuitError>>()?;
2792 let default = op
2793 .default()
2794 .map(|body| {
2795 Self::remap_control_body(body, map_qubit, map_param, var_map, value_map)
2796 })
2797 .transpose()?;
2798 SwitchOp::new(target, cases, default).map(ClassicalControlOp::Switch)
2799 }
2800 ClassicalControlOp::Break => Ok(ClassicalControlOp::Break),
2801 ClassicalControlOp::Continue => Ok(ClassicalControlOp::Continue),
2802 }
2803 }
2804
2805 pub fn compose(
2856 &mut self,
2857 other: &Circuit,
2858 qubits_map: Option<&[Qubit]>,
2859 ) -> Result<(), CircuitError> {
2860 let qubit_mapping: HashMap<Qubit, Qubit> = if let Some(mapping) = qubits_map {
2862 if mapping.len() != other.qubits.len() {
2864 return Err(CircuitError::QubitCountMismatch {
2865 expected: other.qubits.len(),
2866 actual: mapping.len(),
2867 });
2868 }
2869 if !Self::check_qubits_unique(mapping) {
2870 return Err(CircuitError::DuplicateQubits);
2871 }
2872
2873 let mut map = HashMap::with_capacity(mapping.len());
2875 for (other_qubit, target_qubit) in other.qubits.iter().zip(mapping.iter()) {
2876 if !self.qubits.contains(target_qubit) {
2877 return Err(CircuitError::QubitNotFound(target_qubit.id()));
2878 }
2879 map.insert(*other_qubit, *target_qubit);
2880 }
2881 map
2882 } else {
2883 let mut map = HashMap::with_capacity(other.qubits.len());
2885 for other_qubit in other.qubits.iter() {
2886 map.insert(*other_qubit, *other_qubit);
2887 }
2888 map
2889 };
2890
2891 let var_base = self.classical_vars.len();
2894 let mut var_map = HashMap::with_capacity(other.classical_vars.len());
2895 for (idx, ty) in other.classical_vars.iter().enumerate() {
2896 var_map.insert(
2897 ClassicalVar::new(other.circuit_id, idx as u32, *ty),
2898 ClassicalVar::new(self.circuit_id, (var_base + idx) as u32, *ty),
2899 );
2900 }
2901
2902 let value_base = self.classical_values.len();
2903 let mut value_map = HashMap::with_capacity(other.classical_values.len());
2904 for (idx, ty) in other.classical_values.iter().enumerate() {
2905 value_map.insert(
2906 ClassicalValue::new(other.circuit_id, idx as u32, *ty),
2907 ClassicalValue::new(self.circuit_id, (value_base + idx) as u32, *ty),
2908 );
2909 }
2910
2911 let parameter_base = self.parameters.len();
2915 let mut new_parameters = IndexSet::new();
2916 let mut new_symbols = IndexSet::new();
2917 let mut param_index_map: Vec<CircuitParam> = Vec::with_capacity(other.parameters.len());
2918 for param in other.parameters.iter() {
2919 let idx = if let Some(idx) = self.parameters.get_index_of(param) {
2920 idx
2921 } else {
2922 new_symbols.extend(param.get_symbols());
2923 parameter_base + new_parameters.insert_full(param.clone()).0
2924 };
2925 param_index_map.push(CircuitParam::Index(idx as u32));
2926 }
2927
2928 let remapped_ops = other
2929 .data
2930 .iter()
2931 .map(|op| {
2932 Self::remap_compose_operation(
2933 op,
2934 &qubit_mapping,
2935 ¶m_index_map,
2936 &var_map,
2937 &value_map,
2938 )
2939 })
2940 .collect::<Result<Vec<_>, _>>()?;
2941
2942 let global_phase = match (&self.global_phase, &other.global_phase) {
2945 (CircuitParam::Fixed(a), CircuitParam::Fixed(b)) => CircuitParam::Fixed(a + b),
2946 _ => {
2947 let new_expr = self.resolve_parameter(&self.global_phase)?
2948 + other.resolve_parameter(&other.global_phase)?;
2949 let new_idx = self
2951 .parameters
2952 .get_index_of(&new_expr)
2953 .unwrap_or_else(|| parameter_base + new_parameters.insert_full(new_expr).0);
2954 CircuitParam::Index(new_idx as u32)
2955 }
2956 };
2957
2958 if qubits_map.is_none() {
2961 self.qubits.extend(other.qubits.iter().copied());
2962 }
2963 if !new_parameters.is_empty() {
2964 self.parameters.extend(new_parameters);
2965 }
2966 self.symbols.extend(new_symbols);
2967 self.global_phase = global_phase;
2968 self.classical_vars
2969 .extend(other.classical_vars.iter().copied());
2970 self.classical_values
2971 .extend(other.classical_values.iter().copied());
2972 let data = Arc::make_mut(&mut self.data);
2973 data.reserve(remapped_ops.len());
2974 data.extend(remapped_ops);
2975
2976 Ok(())
2977 }
2978
2979 pub fn index(&self, i: usize) -> Result<ValueOperation, CircuitError> {
3003 let operation =
3004 self.data
3005 .get(i)
3006 .cloned()
3007 .ok_or(CircuitError::OperationIndexOutOfBounds {
3008 index: i,
3009 len: self.data.len(),
3010 })?;
3011 storage_operation_to_value(operation, &|param| self.parameter_value(param))
3012 }
3013}
3014
3015impl Circuit {
3016 fn lower_instruction(
3017 &mut self,
3018 instruction: ValueInstruction,
3019 ) -> Result<Instruction, CircuitError> {
3020 let op = match instruction {
3021 ValueInstruction::Instruction(Instruction::ClassicalControl(_)) => {
3022 return Err(CircuitError::InvalidOperation(
3023 "ValueInstruction::Instruction cannot wrap Instruction::ClassicalControl"
3024 .to_string(),
3025 ));
3026 }
3027 ValueInstruction::Instruction(instruction) => return Ok(instruction),
3028 ValueInstruction::ClassicalControl(op) => op,
3029 };
3030
3031 let op = match op {
3032 ValueClassicalControlOp::If {
3033 condition,
3034 then_body,
3035 else_body,
3036 } => {
3037 let then_body = self.lower_body(then_body)?;
3038 let else_body = else_body.map(|body| self.lower_body(body)).transpose()?;
3039 IfOp::new(condition, then_body, else_body).map(ClassicalControlOp::If)?
3040 }
3041 ValueClassicalControlOp::While { condition, body } => {
3042 let body = self.lower_body(body)?;
3043 WhileOp::new(condition, body).map(ClassicalControlOp::While)?
3044 }
3045 ValueClassicalControlOp::For {
3046 var,
3047 start,
3048 stop,
3049 step,
3050 body,
3051 } => {
3052 let body = self.lower_body(body)?;
3053 ForOp::new(var, start, stop, step, body).map(ClassicalControlOp::For)?
3054 }
3055 ValueClassicalControlOp::Switch {
3056 target,
3057 cases,
3058 default,
3059 } => {
3060 let cases = cases
3061 .into_iter()
3062 .map(|case| Ok(SwitchCase::new(case.value, self.lower_body(case.body)?)))
3063 .collect::<Result<Vec<_>, CircuitError>>()?;
3064 let default = default.map(|body| self.lower_body(body)).transpose()?;
3065 SwitchOp::new(target, cases, default).map(ClassicalControlOp::Switch)?
3066 }
3067 ValueClassicalControlOp::Break => ClassicalControlOp::Break,
3068 ValueClassicalControlOp::Continue => ClassicalControlOp::Continue,
3069 };
3070 Ok(Instruction::ClassicalControl(op))
3071 }
3072
3073 fn lower_operation(&mut self, operation: ValueOperation) -> Result<Operation, CircuitError> {
3074 let instruction = self.lower_instruction(operation.instruction)?;
3075 let params = operation
3076 .params
3077 .into_iter()
3078 .enumerate()
3079 .map(
3080 |(param_index, param)| -> Result<CircuitParam, CircuitError> {
3081 match param {
3082 ParameterValue::Param(param) => {
3083 let (index, is_new) = self.parameters.insert_full(param.clone());
3084 if is_new {
3085 for sym in param.get_symbols() {
3086 self.symbols.insert(sym);
3087 }
3088 }
3089 Ok(CircuitParam::Index(index as u32))
3090 }
3091 ParameterValue::Fixed(value) => {
3092 if !value.is_finite() {
3093 return Err(CircuitError::InvalidParameterValue(
3094 param_index,
3095 value,
3096 ));
3097 }
3098 Ok(CircuitParam::Fixed(value))
3099 }
3100 }
3101 },
3102 )
3103 .collect::<Result<_, _>>()?;
3104 Ok(Operation {
3105 instruction,
3106 qubits: operation.qubits,
3107 params,
3108 label: operation.label,
3109 })
3110 }
3111
3112 fn lower_body(&mut self, body: ValueControlBody) -> Result<ControlBody, CircuitError> {
3113 body.operations()
3114 .iter()
3115 .cloned()
3116 .map(|operation| self.lower_operation(operation))
3117 .collect::<Result<Vec<_>, _>>()
3118 .map(ControlBody::new)
3119 }
3120
3121 fn validate_operation_parameters(&self, operations: &[Operation]) -> Result<(), CircuitError> {
3122 for operation in operations {
3123 for param in &operation.params {
3124 match param {
3125 CircuitParam::Fixed(value) => {
3126 if !value.is_finite() {
3127 return Err(CircuitError::InvalidParameterValue(0, *value));
3128 }
3129 }
3130 CircuitParam::Index(index) => {
3131 if self.parameters.get_index(*index as usize).is_none() {
3132 return Err(CircuitError::InvalidParameterIndex(*index));
3133 }
3134 }
3135 }
3136 }
3137 if let Instruction::ClassicalControl(op) = &operation.instruction {
3138 match op {
3139 ClassicalControlOp::If(op) => {
3140 self.validate_operation_parameters(op.then_body().operations())?;
3141 if let Some(body) = op.else_body() {
3142 self.validate_operation_parameters(body.operations())?;
3143 }
3144 }
3145 ClassicalControlOp::While(op) => {
3146 self.validate_operation_parameters(op.body().operations())?;
3147 }
3148 ClassicalControlOp::For(op) => {
3149 self.validate_operation_parameters(op.body().operations())?;
3150 }
3151 ClassicalControlOp::Switch(op) => {
3152 for case in op.cases() {
3153 self.validate_operation_parameters(case.body().operations())?;
3154 }
3155 if let Some(body) = op.default() {
3156 self.validate_operation_parameters(body.operations())?;
3157 }
3158 }
3159 ClassicalControlOp::Break | ClassicalControlOp::Continue => {}
3160 }
3161 }
3162 }
3163 Ok(())
3164 }
3165}
3166
3167fn infer_classical_circuit_id(
3168 operations: &[ValueOperation],
3169) -> Result<Option<CircuitId>, CircuitError> {
3170 fn collect_instruction(instruction: &Instruction, identities: &mut HashSet<CircuitId>) {
3171 match instruction {
3172 Instruction::ClassicalData(op) => match op {
3173 ClassicalDataOp::Store { target, value } => {
3174 identities.insert(target.circuit_id());
3175 identities.extend(value.vars().into_iter().map(ClassicalVar::circuit_id));
3176 identities.extend(value.values().into_iter().map(ClassicalValue::circuit_id));
3177 }
3178 ClassicalDataOp::MeasureBit { result }
3179 | ClassicalDataOp::MeasureBits { result } => {
3180 identities.insert(result.circuit_id());
3181 }
3182 },
3183 Instruction::ClassicalControl(op) => {
3184 identities.extend(
3185 op.classical_var_reads()
3186 .into_iter()
3187 .map(ClassicalVar::circuit_id),
3188 );
3189 identities.extend(
3190 op.classical_value_reads()
3191 .into_iter()
3192 .map(ClassicalValue::circuit_id),
3193 );
3194 identities.extend(
3195 op.classical_writes()
3196 .into_iter()
3197 .map(ClassicalVar::circuit_id),
3198 );
3199 match op {
3200 ClassicalControlOp::If(op) => {
3201 for operation in op
3202 .then_body()
3203 .operations()
3204 .iter()
3205 .chain(op.else_body().into_iter().flat_map(ControlBody::operations))
3206 {
3207 collect_instruction(&operation.instruction, identities);
3208 }
3209 }
3210 ClassicalControlOp::While(op) => {
3211 for operation in op.body().operations() {
3212 collect_instruction(&operation.instruction, identities);
3213 }
3214 }
3215 ClassicalControlOp::For(op) => {
3216 for operation in op.body().operations() {
3217 collect_instruction(&operation.instruction, identities);
3218 }
3219 }
3220 ClassicalControlOp::Switch(op) => {
3221 for operation in op
3222 .cases()
3223 .iter()
3224 .flat_map(|case| case.body().operations())
3225 .chain(op.default().into_iter().flat_map(ControlBody::operations))
3226 {
3227 collect_instruction(&operation.instruction, identities);
3228 }
3229 }
3230 ClassicalControlOp::Break | ClassicalControlOp::Continue => {}
3231 }
3232 }
3233 _ => {}
3234 }
3235 }
3236
3237 fn collect_value(instruction: &ValueInstruction, identities: &mut HashSet<CircuitId>) {
3238 match instruction {
3239 ValueInstruction::Instruction(instruction) => {
3240 collect_instruction(instruction, identities);
3241 }
3242 ValueInstruction::ClassicalControl(op) => {
3243 identities.extend(
3244 op.classical_var_reads()
3245 .into_iter()
3246 .map(ClassicalVar::circuit_id),
3247 );
3248 identities.extend(
3249 op.classical_value_reads()
3250 .into_iter()
3251 .map(ClassicalValue::circuit_id),
3252 );
3253 identities.extend(
3254 op.classical_writes()
3255 .into_iter()
3256 .map(ClassicalVar::circuit_id),
3257 );
3258 match op {
3259 ValueClassicalControlOp::If {
3260 then_body,
3261 else_body,
3262 ..
3263 } => {
3264 for operation in then_body
3265 .operations()
3266 .iter()
3267 .chain(else_body.iter().flat_map(|body| body.operations()))
3268 {
3269 collect_value(&operation.instruction, identities);
3270 }
3271 }
3272 ValueClassicalControlOp::While { body, .. }
3273 | ValueClassicalControlOp::For { body, .. } => {
3274 for operation in body.operations() {
3275 collect_value(&operation.instruction, identities);
3276 }
3277 }
3278 ValueClassicalControlOp::Switch { cases, default, .. } => {
3279 for operation in cases
3280 .iter()
3281 .flat_map(|case| case.body.operations())
3282 .chain(default.iter().flat_map(|body| body.operations()))
3283 {
3284 collect_value(&operation.instruction, identities);
3285 }
3286 }
3287 ValueClassicalControlOp::Break | ValueClassicalControlOp::Continue => {}
3288 }
3289 }
3290 }
3291 }
3292
3293 let mut identities = HashSet::new();
3294 for operation in operations {
3295 collect_value(&operation.instruction, &mut identities);
3296 }
3297 if identities.len() > 1 {
3298 return Err(CircuitError::InvalidOperation(
3299 "operations contain classical handles from multiple circuits".to_string(),
3300 ));
3301 }
3302 Ok(identities.into_iter().next())
3303}
3304
3305#[cfg(test)]
3306#[path = "./circuit_test.rs"]
3307mod circuit_test;