pub mod conditional_without_measurement;
pub mod double_measurement;
pub mod op_after_measurement;
pub mod oversized_circuit;
pub mod unmanipulated_qubits;
pub mod unmeasurable_qubits;
use core::ops::Range;
use std::collections::HashMap;
use oq3_syntax::{
ast::{
AstChildren, Expr, GateOperand, HasName, Identifier, IndexKind, IndexedIdentifier,
LiteralKind, Stmt,
},
AstNode,
};
pub(crate) fn contains_or_equal(operand: &GateOperand, other_operand: &GateOperand) -> bool {
fn contains(identifier: &Identifier, indexed_identifier: &IndexedIdentifier) -> bool {
identifier.ident_token().unwrap().text()
== indexed_identifier
.identifier()
.unwrap()
.ident_token()
.unwrap()
.text()
}
match (operand, other_operand) {
(GateOperand::Identifier(q1), GateOperand::IndexedIdentifier(q2)) => contains(q1, q2),
(GateOperand::IndexedIdentifier(q1), GateOperand::Identifier(q2)) => contains(q2, q1),
(GateOperand::Identifier(q1), GateOperand::Identifier(q2)) => {
q1.ident_token().unwrap().text() == q2.ident_token().unwrap().text()
}
(GateOperand::IndexedIdentifier(q1), GateOperand::IndexedIdentifier(q2)) => {
if let Some(q1_index) = q1.index_operators().next().unwrap().index_kind()
&& let Some(q2_index) = q2.index_operators().next().unwrap().index_kind()
&& let IndexKind::ExpressionList(q1_index) = q1_index
&& let IndexKind::ExpressionList(q2_index) = q2_index
{
q1_index.exprs().zip(q2_index.exprs()).all(|(e1, e2)| {
if let Expr::Literal(index1) = e1
&& let Expr::Literal(index2) = e2
&& let LiteralKind::IntNumber(index1) = index1.kind()
&& let LiteralKind::IntNumber(index2) = index2.kind()
{
index1.value().unwrap() == index2.value().unwrap()
} else {
false
}
}) && q1.identifier().unwrap().ident_token().unwrap().text()
== q2.identifier().unwrap().ident_token().unwrap().text()
} else {
false
}
}
_ => false,
}
}
pub(crate) fn collect_qubits(stmts: AstChildren<Stmt>) -> HashMap<String, (usize, Range<usize>)> {
let mut qubits = HashMap::new();
for stmt in stmts.clone() {
if let Stmt::QuantumDeclarationStatement(declaration) = stmt.clone()
&& let Some(qubit) = declaration.qubit_type()
&& let Some(bits_name) = declaration.name()
&& let Some(designator) = qubit.designator()
&& let Some(expr) = designator.expr()
&& let Expr::Literal(bits) = expr
{
let num_qubits = bits.to_string().parse::<usize>().unwrap();
let qubits_range: Range<usize> = stmt.syntax().text_range().into();
qubits.insert(bits_name.to_string(), (num_qubits, qubits_range));
}
}
qubits
}
pub(crate) fn collect_clbits(stmts: AstChildren<Stmt>) -> HashMap<String, (usize, Range<usize>)> {
let mut clbits = HashMap::new();
for stmt in stmts.clone() {
if let Stmt::ClassicalDeclarationStatement(declaration) = stmt.clone()
&& let Some(qubit) = declaration.scalar_type()
&& let Some(bits_name) = declaration.name()
&& let Some(designator) = qubit.designator()
&& let Some(expr) = designator.expr()
&& let Expr::Literal(bits) = expr
{
let num_clbits = bits.to_string().parse::<usize>().unwrap();
let clbits_range: Range<usize> = stmt.syntax().text_range().into();
clbits.insert(bits_name.to_string(), (num_clbits, clbits_range));
}
}
clbits
}
pub(crate) type ManipulatedQubits = HashMap<String, Vec<bool>>;
pub(crate) fn mark_manipulated_qubits(
manipulated_qubits: &mut ManipulatedQubits,
operand: &GateOperand,
) {
match operand.clone() {
GateOperand::IndexedIdentifier(indexed_identifier) => {
let qubit_name = indexed_identifier
.identifier()
.unwrap()
.ident_token()
.unwrap();
for operator in indexed_identifier.index_operators() {
if let Some(kind) = operator.index_kind()
&& let IndexKind::ExpressionList(list) = kind
{
for expr in list.exprs() {
if let Expr::Literal(literal) = expr {
let qubit_index =
literal.syntax().to_string().parse::<usize>().unwrap();
manipulated_qubits.get_mut(qubit_name.text()).unwrap()[qubit_index] =
true;
}
}
}
}
}
GateOperand::Identifier(identifier) => {
let qubit_name = identifier.ident_token().unwrap();
manipulated_qubits.get_mut(qubit_name.text()).unwrap()[0] = true;
}
_ => {}
}
}