use std::collections::HashMap;
use std::fmt;
#[derive(Debug, Clone, PartialEq)]
pub struct QasmProgram {
pub version: String,
pub includes: Vec<String>,
pub declarations: Vec<Declaration>,
pub statements: Vec<QasmStatement>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Declaration {
QuantumRegister(QasmRegister),
ClassicalRegister(QasmRegister),
GateDefinition(GateDefinition),
Constant(String, Expression),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QasmRegister {
pub name: String,
pub size: usize,
}
#[derive(Debug, Clone, PartialEq)]
pub struct GateDefinition {
pub name: String,
pub params: Vec<String>,
pub qubits: Vec<String>,
pub body: Vec<QasmStatement>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum QasmStatement {
Gate(QasmGate),
Measure(Measurement),
Reset(Vec<QubitRef>),
Barrier(Vec<QubitRef>),
Assignment(String, Expression),
If(Condition, Box<Self>),
For(ForLoop),
While(Condition, Vec<Self>),
Call(String, Vec<Expression>),
Delay(Expression, Vec<QubitRef>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct QasmGate {
pub name: String,
pub params: Vec<Expression>,
pub qubits: Vec<QubitRef>,
pub control: Option<usize>,
pub inverse: bool,
pub power: Option<Expression>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum QubitRef {
Single { register: String, index: usize },
Slice {
register: String,
start: usize,
end: usize,
},
Register(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Measurement {
pub qubits: Vec<QubitRef>,
pub targets: Vec<ClassicalRef>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ClassicalRef {
Single { register: String, index: usize },
Slice {
register: String,
start: usize,
end: usize,
},
Register(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
Literal(Literal),
Variable(String),
Binary(BinaryOp, Box<Self>, Box<Self>),
Unary(UnaryOp, Box<Self>),
Function(String, Vec<Self>),
Index(String, Box<Self>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum Literal {
Integer(i64),
Float(f64),
Bool(bool),
String(String),
Pi,
Euler,
Tau,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
Add,
Sub,
Mul,
Div,
Mod,
Pow,
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
And,
Or,
Xor,
BitAnd,
BitOr,
BitXor,
Shl,
Shr,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
Neg,
Not,
BitNot,
Sin,
Cos,
Tan,
Asin,
Acos,
Atan,
Exp,
Ln,
Sqrt,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Condition {
pub left: Expression,
pub op: ComparisonOp,
pub right: Expression,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ComparisonOp {
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ForLoop {
pub variable: String,
pub start: Expression,
pub end: Expression,
pub step: Option<Expression>,
pub body: Vec<QasmStatement>,
}
impl fmt::Display for QasmProgram {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "OPENQASM {};", self.version)?;
for include in &self.includes {
writeln!(f, "include \"{include}\";")?;
}
if !self.includes.is_empty() {
writeln!(f)?;
}
for decl in &self.declarations {
writeln!(f, "{decl}")?;
}
if !self.declarations.is_empty() {
writeln!(f)?;
}
for stmt in &self.statements {
writeln!(f, "{stmt}")?;
}
Ok(())
}
}
impl fmt::Display for Declaration {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::QuantumRegister(reg) => write!(f, "qubit[{}] {};", reg.size, reg.name),
Self::ClassicalRegister(reg) => write!(f, "bit[{}] {};", reg.size, reg.name),
Self::GateDefinition(def) => {
write!(f, "gate {}", def.name)?;
if !def.params.is_empty() {
write!(f, "({})", def.params.join(", "))?;
}
write!(f, " {}", def.qubits.join(", "))?;
writeln!(f, " {{")?;
for stmt in &def.body {
writeln!(f, " {stmt}")?;
}
write!(f, "}}")
}
Self::Constant(name, expr) => write!(f, "const {name} = {expr};"),
}
}
}
impl fmt::Display for QasmStatement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Gate(gate) => write!(f, "{gate}"),
Self::Measure(meas) => {
write!(f, "measure ")?;
for (i, (q, c)) in meas.qubits.iter().zip(&meas.targets).enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{q} -> {c}")?;
}
write!(f, ";")
}
Self::Reset(qubits) => {
write!(f, "reset ")?;
for (i, q) in qubits.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{q}")?;
}
write!(f, ";")
}
Self::Barrier(qubits) => {
write!(f, "barrier")?;
if !qubits.is_empty() {
write!(f, " ")?;
for (i, q) in qubits.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{q}")?;
}
}
write!(f, ";")
}
Self::Assignment(var, expr) => write!(f, "{var} = {expr};"),
Self::If(cond, stmt) => write!(f, "if ({cond}) {stmt}"),
Self::For(for_loop) => {
writeln!(
f,
"for {} in [{}:{}] {{",
for_loop.variable, for_loop.start, for_loop.end
)?;
for stmt in &for_loop.body {
writeln!(f, " {stmt}")?;
}
write!(f, "}}")
}
Self::While(cond, body) => {
writeln!(f, "while ({cond}) {{")?;
for stmt in body {
writeln!(f, " {stmt}")?;
}
write!(f, "}}")
}
Self::Call(name, args) => {
write!(f, "{name}(")?;
for (i, arg) in args.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{arg}")?;
}
write!(f, ");")
}
Self::Delay(duration, qubits) => {
write!(f, "delay[{duration}]")?;
if !qubits.is_empty() {
write!(f, " ")?;
for (i, q) in qubits.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{q}")?;
}
}
write!(f, ";")
}
}
}
}
impl fmt::Display for QasmGate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(ctrl) = self.control {
write!(f, "ctrl({ctrl}) ")?;
}
if self.inverse {
write!(f, "inv ")?;
}
if let Some(power) = &self.power {
write!(f, "pow({power}) ")?;
}
write!(f, "{}", self.name)?;
if !self.params.is_empty() {
write!(f, "(")?;
for (i, param) in self.params.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{param}")?;
}
write!(f, ")")?;
}
write!(f, " ")?;
for (i, qubit) in self.qubits.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{qubit}")?;
}
write!(f, ";")
}
}
impl fmt::Display for QubitRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Single { register, index } => write!(f, "{register}[{index}]"),
Self::Slice {
register,
start,
end,
} => write!(f, "{register}[{start}:{end}]"),
Self::Register(name) => write!(f, "{name}"),
}
}
}
impl fmt::Display for ClassicalRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Single { register, index } => write!(f, "{register}[{index}]"),
Self::Slice {
register,
start,
end,
} => write!(f, "{register}[{start}:{end}]"),
Self::Register(name) => write!(f, "{name}"),
}
}
}
impl fmt::Display for Expression {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Literal(lit) => write!(f, "{lit}"),
Self::Variable(name) => write!(f, "{name}"),
Self::Binary(op, left, right) => write!(f, "({left} {op} {right})"),
Self::Unary(op, expr) => write!(f, "({op}{expr})"),
Self::Function(name, args) => {
write!(f, "{name}(")?;
for (i, arg) in args.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{arg}")?;
}
write!(f, ")")
}
Self::Index(name, idx) => write!(f, "{name}[{idx}]"),
}
}
}
impl fmt::Display for Literal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Integer(n) => write!(f, "{n}"),
Self::Float(x) => write!(f, "{x}"),
Self::Bool(b) => write!(f, "{b}"),
Self::String(s) => write!(f, "\"{s}\""),
Self::Pi => write!(f, "pi"),
Self::Euler => write!(f, "e"),
Self::Tau => write!(f, "tau"),
}
}
}
impl fmt::Display for BinaryOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let op = match self {
Self::Add => "+",
Self::Sub => "-",
Self::Mul => "*",
Self::Div => "/",
Self::Mod => "%",
Self::Pow => "**",
Self::Eq => "==",
Self::Ne => "!=",
Self::Lt => "<",
Self::Le => "<=",
Self::Gt => ">",
Self::Ge => ">=",
Self::And => "&&",
Self::Or => "||",
Self::Xor => "^^",
Self::BitAnd => "&",
Self::BitOr => "|",
Self::BitXor => "^",
Self::Shl => "<<",
Self::Shr => ">>",
};
write!(f, "{op}")
}
}
impl fmt::Display for UnaryOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let op = match self {
Self::Neg => "-",
Self::Not => "!",
Self::BitNot => "~",
Self::Sin => "sin",
Self::Cos => "cos",
Self::Tan => "tan",
Self::Asin => "asin",
Self::Acos => "acos",
Self::Atan => "atan",
Self::Exp => "exp",
Self::Ln => "ln",
Self::Sqrt => "sqrt",
};
write!(f, "{op}")
}
}
impl fmt::Display for Condition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {} {}", self.left, self.op, self.right)
}
}
impl fmt::Display for ComparisonOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let op = match self {
Self::Eq => "==",
Self::Ne => "!=",
Self::Lt => "<",
Self::Le => "<=",
Self::Gt => ">",
Self::Ge => ">=",
};
write!(f, "{op}")
}
}