quantrs2_device/
qasm3.rs

1//! OpenQASM 3.0 support for QuantRS2.
2//!
3//! This module provides QASM 3.0 circuit representation and conversion,
4//! compatible with IBM Quantum and other modern quantum systems.
5//!
6//! ## Features
7//!
8//! - Full OpenQASM 3.0 syntax support
9//! - Classical control flow (if/else, while, for)
10//! - Dynamic circuits with mid-circuit measurements
11//! - Gate modifiers (ctrl, inv, pow)
12//! - Type system (qubit, bit, int, float, angle)
13//! - Subroutine definitions
14//!
15//! ## Example
16//!
17//! ```rust,ignore
18//! use quantrs2_device::qasm3::{Qasm3Builder, Qasm3Circuit};
19//!
20//! let mut builder = Qasm3Builder::new(5);
21//! builder.gate("h", &[0])?;
22//! builder.gate("cx", &[0, 1])?;
23//! builder.measure(0, "c", 0)?;
24//! builder.if_statement("c[0] == 1", |b| {
25//!     b.gate("x", &[1])
26//! })?;
27//!
28//! let qasm3 = builder.build()?;
29//! println!("{}", qasm3.to_string());
30//! ```
31
32use std::collections::HashMap;
33use std::fmt;
34
35use crate::{DeviceError, DeviceResult};
36
37/// OpenQASM 3.0 version
38pub const QASM3_VERSION: &str = "3.0";
39
40/// QASM 3.0 data types
41#[derive(Debug, Clone, PartialEq)]
42pub enum Qasm3Type {
43    /// Quantum bit
44    Qubit,
45    /// Array of quantum bits
46    QubitArray(usize),
47    /// Classical bit
48    Bit,
49    /// Array of classical bits
50    BitArray(usize),
51    /// Integer type
52    Int(Option<usize>),
53    /// Unsigned integer
54    Uint(Option<usize>),
55    /// Floating point
56    Float(Option<usize>),
57    /// Angle type
58    Angle(Option<usize>),
59    /// Boolean
60    Bool,
61    /// Duration type
62    Duration,
63    /// Stretch (timing constraint)
64    Stretch,
65    /// Complex number
66    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/// QASM 3.0 gate modifier
94#[derive(Debug, Clone)]
95pub enum GateModifier {
96    /// Control modifier: ctrl @ gate
97    Ctrl(usize),
98    /// Negated control: negctrl @ gate
99    NegCtrl(usize),
100    /// Inverse modifier: inv @ gate
101    Inv,
102    /// Power modifier: pow(n) @ gate
103    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/// QASM 3.0 statement
120#[derive(Debug, Clone)]
121pub enum Qasm3Statement {
122    /// Include directive
123    Include(String),
124    /// Variable declaration
125    Declaration {
126        var_type: Qasm3Type,
127        name: String,
128        init_value: Option<String>,
129    },
130    /// Gate definition
131    GateDef {
132        name: String,
133        params: Vec<String>,
134        qubits: Vec<String>,
135        body: Vec<Qasm3Statement>,
136    },
137    /// Gate application
138    Gate {
139        name: String,
140        modifiers: Vec<GateModifier>,
141        params: Vec<String>,
142        qubits: Vec<String>,
143    },
144    /// Measurement
145    Measure { qubit: String, classical: String },
146    /// Reset
147    Reset(String),
148    /// Barrier
149    Barrier(Vec<String>),
150    /// If statement
151    If {
152        condition: String,
153        then_body: Vec<Qasm3Statement>,
154        else_body: Option<Vec<Qasm3Statement>>,
155    },
156    /// Switch statement (QASM 3.0 dynamic circuits)
157    Switch {
158        expression: String,
159        cases: Vec<(Vec<i64>, Vec<Qasm3Statement>)>,
160        default_case: Option<Vec<Qasm3Statement>>,
161    },
162    /// While loop
163    While {
164        condition: String,
165        body: Vec<Qasm3Statement>,
166    },
167    /// For loop
168    For {
169        var_name: String,
170        range: String,
171        body: Vec<Qasm3Statement>,
172    },
173    /// Classical assignment
174    Assignment { target: String, value: String },
175    /// Delay
176    Delay {
177        duration: String,
178        qubits: Vec<String>,
179    },
180    /// Box (timing block)
181    Box { body: Vec<Qasm3Statement> },
182    /// Subroutine definition
183    DefCal {
184        name: String,
185        params: Vec<String>,
186        qubits: Vec<String>,
187        body: String,
188    },
189    /// Comment
190    Comment(String),
191    /// Pragma
192    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/// QASM 3.0 circuit representation
359#[derive(Debug, Clone)]
360pub struct Qasm3Circuit {
361    /// Version (always "3.0")
362    pub version: String,
363    /// Statements in the circuit
364    pub statements: Vec<Qasm3Statement>,
365    /// Input parameters
366    pub inputs: HashMap<String, Qasm3Type>,
367    /// Output parameters
368    pub outputs: HashMap<String, Qasm3Type>,
369}
370
371impl Qasm3Circuit {
372    /// Create a new empty QASM 3.0 circuit
373    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    /// Add an input parameter
383    pub fn add_input(&mut self, name: &str, var_type: Qasm3Type) {
384        self.inputs.insert(name.to_string(), var_type);
385    }
386
387    /// Add an output parameter
388    pub fn add_output(&mut self, name: &str, var_type: Qasm3Type) {
389        self.outputs.insert(name.to_string(), var_type);
390    }
391
392    /// Add a statement
393    pub fn add_statement(&mut self, stmt: Qasm3Statement) {
394        self.statements.push(stmt);
395    }
396
397    /// Get the number of qubits used
398    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    /// Convert to QASM 3.0 string
413    pub fn to_qasm3(&self) -> String {
414        self.to_string()
415    }
416
417    /// Convert to QASM 2.0 string (for backward compatibility)
418    pub fn to_qasm2(&self) -> DeviceResult<String> {
419        let mut qasm2 = String::from("OPENQASM 2.0;\ninclude \"qelib1.inc\";\n\n");
420
421        // Find qubit and bit declarations
422        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        // Convert statements
452        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                    // QASM 2.0 only supports simple if statements
492                    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                    // Skip declarations (handled above) and comments
524                }
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        // Include standard library
545        writeln!(f, "include \"stdgates.inc\";")?;
546        writeln!(f)?;
547
548        // Input declarations
549        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        // Output declarations
557        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        // Statements
565        for stmt in &self.statements {
566            write!(f, "{}", stmt)?;
567        }
568
569        Ok(())
570    }
571}
572
573/// Builder for QASM 3.0 circuits
574pub struct Qasm3Builder {
575    /// The circuit being built
576    pub circuit: Qasm3Circuit,
577    /// Number of qubits in the circuit
578    pub num_qubits: usize,
579    /// Number of classical bits in the circuit
580    pub num_bits: usize,
581}
582
583impl Qasm3Builder {
584    /// Create a new builder with specified number of qubits
585    pub fn new(num_qubits: usize) -> Self {
586        let mut builder = Self {
587            circuit: Qasm3Circuit::new(),
588            num_qubits,
589            num_bits: num_qubits, // Default same number of classical bits
590        };
591
592        // Add qubit and bit declarations
593        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    /// Set number of classical bits
608    pub fn with_bits(mut self, num_bits: usize) -> Self {
609        self.num_bits = num_bits;
610        // Update the bit declaration
611        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    /// Add a gate operation
627    pub fn gate(&mut self, name: &str, qubits: &[usize]) -> DeviceResult<&mut Self> {
628        self.gate_with_params(name, &[], qubits)
629    }
630
631    /// Add a gate with parameters
632    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    /// Add a controlled gate
662    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    /// Add an inverse gate
686    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    /// Add measurement
706    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    /// Measure all qubits
723    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    /// Add reset operation
731    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    /// Add barrier
743    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    /// Add if statement (dynamic circuit)
758    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(); // Clear default declarations
768
769        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    /// Add if-else statement (dynamic circuit)
781    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    /// Add while loop
817    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    /// Add for loop
839    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    /// Add switch statement (QASM 3.0 dynamic circuit feature)
862    ///
863    /// # Arguments
864    /// * `expression` - The expression to switch on (e.g., "c")
865    /// * `case_builder` - A closure that builds the switch cases
866    ///
867    /// # Example
868    /// ```ignore
869    /// builder.switch_statement("c", |sw| {
870    ///     sw.case(&[0], |b| b.gate("x", &[0]))?;
871    ///     sw.case(&[1], |b| b.gate("y", &[0]))?;
872    ///     sw.default(|b| b.gate("z", &[0]))?;
873    ///     Ok(())
874    /// })?;
875    /// ```
876    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    /// Add classical assignment
897    ///
898    /// # Arguments
899    /// * `target` - Target variable (e.g., `"c[0]"`)
900    /// * `value` - Value expression (e.g., `"c[0] + 1"`, `"c[0] & c[1]"`)
901    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    /// Add comment
910    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    /// Build the QASM 3.0 circuit
917    pub fn build(self) -> DeviceResult<Qasm3Circuit> {
918        Ok(self.circuit)
919    }
920}
921
922/// Builder for switch statement cases
923pub 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    /// Add a case to the switch statement
941    ///
942    /// # Arguments
943    /// * `values` - The case values (can be multiple for fallthrough)
944    /// * `body` - A closure that builds the case body
945    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    /// Add a default case to the switch statement
964    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
982/// Convert a QuantRS2 circuit to QASM 3.0
983pub 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    // In a complete implementation, this would iterate through the circuit gates
989    // and convert each to QASM 3.0 statements
990
991    // For now, return a placeholder circuit
992    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}