use std::{
borrow::Borrow,
collections::{HashMap, HashSet},
};
#[cfg(not(feature = "python"))]
use optipy::strip_pyo3;
#[cfg(feature = "stubs")]
use pyo3_stub_gen::derive::{gen_stub_pyclass, gen_stub_pymethods};
use crate::instruction::{FrameAttributes, FrameDefinition, FrameIdentifier, Instruction, Qubit};
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "stubs", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyo3::pyclass(module = "quil.program", eq))]
pub struct FrameSet {
pub(crate) frames: HashMap<FrameIdentifier, FrameAttributes>,
}
impl FrameSet {
pub fn get(&self, identifier: &FrameIdentifier) -> Option<&FrameAttributes> {
self.frames.get(identifier)
}
pub fn get_keys(&self) -> Vec<&FrameIdentifier> {
self.frames.keys().collect()
}
pub(crate) fn filter<'s>(&'s self, condition: FrameMatchConditions) -> MatchedFrames<'s> {
let used = condition
.used
.map_or_else(HashSet::new, |c| self.get_matching_keys_for_condition(c));
let blocked = condition.blocked.map_or_else(HashSet::new, |c| {
let mut blocked = self.get_matching_keys_for_condition(c);
if !used.is_empty() {
blocked.retain(|&f| !used.contains(&f));
}
blocked
});
MatchedFrames { used, blocked }
}
pub(crate) fn get_matching_keys_for_condition<'s>(
&'s self,
condition: FrameMatchCondition,
) -> HashSet<&'s FrameIdentifier> {
let keys = self.frames.keys();
match condition {
FrameMatchCondition::All => keys.collect(),
FrameMatchCondition::AnyOfNames(names) => {
keys.filter(|&f| names.contains(f.name.as_str())).collect()
}
FrameMatchCondition::AnyOfQubits(qubits) => keys
.filter(|&f| f.qubits.iter().any(|q| qubits.contains(&q)))
.collect(),
FrameMatchCondition::ExactQubits(qubits) => keys
.filter(|&f| f.qubits.iter().collect::<HashSet<_>>() == qubits)
.collect(),
FrameMatchCondition::Specific(frame) => {
if let Some((frame, _)) = self.frames.get_key_value(frame) {
HashSet::from([frame])
} else {
HashSet::new()
}
}
FrameMatchCondition::And(conditions) => conditions
.into_iter()
.map(|c| self.get_matching_keys_for_condition(c))
.reduce(|acc, el| acc.into_iter().filter(|&v| el.contains(v)).collect())
.unwrap_or_default(),
FrameMatchCondition::Or(conditions) => conditions
.into_iter()
.flat_map(|c| self.get_matching_keys_for_condition(c))
.collect(),
}
}
pub fn intersection<T>(&self, identifiers: &HashSet<T>) -> Self
where
T: Borrow<FrameIdentifier> + Eq + std::hash::Hash,
{
let mut new_frameset = Self::new();
for (identifier, definition) in &self.frames {
if identifiers.contains(identifier) {
new_frameset.insert(identifier.clone(), definition.clone())
}
}
new_frameset
}
pub fn iter(&self) -> std::collections::hash_map::Iter<'_, FrameIdentifier, FrameAttributes> {
self.frames.iter()
}
pub fn into_instructions(self) -> Vec<Instruction> {
self.frames
.into_iter()
.map(|(identifier, attributes)| {
Instruction::FrameDefinition(FrameDefinition {
identifier,
attributes,
})
})
.collect()
}
}
#[cfg_attr(feature = "stubs", gen_stub_pymethods)]
#[cfg_attr(feature = "python", pyo3::pymethods)]
#[cfg_attr(not(feature = "python"), strip_pyo3)]
impl FrameSet {
#[new]
pub fn new() -> Self {
Self::default()
}
pub fn insert(&mut self, identifier: FrameIdentifier, attributes: FrameAttributes) {
self.frames.insert(identifier, attributes);
}
pub fn merge(&mut self, other: FrameSet) {
self.frames.extend(other.frames);
}
#[pyo3(name = "__len__")]
pub fn len(&self) -> usize {
self.frames.len()
}
pub fn is_empty(&self) -> bool {
self.frames.is_empty()
}
pub fn to_instructions(&self) -> Vec<Instruction> {
self.frames
.iter()
.map(|(identifier, attributes)| {
Instruction::FrameDefinition(FrameDefinition {
identifier: identifier.clone(),
attributes: attributes.clone(),
})
})
.collect()
}
}
#[derive(Debug)]
pub(crate) enum FrameMatchCondition<'a> {
All,
AnyOfNames(HashSet<&'a str>),
AnyOfQubits(HashSet<&'a Qubit>),
ExactQubits(HashSet<&'a Qubit>),
Specific(&'a FrameIdentifier),
And(Vec<FrameMatchCondition<'a>>),
Or(Vec<FrameMatchCondition<'a>>),
}
pub(crate) struct FrameMatchConditions<'a> {
pub used: Option<FrameMatchCondition<'a>>,
pub blocked: Option<FrameMatchCondition<'a>>,
}
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct MatchedFrames<'a> {
pub blocked: HashSet<&'a FrameIdentifier>,
pub used: HashSet<&'a FrameIdentifier>,
}
impl MatchedFrames<'_> {
pub fn new() -> Self {
Self::default()
}
}