use crate::circuit::{Operation, Parameter, ValueInstruction, ValueOperation};
use crate::compile::commutation::{CommutationChecker, CommutationConfig};
use smallvec::SmallVec;
use std::collections::HashMap;
pub(crate) struct OperationView<'a> {
pub(crate) order: usize,
pub(crate) operation: &'a Operation,
pub(crate) params: SmallVec<[Parameter; 3]>,
}
impl<'a> OperationView<'a> {
pub(crate) fn new(
order: usize,
operation: &'a Operation,
params: SmallVec<[Parameter; 3]>,
) -> Self {
Self {
order,
operation,
params,
}
}
}
pub(crate) struct CachedCommutation {
checker: CommutationChecker,
cache: HashMap<(usize, usize), bool>,
exact_only: bool,
}
impl CachedCommutation {
pub(crate) fn new(config: CommutationConfig) -> Self {
Self {
checker: CommutationChecker::with_config(config),
cache: HashMap::new(),
exact_only: true,
}
}
pub(crate) fn commute_ops(&mut self, lhs: &OperationView<'_>, rhs: &OperationView<'_>) -> bool {
if lhs.order == rhs.order {
return true;
}
let key = if lhs.order <= rhs.order {
(lhs.order, rhs.order)
} else {
(rhs.order, lhs.order)
};
if let Some(result) = self.cache.get(&key) {
return *result;
}
let result = self
.checker
.check(
&lhs.operation.instruction,
&lhs.operation.qubits,
&lhs.params,
&rhs.operation.instruction,
&rhs.operation.qubits,
&rhs.params,
)
.is_some_and(|commutation| !self.exact_only || commutation.is_exact());
self.cache.insert(key, result);
result
}
pub(crate) fn replacements_commute_with_crossed(
&self,
crossed: &[&OperationView<'_>],
replacements: &[ValueOperation],
) -> bool {
for crossed_op in crossed {
for replacement in replacements {
if !crossed_op
.operation
.qubits
.iter()
.any(|qubit| replacement.qubits.contains(qubit))
{
continue;
}
if !self.replacement_commutes_with_op(crossed_op, replacement) {
return false;
}
}
}
true
}
pub(crate) fn commute_ops_skip_cache(
&self,
lhs: &OperationView<'_>,
rhs: &OperationView<'_>,
) -> bool {
if lhs.order == rhs.order {
return true;
}
self.checker
.check(
&lhs.operation.instruction,
&lhs.operation.qubits,
&lhs.params,
&rhs.operation.instruction,
&rhs.operation.qubits,
&rhs.params,
)
.is_some_and(|commutation| !self.exact_only || commutation.is_exact())
}
pub(crate) fn commute_ops_rechecked(
&self,
lhs: &OperationView<'_>,
rhs: &OperationView<'_>,
) -> bool {
if lhs.order == rhs.order {
return true;
}
let key = if lhs.order <= rhs.order {
(lhs.order, rhs.order)
} else {
(rhs.order, lhs.order)
};
self.cache
.get(&key)
.copied()
.unwrap_or_else(|| self.commute_ops_skip_cache(lhs, rhs))
}
fn replacement_commutes_with_op(
&self,
operation: &OperationView<'_>,
replacement: &ValueOperation,
) -> bool {
let replacement_instruction = match &replacement.instruction {
ValueInstruction::Instruction(instruction) => instruction,
ValueInstruction::ClassicalControl(_) => return false,
};
let replacement_params = replacement
.params
.iter()
.map(Parameter::from)
.collect::<SmallVec<[Parameter; 3]>>();
self.checker
.check(
&operation.operation.instruction,
&operation.operation.qubits,
&operation.params,
replacement_instruction,
&replacement.qubits,
&replacement_params,
)
.is_some_and(|commutation| !self.exact_only || commutation.is_exact())
}
#[cfg(test)]
pub(super) fn cache_len(&self) -> usize {
self.cache.len()
}
}
#[cfg(test)]
#[path = "commutation_test.rs"]
mod commutation_test;