tree_automata/bottom_up/
width_search.rs

1use std::fmt;
2use terms::Term;
3use crate::{
4	Symbol,
5	State,
6	NoLabel,
7	bottom_up::{
8		Automaton,
9		Configuration,
10		// Configurations
11	}
12};
13
14#[derive(Debug, Clone, Copy)]
15pub struct Killed;
16
17pub trait LanguageState<F: Symbol, E: ?Sized>: State + Sized {
18	fn configurations<'a>(&self, env: &'a E) -> Box<dyn Iterator<Item = Configuration<F, Self>> + 'a>;
19}
20
21impl<F: Symbol, Q: State> LanguageState<F, Automaton<F, Q, NoLabel>> for Q {
22	fn configurations<'a>(&self, aut: &'a Automaton<F, Q, NoLabel>) -> Box<dyn Iterator<Item = Configuration<F, Self>> + 'a> {
23		Box::new(aut.configurations_for_state(self).map(|(conf, _)| conf.clone()))
24	}
25}
26
27impl<'e, F: Symbol, Q: State> LanguageState<F, [&'e Automaton<F, Q, NoLabel>]> for Indexed<Q> {
28	fn configurations<'a>(&self, automata: &'a [&'e Automaton<F, Q, NoLabel>]) -> Box<dyn Iterator<Item = Configuration<F, Self>> + 'a> {
29		let index = self.1;
30		let aut = automata[index];
31		Box::new(aut.configurations_for_state(&self.0).map(move |(conf, _)| {
32			let states = conf.states().iter().map(|q| Indexed((*q).clone(), index)).collect();
33			Configuration(conf.symbol().clone(), states)
34		}))
35	}
36}
37
38fn add_language_state<'a, F: Symbol, E, Q: LanguageState<F, E>>(q: Q, env: &'a E, aut: &mut Automaton<F, Q, NoLabel>) {
39	if !aut.includes(&q) {
40		for conf in q.configurations(env) {
41			aut.add(conf.clone(), NoLabel, q.clone());
42			for sub in conf.1.into_iter() {
43				add_language_state(sub, env, aut);
44			}
45		}
46	}
47}
48
49impl<'a, F: Symbol, E, Q: LanguageState<F, E>> From<(Q, &'a E)> for Automaton<F, Q, NoLabel> {
50	fn from((q, env): (Q, &'a E)) -> Automaton<F, Q, NoLabel> {
51		let mut aut = Automaton::new();
52		add_language_state(q.clone(), env, &mut aut);
53		aut.set_final(q);
54		aut
55	}
56}
57
58impl<'a, F: Symbol, Q: LanguageState<F, ()>> From<Q> for Automaton<F, Q, NoLabel> {
59	fn from(q: Q) -> Automaton<F, Q, NoLabel> {
60		let mut aut = Automaton::new();
61		add_language_state(q.clone(), &(), &mut aut);
62		aut.set_final(q);
63		aut
64	}
65}
66
67#[derive(Clone, Debug, Hash, PartialEq, Eq)]
68pub struct Indexed<Q: State>(pub Q, pub usize);
69
70impl<T: State + fmt::Display> fmt::Display for Indexed<T> {
71	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72		write!(f, "{}.{}", self.0, self.1)
73	}
74}
75
76#[cfg(not(debug_assertions))]
77pub trait SearchPattern<F: Symbol, Q: State, C: SearchContext>: Clone {
78	fn matches(&self, depth: usize, context: &C, q: &Q, configuration: &Configuration<F, Q>) -> Option<(C, Vec<Self>)>;
79}
80
81#[cfg(debug_assertions)]
82pub trait SearchPattern<F: Symbol, Q: State, C: SearchContext>: Clone + fmt::Display + fmt::Debug {
83	fn matches(&self, depth: usize, context: &C, q: &Q, configuration: &Configuration<F, Q>) -> Option<(C, Vec<Self>)>;
84}
85
86#[cfg(not(debug_assertions))]
87pub trait SearchContext: Clone {
88	fn looping(&self) -> bool;
89}
90
91#[cfg(debug_assertions)]
92pub trait SearchContext: Clone + fmt::Display + fmt::Debug {
93	fn looping(&self) -> bool;
94}
95
96#[derive(Hash, PartialEq, Eq)]
97struct Item<F: Symbol, Q: State, C, P>(Configuration<F, Q>, C, Vec<P>);
98
99impl<F: Symbol + fmt::Display, Q: State + fmt::Display, C: fmt::Display, P: fmt::Display> fmt::Debug for Item<F, Q, C, P> {
100	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101		write!(f, "({}/{}/{})", self.0, self.1, PList(&self.2))
102	}
103}
104
105/// A term fragment provides an iterator over the terms satisfying a given context.
106/// It performs a width-first search into the given automata.
107pub struct TermFragment<'a, E: ?Sized, F: Symbol, Q: LanguageState<F, E>, C: SearchContext, P: SearchPattern<F, Q, C>> {
108	env: &'a E,
109
110	/// Context
111	context: C,
112
113	/// Patterns
114	patterns: Vec<P>,
115
116	/// The leaves of the term fragment.
117	leaves: Vec<Q>,
118
119	/// Possible configurations for the leaves
120	leaves_configurations: Vec<Box<dyn Iterator<Item = Configuration<F, Q>> + 'a>>,
121
122	/// Current configurations.
123	current: Vec<Item<F, Q, C, P>>,
124
125	/// Current configurations, and next fragment.
126	next_fragment: Option<Box<TermFragment<'a, E, F, Q, C, P>>>,
127
128	/// Has it been visited yet? (has the `next` method been called at least once?)
129	/// This is important for the empty fragment. The `next` method must then return
130	/// Some(Vec::new()) this first time it is called, and None the rest of the time.
131	visited: bool,
132
133	/// The depth of the fragment.
134	depth: usize,
135
136	kill_signal: Option<crossbeam_channel::Receiver<()>>
137}
138
139impl<'a, E: ?Sized, F: Symbol, Q: LanguageState<F, E>, C: SearchContext, P: SearchPattern<F, Q, C>> TermFragment<'a, E, F, Q, C, P> {
140	pub fn new(env: &'a E, depth: usize, context: C, leaves: Vec<Q>, patterns: Vec<P>, kill_signal: Option<crossbeam_channel::Receiver<()>>) -> TermFragment<'a, E, F, Q, C, P> {
141		let leaves_configurations = if leaves.is_empty() {
142			Vec::new()
143		} else {
144			vec![leaves[0].configurations(env)]
145		};
146		TermFragment {
147			env,
148			context,
149			patterns,
150			leaves,
151			leaves_configurations,
152			current: Vec::new(),
153			next_fragment: None,
154			visited: false,
155			depth,
156			kill_signal
157		}
158	}
159}
160
161impl<'a, E: ?Sized, F: Symbol, Q: LanguageState<F, E>, C: SearchContext, P: SearchPattern<F, Q, C>> Iterator for TermFragment<'a, E, F, Q, C, P> {
162	type Item = Result<Vec<Term<F>>, Killed>;
163
164	fn next(&mut self) -> Option<Result<Vec<Term<F>>, Killed>> {
165		// #[cfg(debug_assertions)]
166		// println!("next: {}", self);
167
168		loop {
169			// Check if the search is canceled.
170			if let Some(kill_signal) = self.kill_signal.as_ref() {
171				if let Ok(()) = kill_signal.try_recv() {
172					return Some(Err(Killed))
173				}
174			}
175
176			if self.leaves.is_empty() {
177				if self.visited {
178					return None
179				} else {
180					self.visited = true;
181					return Some(Ok(Vec::new()))
182				}
183			} else {
184				let current_context = match self.current.last() {
185					Some(Item(_, context, _)) => context,
186					None => &self.context
187				};
188
189				if self.current.len() < self.leaves.len() {
190					let i = self.current.len();
191					let j = i + 1;
192
193					match self.leaves_configurations.last_mut().unwrap().next() {
194						Some(conf) => {
195							if let Some((next_context, sub_patterns)) = self.patterns[i].matches(self.depth, &current_context, &self.leaves[i], &conf) {
196								assert!(conf.states().len() == sub_patterns.len());
197								self.current.push(Item(conf, next_context, sub_patterns));
198
199								// println!("accepted: {:?}", self.current);
200
201								if j < self.leaves.len() {
202									let confs = self.leaves[j].configurations(self.env);
203									self.leaves_configurations.push(confs);
204								}
205							} else {
206								// println!("rejected: {:?} -- {}", self.current, conf)
207							}
208						},
209						None => {
210							if i > 0 {
211								self.current.pop();
212								self.leaves_configurations.pop();
213							} else {
214								return None
215							}
216						}
217					}
218				} else {
219					match self.next_fragment {
220						Some(ref mut frag) => {
221							match frag.next() {
222								Some(Err(Killed)) => return Some(Err(Killed)),
223								Some(Ok(mut sub_terms)) => {
224									sub_terms.reverse();
225									let mut terms = Vec::with_capacity(self.current.len());
226
227									for Item(Configuration(f, sub_states), _, _) in self.current.iter() {
228										let mut subs = Vec::with_capacity(sub_states.len());
229										for _ in sub_states.iter() {
230											subs.push(sub_terms.pop().unwrap());
231										}
232
233										terms.push(Term::new(f.clone(), subs))
234									}
235
236									return Some(Ok(terms))
237								},
238								None => {
239									// println!("not sub fragment.");
240									self.next_fragment = None;
241									self.current.pop();
242								}
243							}
244						},
245						None if !current_context.looping() => {
246							let mut leaves = Vec::new();
247							let mut patterns = Vec::new();
248							for Item(Configuration(_, sub_states), _, sub_patterns) in self.current.iter() {
249								for q in sub_states.iter() {
250									leaves.push(q.clone())
251								}
252
253								for p in sub_patterns.iter() {
254									patterns.push(p.clone())
255								}
256							}
257
258							let next_fragment = TermFragment::new(self.env, self.depth + 1, current_context.clone(), leaves, patterns, self.kill_signal.clone());
259							self.next_fragment = Some(Box::new(next_fragment))
260						},
261						None => { // loop detected
262							self.current.pop();
263						}
264					}
265				}
266			}
267		}
268	}
269}
270
271struct PList<'a, T: fmt::Display>(&'a [T]);
272
273impl<'a, T: fmt::Display> fmt::Display for PList<'a, T> {
274	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
275		match self.0.split_first() {
276			Some((head, tail)) => {
277				head.fmt(f)?;
278				for e in tail.iter() {
279					write!(f, ",")?;
280					e.fmt(f)?;
281				}
282				Ok(())
283			},
284			None => Ok(())
285		}
286	}
287}
288
289#[cfg(debug_assertions)]
290impl<'a, E: ?Sized, F: Symbol, Q: LanguageState<F, E>, C: SearchContext, P: SearchPattern<F, Q, C>> fmt::Display for TermFragment<'a, E, F, Q, C, P> {
291	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
292		write!(f, "({}) {} with context {}", PList(&self.patterns), PList(&self.leaves), self.context)
293	}
294}