1use std::collections::HashMap;
33use std::fmt;
34
35use crate::{DeviceError, DeviceResult};
36
37pub const QASM3_VERSION: &str = "3.0";
39
40#[derive(Debug, Clone, PartialEq)]
42pub enum Qasm3Type {
43 Qubit,
45 QubitArray(usize),
47 Bit,
49 BitArray(usize),
51 Int(Option<usize>),
53 Uint(Option<usize>),
55 Float(Option<usize>),
57 Angle(Option<usize>),
59 Bool,
61 Duration,
63 Stretch,
65 Complex(Option<usize>),
67}
68
69impl fmt::Display for Qasm3Type {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 match self {
72 Self::Qubit => write!(f, "qubit"),
73 Self::QubitArray(n) => write!(f, "qubit[{}]", n),
74 Self::Bit => write!(f, "bit"),
75 Self::BitArray(n) => write!(f, "bit[{}]", n),
76 Self::Int(Some(n)) => write!(f, "int[{}]", n),
77 Self::Int(None) => write!(f, "int"),
78 Self::Uint(Some(n)) => write!(f, "uint[{}]", n),
79 Self::Uint(None) => write!(f, "uint"),
80 Self::Float(Some(n)) => write!(f, "float[{}]", n),
81 Self::Float(None) => write!(f, "float"),
82 Self::Angle(Some(n)) => write!(f, "angle[{}]", n),
83 Self::Angle(None) => write!(f, "angle"),
84 Self::Bool => write!(f, "bool"),
85 Self::Duration => write!(f, "duration"),
86 Self::Stretch => write!(f, "stretch"),
87 Self::Complex(Some(n)) => write!(f, "complex[float[{}]]", n),
88 Self::Complex(None) => write!(f, "complex[float]"),
89 }
90 }
91}
92
93#[derive(Debug, Clone)]
95pub enum GateModifier {
96 Ctrl(usize),
98 NegCtrl(usize),
100 Inv,
102 Pow(f64),
104}
105
106impl fmt::Display for GateModifier {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 match self {
109 Self::Ctrl(n) if *n == 1 => write!(f, "ctrl @"),
110 Self::Ctrl(n) => write!(f, "ctrl({}) @", n),
111 Self::NegCtrl(n) if *n == 1 => write!(f, "negctrl @"),
112 Self::NegCtrl(n) => write!(f, "negctrl({}) @", n),
113 Self::Inv => write!(f, "inv @"),
114 Self::Pow(n) => write!(f, "pow({}) @", n),
115 }
116 }
117}
118
119#[derive(Debug, Clone)]
121pub enum Qasm3Statement {
122 Include(String),
124 Declaration {
126 var_type: Qasm3Type,
127 name: String,
128 init_value: Option<String>,
129 },
130 GateDef {
132 name: String,
133 params: Vec<String>,
134 qubits: Vec<String>,
135 body: Vec<Qasm3Statement>,
136 },
137 Gate {
139 name: String,
140 modifiers: Vec<GateModifier>,
141 params: Vec<String>,
142 qubits: Vec<String>,
143 },
144 Measure { qubit: String, classical: String },
146 Reset(String),
148 Barrier(Vec<String>),
150 If {
152 condition: String,
153 then_body: Vec<Qasm3Statement>,
154 else_body: Option<Vec<Qasm3Statement>>,
155 },
156 Switch {
158 expression: String,
159 cases: Vec<(Vec<i64>, Vec<Qasm3Statement>)>,
160 default_case: Option<Vec<Qasm3Statement>>,
161 },
162 While {
164 condition: String,
165 body: Vec<Qasm3Statement>,
166 },
167 For {
169 var_name: String,
170 range: String,
171 body: Vec<Qasm3Statement>,
172 },
173 Assignment { target: String, value: String },
175 Delay {
177 duration: String,
178 qubits: Vec<String>,
179 },
180 Box { body: Vec<Qasm3Statement> },
182 DefCal {
184 name: String,
185 params: Vec<String>,
186 qubits: Vec<String>,
187 body: String,
188 },
189 Comment(String),
191 Pragma(String),
193}
194
195impl fmt::Display for Qasm3Statement {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 match self {
198 Self::Include(file) => writeln!(f, "include \"{}\";", file),
199 Self::Declaration {
200 var_type,
201 name,
202 init_value,
203 } => {
204 if let Some(val) = init_value {
205 writeln!(f, "{} {} = {};", var_type, name, val)
206 } else {
207 writeln!(f, "{} {};", var_type, name)
208 }
209 }
210 Self::GateDef {
211 name,
212 params,
213 qubits,
214 body,
215 } => {
216 let params_str = if params.is_empty() {
217 String::new()
218 } else {
219 format!("({})", params.join(", "))
220 };
221 writeln!(f, "gate {}{} {} {{", name, params_str, qubits.join(", "))?;
222 for stmt in body {
223 write!(f, " {}", stmt)?;
224 }
225 writeln!(f, "}}")
226 }
227 Self::Gate {
228 name,
229 modifiers,
230 params,
231 qubits,
232 } => {
233 let mod_str = if modifiers.is_empty() {
234 String::new()
235 } else {
236 modifiers
237 .iter()
238 .map(|m| m.to_string())
239 .collect::<Vec<_>>()
240 .join(" ")
241 + " "
242 };
243 let params_str = if params.is_empty() {
244 String::new()
245 } else {
246 format!("({})", params.join(", "))
247 };
248 writeln!(
249 f,
250 "{}{}{} {};",
251 mod_str,
252 name,
253 params_str,
254 qubits.join(", ")
255 )
256 }
257 Self::Measure { qubit, classical } => {
258 writeln!(f, "{} = measure {};", classical, qubit)
259 }
260 Self::Reset(qubit) => writeln!(f, "reset {};", qubit),
261 Self::Barrier(qubits) => writeln!(f, "barrier {};", qubits.join(", ")),
262 Self::If {
263 condition,
264 then_body,
265 else_body,
266 } => {
267 writeln!(f, "if ({}) {{", condition)?;
268 for stmt in then_body {
269 write!(f, " {}", stmt)?;
270 }
271 if let Some(else_stmts) = else_body {
272 writeln!(f, "}} else {{")?;
273 for stmt in else_stmts {
274 write!(f, " {}", stmt)?;
275 }
276 }
277 writeln!(f, "}}")
278 }
279 Self::Switch {
280 expression,
281 cases,
282 default_case,
283 } => {
284 writeln!(f, "switch ({}) {{", expression)?;
285 for (values, body) in cases {
286 let values_str = values
287 .iter()
288 .map(|v| v.to_string())
289 .collect::<Vec<_>>()
290 .join(", ");
291 writeln!(f, " case {}: {{", values_str)?;
292 for stmt in body {
293 write!(f, " {}", stmt)?;
294 }
295 writeln!(f, " }}")?;
296 }
297 if let Some(default_body) = default_case {
298 writeln!(f, " default: {{")?;
299 for stmt in default_body {
300 write!(f, " {}", stmt)?;
301 }
302 writeln!(f, " }}")?;
303 }
304 writeln!(f, "}}")
305 }
306 Self::While { condition, body } => {
307 writeln!(f, "while ({}) {{", condition)?;
308 for stmt in body {
309 write!(f, " {}", stmt)?;
310 }
311 writeln!(f, "}}")
312 }
313 Self::For {
314 var_name,
315 range,
316 body,
317 } => {
318 writeln!(f, "for {} in {} {{", var_name, range)?;
319 for stmt in body {
320 write!(f, " {}", stmt)?;
321 }
322 writeln!(f, "}}")
323 }
324 Self::Assignment { target, value } => {
325 writeln!(f, "{} = {};", target, value)
326 }
327 Self::Delay { duration, qubits } => {
328 writeln!(f, "delay[{}] {};", duration, qubits.join(", "))
329 }
330 Self::Box { body } => {
331 writeln!(f, "box {{")?;
332 for stmt in body {
333 write!(f, " {}", stmt)?;
334 }
335 writeln!(f, "}}")
336 }
337 Self::DefCal {
338 name,
339 params,
340 qubits,
341 body,
342 } => {
343 let params_str = if params.is_empty() {
344 String::new()
345 } else {
346 format!("({})", params.join(", "))
347 };
348 writeln!(f, "defcal {}{} {} {{", name, params_str, qubits.join(", "))?;
349 writeln!(f, " {}", body)?;
350 writeln!(f, "}}")
351 }
352 Self::Comment(text) => writeln!(f, "// {}", text),
353 Self::Pragma(text) => writeln!(f, "#pragma {}", text),
354 }
355 }
356}
357
358#[derive(Debug, Clone)]
360pub struct Qasm3Circuit {
361 pub version: String,
363 pub statements: Vec<Qasm3Statement>,
365 pub inputs: HashMap<String, Qasm3Type>,
367 pub outputs: HashMap<String, Qasm3Type>,
369}
370
371impl Qasm3Circuit {
372 pub fn new() -> Self {
374 Self {
375 version: QASM3_VERSION.to_string(),
376 statements: Vec::new(),
377 inputs: HashMap::new(),
378 outputs: HashMap::new(),
379 }
380 }
381
382 pub fn add_input(&mut self, name: &str, var_type: Qasm3Type) {
384 self.inputs.insert(name.to_string(), var_type);
385 }
386
387 pub fn add_output(&mut self, name: &str, var_type: Qasm3Type) {
389 self.outputs.insert(name.to_string(), var_type);
390 }
391
392 pub fn add_statement(&mut self, stmt: Qasm3Statement) {
394 self.statements.push(stmt);
395 }
396
397 pub fn num_qubits(&self) -> usize {
399 let mut max_qubit = 0;
400 for stmt in &self.statements {
401 if let Qasm3Statement::Declaration {
402 var_type: Qasm3Type::QubitArray(n),
403 ..
404 } = stmt
405 {
406 max_qubit = max_qubit.max(*n);
407 }
408 }
409 max_qubit
410 }
411
412 pub fn to_qasm3(&self) -> String {
414 self.to_string()
415 }
416
417 pub fn to_qasm2(&self) -> DeviceResult<String> {
419 let mut qasm2 = String::from("OPENQASM 2.0;\ninclude \"qelib1.inc\";\n\n");
420
421 let mut num_qubits = 0;
423 let mut num_bits = 0;
424
425 for stmt in &self.statements {
426 match stmt {
427 Qasm3Statement::Declaration {
428 var_type: Qasm3Type::QubitArray(n),
429 ..
430 } => {
431 num_qubits = num_qubits.max(*n);
432 }
433 Qasm3Statement::Declaration {
434 var_type: Qasm3Type::BitArray(n),
435 ..
436 } => {
437 num_bits = num_bits.max(*n);
438 }
439 _ => {}
440 }
441 }
442
443 if num_qubits > 0 {
444 qasm2.push_str(&format!("qreg q[{}];\n", num_qubits));
445 }
446 if num_bits > 0 {
447 qasm2.push_str(&format!("creg c[{}];\n", num_bits));
448 }
449 qasm2.push('\n');
450
451 for stmt in &self.statements {
453 match stmt {
454 Qasm3Statement::Gate {
455 name,
456 modifiers,
457 params,
458 qubits,
459 } => {
460 if !modifiers.is_empty() {
461 return Err(DeviceError::QasmError(
462 "Gate modifiers not supported in QASM 2.0".to_string(),
463 ));
464 }
465 let params_str = if params.is_empty() {
466 String::new()
467 } else {
468 format!("({})", params.join(", "))
469 };
470 qasm2.push_str(&format!("{}{} {};\n", name, params_str, qubits.join(", ")));
471 }
472 Qasm3Statement::Measure { qubit, classical } => {
473 qasm2.push_str(&format!("measure {} -> {};\n", qubit, classical));
474 }
475 Qasm3Statement::Reset(qubit) => {
476 qasm2.push_str(&format!("reset {};\n", qubit));
477 }
478 Qasm3Statement::Barrier(qubits) => {
479 qasm2.push_str(&format!("barrier {};\n", qubits.join(", ")));
480 }
481 Qasm3Statement::If {
482 condition,
483 then_body,
484 else_body,
485 } => {
486 if else_body.is_some() {
487 return Err(DeviceError::QasmError(
488 "If-else not supported in QASM 2.0".to_string(),
489 ));
490 }
491 qasm2.push_str(&format!("if ({}) ", condition));
493 if let Some(stmt) = then_body.first() {
494 if let Qasm3Statement::Gate {
495 name,
496 params,
497 qubits,
498 ..
499 } = stmt
500 {
501 let params_str = if params.is_empty() {
502 String::new()
503 } else {
504 format!("({})", params.join(", "))
505 };
506 qasm2.push_str(&format!(
507 "{}{} {};\n",
508 name,
509 params_str,
510 qubits.join(", ")
511 ));
512 }
513 }
514 }
515 Qasm3Statement::While { .. } | Qasm3Statement::For { .. } => {
516 return Err(DeviceError::QasmError(
517 "Loops not supported in QASM 2.0".to_string(),
518 ));
519 }
520 Qasm3Statement::Declaration { .. }
521 | Qasm3Statement::Include(_)
522 | Qasm3Statement::Comment(_) => {
523 }
525 _ => {}
526 }
527 }
528
529 Ok(qasm2)
530 }
531}
532
533impl Default for Qasm3Circuit {
534 fn default() -> Self {
535 Self::new()
536 }
537}
538
539impl fmt::Display for Qasm3Circuit {
540 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
541 writeln!(f, "OPENQASM {};", self.version)?;
542 writeln!(f)?;
543
544 writeln!(f, "include \"stdgates.inc\";")?;
546 writeln!(f)?;
547
548 for (name, var_type) in &self.inputs {
550 writeln!(f, "input {} {};", var_type, name)?;
551 }
552 if !self.inputs.is_empty() {
553 writeln!(f)?;
554 }
555
556 for (name, var_type) in &self.outputs {
558 writeln!(f, "output {} {};", var_type, name)?;
559 }
560 if !self.outputs.is_empty() {
561 writeln!(f)?;
562 }
563
564 for stmt in &self.statements {
566 write!(f, "{}", stmt)?;
567 }
568
569 Ok(())
570 }
571}
572
573pub struct Qasm3Builder {
575 pub circuit: Qasm3Circuit,
577 pub num_qubits: usize,
579 pub num_bits: usize,
581}
582
583impl Qasm3Builder {
584 pub fn new(num_qubits: usize) -> Self {
586 let mut builder = Self {
587 circuit: Qasm3Circuit::new(),
588 num_qubits,
589 num_bits: num_qubits, };
591
592 builder.circuit.add_statement(Qasm3Statement::Declaration {
594 var_type: Qasm3Type::QubitArray(num_qubits),
595 name: "q".to_string(),
596 init_value: None,
597 });
598 builder.circuit.add_statement(Qasm3Statement::Declaration {
599 var_type: Qasm3Type::BitArray(num_qubits),
600 name: "c".to_string(),
601 init_value: None,
602 });
603
604 builder
605 }
606
607 pub fn with_bits(mut self, num_bits: usize) -> Self {
609 self.num_bits = num_bits;
610 for stmt in &mut self.circuit.statements {
612 if let Qasm3Statement::Declaration {
613 var_type: Qasm3Type::BitArray(n),
614 name,
615 ..
616 } = stmt
617 {
618 if name == "c" {
619 *n = num_bits;
620 }
621 }
622 }
623 self
624 }
625
626 pub fn gate(&mut self, name: &str, qubits: &[usize]) -> DeviceResult<&mut Self> {
628 self.gate_with_params(name, &[], qubits)
629 }
630
631 pub fn gate_with_params(
633 &mut self,
634 name: &str,
635 params: &[f64],
636 qubits: &[usize],
637 ) -> DeviceResult<&mut Self> {
638 for &q in qubits {
639 if q >= self.num_qubits {
640 return Err(DeviceError::InvalidInput(format!(
641 "Qubit {} out of range (max {})",
642 q,
643 self.num_qubits - 1
644 )));
645 }
646 }
647
648 let qubit_strs: Vec<String> = qubits.iter().map(|q| format!("q[{}]", q)).collect();
649 let param_strs: Vec<String> = params.iter().map(|p| format!("{}", p)).collect();
650
651 self.circuit.add_statement(Qasm3Statement::Gate {
652 name: name.to_string(),
653 modifiers: Vec::new(),
654 params: param_strs,
655 qubits: qubit_strs,
656 });
657
658 Ok(self)
659 }
660
661 pub fn ctrl_gate(
663 &mut self,
664 name: &str,
665 control: usize,
666 target: usize,
667 params: &[f64],
668 ) -> DeviceResult<&mut Self> {
669 if control >= self.num_qubits || target >= self.num_qubits {
670 return Err(DeviceError::InvalidInput("Qubit out of range".to_string()));
671 }
672
673 let param_strs: Vec<String> = params.iter().map(|p| format!("{}", p)).collect();
674
675 self.circuit.add_statement(Qasm3Statement::Gate {
676 name: name.to_string(),
677 modifiers: vec![GateModifier::Ctrl(1)],
678 params: param_strs,
679 qubits: vec![format!("q[{}]", control), format!("q[{}]", target)],
680 });
681
682 Ok(self)
683 }
684
685 pub fn inv_gate(&mut self, name: &str, qubits: &[usize]) -> DeviceResult<&mut Self> {
687 for &q in qubits {
688 if q >= self.num_qubits {
689 return Err(DeviceError::InvalidInput("Qubit out of range".to_string()));
690 }
691 }
692
693 let qubit_strs: Vec<String> = qubits.iter().map(|q| format!("q[{}]", q)).collect();
694
695 self.circuit.add_statement(Qasm3Statement::Gate {
696 name: name.to_string(),
697 modifiers: vec![GateModifier::Inv],
698 params: Vec::new(),
699 qubits: qubit_strs,
700 });
701
702 Ok(self)
703 }
704
705 pub fn measure(&mut self, qubit: usize, bit: usize) -> DeviceResult<&mut Self> {
707 if qubit >= self.num_qubits {
708 return Err(DeviceError::InvalidInput("Qubit out of range".to_string()));
709 }
710 if bit >= self.num_bits {
711 return Err(DeviceError::InvalidInput("Bit out of range".to_string()));
712 }
713
714 self.circuit.add_statement(Qasm3Statement::Measure {
715 qubit: format!("q[{}]", qubit),
716 classical: format!("c[{}]", bit),
717 });
718
719 Ok(self)
720 }
721
722 pub fn measure_all(&mut self) -> DeviceResult<&mut Self> {
724 for i in 0..self.num_qubits.min(self.num_bits) {
725 self.measure(i, i)?;
726 }
727 Ok(self)
728 }
729
730 pub fn reset(&mut self, qubit: usize) -> DeviceResult<&mut Self> {
732 if qubit >= self.num_qubits {
733 return Err(DeviceError::InvalidInput("Qubit out of range".to_string()));
734 }
735
736 self.circuit
737 .add_statement(Qasm3Statement::Reset(format!("q[{}]", qubit)));
738
739 Ok(self)
740 }
741
742 pub fn barrier(&mut self, qubits: &[usize]) -> DeviceResult<&mut Self> {
744 for &q in qubits {
745 if q >= self.num_qubits {
746 return Err(DeviceError::InvalidInput("Qubit out of range".to_string()));
747 }
748 }
749
750 let qubit_strs: Vec<String> = qubits.iter().map(|q| format!("q[{}]", q)).collect();
751 self.circuit
752 .add_statement(Qasm3Statement::Barrier(qubit_strs));
753
754 Ok(self)
755 }
756
757 pub fn if_statement<F>(&mut self, condition: &str, then_block: F) -> DeviceResult<&mut Self>
759 where
760 F: FnOnce(&mut Qasm3Builder) -> DeviceResult<()>,
761 {
762 let mut inner_builder = Qasm3Builder {
763 circuit: Qasm3Circuit::new(),
764 num_qubits: self.num_qubits,
765 num_bits: self.num_bits,
766 };
767 inner_builder.circuit.statements.clear(); then_block(&mut inner_builder)?;
770
771 self.circuit.add_statement(Qasm3Statement::If {
772 condition: condition.to_string(),
773 then_body: inner_builder.circuit.statements,
774 else_body: None,
775 });
776
777 Ok(self)
778 }
779
780 pub fn if_else_statement<F, G>(
782 &mut self,
783 condition: &str,
784 then_block: F,
785 else_block: G,
786 ) -> DeviceResult<&mut Self>
787 where
788 F: FnOnce(&mut Qasm3Builder) -> DeviceResult<()>,
789 G: FnOnce(&mut Qasm3Builder) -> DeviceResult<()>,
790 {
791 let mut then_builder = Qasm3Builder {
792 circuit: Qasm3Circuit::new(),
793 num_qubits: self.num_qubits,
794 num_bits: self.num_bits,
795 };
796 then_builder.circuit.statements.clear();
797 then_block(&mut then_builder)?;
798
799 let mut else_builder = Qasm3Builder {
800 circuit: Qasm3Circuit::new(),
801 num_qubits: self.num_qubits,
802 num_bits: self.num_bits,
803 };
804 else_builder.circuit.statements.clear();
805 else_block(&mut else_builder)?;
806
807 self.circuit.add_statement(Qasm3Statement::If {
808 condition: condition.to_string(),
809 then_body: then_builder.circuit.statements,
810 else_body: Some(else_builder.circuit.statements),
811 });
812
813 Ok(self)
814 }
815
816 pub fn while_loop<F>(&mut self, condition: &str, body: F) -> DeviceResult<&mut Self>
818 where
819 F: FnOnce(&mut Qasm3Builder) -> DeviceResult<()>,
820 {
821 let mut inner_builder = Qasm3Builder {
822 circuit: Qasm3Circuit::new(),
823 num_qubits: self.num_qubits,
824 num_bits: self.num_bits,
825 };
826 inner_builder.circuit.statements.clear();
827
828 body(&mut inner_builder)?;
829
830 self.circuit.add_statement(Qasm3Statement::While {
831 condition: condition.to_string(),
832 body: inner_builder.circuit.statements,
833 });
834
835 Ok(self)
836 }
837
838 pub fn for_loop<F>(&mut self, var_name: &str, range: &str, body: F) -> DeviceResult<&mut Self>
840 where
841 F: FnOnce(&mut Qasm3Builder) -> DeviceResult<()>,
842 {
843 let mut inner_builder = Qasm3Builder {
844 circuit: Qasm3Circuit::new(),
845 num_qubits: self.num_qubits,
846 num_bits: self.num_bits,
847 };
848 inner_builder.circuit.statements.clear();
849
850 body(&mut inner_builder)?;
851
852 self.circuit.add_statement(Qasm3Statement::For {
853 var_name: var_name.to_string(),
854 range: range.to_string(),
855 body: inner_builder.circuit.statements,
856 });
857
858 Ok(self)
859 }
860
861 pub fn switch_statement<F>(
877 &mut self,
878 expression: &str,
879 case_builder: F,
880 ) -> DeviceResult<&mut Self>
881 where
882 F: FnOnce(&mut SwitchBuilder) -> DeviceResult<()>,
883 {
884 let mut switch_builder = SwitchBuilder::new(self.num_qubits, self.num_bits);
885 case_builder(&mut switch_builder)?;
886
887 self.circuit.add_statement(Qasm3Statement::Switch {
888 expression: expression.to_string(),
889 cases: switch_builder.cases,
890 default_case: switch_builder.default_case,
891 });
892
893 Ok(self)
894 }
895
896 pub fn assign(&mut self, target: &str, value: &str) -> &mut Self {
902 self.circuit.add_statement(Qasm3Statement::Assignment {
903 target: target.to_string(),
904 value: value.to_string(),
905 });
906 self
907 }
908
909 pub fn comment(&mut self, text: &str) -> &mut Self {
911 self.circuit
912 .add_statement(Qasm3Statement::Comment(text.to_string()));
913 self
914 }
915
916 pub fn build(self) -> DeviceResult<Qasm3Circuit> {
918 Ok(self.circuit)
919 }
920}
921
922pub struct SwitchBuilder {
924 num_qubits: usize,
925 num_bits: usize,
926 cases: Vec<(Vec<i64>, Vec<Qasm3Statement>)>,
927 default_case: Option<Vec<Qasm3Statement>>,
928}
929
930impl SwitchBuilder {
931 fn new(num_qubits: usize, num_bits: usize) -> Self {
932 Self {
933 num_qubits,
934 num_bits,
935 cases: Vec::new(),
936 default_case: None,
937 }
938 }
939
940 pub fn case<F>(&mut self, values: &[i64], body: F) -> DeviceResult<&mut Self>
946 where
947 F: FnOnce(&mut Qasm3Builder) -> DeviceResult<()>,
948 {
949 let mut inner_builder = Qasm3Builder {
950 circuit: Qasm3Circuit::new(),
951 num_qubits: self.num_qubits,
952 num_bits: self.num_bits,
953 };
954 inner_builder.circuit.statements.clear();
955
956 body(&mut inner_builder)?;
957
958 self.cases
959 .push((values.to_vec(), inner_builder.circuit.statements));
960 Ok(self)
961 }
962
963 pub fn default<F>(&mut self, body: F) -> DeviceResult<&mut Self>
965 where
966 F: FnOnce(&mut Qasm3Builder) -> DeviceResult<()>,
967 {
968 let mut inner_builder = Qasm3Builder {
969 circuit: Qasm3Circuit::new(),
970 num_qubits: self.num_qubits,
971 num_bits: self.num_bits,
972 };
973 inner_builder.circuit.statements.clear();
974
975 body(&mut inner_builder)?;
976
977 self.default_case = Some(inner_builder.circuit.statements);
978 Ok(self)
979 }
980}
981
982pub fn circuit_to_qasm3<const N: usize>(
984 _circuit: &quantrs2_circuit::prelude::Circuit<N>,
985) -> DeviceResult<Qasm3Circuit> {
986 let mut builder = Qasm3Builder::new(N);
987
988 builder.build()
993}
994
995#[cfg(test)]
996mod tests {
997 use super::*;
998
999 #[test]
1000 fn test_qasm3_type_display() {
1001 assert_eq!(format!("{}", Qasm3Type::Qubit), "qubit");
1002 assert_eq!(format!("{}", Qasm3Type::QubitArray(5)), "qubit[5]");
1003 assert_eq!(format!("{}", Qasm3Type::BitArray(3)), "bit[3]");
1004 assert_eq!(format!("{}", Qasm3Type::Int(Some(32))), "int[32]");
1005 assert_eq!(format!("{}", Qasm3Type::Float(None)), "float");
1006 }
1007
1008 #[test]
1009 fn test_gate_modifier_display() {
1010 assert_eq!(format!("{}", GateModifier::Ctrl(1)), "ctrl @");
1011 assert_eq!(format!("{}", GateModifier::Ctrl(2)), "ctrl(2) @");
1012 assert_eq!(format!("{}", GateModifier::Inv), "inv @");
1013 assert_eq!(format!("{}", GateModifier::Pow(2.0)), "pow(2) @");
1014 }
1015
1016 #[test]
1017 fn test_qasm3_builder_basic() {
1018 let mut builder = Qasm3Builder::new(3);
1019 builder.gate("h", &[0]).unwrap();
1020 builder.gate("cx", &[0, 1]).unwrap();
1021 builder.measure(0, 0).unwrap();
1022
1023 let circuit = builder.build().unwrap();
1024 let qasm = circuit.to_string();
1025
1026 assert!(qasm.contains("OPENQASM 3.0"));
1027 assert!(qasm.contains("qubit[3]"));
1028 assert!(qasm.contains("h q[0]"));
1029 assert!(qasm.contains("cx q[0], q[1]"));
1030 }
1031
1032 #[test]
1033 fn test_qasm3_builder_params() {
1034 let mut builder = Qasm3Builder::new(2);
1035 builder
1036 .gate_with_params("rx", &[std::f64::consts::PI / 2.0], &[0])
1037 .unwrap();
1038
1039 let circuit = builder.build().unwrap();
1040 let qasm = circuit.to_string();
1041
1042 assert!(qasm.contains("rx"));
1043 }
1044
1045 #[test]
1046 fn test_qasm3_if_statement() {
1047 let mut builder = Qasm3Builder::new(2);
1048 builder.gate("h", &[0]).unwrap();
1049 builder.measure(0, 0).unwrap();
1050 builder
1051 .if_statement("c[0] == 1", |b| {
1052 b.gate("x", &[1])?;
1053 Ok(())
1054 })
1055 .unwrap();
1056
1057 let circuit = builder.build().unwrap();
1058 let qasm = circuit.to_string();
1059
1060 assert!(qasm.contains("if (c[0] == 1)"));
1061 assert!(qasm.contains("x q[1]"));
1062 }
1063
1064 #[test]
1065 fn test_qasm3_to_qasm2() {
1066 let mut builder = Qasm3Builder::new(2);
1067 builder.gate("h", &[0]).unwrap();
1068 builder.gate("cx", &[0, 1]).unwrap();
1069 builder.measure_all().unwrap();
1070
1071 let circuit = builder.build().unwrap();
1072 let qasm2 = circuit.to_qasm2().unwrap();
1073
1074 assert!(qasm2.contains("OPENQASM 2.0"));
1075 assert!(qasm2.contains("qreg q[2]"));
1076 assert!(qasm2.contains("creg c[2]"));
1077 }
1078
1079 #[test]
1080 fn test_qasm3_ctrl_gate() {
1081 let mut builder = Qasm3Builder::new(3);
1082 builder.ctrl_gate("x", 0, 1, &[]).unwrap();
1083
1084 let circuit = builder.build().unwrap();
1085 let qasm = circuit.to_string();
1086
1087 assert!(qasm.contains("ctrl @"));
1088 }
1089
1090 #[test]
1091 fn test_qasm3_inv_gate() {
1092 let mut builder = Qasm3Builder::new(2);
1093 builder.inv_gate("s", &[0]).unwrap();
1094
1095 let circuit = builder.build().unwrap();
1096 let qasm = circuit.to_string();
1097
1098 assert!(qasm.contains("inv @"));
1099 }
1100
1101 #[test]
1102 fn test_qasm3_for_loop() {
1103 let mut builder = Qasm3Builder::new(4);
1104 builder
1105 .for_loop("i", "[0:3]", |b| {
1106 b.gate("h", &[0])?;
1107 Ok(())
1108 })
1109 .unwrap();
1110
1111 let circuit = builder.build().unwrap();
1112 let qasm = circuit.to_string();
1113
1114 assert!(qasm.contains("for i in [0:3]"));
1115 }
1116}