lift-export 0.2.0

LIFT-EXPORT: Backends — LLVM IR, OpenQASM 3, CUDA PTX (planned), XLA (planned)
Documentation
use lift_core::context::Context;
use lift_quantum::gates::QuantumGate;
use thiserror::Error;
use std::fmt::Write;

#[derive(Debug, Error)]
pub enum QasmExportError {
    #[error("Unsupported gate for QASM export: {0}")]
    UnsupportedGate(String),
    #[error("Export error: {0}")]
    General(String),
}

#[derive(Debug)]
pub struct QasmExporter;

impl QasmExporter {
    pub fn new() -> Self { Self }

    pub fn export(&self, ctx: &Context) -> Result<String, QasmExportError> {
        let mut output = String::new();

        let _ = writeln!(output, "OPENQASM 3.0;");
        let _ = writeln!(output, "// Generated by LIFT framework");
        let _ = writeln!(output);

        // Count qubits needed
        let mut max_qubits = 0usize;
        for (_val_key, val) in &ctx.values {
            if ctx.is_qubit_type(val.ty) {
                max_qubits += 1;
            }
        }

        // Estimate unique qubits from block args
        let mut qubit_args = 0;
        for (_block_key, block) in &ctx.blocks {
            for &arg in &block.args {
                if let Some(val) = ctx.get_value(arg) {
                    if ctx.is_qubit_type(val.ty) {
                        qubit_args += 1;
                    }
                }
            }
        }
        let num_qubits = if qubit_args > 0 { qubit_args } else { max_qubits.max(1) };

        let _ = writeln!(output, "qubit[{}] q;", num_qubits);
        let _ = writeln!(output, "bit[{}] c;", num_qubits);
        let _ = writeln!(output);

        // Export gate operations
        let mut qubit_counter = 0usize;
        for (_op_key, op) in &ctx.ops {
            let op_name = ctx.strings.resolve(op.name).to_string();

            if let Some(gate) = QuantumGate::from_name(&op_name) {
                match gate {
                    QuantumGate::H => {
                        let _ = writeln!(output, "h q[{}];", qubit_counter % num_qubits);
                    }
                    QuantumGate::X => {
                        let _ = writeln!(output, "x q[{}];", qubit_counter % num_qubits);
                    }
                    QuantumGate::Y => {
                        let _ = writeln!(output, "y q[{}];", qubit_counter % num_qubits);
                    }
                    QuantumGate::Z => {
                        let _ = writeln!(output, "z q[{}];", qubit_counter % num_qubits);
                    }
                    QuantumGate::CX => {
                        let q0 = qubit_counter % num_qubits;
                        let q1 = (qubit_counter + 1) % num_qubits;
                        let _ = writeln!(output, "cx q[{}], q[{}];", q0, q1);
                    }
                    QuantumGate::CZ => {
                        let q0 = qubit_counter % num_qubits;
                        let q1 = (qubit_counter + 1) % num_qubits;
                        let _ = writeln!(output, "cz q[{}], q[{}];", q0, q1);
                    }
                    QuantumGate::Measure => {
                        let q = qubit_counter % num_qubits;
                        let _ = writeln!(output, "c[{}] = measure q[{}];", q, q);
                    }
                    QuantumGate::RZ => {
                        let angle = op.attrs.get_float("angle").unwrap_or(0.0);
                        let _ = writeln!(output, "rz({}) q[{}];", angle, qubit_counter % num_qubits);
                    }
                    QuantumGate::RX => {
                        let angle = op.attrs.get_float("angle").unwrap_or(0.0);
                        let _ = writeln!(output, "rx({}) q[{}];", angle, qubit_counter % num_qubits);
                    }
                    QuantumGate::RY => {
                        let angle = op.attrs.get_float("angle").unwrap_or(0.0);
                        let _ = writeln!(output, "ry({}) q[{}];", angle, qubit_counter % num_qubits);
                    }
                    _ => {
                        let _ = writeln!(output, "// unsupported gate: {}", op_name);
                    }
                }
                qubit_counter += 1;
            }
        }

        Ok(output)
    }
}

impl Default for QasmExporter {
    fn default() -> Self { Self::new() }
}