quantrs2_core/
quantum_language_compiler.rs

1//! Quantum Programming Language Compilation Targets
2//!
3//! This module provides compilation from QuantRS2's internal circuit representation
4//! to various quantum programming languages and frameworks.
5//!
6//! ## Supported Target Languages
7//!
8//! - **OpenQASM 2.0/3.0**: IBM's open quantum assembly language
9//! - **Quil**: Rigetti's quantum instruction language
10//! - **Q#**: Microsoft's quantum programming language
11//! - **Cirq**: Google's quantum programming framework (Python)
12//! - **Qiskit**: IBM's quantum development kit (Python)
13//! - **PyQuil**: Rigetti's quantum programming library (Python)
14//! - **ProjectQ**: ETH Zurich's quantum programming framework
15//! - **Braket IR**: AWS Braket's intermediate representation
16//! - **Silq**: ETH Zurich's high-level quantum language
17//!
18//! ## Features
19//!
20//! - Automatic gate decomposition to target gate sets
21//! - Optimization for target platform
22//! - Preserves circuit structure and comments
23//! - Handles classical registers and measurements
24use crate::{
25    error::{QuantRS2Error, QuantRS2Result},
26    gate::GateOp,
27    qubit::QubitId,
28};
29use std::collections::HashMap;
30use std::fmt::Write as FmtWrite;
31
32/// Convert fmt::Error to QuantRS2Error for string formatting operations
33#[inline]
34fn fmt_err(e: std::fmt::Error) -> QuantRS2Error {
35    QuantRS2Error::ComputationError(format!("String formatting error: {e}"))
36}
37/// Supported quantum programming languages
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
39pub enum QuantumLanguage {
40    /// OpenQASM 2.0
41    OpenQASM2,
42    /// OpenQASM 3.0
43    OpenQASM3,
44    /// Rigetti Quil
45    Quil,
46    /// Microsoft Q#
47    QSharp,
48    /// Google Cirq (Python)
49    Cirq,
50    /// IBM Qiskit (Python)
51    Qiskit,
52    /// Rigetti PyQuil (Python)
53    PyQuil,
54    /// ProjectQ (Python)
55    ProjectQ,
56    /// AWS Braket IR (JSON)
57    BraketIR,
58    /// Silq high-level language
59    Silq,
60    /// Pennylane (Python)
61    Pennylane,
62}
63impl QuantumLanguage {
64    /// Get language name
65    pub const fn name(&self) -> &'static str {
66        match self {
67            Self::OpenQASM2 => "OpenQASM 2.0",
68            Self::OpenQASM3 => "OpenQASM 3.0",
69            Self::Quil => "Quil",
70            Self::QSharp => "Q#",
71            Self::Cirq => "Cirq",
72            Self::Qiskit => "Qiskit",
73            Self::PyQuil => "PyQuil",
74            Self::ProjectQ => "ProjectQ",
75            Self::BraketIR => "Braket IR",
76            Self::Silq => "Silq",
77            Self::Pennylane => "Pennylane",
78        }
79    }
80    /// Get file extension
81    pub const fn extension(&self) -> &'static str {
82        match self {
83            Self::OpenQASM2 | Self::OpenQASM3 => "qasm",
84            Self::Quil => "quil",
85            Self::QSharp => "qs",
86            Self::Cirq | Self::Qiskit | Self::PyQuil | Self::ProjectQ | Self::Pennylane => "py",
87            Self::BraketIR => "json",
88            Self::Silq => "slq",
89        }
90    }
91    /// Get supported gate set
92    pub fn supported_gates(&self) -> Vec<&'static str> {
93        match self {
94            Self::OpenQASM2 | Self::OpenQASM3 => {
95                vec![
96                    "x", "y", "z", "h", "s", "sdg", "t", "tdg", "rx", "ry", "rz", "cx", "cy", "cz",
97                    "ch", "swap", "ccx", "cswap",
98                ]
99            }
100            Self::Quil => {
101                vec![
102                    "X", "Y", "Z", "H", "S", "T", "RX", "RY", "RZ", "CNOT", "CZ", "SWAP", "CCNOT",
103                    "CSWAP", "PHASE",
104                ]
105            }
106            Self::QSharp => {
107                vec![
108                    "X", "Y", "Z", "H", "S", "T", "CNOT", "CCNOT", "SWAP", "Rx", "Ry", "Rz", "R1",
109                ]
110            }
111            Self::Cirq => {
112                vec![
113                    "X",
114                    "Y",
115                    "Z",
116                    "H",
117                    "S",
118                    "T",
119                    "CNOT",
120                    "CZ",
121                    "SWAP",
122                    "Rx",
123                    "Ry",
124                    "Rz",
125                    "ISWAP",
126                    "SQRT_ISWAP",
127                ]
128            }
129            Self::Qiskit => {
130                vec![
131                    "x", "y", "z", "h", "s", "sdg", "t", "tdg", "rx", "ry", "rz", "cx", "cy", "cz",
132                    "ch", "swap", "ccx",
133                ]
134            }
135            Self::PyQuil => {
136                vec![
137                    "X", "Y", "Z", "H", "S", "T", "RX", "RY", "RZ", "CNOT", "CZ", "SWAP", "PHASE",
138                ]
139            }
140            Self::ProjectQ => {
141                vec![
142                    "X", "Y", "Z", "H", "S", "T", "Rx", "Ry", "Rz", "CNOT", "Swap",
143                ]
144            }
145            Self::BraketIR => {
146                vec![
147                    "x", "y", "z", "h", "s", "si", "t", "ti", "rx", "ry", "rz", "cnot", "cy", "cz",
148                    "swap", "iswap",
149                ]
150            }
151            Self::Silq => vec!["X", "Y", "Z", "H", "S", "T", "CNOT", "phase"],
152            Self::Pennylane => {
153                vec![
154                    "PauliX", "PauliY", "PauliZ", "Hadamard", "S", "T", "RX", "RY", "RZ", "CNOT",
155                    "CZ", "SWAP",
156                ]
157            }
158        }
159    }
160}
161/// Quantum circuit for compilation
162#[derive(Debug, Clone)]
163pub struct CompilableCircuit {
164    /// Number of qubits
165    pub num_qubits: usize,
166    /// Number of classical bits
167    pub num_cbits: usize,
168    /// Circuit gates
169    pub gates: Vec<GateInstruction>,
170    /// Measurements
171    pub measurements: Vec<(usize, usize)>,
172}
173/// Gate instruction in the circuit
174#[derive(Debug, Clone)]
175pub struct GateInstruction {
176    /// Gate name
177    pub name: String,
178    /// Parameters (angles, etc.)
179    pub params: Vec<f64>,
180    /// Target qubits
181    pub qubits: Vec<usize>,
182    /// Control qubits (if controlled gate)
183    pub controls: Vec<usize>,
184}
185impl CompilableCircuit {
186    /// Create a new compilable circuit
187    pub const fn new(num_qubits: usize, num_cbits: usize) -> Self {
188        Self {
189            num_qubits,
190            num_cbits,
191            gates: Vec::new(),
192            measurements: Vec::new(),
193        }
194    }
195    /// Add a gate instruction
196    pub fn add_gate(&mut self, instruction: GateInstruction) {
197        self.gates.push(instruction);
198    }
199    /// Add measurement
200    pub fn add_measurement(&mut self, qubit: usize, cbit: usize) {
201        self.measurements.push((qubit, cbit));
202    }
203    /// Measure all qubits
204    #[must_use]
205    pub fn measure_all(&mut self) {
206        for i in 0..self.num_qubits.min(self.num_cbits) {
207            self.measurements.push((i, i));
208        }
209    }
210}
211/// Compiler for quantum programming languages
212pub struct QuantumLanguageCompiler {
213    target_language: QuantumLanguage,
214    optimize: bool,
215    include_comments: bool,
216}
217impl QuantumLanguageCompiler {
218    /// Create a new compiler
219    pub const fn new(target_language: QuantumLanguage) -> Self {
220        Self {
221            target_language,
222            optimize: true,
223            include_comments: true,
224        }
225    }
226    /// Enable/disable optimization
227    #[must_use]
228    pub const fn with_optimization(mut self, optimize: bool) -> Self {
229        self.optimize = optimize;
230        self
231    }
232    /// Enable/disable comments
233    #[must_use]
234    pub const fn with_comments(mut self, include_comments: bool) -> Self {
235        self.include_comments = include_comments;
236        self
237    }
238    /// Compile circuit to target language
239    pub fn compile(&self, circuit: &CompilableCircuit) -> QuantRS2Result<String> {
240        match self.target_language {
241            QuantumLanguage::OpenQASM2 => Self::compile_to_openqasm2(circuit),
242            QuantumLanguage::OpenQASM3 => Self::compile_to_openqasm3(circuit),
243            QuantumLanguage::Quil => Self::compile_to_quil(circuit),
244            QuantumLanguage::QSharp => Self::compile_to_qsharp(circuit),
245            QuantumLanguage::Cirq => Self::compile_to_cirq(circuit),
246            QuantumLanguage::Qiskit => Self::compile_to_qiskit(circuit),
247            QuantumLanguage::PyQuil => Self::compile_to_pyquil(circuit),
248            QuantumLanguage::ProjectQ => Self::compile_to_projectq(circuit),
249            QuantumLanguage::BraketIR => Self::compile_to_braket_ir(circuit),
250            QuantumLanguage::Silq => Self::compile_to_silq(circuit),
251            QuantumLanguage::Pennylane => Self::compile_to_pennylane(circuit),
252        }
253    }
254    /// Compile to OpenQASM 2.0
255    fn compile_to_openqasm2(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
256        let mut output = String::new();
257        writeln!(output, "OPENQASM 2.0;").map_err(fmt_err)?;
258        writeln!(output, "include \"qelib1.inc\";").map_err(fmt_err)?;
259        writeln!(output).map_err(fmt_err)?;
260        writeln!(output, "qreg q[{}];", circuit.num_qubits).map_err(fmt_err)?;
261        if circuit.num_cbits > 0 {
262            writeln!(output, "creg c[{}];", circuit.num_cbits).map_err(fmt_err)?;
263        }
264        writeln!(output).map_err(fmt_err)?;
265        for gate in &circuit.gates {
266            let qubit0 = gate.qubits.first().ok_or_else(|| {
267                QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
268            })?;
269            match gate.name.as_str() {
270                "H" | "h" => {
271                    writeln!(output, "h q[{qubit0}];").map_err(fmt_err)?;
272                }
273                "X" | "x" => {
274                    writeln!(output, "x q[{qubit0}];").map_err(fmt_err)?;
275                }
276                "Y" | "y" => {
277                    writeln!(output, "y q[{qubit0}];").map_err(fmt_err)?;
278                }
279                "Z" | "z" => {
280                    writeln!(output, "z q[{qubit0}];").map_err(fmt_err)?;
281                }
282                "S" | "s" => {
283                    writeln!(output, "s q[{qubit0}];").map_err(fmt_err)?;
284                }
285                "T" | "t" => {
286                    writeln!(output, "t q[{qubit0}];").map_err(fmt_err)?;
287                }
288                "RX" | "rx" => {
289                    let param = gate.params.first().ok_or_else(|| {
290                        QuantRS2Error::InvalidInput("RX gate missing angle parameter".to_string())
291                    })?;
292                    writeln!(output, "rx({param}) q[{qubit0}];").map_err(fmt_err)?;
293                }
294                "RY" | "ry" => {
295                    let param = gate.params.first().ok_or_else(|| {
296                        QuantRS2Error::InvalidInput("RY gate missing angle parameter".to_string())
297                    })?;
298                    writeln!(output, "ry({param}) q[{qubit0}];").map_err(fmt_err)?;
299                }
300                "RZ" | "rz" => {
301                    let param = gate.params.first().ok_or_else(|| {
302                        QuantRS2Error::InvalidInput("RZ gate missing angle parameter".to_string())
303                    })?;
304                    writeln!(output, "rz({param}) q[{qubit0}];").map_err(fmt_err)?;
305                }
306                "CNOT" | "cx" => {
307                    let qubit1 = gate.qubits.get(1).ok_or_else(|| {
308                        QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
309                    })?;
310                    writeln!(output, "cx q[{qubit0}], q[{qubit1}];").map_err(fmt_err)?;
311                }
312                "CZ" | "cz" => {
313                    let qubit1 = gate.qubits.get(1).ok_or_else(|| {
314                        QuantRS2Error::InvalidInput("CZ gate missing second qubit".to_string())
315                    })?;
316                    writeln!(output, "cz q[{qubit0}], q[{qubit1}];").map_err(fmt_err)?;
317                }
318                "SWAP" | "swap" => {
319                    let qubit1 = gate.qubits.get(1).ok_or_else(|| {
320                        QuantRS2Error::InvalidInput("SWAP gate missing second qubit".to_string())
321                    })?;
322                    writeln!(output, "swap q[{qubit0}], q[{qubit1}];").map_err(fmt_err)?;
323                }
324                _ => {
325                    return Err(QuantRS2Error::UnsupportedOperation(format!(
326                        "Gate {} not supported in OpenQASM 2.0",
327                        gate.name
328                    )));
329                }
330            }
331        }
332        if !circuit.measurements.is_empty() {
333            writeln!(output).map_err(fmt_err)?;
334            for (qubit, cbit) in &circuit.measurements {
335                writeln!(output, "measure q[{qubit}] -> c[{cbit}];").map_err(fmt_err)?;
336            }
337        }
338        Ok(output)
339    }
340    /// Compile to OpenQASM 3.0
341    fn compile_to_openqasm3(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
342        let mut output = String::new();
343        writeln!(output, "OPENQASM 3.0;").map_err(fmt_err)?;
344        writeln!(output, "include \"stdgates.inc\";").map_err(fmt_err)?;
345        writeln!(output).map_err(fmt_err)?;
346        writeln!(output, "qubit[{}] q;", circuit.num_qubits).map_err(fmt_err)?;
347        if circuit.num_cbits > 0 {
348            writeln!(output, "bit[{}] c;", circuit.num_cbits).map_err(fmt_err)?;
349        }
350        writeln!(output).map_err(fmt_err)?;
351        for gate in &circuit.gates {
352            let qubit0 = gate.qubits.first().ok_or_else(|| {
353                QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
354            })?;
355            match gate.name.as_str() {
356                "H" | "h" => writeln!(output, "h q[{qubit0}];").map_err(fmt_err)?,
357                "X" | "x" => writeln!(output, "x q[{qubit0}];").map_err(fmt_err)?,
358                "CNOT" | "cx" => {
359                    let qubit1 = gate.qubits.get(1).ok_or_else(|| {
360                        QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
361                    })?;
362                    writeln!(output, "cx q[{qubit0}], q[{qubit1}];").map_err(fmt_err)?;
363                }
364                _ => {}
365            }
366        }
367        for (qubit, cbit) in &circuit.measurements {
368            writeln!(output, "c[{cbit}] = measure q[{qubit}];").map_err(fmt_err)?;
369        }
370        Ok(output)
371    }
372    /// Compile to Quil
373    fn compile_to_quil(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
374        let mut output = String::new();
375        if circuit.num_cbits > 0 {
376            writeln!(output, "DECLARE ro BIT[{}]", circuit.num_cbits).map_err(fmt_err)?;
377            writeln!(output).map_err(fmt_err)?;
378        }
379        for gate in &circuit.gates {
380            let qubit0 = gate.qubits.first().ok_or_else(|| {
381                QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
382            })?;
383            match gate.name.as_str() {
384                "H" | "h" => writeln!(output, "H {qubit0}").map_err(fmt_err)?,
385                "X" | "x" => writeln!(output, "X {qubit0}").map_err(fmt_err)?,
386                "Y" | "y" => writeln!(output, "Y {qubit0}").map_err(fmt_err)?,
387                "Z" | "z" => writeln!(output, "Z {qubit0}").map_err(fmt_err)?,
388                "RX" | "rx" => {
389                    let param = gate.params.first().ok_or_else(|| {
390                        QuantRS2Error::InvalidInput("RX gate missing angle parameter".to_string())
391                    })?;
392                    writeln!(output, "RX({param}) {qubit0}").map_err(fmt_err)?;
393                }
394                "RY" | "ry" => {
395                    let param = gate.params.first().ok_or_else(|| {
396                        QuantRS2Error::InvalidInput("RY gate missing angle parameter".to_string())
397                    })?;
398                    writeln!(output, "RY({param}) {qubit0}").map_err(fmt_err)?;
399                }
400                "RZ" | "rz" => {
401                    let param = gate.params.first().ok_or_else(|| {
402                        QuantRS2Error::InvalidInput("RZ gate missing angle parameter".to_string())
403                    })?;
404                    writeln!(output, "RZ({param}) {qubit0}").map_err(fmt_err)?;
405                }
406                "CNOT" | "cx" => {
407                    let qubit1 = gate.qubits.get(1).ok_or_else(|| {
408                        QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
409                    })?;
410                    writeln!(output, "CNOT {qubit0} {qubit1}").map_err(fmt_err)?;
411                }
412                "CZ" | "cz" => {
413                    let qubit1 = gate.qubits.get(1).ok_or_else(|| {
414                        QuantRS2Error::InvalidInput("CZ gate missing second qubit".to_string())
415                    })?;
416                    writeln!(output, "CZ {qubit0} {qubit1}").map_err(fmt_err)?;
417                }
418                _ => {}
419            }
420        }
421        for (qubit, cbit) in &circuit.measurements {
422            writeln!(output, "MEASURE {qubit} ro[{cbit}]").map_err(fmt_err)?;
423        }
424        Ok(output)
425    }
426    /// Compile to Q#
427    fn compile_to_qsharp(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
428        let mut output = String::new();
429        writeln!(output, "namespace QuantumCircuit {{").map_err(fmt_err)?;
430        writeln!(output, "    open Microsoft.Quantum.Canon;").map_err(fmt_err)?;
431        writeln!(output, "    open Microsoft.Quantum.Intrinsic;").map_err(fmt_err)?;
432        writeln!(output).map_err(fmt_err)?;
433        writeln!(output, "    operation RunCircuit() : Result[] {{").map_err(fmt_err)?;
434        writeln!(
435            output,
436            "        use qubits = Qubit[{}];",
437            circuit.num_qubits
438        )
439        .map_err(fmt_err)?;
440        writeln!(output).map_err(fmt_err)?;
441        for gate in &circuit.gates {
442            let qubit0 = gate.qubits.first().ok_or_else(|| {
443                QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
444            })?;
445            match gate.name.as_str() {
446                "H" | "h" => {
447                    writeln!(output, "        H(qubits[{qubit0}]);").map_err(fmt_err)?;
448                }
449                "X" | "x" => {
450                    writeln!(output, "        X(qubits[{qubit0}]);").map_err(fmt_err)?;
451                }
452                "Y" | "y" => {
453                    writeln!(output, "        Y(qubits[{qubit0}]);").map_err(fmt_err)?;
454                }
455                "Z" | "z" => {
456                    writeln!(output, "        Z(qubits[{qubit0}]);").map_err(fmt_err)?;
457                }
458                "CNOT" | "cx" => {
459                    let qubit1 = gate.qubits.get(1).ok_or_else(|| {
460                        QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
461                    })?;
462                    writeln!(output, "        CNOT(qubits[{qubit0}], qubits[{qubit1}]);")
463                        .map_err(fmt_err)?;
464                }
465                _ => {}
466            }
467        }
468        writeln!(output).map_err(fmt_err)?;
469        writeln!(output, "        let results = ForEach(M, qubits);").map_err(fmt_err)?;
470        writeln!(output, "        ResetAll(qubits);").map_err(fmt_err)?;
471        writeln!(output, "        return results;").map_err(fmt_err)?;
472        writeln!(output, "    }}").map_err(fmt_err)?;
473        writeln!(output, "}}").map_err(fmt_err)?;
474        Ok(output)
475    }
476    /// Compile to Cirq (Python)
477    fn compile_to_cirq(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
478        let mut output = String::new();
479        writeln!(output, "import cirq").map_err(fmt_err)?;
480        writeln!(output).map_err(fmt_err)?;
481        writeln!(output, "# Create qubits").map_err(fmt_err)?;
482        writeln!(
483            output,
484            "qubits = [cirq.LineQubit(i) for i in range({})]",
485            circuit.num_qubits
486        )
487        .map_err(fmt_err)?;
488        writeln!(output).map_err(fmt_err)?;
489        writeln!(output, "# Create circuit").map_err(fmt_err)?;
490        writeln!(output, "circuit = cirq.Circuit()").map_err(fmt_err)?;
491        writeln!(output).map_err(fmt_err)?;
492        for gate in &circuit.gates {
493            let qubit0 = gate.qubits.first().ok_or_else(|| {
494                QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
495            })?;
496            match gate.name.as_str() {
497                "H" | "h" => {
498                    writeln!(output, "circuit.append(cirq.H(qubits[{qubit0}]))")
499                        .map_err(fmt_err)?;
500                }
501                "X" | "x" => {
502                    writeln!(output, "circuit.append(cirq.X(qubits[{qubit0}]))")
503                        .map_err(fmt_err)?;
504                }
505                "Y" | "y" => {
506                    writeln!(output, "circuit.append(cirq.Y(qubits[{qubit0}]))")
507                        .map_err(fmt_err)?;
508                }
509                "Z" | "z" => {
510                    writeln!(output, "circuit.append(cirq.Z(qubits[{qubit0}]))")
511                        .map_err(fmt_err)?;
512                }
513                "CNOT" | "cx" => {
514                    let qubit1 = gate.qubits.get(1).ok_or_else(|| {
515                        QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
516                    })?;
517                    writeln!(
518                        output,
519                        "circuit.append(cirq.CNOT(qubits[{qubit0}], qubits[{qubit1}]))"
520                    )
521                    .map_err(fmt_err)?;
522                }
523                "RX" | "rx" => {
524                    let param = gate.params.first().ok_or_else(|| {
525                        QuantRS2Error::InvalidInput("RX gate missing angle parameter".to_string())
526                    })?;
527                    writeln!(
528                        output,
529                        "circuit.append(cirq.rx({param}).on(qubits[{qubit0}]))"
530                    )
531                    .map_err(fmt_err)?;
532                }
533                "RY" | "ry" => {
534                    let param = gate.params.first().ok_or_else(|| {
535                        QuantRS2Error::InvalidInput("RY gate missing angle parameter".to_string())
536                    })?;
537                    writeln!(
538                        output,
539                        "circuit.append(cirq.ry({param}).on(qubits[{qubit0}]))"
540                    )
541                    .map_err(fmt_err)?;
542                }
543                "RZ" | "rz" => {
544                    let param = gate.params.first().ok_or_else(|| {
545                        QuantRS2Error::InvalidInput("RZ gate missing angle parameter".to_string())
546                    })?;
547                    writeln!(
548                        output,
549                        "circuit.append(cirq.rz({param}).on(qubits[{qubit0}]))"
550                    )
551                    .map_err(fmt_err)?;
552                }
553                _ => {}
554            }
555        }
556        if !circuit.measurements.is_empty() {
557            writeln!(output).map_err(fmt_err)?;
558            write!(output, "circuit.append(cirq.measure(").map_err(fmt_err)?;
559            for (i, (qubit, _)) in circuit.measurements.iter().enumerate() {
560                if i > 0 {
561                    write!(output, ", ").map_err(fmt_err)?;
562                }
563                write!(output, "qubits[{qubit}]").map_err(fmt_err)?;
564            }
565            writeln!(output, ", key='result'))").map_err(fmt_err)?;
566        }
567        writeln!(output).map_err(fmt_err)?;
568        writeln!(output, "print(circuit)").map_err(fmt_err)?;
569        Ok(output)
570    }
571    /// Compile to Qiskit (Python)
572    fn compile_to_qiskit(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
573        let mut output = String::new();
574        writeln!(
575            output,
576            "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister"
577        )
578        .map_err(fmt_err)?;
579        writeln!(output).map_err(fmt_err)?;
580        writeln!(output, "# Create registers").map_err(fmt_err)?;
581        writeln!(
582            output,
583            "qreg = QuantumRegister({}, 'q'))",
584            circuit.num_qubits
585        )
586        .map_err(fmt_err)?;
587        if circuit.num_cbits > 0 {
588            writeln!(
589                output,
590                "creg = ClassicalRegister({}, 'c')",
591                circuit.num_cbits
592            )
593            .map_err(fmt_err)?;
594            writeln!(output, "circuit = QuantumCircuit(qreg, creg)").map_err(fmt_err)?;
595        } else {
596            writeln!(output, "circuit = QuantumCircuit(qreg)").map_err(fmt_err)?;
597        }
598        writeln!(output).map_err(fmt_err)?;
599        for gate in &circuit.gates {
600            let qubit0 = gate.qubits.first().ok_or_else(|| {
601                QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
602            })?;
603            match gate.name.as_str() {
604                "H" | "h" => writeln!(output, "circuit.h({qubit0})").map_err(fmt_err)?,
605                "X" | "x" => writeln!(output, "circuit.x({qubit0})").map_err(fmt_err)?,
606                "CNOT" | "cx" => {
607                    let qubit1 = gate.qubits.get(1).ok_or_else(|| {
608                        QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
609                    })?;
610                    writeln!(output, "circuit.cx({qubit0}, {qubit1})").map_err(fmt_err)?;
611                }
612                _ => {}
613            }
614        }
615        for (qubit, cbit) in &circuit.measurements {
616            writeln!(output, "circuit.measure({qubit}, {cbit})").map_err(fmt_err)?;
617        }
618        writeln!(output).map_err(fmt_err)?;
619        writeln!(output, "print(circuit)").map_err(fmt_err)?;
620        Ok(output)
621    }
622    /// Compile to PyQuil
623    fn compile_to_pyquil(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
624        let mut output = String::new();
625        writeln!(output, "from pyquil import Program").map_err(fmt_err)?;
626        writeln!(output, "from pyquil.gates import *").map_err(fmt_err)?;
627        writeln!(output).map_err(fmt_err)?;
628        writeln!(output, "program = Program()").map_err(fmt_err)?;
629        writeln!(output).map_err(fmt_err)?;
630        for gate in &circuit.gates {
631            let qubit0 = gate.qubits.first().ok_or_else(|| {
632                QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
633            })?;
634            match gate.name.as_str() {
635                "H" | "h" => writeln!(output, "program += H({qubit0})").map_err(fmt_err)?,
636                "X" | "x" => writeln!(output, "program += X({qubit0})").map_err(fmt_err)?,
637                "CNOT" | "cx" => {
638                    let qubit1 = gate.qubits.get(1).ok_or_else(|| {
639                        QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
640                    })?;
641                    writeln!(output, "program += CNOT({qubit0}, {qubit1})").map_err(fmt_err)?;
642                }
643                _ => {}
644            }
645        }
646        Ok(output)
647    }
648    /// Compile to ProjectQ
649    fn compile_to_projectq(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
650        let mut output = String::new();
651        writeln!(output, "from projectq import MainEngine").map_err(fmt_err)?;
652        writeln!(output, "from projectq.ops import *").map_err(fmt_err)?;
653        writeln!(output).map_err(fmt_err)?;
654        writeln!(output, "eng = MainEngine()").map_err(fmt_err)?;
655        writeln!(
656            output,
657            "qubits = eng.allocate_qureg({}))",
658            circuit.num_qubits
659        )
660        .map_err(fmt_err)?;
661        writeln!(output).map_err(fmt_err)?;
662        for gate in &circuit.gates {
663            let qubit0 = gate.qubits.first().ok_or_else(|| {
664                QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
665            })?;
666            match gate.name.as_str() {
667                "H" | "h" => writeln!(output, "H | qubits[{qubit0}]").map_err(fmt_err)?,
668                "X" | "x" => writeln!(output, "X | qubits[{qubit0}]").map_err(fmt_err)?,
669                "CNOT" | "cx" => {
670                    let qubit1 = gate.qubits.get(1).ok_or_else(|| {
671                        QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
672                    })?;
673                    writeln!(output, "CNOT | (qubits[{qubit0}], qubits[{qubit1}])")
674                        .map_err(fmt_err)?;
675                }
676                _ => {}
677            }
678        }
679        Ok(output)
680    }
681    /// Compile to Braket IR (JSON)
682    fn compile_to_braket_ir(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
683        let mut output = String::new();
684        writeln!(output, "{{").map_err(fmt_err)?;
685        writeln!(output, "  \"braketSchemaHeader\": {{").map_err(fmt_err)?;
686        writeln!(output, "    \"name\": \"braket.ir.jaqcd.program\",").map_err(fmt_err)?;
687        writeln!(output, "    \"version\": \"1\"").map_err(fmt_err)?;
688        writeln!(output, "  }},").map_err(fmt_err)?;
689        writeln!(output, "  \"instructions\": [").map_err(fmt_err)?;
690        for (i, gate) in circuit.gates.iter().enumerate() {
691            if i > 0 {
692                writeln!(output, ",").map_err(fmt_err)?;
693            }
694            let qubit0 = gate.qubits.first().ok_or_else(|| {
695                QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
696            })?;
697            write!(output, "    {{").map_err(fmt_err)?;
698            match gate.name.as_str() {
699                "H" | "h" => {
700                    write!(output, "\"type\": \"h\", \"target\": {qubit0}").map_err(fmt_err)?;
701                }
702                "X" | "x" => {
703                    write!(output, "\"type\": \"x\", \"target\": {qubit0}").map_err(fmt_err)?;
704                }
705                "CNOT" | "cx" => {
706                    let qubit1 = gate.qubits.get(1).ok_or_else(|| {
707                        QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
708                    })?;
709                    write!(
710                        output,
711                        "\"type\": \"cnot\", \"control\": {qubit0}, \"target\": {qubit1}"
712                    )
713                    .map_err(fmt_err)?;
714                }
715                _ => {}
716            }
717            write!(output, "}}").map_err(fmt_err)?;
718        }
719        writeln!(output).map_err(fmt_err)?;
720        writeln!(output, "  ]").map_err(fmt_err)?;
721        writeln!(output, "}}").map_err(fmt_err)?;
722        Ok(output)
723    }
724    /// Compile to Silq
725    fn compile_to_silq(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
726        let mut output = String::new();
727        writeln!(output, "def circuit() {{").map_err(fmt_err)?;
728        writeln!(output, "  // Allocate qubits").map_err(fmt_err)?;
729        writeln!(output, "  q := 0:^{};", circuit.num_qubits).map_err(fmt_err)?;
730        writeln!(output).map_err(fmt_err)?;
731        for gate in &circuit.gates {
732            let qubit0 = gate.qubits.first().ok_or_else(|| {
733                QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
734            })?;
735            match gate.name.as_str() {
736                "H" | "h" => {
737                    writeln!(output, "  q[{qubit0}] := H(q[{qubit0}]);").map_err(fmt_err)?;
738                }
739                "X" | "x" => {
740                    writeln!(output, "  q[{qubit0}] := X(q[{qubit0}]);").map_err(fmt_err)?;
741                }
742                _ => {}
743            }
744        }
745        writeln!(output, "  return q;").map_err(fmt_err)?;
746        writeln!(output, "}}").map_err(fmt_err)?;
747        Ok(output)
748    }
749    /// Compile to Pennylane
750    fn compile_to_pennylane(circuit: &CompilableCircuit) -> QuantRS2Result<String> {
751        let mut output = String::new();
752        writeln!(output, "import pennylane as qml").map_err(fmt_err)?;
753        writeln!(output).map_err(fmt_err)?;
754        writeln!(
755            output,
756            "dev = qml.device('default.qubit', wires={})",
757            circuit.num_qubits
758        )
759        .map_err(fmt_err)?;
760        writeln!(output).map_err(fmt_err)?;
761        writeln!(output, "@qml.qnode(dev)").map_err(fmt_err)?;
762        writeln!(output, "def circuit():").map_err(fmt_err)?;
763        for gate in &circuit.gates {
764            let qubit0 = gate.qubits.first().ok_or_else(|| {
765                QuantRS2Error::InvalidInput("Gate missing target qubit".to_string())
766            })?;
767            match gate.name.as_str() {
768                "H" | "h" => {
769                    writeln!(output, "    qml.Hadamard(wires={qubit0})").map_err(fmt_err)?;
770                }
771                "X" | "x" => {
772                    writeln!(output, "    qml.PauliX(wires={qubit0})").map_err(fmt_err)?;
773                }
774                "CNOT" | "cx" => {
775                    let qubit1 = gate.qubits.get(1).ok_or_else(|| {
776                        QuantRS2Error::InvalidInput("CNOT gate missing second qubit".to_string())
777                    })?;
778                    writeln!(output, "    qml.CNOT(wires=[{qubit0}, {qubit1}])")
779                        .map_err(fmt_err)?;
780                }
781                _ => {}
782            }
783        }
784        writeln!(
785            output,
786            "    return qml.probs(wires=range({}))",
787            circuit.num_qubits
788        )
789        .map_err(fmt_err)?;
790        Ok(output)
791    }
792}
793#[cfg(test)]
794mod tests {
795    use super::*;
796    #[test]
797    fn test_openqasm2_compilation() {
798        let mut circuit = CompilableCircuit::new(2, 2);
799        circuit.add_gate(GateInstruction {
800            name: "H".to_string(),
801            params: vec![],
802            qubits: vec![0],
803            controls: vec![],
804        });
805        circuit.add_gate(GateInstruction {
806            name: "CNOT".to_string(),
807            params: vec![],
808            qubits: vec![0, 1],
809            controls: vec![],
810        });
811        circuit.add_measurement(0, 0);
812        circuit.add_measurement(1, 1);
813        let compiler = QuantumLanguageCompiler::new(QuantumLanguage::OpenQASM2);
814        let result = compiler
815            .compile(&circuit)
816            .expect("OpenQASM 2.0 compilation should succeed");
817        assert!(result.contains("OPENQASM 2.0"));
818        assert!(result.contains("h q[0]"));
819        assert!(result.contains("cx q[0], q[1]"));
820        assert!(result.contains("measure q[0] -> c[0]"));
821    }
822    #[test]
823    fn test_quil_compilation() {
824        let mut circuit = CompilableCircuit::new(1, 1);
825        circuit.add_gate(GateInstruction {
826            name: "H".to_string(),
827            params: vec![],
828            qubits: vec![0],
829            controls: vec![],
830        });
831        let compiler = QuantumLanguageCompiler::new(QuantumLanguage::Quil);
832        let result = compiler
833            .compile(&circuit)
834            .expect("Quil compilation should succeed");
835        assert!(result.contains("H 0"));
836    }
837}