1use std::{
16 borrow::Borrow,
17 collections::{HashMap, HashSet},
18};
19
20#[cfg(not(feature = "python"))]
21use optipy::strip_pyo3;
22#[cfg(feature = "stubs")]
23use pyo3_stub_gen::derive::{gen_stub_pyclass, gen_stub_pymethods};
24
25use crate::instruction::{FrameAttributes, FrameDefinition, FrameIdentifier, Instruction, Qubit};
26
27#[derive(Clone, Debug, Default, PartialEq, Eq)]
29#[cfg_attr(feature = "stubs", gen_stub_pyclass)]
30#[cfg_attr(feature = "python", pyo3::pyclass(module = "quil.program", eq))]
31pub struct FrameSet {
32 pub(crate) frames: HashMap<FrameIdentifier, FrameAttributes>,
33}
34
35impl FrameSet {
36 pub fn get(&self, identifier: &FrameIdentifier) -> Option<&FrameAttributes> {
38 self.frames.get(identifier)
39 }
40
41 pub fn get_keys(&self) -> Vec<&FrameIdentifier> {
43 self.frames.keys().collect()
44 }
45
46 pub(crate) fn get_matching_keys_for_conditions<'s>(
47 &'s self,
48 condition: FrameMatchConditions,
49 ) -> MatchedFrames<'s> {
50 let used = condition
51 .used
52 .map_or_else(HashSet::new, |c| self.get_matching_keys_for_condition(c));
53
54 let blocked = condition.blocked.map_or_else(HashSet::new, |c| {
55 let mut blocked = self.get_matching_keys_for_condition(c);
56
57 if !used.is_empty() {
58 blocked.retain(|&f| !used.contains(&f));
59 }
60
61 blocked
62 });
63
64 MatchedFrames { used, blocked }
65 }
66
67 pub(crate) fn get_matching_keys_for_condition<'s>(
71 &'s self,
72 condition: FrameMatchCondition,
73 ) -> HashSet<&'s FrameIdentifier> {
74 let keys = self.frames.keys();
75
76 match condition {
77 FrameMatchCondition::All => keys.collect(),
78 FrameMatchCondition::AnyOfNames(names) => {
79 keys.filter(|&f| names.contains(f.name.as_str())).collect()
80 }
81 FrameMatchCondition::AnyOfQubits(qubits) => keys
82 .filter(|&f| f.qubits.iter().any(|q| qubits.contains(&q)))
83 .collect(),
84 FrameMatchCondition::ExactQubits(qubits) => keys
85 .filter(|&f| f.qubits.iter().collect::<HashSet<_>>() == qubits)
86 .collect(),
87 FrameMatchCondition::Specific(frame) => {
88 if let Some((frame, _)) = self.frames.get_key_value(frame) {
91 HashSet::from([frame])
92 } else {
93 HashSet::new()
94 }
95 }
96 FrameMatchCondition::And(conditions) => conditions
97 .into_iter()
98 .map(|c| self.get_matching_keys_for_condition(c))
99 .reduce(|acc, el| acc.into_iter().filter(|&v| el.contains(v)).collect())
100 .unwrap_or_default(),
101 FrameMatchCondition::Or(conditions) => conditions
102 .into_iter()
103 .flat_map(|c| self.get_matching_keys_for_condition(c))
104 .collect(),
105 }
106 }
107
108 pub fn intersection<T>(&self, identifiers: &HashSet<T>) -> Self
110 where
111 T: Borrow<FrameIdentifier> + Eq + std::hash::Hash,
112 {
113 let mut new_frameset = Self::new();
114
115 for (identifier, definition) in &self.frames {
116 if identifiers.contains(identifier) {
117 new_frameset.insert(identifier.clone(), definition.clone())
118 }
119 }
120
121 new_frameset
122 }
123
124 pub fn iter(&self) -> std::collections::hash_map::Iter<'_, FrameIdentifier, FrameAttributes> {
126 self.frames.iter()
127 }
128
129 pub fn into_instructions(self) -> Vec<Instruction> {
131 self.frames
132 .into_iter()
133 .map(|(identifier, attributes)| {
134 Instruction::FrameDefinition(FrameDefinition {
135 identifier,
136 attributes,
137 })
138 })
139 .collect()
140 }
141}
142
143#[cfg_attr(feature = "stubs", gen_stub_pymethods)]
144#[cfg_attr(feature = "python", pyo3::pymethods)]
145#[cfg_attr(not(feature = "python"), strip_pyo3)]
146impl FrameSet {
147 #[new]
148 pub fn new() -> Self {
149 Self::default()
150 }
151
152 pub fn insert(&mut self, identifier: FrameIdentifier, attributes: FrameAttributes) {
154 self.frames.insert(identifier, attributes);
155 }
156
157 pub fn merge(&mut self, other: FrameSet) {
159 self.frames.extend(other.frames);
160 }
161
162 #[pyo3(name = "__len__")]
164 pub fn len(&self) -> usize {
165 self.frames.len()
166 }
167
168 pub fn is_empty(&self) -> bool {
170 self.frames.is_empty()
171 }
172
173 pub fn to_instructions(&self) -> Vec<Instruction> {
175 self.frames
176 .iter()
177 .map(|(identifier, attributes)| {
178 Instruction::FrameDefinition(FrameDefinition {
179 identifier: identifier.clone(),
180 attributes: attributes.clone(),
181 })
182 })
183 .collect()
184 }
185}
186
187#[derive(Debug)]
188pub(crate) enum FrameMatchCondition<'a> {
189 All,
191
192 AnyOfNames(HashSet<&'a str>),
194
195 AnyOfQubits(HashSet<&'a Qubit>),
197
198 ExactQubits(HashSet<&'a Qubit>),
200
201 Specific(&'a FrameIdentifier),
203
204 And(Vec<FrameMatchCondition<'a>>),
206
207 Or(Vec<FrameMatchCondition<'a>>),
209}
210
211pub(crate) struct FrameMatchConditions<'a> {
215 pub used: Option<FrameMatchCondition<'a>>,
220
221 pub blocked: Option<FrameMatchCondition<'a>>,
229}
230
231#[derive(Clone, PartialEq, Eq, Debug, Default)]
237pub struct MatchedFrames<'a> {
238 pub blocked: HashSet<&'a FrameIdentifier>,
242
243 pub used: HashSet<&'a FrameIdentifier>,
247}
248
249impl MatchedFrames<'_> {
250 pub fn new() -> Self {
251 Self::default()
252 }
253}