razor_chase/chase/impl/
reference.rs

1//! Provides a fast implementation of the Chase by using references to elements of the model to
2//! avoid additional operations for equational reasoning.
3//!
4//! `chase::impl::reference` is an implementation of the [Chase] that uses references to [`E`]
5//! wrapped in [`Element`] as the [`Model`] elements. Using object references allows for a faster
6//! equational reasoning where the information content of a model does not need to be rewritten
7//! ([as in `basic`][basic]) when the model is augmented by an [`Identity`].
8//!
9//! [Chase]: ../../index.html#the-chase
10//! [`E`]: ../../struct.E.html
11//! [`Element`]: ./struct.Element.html
12//! [`Model`]: ./struct.Model.html
13//! [`Identity`]: ../../enum.Observation.html#variant.Identity
14//! [basic]: ../basic/struct.Model.html#method.reduce_rewrites
15use std::{
16    rc::Rc,
17    cell::Cell,
18    fmt,
19    collections::{HashMap, HashSet},
20    iter,
21    iter::FromIterator,
22    hash::{Hash, Hasher},
23    ops::Deref,
24};
25use razor_fol::syntax::{FApp, Term, V, C, F};
26use crate::chase::{
27    r#impl::basic,
28    E, Rel, Observation, EvaluateResult,
29    WitnessTermTrait, ModelTrait, StrategyTrait, EvaluatorTrait, BounderTrait,
30};
31use itertools::{Itertools, Either};
32
33/// Wraps a reference to [`E`] as the underlying [`ElementType`] of [`WitnessTerm`], used in the
34/// implementation of [`Model`].
35///
36/// [`E`]: ../../struct.E.html
37/// [`ElementType`]: ../../trait.WitnessTermTrait.html#associatedtype.ElementType
38/// [`WitnessTerm`]: ./enum.WitnessTerm.html
39/// [`Model`]: ./struct.Model.html
40#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
41pub struct Element(Rc<Cell<E>>);
42
43impl Element {
44    /// Creates a deep clone of the receiver by cloning the object [`E`] to which the internal
45    /// reference is pointing.
46    ///
47    /// **Note**: `deep_copy` is used when cloning a [`Model`] since identifying two elements in the
48    /// cloned model should not affect the original model and vise versa.
49    ///
50    /// [`E`]: ../../struct.E.html
51    /// [`Model`]: ./struct.Model.html
52    fn deep_clone(&self) -> Self {
53        Element::from(self.get())
54    }
55}
56
57impl From<E> for Element {
58    fn from(e: E) -> Self {
59        Self(Rc::new(Cell::new(e)))
60    }
61}
62
63impl Hash for Element {
64    fn hash<H: Hasher>(&self, state: &mut H) {
65        self.get().hash(state)
66    }
67}
68
69// `Element` derefs to its underlying `E`
70impl Deref for Element {
71    type Target = Rc<Cell<E>>;
72
73    fn deref(&self) -> &Self::Target {
74        &self.0
75    }
76}
77
78impl fmt::Debug for Element {
79    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80        write!(f, "{}", self.get().to_string())
81    }
82}
83
84/// Implements [`WitnessTermTrait`], with [`Element`] as the [`ElementType`] and serves as witness
85/// terms for [`Model`].
86///
87/// [`WitnessTermTrait`]: ../../trait.WitnessTermTrait.html
88/// [`Element`]: ./struct.Element.html
89/// [`ElementType`]: ../../trait.WitnessTermTrait.html#associatedtype.ElementType
90/// [`Model`]: ./struct.Model.html
91#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
92pub enum WitnessTerm {
93    /// Wraps an instance of [`Element`], witnessing itself.
94    ///
95    /// [`Element`]: ./struct.Element.html
96    Elem { element: Element },
97
98    /// Wraps an instance of [`C`] as a witness term.
99    ///
100    /// [`C`]: ../../../formula/syntax/struct.C.html
101    Const { constant: C },
102
103    /// Corresponds to a composite witness term, made by applying an instance of [`F`] to a list of
104    /// witness terms.
105    ///
106    /// [`F`]: ../../../formula/syntax/struct.F.html
107    App { function: F, terms: Vec<WitnessTerm> },
108}
109
110impl WitnessTerm {
111    /// Given a `term` and an assignment function `assign` from variables of the term to elements
112    /// of a [`Model`], constructs a [`WitnessTerm`].
113    ///
114    /// [`WitnessTerm`]: ./enum.WitnessTerm.html
115    /// [`Model`]: ./struct.Model.html
116    pub fn witness(term: &Term, lookup: &impl Fn(&V) -> Element) -> WitnessTerm {
117        match term {
118            Term::Const { constant } => WitnessTerm::Const { constant: constant.clone() },
119            Term::Var { variable } => WitnessTerm::Elem { element: lookup(&variable) },
120            Term::App { function, terms } => {
121                let terms = terms
122                    .iter()
123                    .map(|t| WitnessTerm::witness(t, lookup))
124                    .collect();
125                WitnessTerm::App { function: function.clone(), terms }
126            }
127        }
128    }
129}
130
131impl WitnessTermTrait for WitnessTerm {
132    type ElementType = Element;
133}
134
135impl fmt::Display for WitnessTerm {
136    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
137        match self {
138            WitnessTerm::Elem { element } => write!(f, "{}", element.get()),
139            WitnessTerm::Const { constant } => write!(f, "{}", constant),
140            WitnessTerm::App { function, terms } => {
141                let ts: Vec<String> = terms.iter().map(|t| t.to_string()).collect();
142                write!(f, "{}[{}]", function, ts.join(", "))
143            }
144        }
145    }
146}
147
148impl From<C> for WitnessTerm {
149    fn from(constant: C) -> Self {
150        WitnessTerm::Const { constant }
151    }
152}
153
154impl From<Element> for WitnessTerm {
155    fn from(element: Element) -> Self {
156        WitnessTerm::Elem { element }
157    }
158}
159
160impl FApp for WitnessTerm {
161    fn apply(function: F, terms: Vec<Self>) -> Self {
162        WitnessTerm::App { function, terms }
163    }
164}
165
166/// Is an instance of [`ModelTrait`] with terms of type [`WitnessTerm`], using references to [`E`]
167/// wrapped in objects of type [`Element`] for efficient equational reasoning.
168///
169/// [`ModelTrait`]: ../../trait.ModelTrait.html
170/// [`WitnessTerm`]: ./enum.WitnessTerm.html
171/// [`E`]: ../../struct.E.html
172/// [`Element`]: ./struct.Element.html
173pub struct Model {
174    /// Is a unique identifier for this model.
175    id: u64,
176
177    /// Keeps track of the next index to assign to a new element of this model.
178    element_index: i32,
179
180    /// Is the domain of this model, storing all elements of the model.
181    pub domain: HashSet<Element>,
182
183    /// Maps *flat* witness terms to elements of this model.
184    ///
185    /// **Hint**: Flat (witness) terms are terms that do not contain any composite sub-terms,
186    /// consisting of functions applications.
187    rewrites: HashMap<WitnessTerm, Element>,
188
189    /// Contains a list of relational facts that are true in this model.
190    facts: HashSet<Observation<WitnessTerm>>,
191
192    /// Maintains a list of rewrite rules from elements to elements with which they have been
193    /// identified.
194    ///
195    /// **Explanation**: When augmenting a model with a list of [observations] (such as observations
196    /// that come from the head of a sequent being evaluated), identity observations are
197    /// augmented by collapsing elements, that is, removing one element in favor of the other one.
198    /// However, other augmenting observations may still point to an element that was removed as a
199    /// result of augmenting an `Identity` observation.
200    ///
201    /// `equality_history` is used to keep track of identifications of elements temporarily during
202    /// the time a model is being augmented in a [chase-step]. `equality_history` in a model becomes
203    /// outdated after the [chase-step] ends.
204    ///
205    /// [observations]: ../../enum.Observation.html
206    /// [chase-step]: ../../index.html#chase-step
207    equality_history: HashMap<Element, Element>,
208}
209
210impl Model {
211    /// Creates a new empty instance of this model.
212    pub fn new() -> Self {
213        Self {
214            id: rand::random(),
215            element_index: 0,
216            domain: HashSet::new(),
217            rewrites: HashMap::new(),
218            facts: HashSet::new(),
219            equality_history: HashMap::new(),
220        }
221    }
222
223    /// Applies the rewrite rules in `equality_history` of the receiver to reduce an element to
224    /// the representative element of the equational class to which it belongs.
225    fn history(&self, element: &Element) -> Element {
226        let mut result = element;
227        let mut next;
228        while {
229            next = self.equality_history.get(result);
230            next.is_some() && next.unwrap() != result
231        } { result = next.unwrap() }
232
233        result.clone()
234    }
235
236    /// Creates a new element for the given `witness`, appends the element to the domain of the
237    /// model and records that `witness` denotes the new element.
238    fn new_element(&mut self, witness: WitnessTerm) -> Element {
239        let element = Element::from(E(self.element_index));
240        self.element_index = self.element_index + 1;
241        self.domain.insert(element.clone());
242        self.rewrites.insert(witness, element.clone());
243        element
244    }
245
246    /// Records the given `witness` in the receiver model and returns the element, denoted by
247    /// `witness`.
248    ///
249    /// **Note**: `record` creates new elements that are denoted by `witness` and all sub-terms of
250    /// `witness` and adds them to the domain of the receiver.
251    fn record(&mut self, witness: &WitnessTerm) -> Element {
252        match witness {
253            WitnessTerm::Elem { element } => {
254                let element = self.history(element);
255                self.domain.iter().find(|e| element.eq(e)).unwrap().clone()
256            }
257            WitnessTerm::Const { .. } => {
258                if let Some(e) = self.rewrites.get(&witness) {
259                    e.clone()
260                } else {
261                    self.new_element(witness.clone())
262                }
263            }
264            WitnessTerm::App { function, terms } => {
265                let terms: Vec<WitnessTerm> = terms
266                    .into_iter()
267                    .map(|t| self.record(t).into())
268                    .collect();
269                let witness = WitnessTerm::App { function: function.clone(), terms };
270                if let Some(e) = self.rewrites.get(&witness) {
271                    (*e).clone()
272                } else {
273                    self.new_element(witness)
274                }
275            }
276        }
277    }
278}
279
280impl ModelTrait for Model {
281    type TermType = WitnessTerm;
282
283    fn get_id(&self) -> u64 { self.id }
284
285    fn domain(&self) -> Vec<&Element> {
286        self.domain.iter().unique().collect()
287    }
288
289    fn facts(&self) -> Vec<&Observation<Self::TermType>> {
290        self.facts.iter().sorted().into_iter().dedup().collect()
291    }
292
293    fn observe(&mut self, observation: &Observation<Self::TermType>) {
294        match observation {
295            Observation::Fact { relation, terms } => {
296                let terms: Vec<WitnessTerm> = terms.into_iter().map(|t| self.record(t).into()).collect();
297                let observation = Observation::Fact { relation: relation.clone(), terms };
298                self.facts.insert(observation);
299            }
300            Observation::Identity { left, right } => {
301                let left = self.record(left);
302                let right = self.record(right);
303                let (src, dest) = if left > right {
304                    (right, left)
305                } else {
306                    (left, right)
307                };
308                self.equality_history.insert(dest.deep_clone(), src.deep_clone());
309                dest.replace(src.get());
310            }
311        }
312    }
313
314    fn is_observed(&self, observation: &Observation<Self::TermType>) -> bool {
315        match observation {
316            Observation::Fact { relation, terms } => {
317                let terms: Vec<Option<&Element>> = terms.iter().map(|t| self.element(t)).collect();
318                if terms.iter().any(|e| e.is_none()) {
319                    false
320                } else {
321                    let terms: Vec<WitnessTerm> = terms
322                        .into_iter()
323                        .map(|e| e.unwrap().clone().into())
324                        .collect();
325                    let obs = Observation::Fact { relation: relation.clone(), terms };
326                    self.facts.iter().find(|f| obs.eq(f)).is_some()
327                }
328            }
329            Observation::Identity { left, right } => {
330                let left = self.element(left);
331                left.is_some() && left == self.element(right)
332            }
333        }
334    }
335
336    fn witness(&self, element: &Element) -> Vec<&Self::TermType> {
337        self.rewrites.iter()
338            .filter(|(_, e)| (*e).eq(element))
339            .map(|(t, _)| t)
340            .sorted()
341            .into_iter()
342            .dedup()
343            .collect()
344    }
345
346    fn element(&self, witness: &Self::TermType) -> Option<&Element> {
347        match witness {
348            WitnessTerm::Elem { element } => {
349                self.domain.iter().find(|e| e == &element)
350            }
351            WitnessTerm::Const { .. } => self.rewrites.get(witness),
352            WitnessTerm::App { function, terms } => {
353                let terms: Vec<Option<&Element>> = terms.iter().map(|t| self.element(t)).collect();
354                if terms.iter().any(|e| e.is_none()) {
355                    None
356                } else {
357                    let terms: Vec<WitnessTerm> = terms
358                        .into_iter()
359                        .map(|e| e.unwrap().clone().into())
360                        .collect();
361                    self.rewrites.get(&WitnessTerm::App { function: (*function).clone(), terms })
362                }
363            }
364        }
365    }
366}
367
368impl Clone for Model {
369    fn clone(&self) -> Self {
370        let domain: HashSet<Element> = HashSet::from_iter(self.domain.iter().map(|e| e.deep_clone()));
371        let map_element = |e: &Element| domain.get(e).unwrap().clone();
372        let map_term = |w: &WitnessTerm| {
373            match w {
374                WitnessTerm::Elem { element } => WitnessTerm::Elem { element: map_element(element) },
375                WitnessTerm::Const { .. } => w.clone(),
376                WitnessTerm::App { function, terms } => {
377                    let terms = terms.iter().map(|t| {
378                        if let WitnessTerm::Elem { element } = t {
379                            WitnessTerm::Elem { element: map_element(element) }
380                        } else {
381                            panic!("something is wrong: expecting an element")
382                        }
383                    }).collect();
384                    WitnessTerm::App {
385                        function: function.clone(),
386                        terms,
387                    }
388                }
389            }
390        };
391        let map_observation = |o: &Observation<WitnessTerm>| {
392            if let Observation::Fact { relation, terms } = o {
393                Observation::Fact {
394                    relation: relation.clone(),
395                    terms: terms.iter().map(|t| map_term(t)).collect(),
396                }
397            } else {
398                panic!("something is wrong: expecting a fact")
399            }
400        };
401        let rewrites: HashMap<WitnessTerm, Element> = HashMap::from_iter(self.rewrites.iter().map(|(k, v)| {
402            (map_term(k), map_element(v))
403        }));
404        let facts: HashSet<Observation<WitnessTerm>> = HashSet::from_iter(self.facts.iter().map(|o| map_observation(o)));
405        Model {
406            id: rand::random(),
407            element_index: self.element_index,
408            domain,
409            rewrites,
410            facts,
411            // Because in the `chase::impl::batch` implementation, a model may be cloned multiple
412            // times during a chase step, `equality_history` needs to be cloned as well.
413            equality_history: self.equality_history.clone(),
414        }
415    }
416}
417
418impl fmt::Display for Model {
419    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
420        let domain: Vec<String> = self.domain().into_iter().map(|e| e.get().to_string()).collect();
421        let elements: Vec<String> = self.domain().iter().sorted().iter().map(|e| {
422            let witnesses: Vec<String> = self.witness(e).iter().map(|w| w.to_string()).collect();
423            let witnesses = witnesses.into_iter().sorted();
424            format!("{} -> {}", witnesses.into_iter().sorted().join(", "), e.get())
425        }).collect();
426        let facts: Vec<String> = self.facts().into_iter().map(|e| e.to_string()).collect();
427        write!(f, "Domain: {{{}}}\nElements:{}\nFacts: {}\n",
428               domain.join(", "),
429               elements.join(", "),
430               facts.join(", "))
431    }
432}
433
434/// Evaluates a [`Sequent`] in a [`Model`] within a [chase-step].
435///
436/// [`Sequent`]: ./struct.Sequent.html
437/// [`Model`]: ./struct.Model.html
438/// [chase-step]: ../../index.html#chase-step
439pub struct Evaluator {}
440
441impl<'s, Stg: StrategyTrait<Item=&'s Sequent>, B: BounderTrait> EvaluatorTrait<'s, Stg, B> for Evaluator {
442    type Sequent = Sequent;
443    type Model = Model;
444    fn evaluate(
445        &self,
446        initial_model: &Model,
447        strategy: &mut Stg,
448        bounder: Option<&B>
449    ) -> Option<EvaluateResult<Model>> {
450        let domain: Vec<&Element> = initial_model.domain();
451        let domain_size = domain.len();
452        for sequent in strategy {
453            let vars = &sequent.free_vars;
454            let vars_size = vars.len();
455            if domain_size == 0 && vars_size > 0 {
456                continue; // empty models can only be extended with sequents with no free variables.
457            }
458
459            // maintain a list of indices into the model elements to which variables are mapped
460            let mut assignment: Vec<usize> = iter::repeat(0).take(vars_size).collect();
461
462            // try all the variable assignments to the elements of the model
463            // (notice the do-while pattern)
464            while {
465                // construct a map from variables to elements
466                let mut assignment_map: HashMap<&V, Element> = HashMap::new();
467                for i in 0..vars_size {
468                    assignment_map.insert(vars.get(i).unwrap(), (*domain.get(assignment[i]).unwrap()).clone());
469                }
470                // construct a "characteristic function" for the assignment map
471                let assignment_func = |v: &V| assignment_map.get(v).unwrap().clone();
472
473                // lift the variable assignments to literals (used to make observations)
474                let observe_literal = make_observe_literal(assignment_func);
475
476                // build body and head observations
477                let body: Vec<Observation<WitnessTerm>> = sequent.body_literals
478                    .iter()
479                    .map(&observe_literal)
480                    .collect();
481                let head: Vec<Vec<Observation<WitnessTerm>>> = sequent.head_literals
482                    .iter()
483                    .map(|l| l.iter().map(&observe_literal).collect())
484                    .collect();
485
486                // if all body observations are true in the model but not all the head observations
487                // are true, extend the model:
488                if body.iter().all(|o| initial_model.is_observed(o))
489                    && !head.iter().any(|os| os.iter().all(|o| initial_model.is_observed(o))) {
490                    info!(event = crate::trace::EVALUATE, sequent = %sequent,mapping = ?assignment_map);
491
492                    if head.is_empty() {
493                        return None; // the chase fails if the head is empty (FALSE)
494                    } else {
495                        // if there is a bounder, only extend models that are not out of the given bound:
496                        let models: Vec<Either<Model, Model>> = if let Some(bounder) = bounder {
497                            let extend = make_bounded_extend(bounder, initial_model);
498                            head.iter().map(extend).collect()
499                        } else {
500                            let extend = make_extend(initial_model);
501                            head.iter().map(extend).collect()
502                        };
503
504                        let result = EvaluateResult::from(models);
505                        if !result.empty() {
506                            // this evaluator instantiates the first matching sequent with the first
507                            // matching assignment (unlike impl::batch.rs)
508                            return Some(result);
509                        }
510                    }
511                }
512
513                // try the next variable assignment
514                domain_size > 0 && next_assignment(&mut assignment, domain_size - 1)
515            } {}
516        }
517        Some(EvaluateResult::new()) // if none of the assignments apply, the model is complete already
518    }
519}
520
521// Returns a closure that returns a cloned extension of the given model, extended by a given set of
522// observations.
523fn make_extend<'m>(
524    model: &'m Model
525) -> impl FnMut(&'m Vec<Observation<WitnessTerm>>) -> Either<Model, Model>
526{
527    move |os: &'m Vec<Observation<WitnessTerm>>| {
528        let mut model = model.clone();
529        os.iter().foreach(|o| model.observe(o));
530        Either::Left(model)
531    }
532}
533
534// Returns a closure that returns a cloned extension of the given model, extended by a given set of
535// observations. Unlike `make_extend`, `make_bounded_extend` extends the model with respect to a
536// bounder: a model wrapped in `Either::Right` has not reached the bounds while a model wrapped in
537// `Either::Left` has reached the bounds provided by `bounder`.
538fn make_bounded_extend<'m, B: BounderTrait>(
539    bounder: &'m B,
540    model: &'m Model,
541) -> impl FnMut(&'m Vec<Observation<WitnessTerm>>) -> Either<Model, Model>
542{
543    move |os: &Vec<Observation<WitnessTerm>>| {
544        let mut model = model.clone();
545        let mut modified = false;
546        os.iter().foreach(|o| {
547            if bounder.bound(&model, o) {
548                if !model.is_observed(o) {
549                    modified = true;
550                }
551            } else {
552                if !model.is_observed(o) {
553                    model.observe(o);
554                }
555            }
556        });
557        if modified {
558            Either::Right(model)
559        } else {
560            Either::Left(model)
561        }
562    }
563}
564
565// Given an function from variables to elements of a model, returns a closure that lift the variable
566// assignments to literals of a sequent, returning observations.
567fn make_observe_literal(assignment_func: impl Fn(&V) -> Element)
568    -> impl Fn(&Literal) -> Observation<WitnessTerm> {
569    move |lit: &Literal| {
570        match lit {
571            basic::Literal::Atm { predicate, terms } => {
572                let terms = terms
573                    .into_iter()
574                    .map(|t| WitnessTerm::witness(t, &assignment_func))
575                    .collect();
576                Observation::Fact { relation: Rel(predicate.0.clone()), terms }
577            }
578            basic::Literal::Eql { left, right } => {
579                let left = WitnessTerm::witness(left, &assignment_func);
580                let right = WitnessTerm::witness(right, &assignment_func);
581                Observation::Identity { left, right }
582            }
583        }
584    }
585}
586
587// Implements a counter to enumerate all the possible assignments of a domain of elements to free
588// variables of a sequent. It mutates the given a list of indices, corresponding to mapping of each
589// position to an element of a domain to the next assignment. Returns true if a next assignment
590// exists and false otherwise.
591fn next_assignment(vec: &mut Vec<usize>, last: usize) -> bool {
592    let len = vec.len();
593    for i in 0..len {
594        if vec[i] != last {
595            vec[i] += 1;
596            return true;
597        } else {
598            vec[i] = 0;
599        }
600    }
601    false
602}
603
604/// Is a type synonym for [`basic::Sequent`].
605///
606/// **Note**: [`chase::impl::reference`] uses the same sequent type as [`chase::impl::basic`].
607///
608/// [`basic::Sequent`]: ../basic/struct.Sequent.html
609/// [`chase::impl::reference`]: ./index.html
610/// [`chase::impl::basic`]: ../basic/index.html
611pub type Sequent = basic::Sequent;
612
613/// Is a type synonym for [`basic::Literal`].
614///
615/// **Note**: [`chase::impl::reference`] uses the same sequent type as [`chase::impl::basic`].
616///
617/// [`basic::Literal`]: ../basic/struct.Literal.html
618/// [`chase::impl::reference`]: ./index.html
619/// [`chase::impl::basic`]: ../basic/index.html
620pub type Literal = basic::Literal;
621
622#[cfg(test)]
623mod test_reference {
624    use super::{Model, Sequent, Evaluator, next_assignment};
625    use razor_fol::syntax::Theory;
626    use crate::chase::{SchedulerTrait, StrategyTrait, strategy::{Bootstrap, Fair}
627                       , scheduler::FIFO, bounder::DomainSize, chase_all};
628    use crate::test_prelude::*;
629    use std::collections::HashSet;
630    use std::fs;
631
632    #[test]
633    fn test_next_assignment() {
634        {
635            let mut assignment = vec![];
636            assert_eq!(false, next_assignment(&mut assignment, 1));
637            assert!(assignment.is_empty());
638        }
639        {
640            let mut assignment = vec![0];
641            assert_eq!(true, next_assignment(&mut assignment, 1));
642            assert_eq!(vec![1], assignment);
643        }
644        {
645            let mut assignment = vec![1];
646            assert_eq!(false, next_assignment(&mut assignment, 1));
647            assert_eq!(vec![0], assignment);
648        }
649        {
650            let mut assignment = vec![0, 1];
651            assert_eq!(true, next_assignment(&mut assignment, 1));
652            assert_eq!(vec![1, 1], assignment);
653        }
654        {
655            let mut assignment = vec![1, 1];
656            assert_eq!(true, next_assignment(&mut assignment, 2));
657            assert_eq!(vec![2, 1], assignment);
658        }
659        {
660            let mut assignment = vec![2, 1];
661            assert_eq!(true, next_assignment(&mut assignment, 2));
662            assert_eq!(vec![0, 2], assignment);
663        }
664        {
665            let mut assignment = vec![2, 2];
666            assert_eq!(false, next_assignment(&mut assignment, 2));
667            assert_eq!(vec![0, 0], assignment);
668        }
669        {
670            let mut counter = 1;
671            let mut vec = vec![0, 0, 0, 0, 0];
672            while next_assignment(&mut vec, 4) {
673                counter += 1;
674            }
675            assert_eq!(3125, counter);
676        }
677    }
678
679    fn run_test(theory: &Theory) -> Vec<Model> {
680        let geometric_theory = theory.gnf();
681        let sequents: Vec<Sequent> = geometric_theory
682            .formulae
683            .iter()
684            .map(|f| f.into()).collect();
685
686        let evaluator = Evaluator {};
687        let strategy: Bootstrap<Sequent, Fair<Sequent>> = Bootstrap::new(sequents.iter().collect());
688        let mut scheduler = FIFO::new();
689        let bounder: Option<&DomainSize> = None;
690        scheduler.add(Model::new(), strategy);
691        chase_all(&mut scheduler, &evaluator, bounder)
692    }
693
694    #[test]
695    fn test() {
696        for item in fs::read_dir("../theories/core").unwrap() {
697            let theory = read_theory_from_file(item.unwrap().path().display().to_string().as_str());
698            let basic_models = solve_basic(&theory);
699            let test_models = run_test(&theory);
700            let basic_models: HashSet<String> = basic_models.into_iter().map(|m| print_basic_model(m)).collect();
701            let test_models: HashSet<String> = test_models.into_iter().map(|m| print_reference_model(m)).collect();
702            assert_eq!(basic_models, test_models);
703        }
704    }
705}