1use crate::{BottomUpTa, DetBottomUpTa, StateId, Symbol};
4use fixedbitset::FixedBitSet;
5use packed_term_arena::tree::{Tree, TreeArena};
6use smallvec::SmallVec;
7
8#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct DetRun {
14 pub states: Vec<StateId>,
16 pub root_state: StateId,
18}
19
20#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct StateSet<S>(SmallVec<[S; 4]>);
27
28impl<S> Default for StateSet<S> {
29 fn default() -> Self {
30 Self(SmallVec::new())
31 }
32}
33
34impl<S: Clone + Ord> StateSet<S> {
35 pub fn new() -> Self {
37 Self::default()
38 }
39
40 pub fn insert(&mut self, s: S) {
42 match self.0.binary_search(&s) {
43 Ok(_) => {}
44 Err(idx) => self.0.insert(idx, s),
45 }
46 }
47
48 pub fn iter(&self) -> impl Iterator<Item = &S> {
50 self.0.iter()
51 }
52
53 pub fn as_slice(&self) -> &[S] {
55 &self.0
56 }
57
58 pub fn is_empty(&self) -> bool {
60 self.0.is_empty()
61 }
62
63 pub fn len(&self) -> usize {
65 self.0.len()
66 }
67}
68
69#[derive(Clone, Debug, PartialEq, Eq)]
74pub struct NonDetRun<S> {
75 pub states: Vec<StateSet<S>>,
77 pub root_states: StateSet<S>,
79}
80
81pub fn run_det<A>(a: &A, arena: &TreeArena<Symbol>, root: Tree) -> DetRun
89where
90 A: DetBottomUpTa<State = StateId>,
91{
92 let mut states = vec![StateId::STUCK; arena.len()];
93 let mut visited = FixedBitSet::with_capacity(arena.len());
94 let mut buf: SmallVec<[StateId; 4]> = SmallVec::new();
95
96 for node in arena.post_order(root) {
97 if visited.contains(node.index()) {
98 continue;
99 }
100 visited.set(node.index(), true);
101
102 buf.clear();
103 let mut any_stuck = false;
104 for &child in arena.get_children(node) {
105 let cs = states[child.index()];
106 if cs.is_stuck() {
107 any_stuck = true;
108 break;
109 }
110 buf.push(cs);
111 }
112 if any_stuck {
113 continue;
114 }
115 states[node.index()] = a
116 .step_det(*arena.get_label(node), &buf)
117 .unwrap_or(StateId::STUCK);
118 }
119
120 DetRun {
121 root_state: states[root.index()],
122 states,
123 }
124}
125
126pub fn run_nondet<A>(a: &A, arena: &TreeArena<Symbol>, root: Tree) -> NonDetRun<A::State>
132where
133 A: BottomUpTa,
134 A::State: Ord,
135{
136 let mut states = vec![StateSet::new(); arena.len()];
137 let mut visited = FixedBitSet::with_capacity(arena.len());
138
139 for node in arena.post_order(root) {
140 if visited.contains(node.index()) {
141 continue;
142 }
143 visited.set(node.index(), true);
144
145 let local = {
146 let child_ids: SmallVec<[Tree; 4]> = arena.get_children(node).iter().copied().collect();
147 let mut pools: SmallVec<[&[A::State]; 4]> = SmallVec::new();
148 let mut any_empty = false;
149 for child in child_ids {
150 let set = &states[child.index()];
151 if set.is_empty() {
152 any_empty = true;
153 break;
154 }
155 pools.push(set.as_slice());
156 }
157 if any_empty {
158 None
159 } else {
160 let mut local = StateSet::new();
161 cartesian_product(&pools, |tuple| {
162 a.step(*arena.get_label(node), tuple, &mut |q| local.insert(q));
163 });
164 Some(local)
165 }
166 };
167
168 if let Some(local) = local {
169 states[node.index()] = local;
170 }
171 }
172
173 NonDetRun {
174 root_states: states[root.index()].clone(),
175 states,
176 }
177}
178
179pub(crate) fn cartesian_product<T: Clone>(pools: &[&[T]], mut f: impl FnMut(&[T])) {
180 if pools.iter().any(|pool| pool.is_empty()) {
181 return;
182 }
183 if pools.is_empty() {
184 f(&[]);
185 return;
186 }
187
188 let mut indices = vec![0; pools.len()];
189 let mut tuple: Vec<T> = pools.iter().map(|pool| pool[0].clone()).collect();
190
191 loop {
192 f(&tuple);
193
194 let mut pos = pools.len();
195 loop {
196 if pos == 0 {
197 return;
198 }
199 pos -= 1;
200 indices[pos] += 1;
201 if indices[pos] < pools[pos].len() {
202 tuple[pos] = pools[pos][indices[pos]].clone();
203 for reset in pos + 1..pools.len() {
204 indices[reset] = 0;
205 tuple[reset] = pools[reset][0].clone();
206 }
207 break;
208 }
209 }
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216 use crate::{ExplicitBuilder, Symbol};
217
218 #[test]
219 fn cartesian_empty_pools_is_unit() {
220 let mut tuples = Vec::<Vec<u8>>::new();
221 cartesian_product::<u8>(&[], |tuple| tuples.push(tuple.to_vec()));
222 assert_eq!(tuples, vec![vec![]]);
223 }
224
225 #[test]
226 fn cartesian_empty_member_is_empty() {
227 let a = [1, 2];
228 let b: [i32; 0] = [];
229 let mut count = 0;
230 cartesian_product(&[&a[..], &b[..]], |_| count += 1);
231 assert_eq!(count, 0);
232 }
233
234 #[test]
235 fn deterministic_run_accepts_tree() {
236 let a = Symbol(0);
237 let f = Symbol(1);
238 let mut builder = ExplicitBuilder::new();
239 let leaf = builder.new_state();
240 let root_state = builder.new_state();
241 builder.add_rule(a, vec![], leaf);
242 builder.add_rule(f, vec![leaf, leaf], root_state);
243 builder.add_accepting(root_state);
244 let automaton = builder.build();
245
246 let mut arena = TreeArena::new();
247 let left = arena.add_node(a, vec![]);
248 let right = arena.add_node(a, vec![]);
249 let root = arena.add_node(f, vec![left, right]);
250
251 let run = run_det(&automaton, &arena, root);
252 assert_eq!(run.root_state, root_state);
253 assert!(automaton.is_accepting(&run.root_state));
254 }
255
256 #[test]
257 fn nondeterministic_run_collects_states() {
258 let a = Symbol(0);
259 let mut builder = ExplicitBuilder::new();
260 let q0 = builder.new_state();
261 let q1 = builder.new_state();
262 builder.add_rule(a, vec![], q0);
263 builder.add_rule(a, vec![], q1);
264 let automaton = builder.build();
265 let mut arena = TreeArena::new();
266 let root = arena.add_node(a, vec![]);
267 let run = run_nondet(&automaton, &arena, root);
268 assert_eq!(run.root_states.len(), 2);
269 }
270
271 #[test]
272 fn deterministic_run_handles_shared_stuck_nodes() {
273 let leaf_symbol = Symbol(0);
274 let parent_symbol = Symbol(1);
275 let builder = ExplicitBuilder::new();
276 let automaton = builder.build();
277
278 let mut arena = TreeArena::new();
279 let shared = arena.add_node(leaf_symbol, vec![]);
280 let root = arena.add_node(parent_symbol, vec![shared, shared]);
281
282 let run = run_det(&automaton, &arena, root);
283 assert!(run.states[shared.index()].is_stuck());
284 assert!(run.root_state.is_stuck());
285 }
286}